From 232fdcb82c3c8278694124bcfa3ab4524de6e964 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Thu, 1 Jun 2023 00:24:45 +0300 Subject: [PATCH] Kernel: add basic support for symlinks --- kernel/include/kernel/FS/Ext2.h | 5 +++- kernel/include/kernel/FS/Inode.h | 2 ++ kernel/include/kernel/FS/VirtualFileSystem.h | 4 +-- kernel/kernel/FS/Ext2.cpp | 8 ++++++ kernel/kernel/FS/VirtualFileSystem.cpp | 28 +++++++++++++++++--- kernel/kernel/Process.cpp | 6 ++--- 6 files changed, 44 insertions(+), 9 deletions(-) diff --git a/kernel/include/kernel/FS/Ext2.h b/kernel/include/kernel/FS/Ext2.h index a0606317f..c7b10832a 100644 --- a/kernel/include/kernel/FS/Ext2.h +++ b/kernel/include/kernel/FS/Ext2.h @@ -141,10 +141,13 @@ namespace Kernel virtual BAN::StringView name() const override { return m_name; } - virtual BAN::ErrorOr read(size_t, void*, size_t) override; + virtual BAN::ErrorOr link_target() override; + virtual BAN::ErrorOr> read_directory_entries(size_t) override; virtual BAN::ErrorOr> read_directory_inode(BAN::StringView) override; + virtual BAN::ErrorOr read(size_t, void*, size_t) override; + virtual BAN::ErrorOr create_file(BAN::StringView, mode_t) override; private: diff --git a/kernel/include/kernel/FS/Inode.h b/kernel/include/kernel/FS/Inode.h index 354b8332a..0f602f063 100644 --- a/kernel/include/kernel/FS/Inode.h +++ b/kernel/include/kernel/FS/Inode.h @@ -78,6 +78,8 @@ namespace Kernel virtual BAN::StringView name() const = 0; + virtual BAN::ErrorOr link_target() { ASSERT_NOT_REACHED(); } + virtual BAN::ErrorOr> read_directory_inode(BAN::StringView) { if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); ASSERT_NOT_REACHED(); } virtual BAN::ErrorOr> read_directory_entries(size_t) { if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); ASSERT_NOT_REACHED(); } diff --git a/kernel/include/kernel/FS/VirtualFileSystem.h b/kernel/include/kernel/FS/VirtualFileSystem.h index d74bfcfba..c2e815d2b 100644 --- a/kernel/include/kernel/FS/VirtualFileSystem.h +++ b/kernel/include/kernel/FS/VirtualFileSystem.h @@ -25,7 +25,7 @@ namespace Kernel BAN::RefPtr inode; BAN::String canonical_path; }; - BAN::ErrorOr file_from_absolute_path(BAN::StringView); + BAN::ErrorOr 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); private: - SpinLock m_lock; + RecursiveSpinLock m_lock; FileSystem* m_root_fs = nullptr; BAN::Vector m_mount_points; }; diff --git a/kernel/kernel/FS/Ext2.cpp b/kernel/kernel/FS/Ext2.cpp index 0237ee1ea..0fb86e073 100644 --- a/kernel/kernel/FS/Ext2.cpp +++ b/kernel/kernel/FS/Ext2.cpp @@ -247,6 +247,14 @@ namespace Kernel ASSERT_NOT_REACHED(); } + BAN::ErrorOr 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 Ext2Inode::read(size_t offset, void* buffer, size_t count) { // FIXME: update atime if needed diff --git a/kernel/kernel/FS/VirtualFileSystem.cpp b/kernel/kernel/FS/VirtualFileSystem.cpp index d22c75440..e4b852424 100644 --- a/kernel/kernel/FS/VirtualFileSystem.cpp +++ b/kernel/kernel/FS/VirtualFileSystem.cpp @@ -40,7 +40,7 @@ namespace Kernel BAN::ErrorOr 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 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_from_absolute_path(BAN::StringView path) + BAN::ErrorOr 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); + } + } } } diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index e62182069..1f2060ae9 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -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);