commit 142ee1a6a87651c3b727ed2bfbacf231d8783a27 from: Sergey Bronnikov date: Tue Mar 02 10:54:16 2021 UTC Add FUSE wrapper for utimensat() Fixes #52 Closes #16 commit - 21cc568c69c3d3331993c72b5b36b6f8dfa9bcd1 commit + 142ee1a6a87651c3b727ed2bfbacf231d8783a27 blob - dd3ebd11438d2c890e629700699df429f832f6d5 blob + 4ff61ed78acad0a8b635930425a54000e6c24f0e --- CMakeLists.txt +++ CMakeLists.txt @@ -1,4 +1,7 @@ cmake_minimum_required (VERSION 3.10.2) + +include(CheckFunctionExists) + project (unreliablefs DESCRIPTION "A FUSE-based fault injection filesystem.") @@ -17,6 +20,11 @@ add_executable(${PROJECT_NAME} ${UNRELIABLEFS_SRC}) target_include_directories(${PROJECT_NAME} PRIVATE ${FUSE_INCLUDE_DIRS}) target_link_libraries(${PROJECT_NAME} ${FUSE_LIBRARIES}) +check_function_exists(utimensat HAVE_UTIMENSAT) +if (${HAVE_UTIMENSAT}) + target_compile_definitions(${PROJECT_NAME} PUBLIC HAVE_UTIMENSAT) +endif () + enable_testing() add_test(NAME pytest COMMAND pytest -c ${PROJECT_SOURCE_DIR}/tests/pytest.ini ${PROJECT_SOURCE_DIR}/tests/ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) blob - c50e3ca4a4d639a08c0031b66104f62b95db33b9 blob + 747bdb57e744d6830967dca557f2160d462abe83 --- tests/test_unreliablefs.py +++ tests/test_unreliablefs.py @@ -514,3 +514,36 @@ def test_flock(setup_unreliablefs): with open(mnt_name, 'w') as fh: fcntl.flock(fh, fcntl.LOCK_EX | fcntl.LOCK_NB) fcntl.flock(fh, fcntl.LOCK_UN) + +@pytest.mark.parametrize("symlink", (False, True)) +def test_utimens(setup_unreliablefs, symlink): + mnt_dir, src_dir = setup_unreliablefs + name = name_generator() + src_name = pjoin(src_dir, name) + mnt_name = pjoin(mnt_dir, name) + os_create(mnt_name) + linkname = name_generator() + link_path = os.path.join(mnt_dir, linkname) + os.symlink(mnt_name, link_path) + if symlink: + target = link_path + else: + target = mnt_name + + fstat = os.lstat(link_path) + link_atime = fstat.st_atime + link_mtime = fstat.st_mtime + + fstat = os.lstat(mnt_name) + mnt_name_atime = fstat.st_atime + 10 + mnt_name_mtime = fstat.st_mtime + 10 + os.utime(target, (mnt_name_atime, mnt_name_mtime)) + + fstat = os.lstat(mnt_name) + assert fstat.st_atime == mnt_name_atime + assert fstat.st_mtime == mnt_name_mtime + + if symlink: + fstat = os.lstat(link_path) + assert fstat.st_atime == link_atime + assert fstat.st_mtime == link_mtime blob - 634a6331e48b6b251701d956ab4b24a5c93351ce blob + cc0826a6abbfa403b1d8518fe2c2ec157978d90c --- unreliablefs.1 +++ unreliablefs.1 @@ -54,6 +54,7 @@ Supported file operations are: .Xr symlink 2 , .Xr truncate 2 , .Xr unlink 2 , +.Xr utimensat 2 , .Xr write 2 . .Pp Following functions are unsupported on OpenBSD: blob - 4c49e2c929e3e21b4186fb552ab01f2756f2ecd1 blob + e9ac458231bf34ae4c4ecfbc35e39c6f6409c2c2 --- unreliablefs.c +++ unreliablefs.c @@ -53,6 +53,9 @@ static struct fuse_operations unreliable_ops = { .flock = unreliable_flock, .fallocate = unreliable_fallocate, #endif /* __OpenBSD__ */ +#ifdef HAVE_UTIMENSAT + .utimens = unreliable_utimens, +#endif }; int main(int argc, char *argv[]) blob - c36cd92b912bb0d19595349075a9844ee785f9e2 blob + f416c6fd23aa5a038a7be649dacca2be8734a0c0 --- unreliablefs_ops.c +++ unreliablefs_ops.c @@ -13,6 +13,11 @@ #include #endif /* __OpenBSD__ */ +#ifdef linux +/* For pread()/pwrite()/utimensat() */ +#define _XOPEN_SOURCE 700 +#endif + #include "unreliablefs_errinj.h" #include "unreliablefs_ops.h" @@ -686,3 +691,21 @@ int unreliable_fallocate(const char *path, int mode, return 0; } #endif /* __OpenBSD__ */ + +#ifdef HAVE_UTIMENSAT +int unreliable_utimens(const char *path, const struct timespec ts[2]) +{ + int ret = error_inject(path, "utimens"); + if (ret) { + return ret; + } + + /* don't use utime/utimes since they follow symlinks */ + ret = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); + if (ret == -1) { + return -errno; + } + + return 0; +} +#endif blob - eaced3f65b1ae24d76b449d97d2df3f97babf0ae blob + 92b635ecae2da610402feb5f1ba53528f8e0c903 --- unreliablefs_ops.h +++ unreliablefs_ops.h @@ -62,4 +62,8 @@ int unreliable_fallocate(const char *, int, off_t, off struct fuse_file_info *); #endif /* __OpenBSD__ */ +#ifdef HAVE_UTIMENSAT +int unreliable_utimens(const char *path, const struct timespec ts[2]); +#endif + #endif /* UNRELIABLEFS_OPS_HH */