Kernel: add basic support for symlinks

This commit is contained in:
Bananymous 2023-06-01 00:24:45 +03:00
parent 0ccc23d544
commit 232fdcb82c
6 changed files with 44 additions and 9 deletions

View File

@ -141,10 +141,13 @@ namespace Kernel
virtual BAN::StringView name() const override { return m_name; }
virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) override;
virtual BAN::ErrorOr<BAN::String> link_target() override;
virtual BAN::ErrorOr<BAN::Vector<BAN::String>> read_directory_entries(size_t) override;
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> read_directory_inode(BAN::StringView) override;
virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) override;
virtual BAN::ErrorOr<void> create_file(BAN::StringView, mode_t) override;
private:

View File

@ -78,6 +78,8 @@ namespace Kernel
virtual BAN::StringView name() const = 0;
virtual BAN::ErrorOr<BAN::String> link_target() { ASSERT_NOT_REACHED(); }
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> read_directory_inode(BAN::StringView) { if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); ASSERT_NOT_REACHED(); }
virtual BAN::ErrorOr<BAN::Vector<BAN::String>> read_directory_entries(size_t) { if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); ASSERT_NOT_REACHED(); }

View File

@ -25,7 +25,7 @@ namespace Kernel
BAN::RefPtr<Inode> inode;
BAN::String canonical_path;
};
BAN::ErrorOr<File> file_from_absolute_path(BAN::StringView);
BAN::ErrorOr<File> file_from_absolute_path(BAN::StringView, bool follow_links);
private:
VirtualFileSystem() = default;
@ -39,7 +39,7 @@ namespace Kernel
MountPoint* mount_from_root_inode(BAN::RefPtr<Inode>);
private:
SpinLock m_lock;
RecursiveSpinLock m_lock;
FileSystem* m_root_fs = nullptr;
BAN::Vector<MountPoint> m_mount_points;
};

View File

@ -247,6 +247,14 @@ namespace Kernel
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<BAN::String> Ext2Inode::link_target()
{
ASSERT(mode().iflnk());
if (m_inode.size < sizeof(m_inode.block))
return BAN::String((const char*)m_inode.block);
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<size_t> Ext2Inode::read(size_t offset, void* buffer, size_t count)
{
// FIXME: update atime if needed

View File

@ -40,7 +40,7 @@ namespace Kernel
BAN::ErrorOr<void> VirtualFileSystem::mount(BAN::StringView partition, BAN::StringView target)
{
auto partition_file = TRY(file_from_absolute_path(partition));
auto partition_file = TRY(file_from_absolute_path(partition, true));
if (partition_file.inode->inode_type() != Inode::InodeType::Device)
return BAN::Error::from_errno(ENOTBLK);
@ -54,7 +54,7 @@ namespace Kernel
BAN::ErrorOr<void> VirtualFileSystem::mount(FileSystem* file_system, BAN::StringView path)
{
auto file = TRY(file_from_absolute_path(path));
auto file = TRY(file_from_absolute_path(path, true));
if (!file.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);
@ -82,7 +82,7 @@ namespace Kernel
return nullptr;
}
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_absolute_path(BAN::StringView path)
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_absolute_path(BAN::StringView path, bool follow_links)
{
LockGuard _(m_lock);
@ -124,6 +124,28 @@ namespace Kernel
if (auto* mount_point = mount_from_host_inode(inode))
inode = mount_point->target->root_inode();
if (follow_links && inode->mode().iflnk())
{
auto target = TRY(inode->link_target());
if (target.empty())
return BAN::Error::from_errno(ENOENT);
if (target.front() == '/')
{
File file = TRY(file_from_absolute_path(target, follow_links));
inode = file.inode;
canonical_path = BAN::move(file.canonical_path);
}
else
{
while (canonical_path.back() != '/')
canonical_path.pop_back();
TRY(canonical_path.append(target));
File file = TRY(file_from_absolute_path(canonical_path, follow_links));
inode = file.inode;
canonical_path = BAN::move(file.canonical_path);
}
}
}
}

View File

@ -301,7 +301,7 @@ namespace Kernel
BAN::String absolute_path = TRY(absolute_path_of(path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path, !(flags & O_NOFOLLOW)));
LockGuard _(m_lock);
int fd = TRY(get_free_fd());
@ -421,7 +421,7 @@ namespace Kernel
auto directory = absolute_path.sv().substring(0, index);
auto file_name = absolute_path.sv().substring(index);
auto parent_file = TRY(VirtualFileSystem::get().file_from_absolute_path(directory));
auto parent_file = TRY(VirtualFileSystem::get().file_from_absolute_path(directory, true));
TRY(parent_file.inode->create_file(file_name, mode));
return {};
@ -510,7 +510,7 @@ namespace Kernel
{
BAN::String absolute_path = TRY(absolute_path_of(path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path, true));
if (!file.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR);