#include "kernel/filesystem/mount_table.hpp" #include "kernel/filesystem/dentry.hpp" #include "kernel/filesystem/mount.hpp" #include #include #include #include #include #include namespace kernel::filesystem { namespace { auto is_descendant_of(kstd::shared_ptr const & candidate, kstd::shared_ptr const & ancestor) -> bool { for (auto current = candidate; current; current = current->get_parent_mount()) { if (current == ancestor) { return true; } } return false; } auto is_strict_prefix(std::string_view prefix, std::string_view path) -> bool { return prefix != "/" && path.starts_with(prefix) && path.size() > prefix.size() && path[prefix.size()] == '/'; } auto is_visible_mount(kstd::shared_ptr const & candidate, kstd::vector> const & mounts) -> bool { return std::ranges::none_of(mounts, [&](auto const & other) { return other != candidate && is_strict_prefix(other->get_mount_path(), candidate->get_mount_path()) && !is_descendant_of(candidate, other); }); } } // namespace auto mount_table::has_child_mounts(kstd::shared_ptr const & parent_mount) const -> bool { return std::ranges::any_of( m_mounts, [&parent_mount](auto const & mount) { return mount->get_parent_mount() == parent_mount; }); } void mount_table::add_mount(kstd::shared_ptr const & mount) { m_mounts.push_back(mount); if (auto mount_dentry = mount->get_mount_dentry()) { mount_dentry->set_flag(dentry::dentry_flags::dcache_mounted); } } auto mount_table::remove_mount(std::string_view path) -> operation_result { auto mount_it = std::ranges::find_if(std::ranges::reverse_view(m_mounts), [&](auto const & mount) { return mount->get_mount_path() == path && is_visible_mount(mount, m_mounts); }); if (mount_it == std::ranges::reverse_view(m_mounts).end()) { return operation_result::mount_not_found; } auto const & mount = *mount_it; if (has_child_mounts(mount)) { return operation_result::has_child_mounts; } mount->get_mount_dentry()->unset_flag(dentry::dentry_flags::dcache_mounted); m_mounts.erase(std::ranges::find(m_mounts, mount)); return operation_result::removed; } auto mount_table::find_longest_prefix_mount(std::string_view path) const -> kstd::shared_ptr { kstd::shared_ptr mount_with_longest_prefix = nullptr; std::size_t best_len = 0; for (auto const & mount : m_mounts) { auto mp = mount->get_mount_path(); // /a/b/c should match /a/b but not /a/bb or /a/b/c/d, / should match everything bool is_prefix = path.starts_with(mp) && (mp == "/" || path.size() == mp.size() || path[mp.size()] == '/'); bool visible = is_visible_mount(mount, m_mounts); if (is_prefix && visible && mp.size() >= best_len) { mount_with_longest_prefix = mount; best_len = mp.size(); } } return mount_with_longest_prefix; } } // namespace kernel::filesystem