Commit Diff


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 <sys/xattr.h>
 #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 */