Kernel/LibC: Implement rename{,at}

This commit is contained in:
Bananymous 2025-11-22 23:53:52 +02:00
parent 05d59a05df
commit 4ec8f4a4bf
10 changed files with 135 additions and 60 deletions

View File

@ -37,6 +37,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override; virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override; virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override; virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override;
virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) override;
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override; virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
virtual BAN::ErrorOr<BAN::String> link_target_impl() override; virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
@ -64,6 +65,7 @@ namespace Kernel
BAN::ErrorOr<BAN::Optional<uint32_t>> fs_block_of_data_block_index(uint32_t data_block_index); BAN::ErrorOr<BAN::Optional<uint32_t>> fs_block_of_data_block_index(uint32_t data_block_index);
BAN::ErrorOr<void> link_inode_to_directory(Ext2Inode&, BAN::StringView name); BAN::ErrorOr<void> link_inode_to_directory(Ext2Inode&, BAN::StringView name);
BAN::ErrorOr<void> remove_inode_from_directory(BAN::StringView name, bool cleanup_directory);
BAN::ErrorOr<bool> is_directory_empty(); BAN::ErrorOr<bool> is_directory_empty();
BAN::ErrorOr<void> cleanup_indirect_block(uint32_t block, uint32_t depth); BAN::ErrorOr<void> cleanup_indirect_block(uint32_t block, uint32_t depth);

View File

@ -97,6 +97,7 @@ namespace Kernel
BAN::ErrorOr<void> create_file(BAN::StringView, mode_t, uid_t, gid_t); BAN::ErrorOr<void> create_file(BAN::StringView, mode_t, uid_t, gid_t);
BAN::ErrorOr<void> create_directory(BAN::StringView, mode_t, uid_t, gid_t); BAN::ErrorOr<void> create_directory(BAN::StringView, mode_t, uid_t, gid_t);
BAN::ErrorOr<void> link_inode(BAN::StringView, BAN::RefPtr<Inode>); BAN::ErrorOr<void> link_inode(BAN::StringView, BAN::RefPtr<Inode>);
BAN::ErrorOr<void> rename_inode(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView);
BAN::ErrorOr<void> unlink(BAN::StringView); BAN::ErrorOr<void> unlink(BAN::StringView);
// Link API // Link API
@ -139,12 +140,13 @@ namespace Kernel
protected: protected:
// Directory API // Directory API
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
// Link API // Link API
virtual BAN::ErrorOr<BAN::String> link_target_impl() { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<BAN::String> link_target_impl() { return BAN::Error::from_errno(ENOTSUP); }
@ -187,7 +189,7 @@ namespace Kernel
friend class Epoll; friend class Epoll;
friend class FileBackedRegion; friend class FileBackedRegion;
friend class OpenFileDescriptorSet; friend class OpenFileDescriptorSet;
friend class SharedFileData; friend struct SharedFileData;
friend class TTY; friend class TTY;
}; };

View File

@ -157,6 +157,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final; virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final; virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override final; virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override final;
virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) override final;
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override; virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
virtual bool can_read_impl() const override { return false; } virtual bool can_read_impl() const override { return false; }
@ -168,6 +169,8 @@ namespace Kernel
template<TmpFuncs::for_each_valid_entry_callback F> template<TmpFuncs::for_each_valid_entry_callback F>
void for_each_valid_entry(F callback); void for_each_valid_entry(F callback);
BAN::ErrorOr<void> unlink_inode(BAN::StringView, bool cleanup);
friend class TmpInode; friend class TmpInode;
}; };

View File

@ -109,9 +109,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_access(const char* path, int amode); BAN::ErrorOr<long> sys_access(const char* path, int amode);
BAN::ErrorOr<long> sys_create_dir(const char*, mode_t); BAN::ErrorOr<long> sys_create_dir(const char*, mode_t);
BAN::ErrorOr<long> sys_hardlinkat(int fd1, const char* path1, int fd2, const char* path2, int flag); BAN::ErrorOr<long> sys_hardlinkat(int fd1, const char* path1, int fd2, const char* path2, int flag);
BAN::ErrorOr<long> sys_renameat(int oldfd, const char* old, int newfd, const char* _new);
BAN::ErrorOr<long> sys_unlinkat(int fd, const char* path, int flag); BAN::ErrorOr<long> sys_unlinkat(int fd, const char* path, int flag);
BAN::ErrorOr<long> sys_readlinkat(int fd, const char* path, char* buffer, size_t bufsize); BAN::ErrorOr<long> sys_readlinkat(int fd, const char* path, char* buffer, size_t bufsize);
BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2); BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2);
BAN::ErrorOr<long> sys_flock(int fd, int op); BAN::ErrorOr<long> sys_flock(int fd, int op);

View File

@ -2,6 +2,7 @@
#include <BAN/ScopeGuard.h> #include <BAN/ScopeGuard.h>
#include <kernel/FS/Ext2/FileSystem.h> #include <kernel/FS/Ext2/FileSystem.h>
#include <kernel/FS/Ext2/Inode.h> #include <kernel/FS/Ext2/Inode.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -585,6 +586,37 @@ done:
return {}; return {};
} }
BAN::ErrorOr<void> Ext2Inode::rename_inode_impl(BAN::RefPtr<Inode> old_parent, BAN::StringView old_name, BAN::StringView new_name)
{
ASSERT(this->mode().ifdir());
ASSERT(old_parent->mode().ifdir());
ASSERT(&m_fs == old_parent->filesystem());
auto* ext2_parent = static_cast<Ext2Inode*>(old_parent.ptr());
// FIXME: possible deadlock :)
LockGuard _(ext2_parent->m_mutex);
auto old_inode = TRY(ext2_parent->find_inode_impl(old_name));
auto* ext2_inode = static_cast<Ext2Inode*>(old_inode.ptr());
if (auto replace_or_error = find_inode_impl(new_name); replace_or_error.is_error())
{
if (replace_or_error.error().get_error_code() != ENOENT)
return replace_or_error.release_error();
}
else
{
TRY(unlink_impl(new_name));
}
TRY(link_inode_to_directory(*ext2_inode, new_name));
TRY(ext2_parent->remove_inode_from_directory(old_name, false));
return {};
}
BAN::ErrorOr<void> Ext2Inode::link_inode_to_directory(Ext2Inode& inode, BAN::StringView name) BAN::ErrorOr<void> Ext2Inode::link_inode_to_directory(Ext2Inode& inode, BAN::StringView name)
{ {
if (!this->mode().ifdir()) if (!this->mode().ifdir())
@ -778,7 +810,7 @@ needs_new_block:
return {}; return {};
} }
BAN::ErrorOr<void> Ext2Inode::unlink_impl(BAN::StringView name) BAN::ErrorOr<void> Ext2Inode::remove_inode_from_directory(BAN::StringView name, bool cleanup_directory)
{ {
ASSERT(mode().ifdir()); ASSERT(mode().ifdir());
if (m_inode.flags & Ext2::Enum::INDEX_FL) if (m_inode.flags & Ext2::Enum::INDEX_FL)
@ -802,7 +834,7 @@ needs_new_block:
if (entry.inode && name == BAN::StringView(entry.name, entry.name_len)) if (entry.inode && name == BAN::StringView(entry.name, entry.name_len))
{ {
auto inode = TRY(Ext2Inode::create(m_fs, entry.inode)); auto inode = TRY(Ext2Inode::create(m_fs, entry.inode));
if (inode->mode().ifdir()) if (cleanup_directory && inode->mode().ifdir())
{ {
if (!TRY(inode->is_directory_empty())) if (!TRY(inode->is_directory_empty()))
return BAN::Error::from_errno(ENOTEMPTY); return BAN::Error::from_errno(ENOTEMPTY);
@ -836,6 +868,12 @@ needs_new_block:
return {}; return {};
} }
BAN::ErrorOr<void> Ext2Inode::unlink_impl(BAN::StringView name)
{
TRY(remove_inode_from_directory(name, true));
return {};
}
BAN::ErrorOr<uint32_t> Ext2Inode::allocate_new_block_to_indirect_block(uint32_t& block, uint32_t index, uint32_t depth) BAN::ErrorOr<uint32_t> Ext2Inode::allocate_new_block_to_indirect_block(uint32_t& block, uint32_t index, uint32_t depth)
{ {
const uint32_t inode_blocks_per_fs_block = blksize() / 512; const uint32_t inode_blocks_per_fs_block = blksize() / 512;

View File

@ -114,6 +114,20 @@ namespace Kernel
return link_inode_impl(name, inode); return link_inode_impl(name, inode);
} }
BAN::ErrorOr<void> Inode::rename_inode(BAN::RefPtr<Inode> old_parent, BAN::StringView old_name, BAN::StringView new_name)
{
LockGuard _(m_mutex);
if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
if (!old_parent->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
if (this->filesystem() != old_parent->filesystem())
return BAN::Error::from_errno(EXDEV);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS);
return rename_inode_impl(old_parent, old_name, new_name);
}
BAN::ErrorOr<void> Inode::unlink(BAN::StringView name) BAN::ErrorOr<void> Inode::unlink(BAN::StringView name)
{ {
LockGuard _(m_mutex); LockGuard _(m_mutex);

View File

@ -669,7 +669,44 @@ namespace Kernel
return {}; return {};
} }
BAN::ErrorOr<void> TmpDirectoryInode::rename_inode_impl(BAN::RefPtr<Inode> old_parent, BAN::StringView old_name, BAN::StringView new_name)
{
ASSERT(this->mode().ifdir());
ASSERT(old_parent->mode().ifdir());
ASSERT(&m_fs == old_parent->filesystem());
auto* tmp_parent = static_cast<TmpDirectoryInode*>(old_parent.ptr());
// FIXME: possible deadlock :)
LockGuard _(tmp_parent->m_mutex);
auto old_inode = TRY(tmp_parent->find_inode_impl(old_name));
auto* tmp_inode = static_cast<TmpInode*>(old_inode.ptr());
if (auto replace_or_error = find_inode_impl(new_name); replace_or_error.is_error())
{
if (replace_or_error.error().get_error_code() != ENOENT)
return replace_or_error.release_error();
}
else
{
TRY(unlink_impl(new_name));
}
TRY(link_inode(*tmp_inode, new_name));
TRY(tmp_parent->unlink_inode(old_name, false));
return {};
}
BAN::ErrorOr<void> TmpDirectoryInode::unlink_impl(BAN::StringView name) BAN::ErrorOr<void> TmpDirectoryInode::unlink_impl(BAN::StringView name)
{
TRY(unlink_inode(name, true));
return {};
}
BAN::ErrorOr<void> TmpDirectoryInode::unlink_inode(BAN::StringView name, bool cleanup)
{ {
ino_t entry_ino = 0; ino_t entry_ino = 0;
@ -687,7 +724,8 @@ namespace Kernel
ASSERT(inode->nlink() > 0); ASSERT(inode->nlink() > 0);
TRY(inode->prepare_unlink()); if (cleanup)
TRY(inode->prepare_unlink());
inode->m_inode_info.nlink--; inode->m_inode_info.nlink--;
if (inode->nlink() == 0) if (inode->nlink() == 0)

View File

@ -1302,6 +1302,27 @@ namespace Kernel
return 0; return 0;
} }
BAN::ErrorOr<long> Process::sys_renameat(int oldfd, const char* old, int newfd, const char* _new)
{
LockGuard _(m_process_lock);
if (old != nullptr)
TRY(validate_string_access(old));
if (_new != nullptr)
TRY(validate_string_access(_new));
auto [old_parent, old_name] = TRY(find_parent_file(oldfd, old, O_WRONLY));
if (!old_parent.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
auto [new_parent, new_name] = TRY(find_parent_file(newfd, _new, O_WRONLY));
if (!new_parent.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
TRY(new_parent.inode->rename_inode(old_parent.inode, old_name, new_name));
return 0;
}
BAN::ErrorOr<long> Process::sys_unlinkat(int fd, const char* path, int flag) BAN::ErrorOr<long> Process::sys_unlinkat(int fd, const char* path, int flag)
{ {
if (flag && flag != AT_REMOVEDIR) if (flag && flag != AT_REMOVEDIR)

View File

@ -14,6 +14,7 @@ __BEGIN_DECLS
O(SYS_OPENAT, openat) \ O(SYS_OPENAT, openat) \
O(SYS_SEEK, seek) \ O(SYS_SEEK, seek) \
O(SYS_TELL, tell) \ O(SYS_TELL, tell) \
O(SYS_RENAMEAT, renameat) \
O(SYS_TCGETATTR, tcgetattr) \ O(SYS_TCGETATTR, tcgetattr) \
O(SYS_TCSETATTR, tcsetattr) \ O(SYS_TCSETATTR, tcsetattr) \
O(SYS_FORK, fork) \ O(SYS_FORK, fork) \

View File

@ -820,56 +820,12 @@ int remove(const char* path)
int rename(const char* old, const char* _new) int rename(const char* old, const char* _new)
{ {
struct stat st; return renameat(AT_FDCWD, old, AT_FDCWD, _new);
if (lstat(old, &st) == -1) }
return -1;
if (!S_ISREG(st.st_mode)) int renameat(int oldfd, const char* old, int newfd, const char* _new)
{ {
errno = ENOTSUP; return syscall(SYS_RENAMEAT, oldfd, old, newfd, _new);
return -1;
}
if (unlink(_new) == -1 && errno != ENOENT)
return -1;
int old_fd = open(old, O_RDWR);
int new_fd = open(_new, O_RDWR | O_CREAT | O_EXCL, st.st_mode);
if (old_fd == -1 || new_fd == -1)
goto error;
for (;;)
{
char buffer[512];
ssize_t nread = read(old_fd, buffer, sizeof(buffer));
if (nread == -1)
{
unlink(_new);
goto error;
}
if (nread == 0)
break;
if (write(new_fd, buffer, nread) != nread)
{
unlink(_new);
goto error;
}
}
close(new_fd);
close(old_fd);
unlink(old);
return 0;
error:
if (old_fd != -1)
close(old_fd);
if (new_fd != -1)
close(new_fd);
return -1;
} }
void rewind(FILE* file) void rewind(FILE* file)