Kernel/LibC: Add support for creating hardlinks

This commit is contained in:
2024-12-03 16:07:30 +02:00
parent 12abe81c6d
commit 713daf6cd3
8 changed files with 76 additions and 0 deletions

View File

@@ -518,6 +518,23 @@ done:
return {};
}
BAN::ErrorOr<void> Ext2Inode::link_inode_impl(BAN::StringView name, BAN::RefPtr<Inode> inode)
{
ASSERT(this->mode().ifdir());
ASSERT(!inode->mode().ifdir());
if (&m_fs != inode->filesystem())
return BAN::Error::from_errno(EXDEV);
if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST);
auto ext2_inode = static_cast<Ext2Inode*>(inode.ptr());
TRY(link_inode_to_directory(*ext2_inode, name));
return {};
}
BAN::ErrorOr<void> Ext2Inode::link_inode_to_directory(Ext2Inode& inode, BAN::StringView name)
{
if (!this->mode().ifdir())

View File

@@ -93,6 +93,16 @@ namespace Kernel
return create_directory_impl(name, mode, uid, gid);
}
BAN::ErrorOr<void> Inode::link_inode(BAN::StringView name, BAN::RefPtr<Inode> inode)
{
LockGuard _(m_mutex);
if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
if (inode->mode().ifdir())
return BAN::Error::from_errno(EINVAL);
return link_inode_impl(name, inode);
}
BAN::ErrorOr<void> Inode::unlink(BAN::StringView name)
{
LockGuard _(m_mutex);

View File

@@ -1042,6 +1042,40 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_hardlinkat(int fd1, const char* path1, int fd2, const char* path2, int flag)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path1));
TRY(validate_string_access(path2));
auto inode = TRY(find_file(fd1, path1, flag)).inode;
if (inode->mode().ifdir())
return BAN::Error::from_errno(EISDIR);
auto parent = TRY(find_parent(fd2, path2));
BAN::RefPtr<Inode> parent_inode;
BAN::StringView file_name;
BAN::StringView path2_sv = path2;
if (auto index = path2_sv.rfind('/'); index.has_value())
{
parent_inode = TRY(VirtualFileSystem::get().file_from_relative_path(parent, m_credentials, path2_sv.substring(0, index.value()), O_EXEC | O_WRONLY)).inode;
file_name = path2_sv.substring(index.value() + 1);
}
else
{
parent_inode = parent.inode;
file_name = path2_sv;
if (!parent_inode->can_access(m_credentials, O_WRONLY))
return BAN::Error::from_errno(EACCES);
}
ASSERT(parent_inode->mode().ifdir());
TRY(parent_inode->link_inode(file_name, inode));
return 0;
}
BAN::ErrorOr<long> Process::sys_unlink(const char* path)
{
LockGuard _(m_process_lock);