From 5b2dba5f453ef436822d8989685cb5e8b39bd4f9 Mon Sep 17 00:00:00 2001 From: Lucas Chollet Date: Thu, 15 Oct 2026 09:28:40 +0200 Subject: [PATCH] Kernel/VFS: Allow rename to overwrite a symlink Per POSIX: If either the old or new argument names a symbolic link, rename() shall operate on the symbolic link itself, and shall not resolve the last component of the argument. --- Kernel/FileSystem/VirtualFileSystem.cpp | 2 +- Tests/Kernel/POSIX/TestRename.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 9ddfd5f9e4a..d400adfa8a5 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -623,7 +623,7 @@ ErrorOr VirtualFileSystem::rename(VFSRootContext const& vfs_root_context, auto& old_inode = old_custody->inode(); RefPtr new_parent_custody; - auto new_custody_or_error = resolve_path(vfs_root_context, credentials, new_path, new_base, &new_parent_custody); + auto new_custody_or_error = resolve_path(vfs_root_context, credentials, new_path, new_base, &new_parent_custody, O_NOFOLLOW_NOERROR); if (new_custody_or_error.is_error()) { if (new_custody_or_error.error().code() != ENOENT || !new_parent_custody) return new_custody_or_error.release_error(); diff --git a/Tests/Kernel/POSIX/TestRename.cpp b/Tests/Kernel/POSIX/TestRename.cpp index cfb9f0811ec..e1302c30837 100644 --- a/Tests/Kernel/POSIX/TestRename.cpp +++ b/Tests/Kernel/POSIX/TestRename.cpp @@ -8,6 +8,23 @@ #include #include +TEST_CASE(rename_file_over_symlink) +{ + auto file = TRY_OR_FAIL(FileSystem::TempFile::create_temp_file()); + TRY_OR_FAIL(Core::System::truncate(file->path(), 256)); + + static constexpr StringView LINK_PATH = "/tmp/link"sv; + (void)Core::System::unlink(LINK_PATH); + TRY_OR_FAIL(Core::System::symlink(file->path(), LINK_PATH)); + + TRY_OR_FAIL(Core::System::rename(file->path(), LINK_PATH)); + + auto stat = TRY_OR_FAIL(Core::System::lstat(LINK_PATH)); + EXPECT(!S_ISLNK(stat.st_mode)); + EXPECT(S_ISREG(stat.st_mode)); + EXPECT_EQ(stat.st_size, 256u); +} + TEST_CASE(rename_directory_over_file_fails) { auto directory = TRY_OR_FAIL(FileSystem::TempFile::create_temp_directory());