aboutsummaryrefslogtreecommitdiff
path: root/kernel/src/filesystem/vfs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src/filesystem/vfs.cpp')
-rw-r--r--kernel/src/filesystem/vfs.cpp151
1 files changed, 119 insertions, 32 deletions
diff --git a/kernel/src/filesystem/vfs.cpp b/kernel/src/filesystem/vfs.cpp
index 5b454f6..519550b 100644
--- a/kernel/src/filesystem/vfs.cpp
+++ b/kernel/src/filesystem/vfs.cpp
@@ -1,16 +1,22 @@
#include <kernel/filesystem/vfs.hpp>
+#include <kernel/filesystem/constants.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/path.hpp>
#include <kernel/filesystem/rootfs/filesystem.hpp>
#include <kapi/system.hpp>
#include <kstd/memory>
+#include <kstd/string>
+#include <kstd/vector>
+#include <algorithm>
+#include <cstdint>
#include <optional>
#include <ranges>
#include <string_view>
@@ -38,18 +44,34 @@ namespace kernel::filesystem
auto root_fs = kstd::make_shared<rootfs::filesystem>();
root_fs->mount(nullptr);
- auto root_fs_root_dentry = kstd::make_shared<dentry>(nullptr, root_fs->root_inode());
- m_mount_table.add_mount(kstd::make_shared<mount>(nullptr, root_fs_root_dentry, root_fs, "", nullptr));
+ auto root_fs_root_dentry = kstd::make_shared<dentry>(nullptr, root_fs->root_inode(), "/");
+ m_mount_table.add_mount(kstd::make_shared<mount>(nullptr, root_fs_root_dentry, root_fs, "/", nullptr));
+ // Mount devfs at /dev in rootfs (temporary, will be shadowed)
auto device_fs = kstd::make_shared<devfs::filesystem>();
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_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);
+ 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<dentry>(boot_root_dentry, device_fs->root_inode(), "dev");
+ boot_root_dentry->add_child(dev_dentry);
+
+ do_mount_internal(dev_dentry, device_fs);
+ }
}
}
}
@@ -71,7 +93,7 @@ namespace kernel::filesystem
auto vfs::do_mount(std::string_view source, std::string_view target) -> operation_result
{
- if (target.empty() || target.front() != '/' || (target.size() > 1 && target.back() == '/'))
+ if (!path::is_valid_path(source) || !path::is_valid_path(target))
{
return operation_result::invalid_path;
}
@@ -82,7 +104,7 @@ namespace kernel::filesystem
{
if (auto fs = kernel::filesystem::filesystem::probe_and_mount(source_dentry->get_inode()))
{
- do_mount_internal(target, mount_point_dentry, fs);
+ do_mount_internal(mount_point_dentry, fs);
return operation_result::success;
}
return operation_result::invalid_filesystem;
@@ -94,7 +116,7 @@ namespace kernel::filesystem
auto vfs::unmount(std::string_view path) -> operation_result
{
- if (path.empty() || path.front() != '/' || (path.size() > 1 && path.back() == '/'))
+ if (!path::is_valid_path(path))
{
return operation_result::invalid_path;
}
@@ -113,55 +135,120 @@ namespace kernel::filesystem
return operation_result::mount_point_not_found;
}
- auto vfs::do_mount_internal(std::string_view path, kstd::shared_ptr<dentry> const & mount_point_dentry,
+ auto vfs::do_mount_internal(kstd::shared_ptr<dentry> const & mount_point_dentry,
kstd::shared_ptr<filesystem> const & fs) -> void
{
- auto parent_mount = m_mount_table.find_longest_prefix_mount(path);
- auto new_fs_root = kstd::make_shared<dentry>(mount_point_dentry, fs->root_inode());
- auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, path, parent_mount);
+ auto mount_path = mount_point_dentry->get_full_path();
+ // TODO BA-FS26 refactoring, implement dentry lookup to get the parent mount...
+ auto parent_mount = m_mount_table.find_longest_prefix_mount(mount_path.view());
+
+ auto new_fs_root =
+ kstd::make_shared<dentry>(mount_point_dentry->get_parent(), fs->root_inode(), mount_point_dentry->get_name());
+ auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, mount_path.view(), parent_mount);
m_mount_table.add_mount(new_mount);
}
auto vfs::resolve_path(std::string_view path) -> kstd::shared_ptr<dentry>
{
- // 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() != '/')
+ if (!path::is_valid_absolute_path(path))
+ {
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_exact_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();
- std::string_view remaining = path.substr(best_mount->get_mount_path().size());
+ auto path_parts = path::split(path);
+ kstd::vector path_parts_vector(path_parts.begin(), path_parts.end());
+ std::ranges::reverse(path_parts_vector);
- auto path_parts =
- std::views::split(remaining, '/') | std::views::filter([](auto const & part) { return !part.empty(); });
+ auto symlink_counter = 0uz;
- for (auto const & part : path_parts)
+ while (!path_parts_vector.empty())
{
- std::string_view part_view{part};
+ 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->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);
+ auto next_dentry = current_dentry->find_child(part.view());
if (!next_dentry)
{
- auto found_inode = current_fs->lookup(current_dentry->get_inode(), part_view);
+ auto current_fs = current_mount->get_filesystem();
+ auto found_inode = current_fs->lookup(current_dentry->get_inode(), part.view());
if (!found_inode)
+ {
return nullptr;
+ }
- next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part_view);
+ next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part.view());
current_dentry->add_child(next_dentry);
}
+ else if (next_dentry->has_flag(dentry::dentry_flags::mounted))
+ {
+ current_mount = m_mount_table.find_exact_mount(next_dentry->get_full_path().view());
+ if (!current_mount)
+ {
+ kapi::system::panic("[FILESYSTEM] mount for dentry with mounted flag not found.");
+ }
+
+ next_dentry = current_mount->root_dentry();
+ }
+
+ if (next_dentry->get_inode()->is_symbolic_link())
+ {
+ if (symlink_counter++ > constants::symloop_max)
+ {
+ return nullptr;
+ }
+
+ kstd::vector<uint8_t> 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<char const *>(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_exact_mount("/");
+ current_dentry = current_mount->root_dentry();
+ }
+ continue;
+ }
current_dentry = next_dentry;
}