V2: The implementation uses vfs_fun_at2() instead of vfs_fun_at()
to further simplify code. We also expose symlinkat though syscall.

This patch implements the symlinkat() function and enhances
tst-symlink.cc to unit test it.

#Refs 1188

Signed-off-by: Waldemar Kozaczuk <[email protected]>
---
 exported_symbols/osv_ld-musl.so.1.symbols |  1 +
 exported_symbols/osv_libc.so.6.symbols    |  1 +
 fs/vfs/main.cc                            | 13 +++++++++++++
 linux.cc                                  |  1 +
 tests/tst-symlink.cc                      | 18 +++++++++++++++---
 5 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/exported_symbols/osv_ld-musl.so.1.symbols 
b/exported_symbols/osv_ld-musl.so.1.symbols
index f1c61a3f..3db22e0d 100644
--- a/exported_symbols/osv_ld-musl.so.1.symbols
+++ b/exported_symbols/osv_ld-musl.so.1.symbols
@@ -1081,6 +1081,7 @@ swab
 swprintf
 swscanf
 symlink
+symlinkat
 sync
 syscall
 sysconf
diff --git a/exported_symbols/osv_libc.so.6.symbols 
b/exported_symbols/osv_libc.so.6.symbols
index 7ae57c38..e29059bb 100644
--- a/exported_symbols/osv_libc.so.6.symbols
+++ b/exported_symbols/osv_libc.so.6.symbols
@@ -887,6 +887,7 @@ swprintf
 __swprintf_chk
 swscanf
 symlink
+symlinkat
 sync
 syscall
 sysconf
diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
index 9b2e2c02..8e3d4e5e 100644
--- a/fs/vfs/main.cc
+++ b/fs/vfs/main.cc
@@ -1132,6 +1132,19 @@ int symlink(const char *oldpath, const char *newpath)
     return 0;
 }
 
+OSV_LIBC_API
+int symlinkat(const char *oldpath, int newdirfd, const char *newpath)
+{
+    if (!oldpath) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    return vfs_fun_at2(newdirfd, newpath, [oldpath](const char * path) {
+        return symlink(oldpath, path);
+    });
+}
+
 TRACEPOINT(trace_vfs_unlink, "\"%s\"", const char*);
 TRACEPOINT(trace_vfs_unlink_ret, "");
 TRACEPOINT(trace_vfs_unlink_err, "%d", int);
diff --git a/linux.cc b/linux.cc
index 5c271df1..dd0dabd1 100644
--- a/linux.cc
+++ b/linux.cc
@@ -496,6 +496,7 @@ OSV_LIBC_API long syscall(long number, ...)
     SYSCALL3(lseek, int, off_t, int);
     SYSCALL2(statfs, const char *, struct statfs *);
     SYSCALL3(unlinkat, int, const char *, int);
+    SYSCALL3(symlinkat, const char *, int, const char *);
     }
 
     debug_always("syscall(): unimplemented system call %d\n", number);
diff --git a/tests/tst-symlink.cc b/tests/tst-symlink.cc
index 978cfda3..1322e79e 100644
--- a/tests/tst-symlink.cc
+++ b/tests/tst-symlink.cc
@@ -25,6 +25,9 @@
 
 #define N1    "f1"
 #define N2    "f2_AAA"
+#define N2B   "f2_BBB"
+#define N2B   "f2_BBB"
+#define N2C   "f2_CCC"
 #define N3    "f3"
 #define N4    "f4"
 #define N5    "f5"
@@ -91,6 +94,8 @@ int main(int argc, char **argv)
 #endif
 
     report(chdir(TESTDIR) == 0, "chdir");
+    auto test_dir = opendir(TESTDIR);
+    report(test_dir, "opendir");
 
     /*
      * test to check
@@ -115,6 +120,10 @@ int main(int argc, char **argv)
 #else
     report(symlink(N1, N2) == 0, "symlink");
     report(search_dir(TESTDIR, N2) == true, "search dir");
+    report(symlinkat(N1, dirfd(test_dir), N2B) == 0, "symlinkat");
+    report(search_dir(TESTDIR, N2B) == true, "search dir N2B");
+    report(symlinkat(N1, AT_FDCWD, N2C) == 0, "symlinkat");
+    report(search_dir(TESTDIR, N2C) == true, "search dir N2B");
 #endif
 
 #if defined(READ_ONLY_FS)
@@ -125,6 +134,8 @@ int main(int argc, char **argv)
 #else
     report(access(N1, R_OK | W_OK) == 0, "access");
     report(access(N2, R_OK | W_OK) == 0, "access");
+    report(access(N2B, R_OK | W_OK) == 0, "access");
+    report(access(N2C, R_OK | W_OK) == 0, "access");
 #endif
 
     rc = readlink(N2, path, sizeof(path));
@@ -157,6 +168,8 @@ int main(int argc, char **argv)
     error = errno;
     report(rc < 0 && errno == ENOENT, "ENOENT expected");
     report(unlink(N2) == 0, "unlink");
+    report(unlinkat(dirfd(test_dir),N2B,0) == 0, "unlinkat");
+    report(unlinkat(dirfd(test_dir),N2C,0) == 0, "unlinkat");
 
     /*
      * IO Tests 1: write(file), read(symlink), truncate(symlink)
@@ -365,8 +378,6 @@ 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;
@@ -381,7 +392,6 @@ int main(int argc, char **argv)
     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;
@@ -399,6 +409,8 @@ int main(int argc, char **argv)
     report(rmdir(D4) == 0, "rmdir");
 #endif
 
+    report(closedir(test_dir) == 0, "closedir(test_dir)");
+
 #if defined(READ_ONLY_FS)
     report(-1 == rmdir(TESTDIR) && errno == ENOTEMPTY, "rmdir");
 #else
-- 
2.34.1

-- 
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/20220520191210.141585-1-jwkozaczuk%40gmail.com.

Reply via email to