#include "kernel/filesystem/vfs.hpp" #include "kapi/system.hpp" #include "kernel/devices/storage/management.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/open_file_description.hpp" #include "kernel/filesystem/rootfs/filesystem.hpp" #include #include #include #include namespace kernel::filesystem { namespace { constinit auto static active_vfs = std::optional{}; } // namespace auto vfs::init() -> void { if (active_vfs) { kapi::system::panic("[FILESYSTEM] vfs has already been initialized."); } active_vfs.emplace(vfs{}); active_vfs->init_internal(); } auto vfs::init_internal() -> void { 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 storage_mgmt = devices::storage::management::get(); if (auto boot_device = storage_mgmt.determine_boot_device()) { auto boot_root_fs = kernel::filesystem::filesystem::probe_and_mount(boot_device); do_mount_internal("/", root_fs_root_dentry, boot_root_fs); } auto device_fs = kstd::make_shared(); device_fs->mount(nullptr); do_mount_internal("/dev", root_fs_root_dentry, device_fs); } auto vfs::get() -> vfs & { if (!active_vfs) { kapi::system::panic("[FILESYSTEM] vfs has not been initialized."); } return *active_vfs; } auto vfs::open(std::string_view path) -> kstd::shared_ptr { if (auto dentry = resolve_path(path)) { return kstd::make_shared(dentry->get_inode()); } return nullptr; } auto vfs::do_mount(std::string_view path, kstd::shared_ptr const & filesystem) -> operation_result { if (!filesystem) { return operation_result::filesystem_null; } if (path.empty() || path.front() != '/' || (path.size() > 1 && path.back() == '/')) { return operation_result::invalid_path; } if (auto mount_point_dentry = resolve_path(path)) { do_mount_internal(path, mount_point_dentry, filesystem); return operation_result::success; } return operation_result::mount_point_not_found; } auto vfs::unmount(std::string_view path) -> operation_result { if (path.empty() || path.front() != '/' || (path.size() > 1 && path.back() == '/')) { return operation_result::invalid_path; } auto remove_result = m_mount_table.remove_mount(path); if (remove_result == mount_table::operation_result::removed) { return operation_result::success; } if (remove_result == mount_table::operation_result::has_child_mounts) { return operation_result::unmount_failed; } return operation_result::mount_point_not_found; } auto vfs::do_mount_internal(std::string_view path, kstd::shared_ptr const & mount_point_dentry, 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_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) { kapi::system::panic("[FILESYSTEM] no root mount found."); } auto current_dentry = best_mount->root_dentry(); auto current_fs = best_mount->get_filesystem(); std::string_view remaining = path.substr(best_mount->get_mount_path().size()); auto path_parts = std::views::split(remaining, '/') | std::views::filter([](auto const & part) { return !part.empty(); }); for (auto const & part : path_parts) { std::string_view part_view{part}; auto next_dentry = current_dentry->find_child(part_view); if (!next_dentry) { auto found_inode = current_fs->lookup(current_dentry->get_inode(), part_view); if (!found_inode) return nullptr; next_dentry = kstd::make_shared(current_dentry, found_inode, part_view); current_dentry->add_child(next_dentry); } current_dentry = next_dentry; } return current_dentry; } } // namespace kernel::filesystem