From: Waldemar Kozaczuk <jwkozac...@gmail.com>
Committer: Waldemar Kozaczuk <jwkozac...@gmail.com>
Branch: master

vfs: refactor the *at() functions

Comparing to the 1st version, this one adds another helper
function - vfs_fun_at2() - which calls supplied lambda if
dirfd == AT_FDCWD or pathname is an absolute path and otherwise
delegates to vfs_fun_at(). It also checks if pathname is not null.
The __fxstatat() and futimesat() call vfs_fun_at() directly as their
logic is slightly different.

The VFS functions like openat(), faccessat() and others alike
take a directory descriptor argument intended to make a filesystem
action happen relative to that directory.

The implemetations of those function repeat almost the same code
over and over. So this patch makes vfs more DRY by introducing
a helper function - vfs_fun_at() - which implements common
logic and executed a lambda function specific to given
VFS action.

This patch also adds some unit tests around readlinkat() and mkdirat().

#Refs 1188

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>

---
diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
--- a/fs/vfs/main.cc
+++ b/fs/vfs/main.cc
@@ -160,21 +160,8 @@ int open(const char *pathname, int flags, ...)
 
 LFS64(open);
 
-OSV_LIBC_API
-int openat(int dirfd, const char *pathname, int flags, ...)
+static int vfs_fun_at(int dirfd, const char *pathname, std::function<int(const 
char *)> fun)
 {
-    mode_t mode = 0;
-    if (flags & O_CREAT) {
-        va_list ap;
-        va_start(ap, flags);
-        mode = apply_umask(va_arg(ap, mode_t));
-        va_end(ap);
-    }
-
-    if (pathname[0] == '/' || dirfd == AT_FDCWD) {
-        return open(pathname, flags, mode);
-    }
-
     struct file *fp;
     int error = fget(dirfd, &fp);
     if (error) {
@@ -191,16 +178,48 @@ int openat(int dirfd, const char *pathname, int flags, 
...)
     /* build absolute path */
     strlcpy(p, fp->f_dentry->d_mount->m_path, PATH_MAX);
     strlcat(p, fp->f_dentry->d_path, PATH_MAX);
-    strlcat(p, "/", PATH_MAX);
-    strlcat(p, pathname, PATH_MAX);
+    if (pathname) {
+        strlcat(p, "/", PATH_MAX);
+        strlcat(p, pathname, PATH_MAX);
+    }
 
-    error = open(p, flags, mode);
+    error = fun(p);
 
     vn_unlock(vp);
     fdrop(fp);
 
     return error;
 }
+
+static int vfs_fun_at2(int dirfd, const char *pathname, 
std::function<int(const char *)> fun)
+{
+    if (!pathname) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    if (pathname[0] == '/' || dirfd == AT_FDCWD) {
+        return fun(pathname);
+    }
+
+    return vfs_fun_at(dirfd, pathname, fun);
+}
+
+OSV_LIBC_API
+int openat(int dirfd, const char *pathname, int flags, ...)
+{
+    mode_t mode = 0;
+    if (flags & O_CREAT) {
+        va_list ap;
+        va_start(ap, flags);
+        mode = apply_umask(va_arg(ap, mode_t));
+        va_end(ap);
+    }
+
+    return vfs_fun_at2(dirfd, pathname, [flags, mode](const char *path) {
+        return open(path, flags, mode);
+    });
+}
 LFS64(openat);
 
 // open() has an optional third argument, "mode", which is only needed in
@@ -602,6 +621,11 @@ extern "C" OSV_LIBC_API
 int __fxstatat(int ver, int dirfd, const char *pathname, struct stat *st,
         int flags)
 {
+    if (!pathname) {
+        errno = EINVAL;
+        return -1;
+    }
+
     if (pathname[0] == '/' || dirfd == AT_FDCWD) {
         return stat(pathname, st);
     }
@@ -611,35 +635,14 @@ int __fxstatat(int ver, int dirfd, const char *pathname, 
struct stat *st,
         return fstat(dirfd, st);
     }
 
-    struct file *fp;
-    int error = fget(dirfd, &fp);
-    if (error) {
-        errno = error;
-        return -1;
-    }
-
-    struct vnode *vp = fp->f_dentry->d_vnode;
-    vn_lock(vp);
-
-    std::unique_ptr<char []> up (new char[PATH_MAX]);
-    char *p = up.get();
-    /* build absolute path */
-    strlcpy(p, fp->f_dentry->d_mount->m_path, PATH_MAX);
-    strlcat(p, fp->f_dentry->d_path, PATH_MAX);
-    strlcat(p, "/", PATH_MAX);
-    strlcat(p, pathname, PATH_MAX);
-
-    if (flags & AT_SYMLINK_NOFOLLOW) {
-        error = lstat(p, st);
-    }
-    else {
-        error = stat(p, st);
-    }
-
-    vn_unlock(vp);
-    fdrop(fp);
-
-    return error;
+    return vfs_fun_at(dirfd, pathname, [flags,st](const char *absolute_path) {
+        if (flags & AT_SYMLINK_NOFOLLOW) {
+            return lstat(absolute_path, st);
+        }
+        else {
+            return stat(absolute_path, st);
+        }
+    });
 }
 
 LFS64(__fxstatat);
@@ -870,37 +873,9 @@ int mkdirat(int dirfd, const char *pathname, mode_t mode)
 {
     mode = apply_umask(mode);
 
-       if (pathname[0] == '/' || dirfd == AT_FDCWD) {
-        // Supplied path is either absolute or relative to cwd
-        return mkdir(pathname, mode);
-    }
-
-    // Supplied path is relative to folder specified by dirfd
-    struct file *fp;
-    int error = fget(dirfd, &fp);
-    if (error) {
-        errno = error;
-        return -1;
-    }
-
-    struct vnode *vp = fp->f_dentry->d_vnode;
-    vn_lock(vp);
-
-    std::unique_ptr<char []> up (new char[PATH_MAX]);
-    char *p = up.get();
-
-    /* build absolute path */
-    strlcpy(p, fp->f_dentry->d_mount->m_path, PATH_MAX);
-    strlcat(p, fp->f_dentry->d_path, PATH_MAX);
-    strlcat(p, "/", PATH_MAX);
-    strlcat(p, pathname, PATH_MAX);
-
-    error = mkdir(p, mode);
-
-    vn_unlock(vp);
-    fdrop(fp);
-
-    return error;
+    return vfs_fun_at2(dirfd, pathname, [mode](const char *path) {
+        return mkdir(path, mode);
+    });
 }
 
 TRACEPOINT(trace_vfs_rmdir, "\"%s\"", const char*);
@@ -1717,35 +1692,9 @@ int faccessat(int dirfd, const char *pathname, int mode, 
int flags)
         UNIMPLEMENTED("faccessat() with AT_SYMLINK_NOFOLLOW");
     }
 
-    if (pathname[0] == '/' || dirfd == AT_FDCWD) {
-        return access(pathname, mode);
-    }
-
-    struct file *fp;
-    int error = fget(dirfd, &fp);
-    if (error) {
-        errno = error;
-        return -1;
-    }
-
-    struct vnode *vp = fp->f_dentry->d_vnode;
-    vn_lock(vp);
-
-    std::unique_ptr<char []> up (new char[PATH_MAX]);
-    char *p = up.get();
-
-    /* build absolute path */
-    strlcpy(p, fp->f_dentry->d_mount->m_path, PATH_MAX);
-    strlcat(p, fp->f_dentry->d_path, PATH_MAX);
-    strlcat(p, "/", PATH_MAX);
-    strlcat(p, pathname, PATH_MAX);
-
-    error = access(p, mode);
-
-    vn_unlock(vp);
-    fdrop(fp);
-
-    return error;
+    return vfs_fun_at2(dirfd, pathname, [mode](const char *path) {
+        return access(path, mode);
+    });
 }
 
 extern "C" OSV_LIBC_API
@@ -1928,35 +1877,9 @@ ssize_t readlink(const char *pathname, char *buf, size_t 
bufsize)
 OSV_LIBC_API
 ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize)
 {
-    if (pathname[0] == '/' || dirfd == AT_FDCWD) {
-        return readlink(pathname, buf, bufsize);
-    }
-
-    struct file *fp;
-    int error = fget(dirfd, &fp);
-    if (error) {
-        errno = error;
-        return -1;
-    }
-
-    struct vnode *vp = fp->f_dentry->d_vnode;
-    vn_lock(vp);
-
-    std::unique_ptr<char []> up (new char[PATH_MAX]);
-    char *p = up.get();
-
-    /* build absolute path */
-    strlcpy(p, fp->f_dentry->d_mount->m_path, PATH_MAX);
-    strlcat(p, fp->f_dentry->d_path, PATH_MAX);
-    strlcat(p, "/", PATH_MAX);
-    strlcat(p, pathname, PATH_MAX);
-
-    error = readlink(p, buf, bufsize);
-
-    vn_unlock(vp);
-    fdrop(fp);
-
-    return error;
+    return vfs_fun_at2(dirfd, pathname, [buf, bufsize](const char *path) {
+        return readlink(path, buf, bufsize);
+    });
 }
 
 TRACEPOINT(trace_vfs_fallocate, "%d %d 0x%x 0x%x", int, int, loff_t, loff_t);
@@ -2004,9 +1927,7 @@ OSV_LIBC_API
 int futimesat(int dirfd, const char *pathname, const struct timeval times[2])
 {
     struct stat st;
-    struct file *fp;
     int error;
-    char *absolute_path;
 
     if ((pathname && pathname[0] == '/') || dirfd == AT_FDCWD)
         return utimes(pathname, times);
@@ -2026,24 +1947,9 @@ int futimesat(int dirfd, const char *pathname, const 
struct timeval times[2])
         }
     }
 
-    error = fget(dirfd, &fp);
-    if (error)
-        goto out_errno;
-
-    /* build absolute path */
-    absolute_path = (char*)malloc(PATH_MAX);
-    strlcpy(absolute_path, fp->f_dentry->d_mount->m_path, PATH_MAX);
-    strlcat(absolute_path, fp->f_dentry->d_path, PATH_MAX);
-
-    if (pathname) {
-        strlcat(absolute_path, "/", PATH_MAX);
-        strlcat(absolute_path, pathname, PATH_MAX);
-    }
-
-    error = utimes(absolute_path, times);
-    free(absolute_path);
-
-    fdrop(fp);
+    error = vfs_fun_at(dirfd, pathname, [times](const char *absolute_path) {
+        return utimes(absolute_path, times);
+    });
 
     if (error)
         goto out_errno;
diff --git a/tests/tst-readdir.cc b/tests/tst-readdir.cc
--- a/tests/tst-readdir.cc
+++ b/tests/tst-readdir.cc
@@ -216,6 +216,15 @@ int main(int argc, char **argv)
     report(unlink("/tmp/tst-readdir/d")==0, "unlink");
     report(rmdir("/tmp/tst-readdir")==0, "rmdir");
     report(rmdir("/tmp/tst-readdir-empty")==0, "rmdir empty");
+
+    auto tmp_dir = opendir("/tmp");
+    report(tmp_dir,"opendir /tmp");
+    report(mkdirat(dirfd(tmp_dir), "tst-mkdirat", 0777)==0, "mkdirat");
+    auto mk_dir = opendir("/tmp/tst-mkdirat");
+    report(mk_dir,"opendir /tmp/tst-mkdirat");
+    report(rmdir("/tmp/tst-mkdirat")==0, "rmdir empty");
+    report(closedir(mk_dir)==0, "closedir /tmp/tst-mkdirat");
+    report(closedir(tmp_dir)==0, "closedir /tmp");
 #endif
 
     printf("SUMMARY: %d tests, %d failures\n", tests, fails);
diff --git a/tests/tst-symlink.cc b/tests/tst-symlink.cc
--- a/tests/tst-symlink.cc
+++ b/tests/tst-symlink.cc
@@ -262,7 +262,6 @@ int main(int argc, char **argv)
     report(symlink(N1, path) == 0, "symlink");
     report(unlink(path) == 0, "unlink");
 
-    printf("-->Smok\n");
     fill_buf(path, 257);
     rc = symlink(N1, path);
     error = errno;
@@ -366,12 +365,23 @@ int main(int argc, char **argv)
     report(search_dir(D2, N5) == true, "Symlink search");
 
     report(rename(D2, D3) == 0, "rename(d2, d3)");
+    auto test_dir = opendir(TESTDIR);
+    report(test_dir, "opendir");
+    rc = readlinkat(dirfd(test_dir), D3, path, sizeof(path));
+    report(rc >= 0, "readlinkat");
+    path[rc] = 0;
+    report(strcmp(path, D1) == 0, "readlinkat path");
     rc = readlink(D3, path, sizeof(path));
     report(rc >= 0, "readlink");
     path[rc] = 0;
     report(strcmp(path, D1) == 0, "readlink path");
 
     report(rename(D1, D4) == 0, "rename(d1, d4)");
+    rc = readlinkat(dirfd(test_dir), D3, path, sizeof(path));
+    report(rc >= 0, "readlinkat");
+    path[rc] = 0;
+    report(strcmp(path, D1) == 0, "readlinkat path");
+    report(closedir(test_dir) == 0, "closedir(test_dir)");
     rc = readlink(D3, path, sizeof(path));
     report(rc >= 0, "readlink");
     path[rc] = 0;

-- 
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 osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/000000000000e0f77e05dfffc522%40google.com.

Reply via email to