#include "filesystem/vfs.hpp" #include "kapi/system.hpp" #include "devices/device.hpp" #include "devices/storage/storage_management.hpp" #include "filesystem/custody.hpp" #include "filesystem/device_file.hpp" #include "filesystem/ext2/ext2_filesystem.hpp" #include "filesystem/inode.hpp" #include "filesystem/inode_file.hpp" #include "filesystem/mount.hpp" #include "filesystem/open_file_description.hpp" #include #include #include #include namespace filesystem { namespace { constinit auto static active_vfs = std::optional{}; // TODO BA-FS26 @Felix better solution? while dynamic memory not available? // TODO BA-FS26 remove when dynamic memory available; constinit auto static root_fs = std::optional{}; // TODO BA-FS26 remove when dynamic memory available; constinit auto static temp_device_file = std::optional{}; // TODO BA-FS26 remove when dynamic memory available; constinit auto static temp_inode_file = std::optional{}; } // namespace auto vfs::init() -> void { if (active_vfs) { kapi::system::panic("[FILESYSTEM] vfs has already been initialized."); } active_vfs.emplace(vfs{}); auto storage_mgmt = devices::storage::storage_management::get(); if (auto boot_device = storage_mgmt.determine_boot_device()) { root_fs.emplace(ext2::ext2_filesystem{}); if (root_fs->mount(boot_device) != 0) { kapi::system::panic("[FILESYSTEM] Failed to mount root filesystem."); } active_vfs->m_root_mount = mount{"/", &*root_fs}; std::ranges::for_each(storage_mgmt.all_controllers(), [&](auto controller) { std::ranges::for_each(controller->all_devices(), [&](auto device) { active_vfs->make_device_node(device); }); }); } 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) -> std::optional { if (auto custody = resolve_path(path)) { auto * node = custody->get_inode(); if (node->is_device()) { temp_device_file.emplace(node->backing_device()); temp_device_file->open(); return open_file_description{&*temp_device_file}; } temp_inode_file.emplace(node); temp_inode_file->open(); return open_file_description{&*temp_inode_file}; } return std::nullopt; } auto vfs::make_device_node(devices::device * device) -> void { if (!device) { kapi::system::panic("[FILESYSTEM] make_device_node called with null device."); } auto const device_name = device->name(); // TODO BA-FS26 this logic isn't needed anymore when kstd::vector available, just use push_back auto const slot = std::ranges::find_if(m_device_nodes, [](auto const & entry) { return !entry.has_value(); }); if (slot == m_device_nodes.end()) { kapi::system::panic("[FILESYSTEM] No free slot available for device nodes."); } slot->emplace(device_node_entry{device_name, inode{device}}); } auto vfs::resolve_path(std::string_view path) -> std::optional { // TODO BA-FS26 implement real path resolution with mounts and directories etc. // For now, just support device nodes at /dev/. constexpr auto device_prefix = std::string_view{"/dev/"}; if (path.starts_with(device_prefix)) { auto const device_name = path.substr(device_prefix.size()); auto entry = std::ranges::find_if(m_device_nodes, [&](auto const & device_entry) { return device_entry.has_value() && device_entry->name == device_name; }); if (entry != m_device_nodes.end()) { return custody{nullptr, &entry->value().node}; } return std::nullopt; } return std::nullopt; } } // namespace filesystem