diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/kernel/main.cpp | 2 | ||||
| -rw-r--r-- | kernel/kernel/vfs.cpp | 10 | ||||
| -rw-r--r-- | kernel/kernel/vfs.hpp | 14 | ||||
| -rw-r--r-- | kernel/kernel/vfs/directory_file_descriptor.cpp | 80 | ||||
| -rw-r--r-- | kernel/kernel/vfs/mount_table.cpp | 17 | ||||
| -rw-r--r-- | kernel/kernel/vfs/mount_table.hpp | 13 |
6 files changed, 134 insertions, 2 deletions
diff --git a/kernel/kernel/main.cpp b/kernel/kernel/main.cpp index 52562ad7..7083d517 100644 --- a/kernel/kernel/main.cpp +++ b/kernel/kernel/main.cpp @@ -227,7 +227,7 @@ auto run_demo() -> void auto stat = kapi::filesystem::status(kstd::format("{}/{}", path, entry.name)); if (stat) { - kstd::println("\t{:<8} {:<#8o} {:>#8} {:>3}:{<3} {}", stat->inode_number, stat->mode, stat->size, + kstd::println("\t{:<8} {:<#8o} {:>#8} {:>3}:{<3} {}", entry.inode_number, stat->mode, stat->size, stat->raw_device.major, stat->raw_device.minor, entry.name); } else diff --git a/kernel/kernel/vfs.cpp b/kernel/kernel/vfs.cpp index 742af328..42e98219 100644 --- a/kernel/kernel/vfs.cpp +++ b/kernel/kernel/vfs.cpp @@ -279,6 +279,16 @@ namespace kernel::vfs return kstd::failure(errc::invalid_argument); } + auto vfs::houses_mounts(kstd::shared_ptr<dentry> parent) const -> bool + { + return m_mount_table.houses_mounts(parent); + } + + auto vfs::find_mount_at(kstd::shared_ptr<dentry> parent, std::string_view name) -> kstd::shared_ptr<struct mount> + { + return m_mount_table.find_mount_at(parent, name); + } + auto vfs::create_inode(std::string_view path, kapi::filesystem::file_type type, std::optional<kapi::filesystem::device_number> raw_device) -> kstd::result<void> { diff --git a/kernel/kernel/vfs.hpp b/kernel/kernel/vfs.hpp index 4528ab2e..a722a48d 100644 --- a/kernel/kernel/vfs.hpp +++ b/kernel/kernel/vfs.hpp @@ -109,6 +109,20 @@ namespace kernel::vfs auto create_device_node(std::string_view path, std::uint32_t mode, kapi::filesystem::device_number device) -> kstd::result<void>; + //! Check if a given given dentry houses any mounts. + //! + //! @param parent The suspected mount parent. + //! @return @c true iff. there is directory below the dentry that is a mount point, @c false otherwise. + [[nodiscard]] auto houses_mounts(kstd::shared_ptr<dentry> parent) const -> bool; + + //! Find the mount associated with a given directory in a given parent. + //! + //! @param parent The suspected parent of the suspected mount point. + //! @param name The name of the mount point. + //! @return The mount if it exists, nullptr otherwise. + [[nodiscard]] auto find_mount_at(kstd::shared_ptr<dentry> parent, std::string_view name) + -> kstd::shared_ptr<struct mount>; + private: // Note: Resolving a dentry requires traversing mount points; since the associated 'mount' object is discovered as a // byproduct of this traversal, we return it alongside the dentry to avoid redundant lookups in callers that require diff --git a/kernel/kernel/vfs/directory_file_descriptor.cpp b/kernel/kernel/vfs/directory_file_descriptor.cpp index c1fb2a55..54785f81 100644 --- a/kernel/kernel/vfs/directory_file_descriptor.cpp +++ b/kernel/kernel/vfs/directory_file_descriptor.cpp @@ -1,18 +1,89 @@ #include <kernel/vfs/directory_file_descriptor.hpp> -#include <kernel/vfs/dentry.hpp> +#include <kernel/vfs.hpp> #include <kapi/filesystem.hpp> #include <kstd/memory.hpp> #include <kstd/result.hpp> +#include <algorithm> #include <cstddef> +#include <ranges> #include <span> namespace kernel::vfs { + namespace + { + + auto fixup_dot_dot(std::span<kapi::filesystem::directory_entry> entries, + kstd::shared_ptr<dentry> const & current_directory) -> void + { + auto state = current_directory->inode()->driver_state().lock(); + if (!state) + { + return; + } + + auto mount = state->owner().lock(); + if (!mount || mount->root_dentry() != current_directory || mount->mount_path() == "/") + { + return; + } + + auto parent = mount->mount_dentry()->parent(); + if (!parent) + { + return; + } + + auto parent_status = parent->inode()->status(); + if (!parent_status) + { + return; + } + + auto found = std::ranges::find(entries, "..", &kapi::filesystem::directory_entry::name); + if (found != std::ranges::end(entries)) + { + found->inode_number = parent_status->inode_number; + } + } + + auto fixup_mounts(std::span<kapi::filesystem::directory_entry> entries, + kstd::shared_ptr<dentry> const & current_directory) -> void + { + auto directories = std::views::filter( + entries, [](auto const & entry) { return entry.type == kapi::filesystem::file_type::directory; }); + + auto & vfs_instance = vfs::vfs::get(); + + if (!vfs_instance.houses_mounts(current_directory)) + { + return; + } + + std::ranges::for_each(directories, [&](auto & entry) { + auto mounted = vfs_instance.find_mount_at(current_directory, entry.name); + if (!mounted) + { + return; + } + + auto mount_root_status = mounted->root_dentry()->inode()->status(); + if (!mount_root_status) + { + return; + } + + entry.inode_number = mount_root_status->inode_number; + }); + } + + } // namespace + auto directory_file_descriptor::read_directory(std::span<kapi::filesystem::directory_entry> entries) -> kstd::result<std::size_t> { @@ -23,6 +94,13 @@ namespace kernel::vfs } m_position = result->second; + auto const count = result->first; + + auto valid_entries = entries.first(count); + + fixup_dot_dot(valid_entries, get_dentry()); + fixup_mounts(valid_entries, get_dentry()); + return result->first; } diff --git a/kernel/kernel/vfs/mount_table.cpp b/kernel/kernel/vfs/mount_table.cpp index 43dff516..c7198396 100644 --- a/kernel/kernel/vfs/mount_table.cpp +++ b/kernel/kernel/vfs/mount_table.cpp @@ -83,6 +83,23 @@ namespace kernel::vfs return (mount_it != m_mounts.end()) ? *mount_it : nullptr; } + auto mount_table::houses_mounts(kstd::shared_ptr<dentry> parent) const -> bool + { + return std::ranges::any_of(m_mounts, [&](auto const & mount) { + auto const dentry = mount->mount_dentry(); + return dentry && dentry->parent() == parent; + }); + } + + auto mount_table::find_mount_at(kstd::shared_ptr<dentry> parent, std::string_view name) -> kstd::shared_ptr<mount> + { + auto found = std::ranges::find_last_if(m_mounts, [&](auto const & mount) { + auto const & dentry = mount->mount_dentry(); + return dentry && dentry->parent() == parent && dentry->name() == name; + }); + return found.begin() != std::ranges::end(m_mounts) ? *found.begin() : nullptr; + } + auto mount_table::move_mount(kstd::shared_ptr<mount> const & mount, kstd::shared_ptr<dentry> const & mount_point, kstd::shared_ptr<struct mount> const & parent) -> void { diff --git a/kernel/kernel/vfs/mount_table.hpp b/kernel/kernel/vfs/mount_table.hpp index d2bb2f94..afeaf5eb 100644 --- a/kernel/kernel/vfs/mount_table.hpp +++ b/kernel/kernel/vfs/mount_table.hpp @@ -38,6 +38,19 @@ namespace kernel::vfs //! @return A pointer to the mount with the exact matching path on success, nullpointer otherwise. [[nodiscard]] auto find_mount(std::string_view path) const -> kstd::shared_ptr<mount>; + //! Check if a given given dentry houses any mounts. + //! + //! @param parent The suspected mount parent. + //! @return @c true iff. there is directory below the dentry that is a mount point, @c false otherwise. + [[nodiscard]] auto houses_mounts(kstd::shared_ptr<dentry> parent) const -> bool; + + //! Find the mount associated with a given directory in a given parent. + //! + //! @param parent The suspected parent of the suspected mount point. + //! @param name The name of the mount point. + //! @return The mount if it exists, nullptr otherwise. + [[nodiscard]] auto find_mount_at(kstd::shared_ptr<dentry> parent, std::string_view name) -> kstd::shared_ptr<mount>; + //! Move the mount attachment of an existing mount //! //! @param mount The mount to modify. |
