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

This patch also exposes renameat as a syscall.

#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                            | 30 ++++++++++++++
 linux.cc                                  |  1 +
 tests/tst-rename.cc                       | 48 ++++++++++++++++++++++-
 5 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/exported_symbols/osv_ld-musl.so.1.symbols 
b/exported_symbols/osv_ld-musl.so.1.symbols
index 3db22e0d..6d88fda4 100644
--- a/exported_symbols/osv_ld-musl.so.1.symbols
+++ b/exported_symbols/osv_ld-musl.so.1.symbols
@@ -868,6 +868,7 @@ remquo
 remquof
 remquol
 rename
+renameat
 res_init
 res_mkquery
 rewind
diff --git a/exported_symbols/osv_libc.so.6.symbols 
b/exported_symbols/osv_libc.so.6.symbols
index e29059bb..b27fbba1 100644
--- a/exported_symbols/osv_libc.so.6.symbols
+++ b/exported_symbols/osv_libc.so.6.symbols
@@ -696,6 +696,7 @@ register_printf_specifier
 register_printf_type
 remove
 rename
+renameat
 __res_init
 rewind
 rewinddir
diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
index bdedc6c6..76e1ee0e 100644
--- a/fs/vfs/main.cc
+++ b/fs/vfs/main.cc
@@ -1043,6 +1043,36 @@ int rename(const char *oldpath, const char *newpath)
     return -1;
 }
 
+OSV_LIBC_API
+int renameat(int olddirfd, const char *oldpath,
+             int newdirfd, const char *newpath)
+{
+    if (!oldpath || !newpath) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    if (newpath[0] == '/' || newdirfd == AT_FDCWD) {
+        return vfs_fun_at2(olddirfd, oldpath, [newpath](const char *path) {
+            return rename(path, newpath);
+        });
+    } else {
+        char absolute_newpath[PATH_MAX];
+        auto error = vfs_fun_at(newdirfd, newpath, [&absolute_newpath](const 
char *absolute_path) {
+            strcpy(absolute_newpath, absolute_path);
+            return 0;
+        });
+
+        if (error) {
+            return error;
+        } else {
+            return vfs_fun_at2(olddirfd, oldpath, [absolute_newpath](const 
char *path) {
+                return rename(path, absolute_newpath);
+            });
+        }
+    }
+}
+
 TRACEPOINT(trace_vfs_chdir, "\"%s\"", const char*);
 TRACEPOINT(trace_vfs_chdir_ret, "");
 TRACEPOINT(trace_vfs_chdir_err, "%d", int);
diff --git a/linux.cc b/linux.cc
index f60489e3..1fa01326 100644
--- a/linux.cc
+++ b/linux.cc
@@ -516,6 +516,7 @@ OSV_LIBC_API long syscall(long number, ...)
     SYSCALL3(unlinkat, int, const char *, int);
     SYSCALL3(symlinkat, const char *, int, const char *);
     SYSCALL3(sys_getdents64, int, void *, size_t);
+    SYSCALL4(renameat, int, const char *, int, const char *);
     }
 
     debug_always("syscall(): unimplemented system call %d\n", number);
diff --git a/tests/tst-rename.cc b/tests/tst-rename.cc
index 722fdc4c..0668bf77 100644
--- a/tests/tst-rename.cc
+++ b/tests/tst-rename.cc
@@ -73,6 +73,9 @@ static void assert_rename_fails(const fs::path &src, const 
fs::path &dst, std::v
     BOOST_TEST_MESSAGE("Renaming " + src.string() + " to " + dst.string());
     BOOST_REQUIRE(rename(src.c_str(), dst.c_str()) == -1);
     assert_one_of(errno, errnos);
+    BOOST_TEST_MESSAGE("Renaming(at) " + src.string() + " to " + dst.string());
+    BOOST_REQUIRE(renameat(AT_FDCWD, src.c_str(), AT_FDCWD, dst.c_str()) == 
-1);
+    assert_one_of(errno, errnos);
 }
 
 static void assert_renames(const fs::path src, const fs::path dst)
@@ -82,11 +85,27 @@ static void assert_renames(const fs::path src, const 
fs::path dst)
     BOOST_REQUIRE_MESSAGE(result == 0, fmt("Rename should succeed, errno=%d") 
% errno);
 }
 
-static void test_rename(const fs::path &src, const fs::path &dst)
+static void assert_renames_at(const fs::path src, const fs::path dst)
+{
+    BOOST_TEST_MESSAGE("Renaming " + src.string() + " to " + dst.string());
+    auto src_dir_fd = open(src.parent_path().c_str(), O_DIRECTORY);
+    auto dst_dir_fd = open(dst.parent_path().c_str(), O_DIRECTORY);
+    int result = renameat(src_dir_fd, src.filename().c_str(), dst_dir_fd, 
dst.filename().c_str());
+    BOOST_REQUIRE_MESSAGE(result == 0, fmt("Renameat should succeed, 
errno=%d") % errno);
+    close(src_dir_fd);
+    close(dst_dir_fd);
+}
+
+static void test_rename(const fs::path &src, const fs::path &dst, bool at = 
false)
 {
     prepare_file(src);
 
-    assert_renames(src, dst);
+    if (at) {
+        assert_renames_at(src, dst);
+    }
+    else {
+        assert_renames(src, dst);
+    }
 
     check_file(dst);
     BOOST_CHECK_MESSAGE(!fs::exists(src), "Old file should not exist");
@@ -136,6 +155,10 @@ BOOST_AUTO_TEST_CASE(test_renaming_in_the_same_directory)
             dir / "file1",
             dir / "file2");
 
+    test_rename(
+            dir / "file1",
+            dir / "file2", true);
+
     test_rename_from_open_file(
             dir / "file1",
             dir / "file2");
@@ -148,9 +171,17 @@ BOOST_AUTO_TEST_CASE(test_renaming_in_the_same_directory)
             dir / "a",
             dir / "aaaaa");
 
+    test_rename(
+            dir / "a",
+            dir / "aaaaa", true);
+
     test_rename(
             dir / "aaaaaaaaa",
             dir / "aa");
+
+    test_rename(
+            dir / "aaaaaaaaa",
+            dir / "aa", true);
 }
 
 BOOST_AUTO_TEST_CASE(test_renaming_to_child_path_should_fail) {
@@ -169,13 +200,25 @@ 
BOOST_AUTO_TEST_CASE(test_moving_file_to_another_directory)
             dir / "file",
             dir / sub / "file");
 
+    test_rename(
+            dir / "file",
+            dir / sub / "file", true);
+
     test_rename(
             dir / sub / "file2",
             dir / "file2");
 
+    test_rename(
+            dir / sub / "file2",
+            dir / "file2", true);
+
     test_rename(
             dir / sub / "a",
             dir / "aaaa");
+
+    test_rename(
+            dir / sub / "a",
+            dir / "aaaa", true);
 }
 
 BOOST_AUTO_TEST_CASE(test_renaming_when_destination_is_substring)
@@ -201,6 +244,7 @@ 
BOOST_AUTO_TEST_CASE(test_renaming_works_with_non_uniform_paths)
 
     test_rename(file, dir / "/file2");
     test_rename(file, dir / "/sub///file2");
+    test_rename(file, dir / "/sub///file2", true);
 }
 
 
BOOST_AUTO_TEST_CASE(test_file_can_be_located_using_different_paths_after_rename)
-- 
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/20220521021345.18548-1-jwkozaczuk%40gmail.com.

Reply via email to