From 8550b6a1aacc2bfce733dcac7a44065b7e9116a1 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Sat, 2 May 2026 14:14:24 +0200 Subject: relative path support --- kernel/src/filesystem/vfs.cpp | 115 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 100 insertions(+), 15 deletions(-) (limited to 'kernel/src/filesystem/vfs.cpp') diff --git a/kernel/src/filesystem/vfs.cpp b/kernel/src/filesystem/vfs.cpp index 5b454f6..41afad3 100644 --- a/kernel/src/filesystem/vfs.cpp +++ b/kernel/src/filesystem/vfs.cpp @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include @@ -35,21 +37,38 @@ namespace kernel::filesystem auto vfs::init_internal() -> void { + // Mount rootfs at / as the temporary base auto root_fs = kstd::make_shared(); root_fs->mount(nullptr); - auto root_fs_root_dentry = kstd::make_shared(nullptr, root_fs->root_inode()); - m_mount_table.add_mount(kstd::make_shared(nullptr, root_fs_root_dentry, root_fs, "", nullptr)); + auto root_fs_root_dentry = kstd::make_shared(nullptr, root_fs->root_inode(), "/"); + m_mount_table.add_mount(kstd::make_shared(nullptr, root_fs_root_dentry, root_fs, "/", nullptr)); + // Mount devfs at /dev in rootfs (temporary, will be shadowed) auto device_fs = kstd::make_shared(); 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", 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); + + // Resolve / to get the boot root dentry + if (auto boot_root_dentry = resolve_path("/")) + { + auto dev_dentry = kstd::make_shared(boot_root_dentry, device_fs->root_inode(), "dev"); + boot_root_dentry->add_child(dev_dentry); + + do_mount_internal("/dev", dev_dentry, device_fs); + } } } } @@ -117,33 +136,46 @@ namespace kernel::filesystem kstd::shared_ptr const & fs) -> void { auto parent_mount = m_mount_table.find_longest_prefix_mount(path); - auto new_fs_root = kstd::make_shared(mount_point_dentry, fs->root_inode()); + auto new_fs_root = + kstd::make_shared(mount_point_dentry->get_parent(), fs->root_inode(), mount_point_dentry->get_name()); auto new_mount = kstd::make_shared(mount_point_dentry, new_fs_root, fs, path, parent_mount); m_mount_table.add_mount(new_mount); } auto vfs::resolve_path(std::string_view path) -> kstd::shared_ptr { - // 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() != '/') 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_longest_prefix_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(); + kstd::vector resolved_parts{}; + + // TODO BA-FS26 remove again an get path out of the dentires instead of building it up again here + auto build_resolved_path = [&resolved_parts]() { + kstd::string resolved_path{"/"}; + + for (auto const & resolved_part : resolved_parts) + { + if (resolved_path.size() > 1) + { + resolved_path += '/'; + } + + resolved_path += resolved_part; + } - std::string_view remaining = path.substr(best_mount->get_mount_path().size()); + return resolved_path; + }; + + std::string_view remaining = path.substr(current_mount->get_mount_path().size()); auto path_parts = std::views::split(remaining, '/') | std::views::filter([](auto const & part) { return !part.empty(); }); @@ -152,9 +184,50 @@ namespace kernel::filesystem { std::string_view part_view{part}; + if (part_view == ".") + { + continue; + } + + if (part_view == "..") + { + if (!resolved_parts.empty()) + { + resolved_parts.pop_back(); + } + + auto parent_dentry = current_dentry->get_parent(); + + if (current_dentry == current_mount->root_dentry()) + { + // change the mount point + if (auto parent_mount = current_mount->get_parent_mount()) + { + current_mount = parent_mount; + current_dentry = current_dentry->get_parent(); + + if (!parent_dentry) + { + parent_dentry = current_mount->root_dentry(); + } + } + } + + if (!parent_dentry) + { + return nullptr; + } + + current_dentry = parent_dentry; + continue; + } + + resolved_parts.push_back(part_view); + auto next_dentry = current_dentry->find_child(part_view); if (!next_dentry) { + auto current_fs = current_mount->get_filesystem(); auto found_inode = current_fs->lookup(current_dentry->get_inode(), part_view); if (!found_inode) return nullptr; @@ -162,6 +235,18 @@ namespace kernel::filesystem next_dentry = kstd::make_shared(current_dentry, found_inode, part_view); current_dentry->add_child(next_dentry); } + else if (next_dentry->has_flag(dentry::dentry_flags::mounted)) + { + // change the mount point + // TODO BA-FS26 get resolved path out of the dentry... + current_mount = m_mount_table.find_longest_prefix_mount(build_resolved_path().view()); + if (!current_mount) + { + kapi::system::panic("[FILESYSTEM] mount for dentry with mounted flag not found."); + } + + next_dentry = current_mount->root_dentry(); + } current_dentry = next_dentry; } -- cgit v1.2.3