#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { constinit auto static active_vfs = std::optional{}; } // namespace namespace kernel::filesystem { 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 { // mount rootfs at / auto root_fs = kstd::make_shared(); root_fs->mount(nullptr); auto root_fs_root_dentry = kstd::make_shared(nullptr, root_fs->root_inode(), "/"); auto root_mount = kstd::make_shared(nullptr, root_fs_root_dentry, root_fs, nullptr); m_mount_table.add_mount(root_mount); // mount devfs at /dev (inside rootfs, temporary, will be shadowed) auto device_fs = kstd::make_shared(); device_fs->mount(nullptr); graft_persistent_device_fs(device_fs); // mount boot fs at / (shadows rootfs), re-graft devfs 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())) { if (auto root_dentry = resolve_path("/")) { do_mount_internal(root_dentry, root_mount, boot_root_fs); graft_persistent_device_fs(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 { auto [dentry, mount] = resolve_path_internal(path); mount->increment_ref_count(); return dentry; } auto vfs::close(kstd::shared_ptr const & dentry) -> operation_result { if (auto mount = find_mount(dentry->get_absolute_path().view())) { if (mount->decrement_ref_count()) { return operation_result::success; } return operation_result::close_failed; } return operation_result::invalid_path; } auto vfs::do_mount(std::string_view source, std::string_view target) -> operation_result { if (!path::is_valid_path(source) || !path::is_valid_path(target)) { return operation_result::invalid_path; } auto [mount_point_dentry, mount_context] = resolve_path_internal(target); if (mount_point_dentry && mount_context) { if (auto source_dentry = resolve_path(source)) { if (auto fs = kernel::filesystem::filesystem::probe_and_mount(source_dentry->get_inode())) { do_mount_internal(mount_point_dentry, mount_context, fs); return operation_result::success; } return operation_result::invalid_filesystem; } return operation_result::non_existent_path; } return operation_result::mount_point_not_found; } auto vfs::unmount(std::string_view path) -> operation_result { if (!path::is_valid_path(path)) { 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(kstd::shared_ptr const & mount_point_dentry, kstd::shared_ptr const & parent_mount, kstd::shared_ptr const & fs) -> void { 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, parent_mount); m_mount_table.add_mount(new_mount); } auto vfs::graft_persistent_device_fs(kstd::shared_ptr const & device_fs) -> void { auto [root_mount_point_dentry, root_mount] = resolve_path_internal("/"); if (root_mount_point_dentry && root_mount) { auto dev_dentry = root_mount_point_dentry->find_child("dev"); if (!dev_dentry) { dev_dentry = kstd::make_shared(root_mount_point_dentry, device_fs->root_inode(), "dev"); root_mount_point_dentry->add_child(dev_dentry); } do_mount_internal(dev_dentry, root_mount, device_fs); } } auto vfs::resolve_path_internal(std::string_view path) -> std::pair, kstd::shared_ptr> { if (!path::is_valid_absolute_path(path)) { return {nullptr, nullptr}; } auto current_mount = m_mount_table.find_mount("/"); if (!current_mount) { kapi::system::panic("[FILESYSTEM] no root mount found."); } auto current_dentry = current_mount->get_root_dentry(); auto path_parts = path::split(path); kstd::vector path_parts_vector(path_parts.begin(), path_parts.end()); std::ranges::reverse(path_parts_vector); auto symlink_counter = 0uz; while (!path_parts_vector.empty()) { 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->get_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()); 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, nullptr}; } 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::is_mount_point)) { current_mount = m_mount_table.find_mount(next_dentry->get_absolute_path().view()); if (!current_mount) { kapi::system::panic("[FILESYSTEM] mount for dentry with mounted flag not found."); } next_dentry = current_mount->get_root_dentry(); } if (next_dentry->get_inode()->is_symbolic_link()) { if (symlink_counter++ > constants::symloop_max) { return {nullptr, nullptr}; } kstd::vector 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(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_mount("/"); current_dentry = current_mount->get_root_dentry(); } continue; } current_dentry = next_dentry; } return {current_dentry, current_mount}; } auto vfs::resolve_path(std::string_view path) -> kstd::shared_ptr { return resolve_path_internal(path).first; } auto vfs::find_mount(std::string_view path) -> kstd::shared_ptr { return resolve_path_internal(path).second; } } // namespace kernel::filesystem namespace kernel::tests::filesystem::vfs { auto deinit() -> void { active_vfs.reset(); } } // namespace kernel::tests::filesystem::vfs