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.
