From: Waldemar Kozaczuk <[email protected]>
Committer: Waldemar Kozaczuk <[email protected]>
Branch: master

vfs: make sys_utimensat handle AT_SYMLINK_NOFOLLOW

This patch adds missing logic (marked by TODO) to handle AT_SYMLINK_NOFOLLOW
in the implementation of sys_utimensat().

We do it by extracting relevant code from sys_utimes() into
new helper function handle_symlink_nofollow() which is then reused
in both sys_utimes() and sys_utimensat().

Please note the tst-utimensat.cc has to be slightly adjusted with
ifdef to account for differences between how gibc and OSv libc handles
this case with utimensat():

"Force utimensat to fail when dirfd was AT_FDCWD and pathname is NULL"

Linux manual states this about when EFAULT errno is set:
"EFAULT times pointed to an invalid address; or, dirfd was
AT_FDCWD, and pathname is NULL or an invalid address.

Likewise, we also have to adjust tst-utimes.cc with ifdef to account
for differences between how utimes() called with invalid times argument
gets handled by glibc and OSv libc.

Changes in this patch and 8 previous patches make it possible
to run more unit tests on OSv with linux dynamic linker:

scripts/test.py --linux_ld -m modules/tests-with-linux-ld/usr.manifest \
      -d tst-kill \
      -d tst-pthread-clock \
      -d tst-sigaction \
      -d tst-sigwait \
      -d tst-stdio-rofs \
      -d tst-wctype

Signed-off-by: Waldemar Kozaczuk <[email protected]>

---
diff --git a/fs/vfs/vfs_syscalls.cc b/fs/vfs/vfs_syscalls.cc
--- a/fs/vfs/vfs_syscalls.cc
+++ b/fs/vfs/vfs_syscalls.cc
@@ -1248,41 +1248,52 @@ static void convert_timeval(struct timespec &to, const 
struct timeval *from)
     }
 }
 
-int
-sys_utimes(char *path, const struct timeval times[2], int flags)
+static int handle_symlink_nofollow(const char *path, int flags, struct dentry 
**dpp)
 {
     int error;
-    struct dentry *dp;
-    struct timespec timespec_times[2];
-
-    DPRINTF(VFSDB_SYSCALL, ("sys_utimes: path=%s\n", path));
-
-    if (times && (!is_timeval_valid(&times[0]) || 
!is_timeval_valid(&times[1])))
-        return EINVAL;
-
-    // Convert each element of timeval array to the timespec type
-    convert_timeval(timespec_times[0], times ? times + 0 : nullptr);
-    convert_timeval(timespec_times[1], times ? times + 1 : nullptr);
-
+    char *_path = const_cast<char *>(path);
     if (flags & AT_SYMLINK_NOFOLLOW) {
         struct dentry *ddp;
-        error = lookup(path, &ddp, nullptr);
+        error = lookup(_path, &ddp, nullptr);
         if (error) {
             return error;
         }
 
-        error = namei_last_nofollow(path, ddp, &dp);
+        error = namei_last_nofollow(_path, ddp, dpp);
         if (ddp != nullptr) {
             drele(ddp);
         }
         if (error) {
             return error;
         }
     } else {
-        error = namei(path, &dp);
+        error = namei(_path, dpp);
         if (error)
             return error;
     }
+    return 0;
+}
+
+int
+sys_utimes(char *path, const struct timeval times[2], int flags)
+{
+    int error;
+    struct dentry *dp;
+    struct timespec timespec_times[2];
+
+    DPRINTF(VFSDB_SYSCALL, ("sys_utimes: path=%s\n", path));
+
+    if (times && (!is_timeval_valid(&times[0]) || 
!is_timeval_valid(&times[1])))
+        return EINVAL;
+
+    // Convert each element of timeval array to the timespec type
+    convert_timeval(timespec_times[0], times ? times + 0 : nullptr);
+    convert_timeval(timespec_times[1], times ? times + 1 : nullptr);
+
+    error = handle_symlink_nofollow(path, flags, &dp);
+    if (error) {
+        return error;
+    }
 
     if (dp->d_mount->m_flags & MNT_RDONLY) {
         error = EROFS;
@@ -1367,12 +1378,10 @@ sys_utimensat(int dirfd, const char *pathname, const 
struct timespec times[2], i
        ap = std::string(fp->f_dentry->d_mount->m_path) + "/" + ap;
     }
 
-    /* FIXME: Add support for AT_SYMLINK_NOFOLLOW */
-
-    error = namei(ap.c_str(), &dp);
-
-    if (error)
+    error = handle_symlink_nofollow(ap.c_str(), flags, &dp);
+    if (error) {
         return error;
+    }
 
     if (dp->d_mount->m_flags & MNT_RDONLY) {
         error = EROFS;
diff --git a/tests/tst-utimensat.cc b/tests/tst-utimensat.cc
--- a/tests/tst-utimensat.cc
+++ b/tests/tst-utimensat.cc
@@ -100,9 +100,9 @@ int main(int argc, char *argv[])
     ret = utimensat(AT_FDCWD, rel_path_bar_to_tmp, times, 0);
     report(ret == 0, "utimensat worked successfully with AT_FDCWD");
 
-     /* Use dirfd and relative path of bar to check utimensat */
-     ret = utimensat(dirfd, rel_path_bar_to_foo, times, 0);
-     report(ret == 0, "utimensat works with dirfd and relative path");
+    /* Use dirfd and relative path of bar to check utimensat */
+    ret = utimensat(dirfd, rel_path_bar_to_foo, times, 0);
+    report(ret == 0, "utimensat works with dirfd and relative path");
 
     /* Force utimensat to fail using invalid dirfd */
     ret = utimensat(100, rel_path_bar_to_foo, times, 0);
@@ -114,15 +114,19 @@ int main(int argc, char *argv[])
 
     /* Force utimensat to fail when dirfd was AT_FDCWD and pathname is NULL */
     ret = utimensat(AT_FDCWD, NULL, times, 0);
+#ifdef LINUX
+    report(ret == -1 && errno == EINVAL, "utimensat fails when dirfd is 
AT_FDCWD and pathname is NULL");
+#else
     report(ret == -1 && errno == EFAULT, "utimensat fails when dirfd is 
AT_FDCWD and pathname is NULL");
+#endif
 
     /* Force utimensat to fail with invalid flags */
     ret = utimensat(dirfd, rel_path_bar_to_tmp, times, 23);
     report(ret == -1 && errno == EINVAL, "utimensat fails with invalid flags");
 
     /* Force utimensat to fail with invalid values in times */
-    init_timespec(times[0], -1, 100); /* change atime */
-    ret = utimensat(dirfd, rel_path_bar_to_tmp, times, 0);
+    init_timespec(times[0], -1, -1); /* change atime */
+    ret = utimensat(dirfd, rel_path_bar_to_foo, times, 0);
     report(ret == -1 && errno == EINVAL, "utimensat fails with invalid value 
in times");
 
     init_timespec(times[0], 1234, 100);
@@ -143,8 +147,8 @@ int main(int argc, char *argv[])
     report(ret == -1 && errno == ENOTDIR, "utimensat fails when dirfd points 
to file and relative pathname is given");
 
     /* Clean up temporary files */
-     report(unlink(tmp_file_bar) == 0, "remove the file bar");
-     report(rmdir(tmp_folder_foo) == 0, "remove the folder foo");
+    report(unlink(tmp_file_bar) == 0, "remove the file bar");
+    report(rmdir(tmp_folder_foo) == 0, "remove the folder foo");
 
     /* Report results. */
     printf("SUMMARY: %d tests, %d failures\n", tests, fails);
diff --git a/tests/tst-utimes.cc b/tests/tst-utimes.cc
--- a/tests/tst-utimes.cc
+++ b/tests/tst-utimes.cc
@@ -82,7 +82,7 @@ int main(int argc, char *argv[])
     report(stat(path, &st) == 0, "stat the file");
 
     /* Dump current atime and mtime */
-    printf("ino: %u - old -> st_atim: %ld:%ld - st_mtim: %ld:%ld\n",
+    printf("ino: %lu - old -> st_atim: %ld:%ld - st_mtim: %ld:%ld\n",
         st.st_ino,
         st.st_atim.tv_sec, st.st_atim.tv_nsec,
         st.st_mtim.tv_sec, st.st_mtim.tv_nsec);
@@ -110,7 +110,7 @@ int main(int argc, char *argv[])
         "check changes made to mtime");
 
     /* Dump the changes to atime and mtime */
-    printf("ino: %u - new -> st_atim: %ld:%ld - st_mtim: %ld:%ld\n",
+    printf("ino: %lu - new -> st_atim: %ld:%ld - st_mtim: %ld:%ld\n",
         st.st_ino,
         st.st_atim.tv_sec, st.st_atim.tv_nsec,
         st.st_mtim.tv_sec, st.st_mtim.tv_nsec);
@@ -138,11 +138,13 @@ int main(int argc, char *argv[])
         "check if utimes made changes to link target's mtime");
 
 
+#ifndef LINUX
     /* Force utimes to fail */
     times[0].tv_sec = -1;
     ret = utimes(path, times);
     report(ret == -1 && errno == EINVAL,
         "check if utimes failed as desired!");
+#endif
 
     /* Check if utimes works with NULL as argument */
     ret = utimes(path, NULL);

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/000000000000b8af27060c90822d%40google.com.

Reply via email to