#include "kernel/filesystem/vfs.hpp" #include "kapi/system.hpp" #include "kernel/devices/storage/storage_management.hpp" #include "kernel/filesystem/dentry.hpp" #include "kernel/filesystem/devfs/devfs_filesystem.hpp" #include "kernel/filesystem/ext2/ext2_filesystem.hpp" #include "kernel/filesystem/filesystem.hpp" #include "kernel/filesystem/mount.hpp" #include "kernel/filesystem/open_file_description.hpp" #include "kernel/filesystem/rootfs/rootfs_filesystem.hpp" #include #include #include #include namespace 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 virtual_fs = kstd::make_shared(); virtual_fs->mount(nullptr); auto virtual_root_dentry = kstd::make_shared(nullptr, virtual_fs->root_inode(), "/"); m_mount_table.add_mount(kstd::make_shared(nullptr, virtual_root_dentry, virtual_fs)); auto storage_mgmt = devices::storage::storage_management::get(); if (auto boot_device = storage_mgmt.determine_boot_device()) { // TODO BA-FS26 detect fs type from boot device and load corresponding fs, for now just assume ext2 auto boot_root_fs = kstd::make_shared(); boot_root_fs->mount(boot_device); if (do_mount("/", boot_root_fs) != 0) { kapi::system::panic("[FILESYSTEM] failed to mount root filesystem."); } auto device_fs = kstd::make_shared(); device_fs->mount(nullptr); if (do_mount("/dev", device_fs) != 0) { kapi::system::panic("[FILESYSTEM] failed to mount devfs at /dev."); } } else { // TODO BA-FS26 ?? what when no boot_device == no modules loaded?? } } 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) -> int { if (!filesystem) { return -1; // TODO BA-FS26 panic or errorcode? } if (path.empty() || path.front() != '/') { return -1; // TODO BA-FS26 panic or errorcode? } // TODO BA-FS26 better path validation if ((path.size() > 1 && path.back() == '/')) { return -1; // TODO BA-FS26 panic or errorcode? } if (auto mount_dentry = resolve_path(path)) { // TODO BA-FS26 check if mount point is already mounted and handle it (unmount old fs, fail, etc.) auto new_fs_root = kstd::make_shared(mount_dentry, filesystem->root_inode()); auto new_mount = kstd::make_shared(mount_dentry, new_fs_root, filesystem); m_mount_table.add_mount(new_mount); mount_dentry->set_flag(dentry::dentry_flags::dcache_mounted); return 0; } return -1; } 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() == '/') { auto root_mount = m_mount_table.get_root_mount(); if (!root_mount) { kapi::system::panic("[FILESYSTEM] no root mount found."); } auto current_dentry = root_mount->root_dentry(); auto current_fs = root_mount->get_filesystem(); // TODO BA-FS26 use while to allow stacked mounts? if (current_dentry->has_flag(dentry::dentry_flags::dcache_mounted)) { auto mnt = m_mount_table.find_mount_by_dentry(current_dentry); if (!mnt) kapi::system::panic("[FILESYSTEM] dcache_mounted set but no covering mount found."); current_dentry = mnt->root_dentry(); current_fs = mnt->get_filesystem(); } auto path_parts = std::views::split(path, '/') | 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) { if (auto found_inode = current_fs->lookup(current_dentry->get_inode(), part_view)) { next_dentry = kstd::make_shared(current_dentry, found_inode, part_view); current_dentry->add_child(next_dentry); } else { return nullptr; } } // TODO BA-FS26 use while to allow stacked mounts? if (next_dentry->has_flag(dentry::dentry_flags::dcache_mounted)) { auto found_mount = m_mount_table.find_mount_by_dentry(next_dentry); current_fs = found_mount->get_filesystem(); current_dentry = found_mount->root_dentry(); } else { current_dentry = next_dentry; } } return current_dentry; } return nullptr; } } // namespace filesystem