diff options
Diffstat (limited to 'kernel/src/filesystem/vfs.cpp')
| -rw-r--r-- | kernel/src/filesystem/vfs.cpp | 151 |
1 files changed, 119 insertions, 32 deletions
diff --git a/kernel/src/filesystem/vfs.cpp b/kernel/src/filesystem/vfs.cpp index 5b454f6..519550b 100644 --- a/kernel/src/filesystem/vfs.cpp +++ b/kernel/src/filesystem/vfs.cpp @@ -1,16 +1,22 @@ #include <kernel/filesystem/vfs.hpp> +#include <kernel/filesystem/constants.hpp> #include <kernel/filesystem/dentry.hpp> #include <kernel/filesystem/devfs/filesystem.hpp> #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/mount.hpp> #include <kernel/filesystem/mount_table.hpp> +#include <kernel/filesystem/path.hpp> #include <kernel/filesystem/rootfs/filesystem.hpp> #include <kapi/system.hpp> #include <kstd/memory> +#include <kstd/string> +#include <kstd/vector> +#include <algorithm> +#include <cstdint> #include <optional> #include <ranges> #include <string_view> @@ -38,18 +44,34 @@ namespace kernel::filesystem auto root_fs = kstd::make_shared<rootfs::filesystem>(); root_fs->mount(nullptr); - auto root_fs_root_dentry = kstd::make_shared<dentry>(nullptr, root_fs->root_inode()); - m_mount_table.add_mount(kstd::make_shared<mount>(nullptr, root_fs_root_dentry, root_fs, "", nullptr)); + auto root_fs_root_dentry = kstd::make_shared<dentry>(nullptr, root_fs->root_inode(), "/"); + m_mount_table.add_mount(kstd::make_shared<mount>(nullptr, root_fs_root_dentry, root_fs, "/", nullptr)); + // Mount devfs at /dev in rootfs (temporary, will be shadowed) auto device_fs = kstd::make_shared<devfs::filesystem>(); device_fs->mount(nullptr); - do_mount_internal("/dev", root_fs_root_dentry, device_fs); + auto dev_mount_point_dentry = resolve_path("/dev"); + if (!dev_mount_point_dentry) + { + kapi::system::panic("[FILESYSTEM] failed to resolve /dev for initial devfs mount."); + } + do_mount_internal(dev_mount_point_dentry, device_fs); - if (auto boot_device_dentry = resolve_path("/dev/ram0")) // TODO BA-FS26 better boot device detection + // Mount boot filesystem at / (will shadow rootfs) + if (auto boot_device_dentry = resolve_path("/dev/ram0")) { if (auto boot_root_fs = kernel::filesystem::filesystem::probe_and_mount(boot_device_dentry->get_inode())) { - do_mount_internal("/", root_fs_root_dentry, boot_root_fs); + do_mount_internal(root_fs_root_dentry, boot_root_fs); + + // Resolve / to get the boot root dentry + if (auto boot_root_dentry = resolve_path("/")) + { + auto dev_dentry = kstd::make_shared<dentry>(boot_root_dentry, device_fs->root_inode(), "dev"); + boot_root_dentry->add_child(dev_dentry); + + do_mount_internal(dev_dentry, device_fs); + } } } } @@ -71,7 +93,7 @@ namespace kernel::filesystem auto vfs::do_mount(std::string_view source, std::string_view target) -> operation_result { - if (target.empty() || target.front() != '/' || (target.size() > 1 && target.back() == '/')) + if (!path::is_valid_path(source) || !path::is_valid_path(target)) { return operation_result::invalid_path; } @@ -82,7 +104,7 @@ namespace kernel::filesystem { if (auto fs = kernel::filesystem::filesystem::probe_and_mount(source_dentry->get_inode())) { - do_mount_internal(target, mount_point_dentry, fs); + do_mount_internal(mount_point_dentry, fs); return operation_result::success; } return operation_result::invalid_filesystem; @@ -94,7 +116,7 @@ namespace kernel::filesystem auto vfs::unmount(std::string_view path) -> operation_result { - if (path.empty() || path.front() != '/' || (path.size() > 1 && path.back() == '/')) + if (!path::is_valid_path(path)) { return operation_result::invalid_path; } @@ -113,55 +135,120 @@ namespace kernel::filesystem return operation_result::mount_point_not_found; } - auto vfs::do_mount_internal(std::string_view path, kstd::shared_ptr<dentry> const & mount_point_dentry, + auto vfs::do_mount_internal(kstd::shared_ptr<dentry> const & mount_point_dentry, kstd::shared_ptr<filesystem> const & fs) -> void { - auto parent_mount = m_mount_table.find_longest_prefix_mount(path); - auto new_fs_root = kstd::make_shared<dentry>(mount_point_dentry, fs->root_inode()); - auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, path, parent_mount); + auto mount_path = mount_point_dentry->get_full_path(); + // TODO BA-FS26 refactoring, implement dentry lookup to get the parent mount... + auto parent_mount = m_mount_table.find_longest_prefix_mount(mount_path.view()); + + auto new_fs_root = + kstd::make_shared<dentry>(mount_point_dentry->get_parent(), fs->root_inode(), mount_point_dentry->get_name()); + auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, mount_path.view(), parent_mount); m_mount_table.add_mount(new_mount); } auto vfs::resolve_path(std::string_view path) -> kstd::shared_ptr<dentry> { - // TODO BA-FS26 implement full path resolution semantics. - // TODO BA-FS26 better path validation - // TODO BA-FS26 implement a path parser (maybe in libs?) and use it here and in do_mount - - if (path.empty() || path.front() != '/') + if (!path::is_valid_absolute_path(path)) + { return nullptr; + } - // TODO BA-FS26 longest match in mount_table -> jump into final fs directly - // TODO BA-FS26 performance optimization first check mounted_flag O(1) then check mount_table O(n) - - auto best_mount = m_mount_table.find_longest_prefix_mount(path); - if (!best_mount) + auto current_mount = m_mount_table.find_exact_mount("/"); + if (!current_mount) { kapi::system::panic("[FILESYSTEM] no root mount found."); } - auto current_dentry = best_mount->root_dentry(); - auto current_fs = best_mount->get_filesystem(); + auto current_dentry = current_mount->root_dentry(); - std::string_view remaining = path.substr(best_mount->get_mount_path().size()); + auto path_parts = path::split(path); + kstd::vector path_parts_vector(path_parts.begin(), path_parts.end()); + std::ranges::reverse(path_parts_vector); - auto path_parts = - std::views::split(remaining, '/') | std::views::filter([](auto const & part) { return !part.empty(); }); + auto symlink_counter = 0uz; - for (auto const & part : path_parts) + while (!path_parts_vector.empty()) { - std::string_view part_view{part}; + auto part = path_parts_vector.back(); + path_parts_vector.pop_back(); + + if (part == ".") + { + continue; + } + + if (part == "..") + { + auto parent_dentry = current_dentry->get_parent(); + + if (current_dentry == current_mount->root_dentry()) + { + if (current_mount->get_mount_path() == "/") + { + continue; + } + + if (auto parent_mount = current_mount->get_parent_mount()) + { + current_mount = parent_mount; + current_dentry = parent_dentry; + } + } + + current_dentry = parent_dentry; + continue; + } - auto next_dentry = current_dentry->find_child(part_view); + auto next_dentry = current_dentry->find_child(part.view()); if (!next_dentry) { - auto found_inode = current_fs->lookup(current_dentry->get_inode(), part_view); + auto current_fs = current_mount->get_filesystem(); + auto found_inode = current_fs->lookup(current_dentry->get_inode(), part.view()); if (!found_inode) + { return nullptr; + } - next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part_view); + next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part.view()); current_dentry->add_child(next_dentry); } + else if (next_dentry->has_flag(dentry::dentry_flags::mounted)) + { + current_mount = m_mount_table.find_exact_mount(next_dentry->get_full_path().view()); + if (!current_mount) + { + kapi::system::panic("[FILESYSTEM] mount for dentry with mounted flag not found."); + } + + next_dentry = current_mount->root_dentry(); + } + + if (next_dentry->get_inode()->is_symbolic_link()) + { + if (symlink_counter++ > constants::symloop_max) + { + return nullptr; + } + + kstd::vector<uint8_t> buffer(constants::symlink_max_path_length); + auto const bytes_read = next_dentry->get_inode()->read(buffer.data(), 0, buffer.size()); + auto const symbolic_link_path = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read}; + + auto symbolic_link_parts = path::split(symbolic_link_path); + kstd::vector symbolic_link_parts_vector(symbolic_link_parts.begin(), symbolic_link_parts.end()); + std::ranges::reverse(symbolic_link_parts_vector); + + path_parts_vector.insert_range(path_parts_vector.end(), symbolic_link_parts_vector); + + if (path::is_valid_absolute_path(symbolic_link_path)) + { + current_mount = m_mount_table.find_exact_mount("/"); + current_dentry = current_mount->root_dentry(); + } + continue; + } current_dentry = next_dentry; } |
