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

vfs: implement renameat()

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 <jwkozac...@gmail.com>

---
diff --git a/exported_symbols/osv_ld-musl.so.1.symbols 
b/exported_symbols/osv_ld-musl.so.1.symbols
--- 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
--- 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
--- 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
--- 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
--- 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)

-- 
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/0000000000004b846e05dfffc6ae%40google.com.

Reply via email to