Kernel/LibC: Implement rename{,at}
This commit is contained in:
parent
05d59a05df
commit
4ec8f4a4bf
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -144,6 +145,7 @@ namespace Kernel
|
||||||
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> 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); }
|
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
||||||
|
|
||||||
// Link API
|
// Link API
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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,6 +724,7 @@ namespace Kernel
|
||||||
|
|
||||||
ASSERT(inode->nlink() > 0);
|
ASSERT(inode->nlink() > 0);
|
||||||
|
|
||||||
|
if (cleanup)
|
||||||
TRY(inode->prepare_unlink());
|
TRY(inode->prepare_unlink());
|
||||||
inode->m_inode_info.nlink--;
|
inode->m_inode_info.nlink--;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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) \
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue