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().
Signed-off-by: Waldemar Kozaczuk <
jwkoz...@gmail.com>
---
fs/vfs/main.cc | 188 +++++++++++--------------------------------
tests/tst-readdir.cc | 9 +++
tests/tst-symlink.cc | 12 ++-
3 files changed, 66 insertions(+), 143 deletions(-)
diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
index ca357cc8..a72042b2 100644
--- 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,38 @@ 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;
}
+
+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);
+ }
+
+ if (pathname[0] == '/' || dirfd == AT_FDCWD) {
+ return open(pathname, flags, mode);
+ }
+
+ return vfs_fun_at(dirfd, pathname, [flags, mode](const char *absolute_path) {
+ return open(absolute_path, flags, mode);
+ });
+}
LFS64(openat);
// open() has an optional third argument, "mode", which is only needed in
@@ -611,35 +620,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);
@@ -875,32 +863,9 @@ int mkdirat(int dirfd, const char *pathname, mode_t mode)
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_at(dirfd, pathname, [mode](const char *absolute_path) {
+ return mkdir(absolute_path, mode);
+ });
}
TRACEPOINT(trace_vfs_rmdir, "\"%s\"", const char*);
@@ -1721,31 +1686,9 @@ int faccessat(int dirfd, const char *pathname, int mode, int flags)
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_at(dirfd, pathname, [mode](const char *absolute_path) {
+ return access(absolute_path, mode);
+ });
}
extern "C" OSV_LIBC_API
@@ -1932,31 +1875,9 @@ ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize)
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_at(dirfd, pathname, [buf, bufsize](const char *absolute_path) {
+ return readlink(absolute_path, buf, bufsize);
+ });
}
TRACEPOINT(trace_vfs_fallocate, "%d %d 0x%x 0x%x", int, int, loff_t, loff_t);
@@ -2004,9 +1925,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 +1945,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
index 9154d252..0b1d2a8c 100644
--- 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
index 0eff52f3..978cfda3 100644
--- 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;
--
2.34.1