aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-06-02 17:32:08 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-06-02 17:32:08 +0200
commit3274bb4377b9f04b7a70139a86283e0fae44b228 (patch)
treeface2b0b544578e5efd1c28c8d75b3307d6e4a8a
parente92df52c599f78f36a278508a2b6be5f3a15f3db (diff)
parent46d3f8978e9f4235064daf5f19de5bf3054e7c24 (diff)
downloadkernel-3274bb4377b9f04b7a70139a86283e0fae44b228.tar.xz
kernel-3274bb4377b9f04b7a70139a86283e0fae44b228.zip
Merge branch 'fmorgner/develop-BA-FS26/dynamic-fs' into 'develop-BA-FS26'
Add support infrastructure for automatic file system registration See merge request teachos/kernel!46
-rw-r--r--arch/x86_64/scripts/kernel.ld6
-rw-r--r--kernel/CMakeLists.txt2
-rw-r--r--kernel/include/kernel/filesystem/type.hpp42
-rw-r--r--kernel/include/kernel/filesystem/type_registry.hpp53
-rw-r--r--kernel/include/kernel/filesystem/vfs.hpp7
-rw-r--r--kernel/kapi/filesystem.cpp2
-rw-r--r--kernel/src/filesystem/dentry.cpp2
-rw-r--r--kernel/src/filesystem/devfs/filesystem.cpp22
-rw-r--r--kernel/src/filesystem/ext2/filesystem.cpp23
-rw-r--r--kernel/src/filesystem/rootfs/filesystem.cpp25
-rw-r--r--kernel/src/filesystem/type_registry.cpp72
-rw-r--r--kernel/src/filesystem/type_registry.tests.cpp77
-rw-r--r--kernel/src/filesystem/vfs.cpp14
-rw-r--r--kernel/src/filesystem/vfs.tests.cpp32
-rw-r--r--kernel/src/main.cpp4
-rw-r--r--libs/acpi/acpi/common/basic_table.hpp5
-rw-r--r--libs/acpi/acpi/common/vla_table.hpp5
-rw-r--r--libs/kstd/kstd/flat_map16
-rw-r--r--libs/kstd/kstd/flat_map.test.cpp10
-rw-r--r--libs/kstd/kstd/string105
-rw-r--r--libs/kstd/kstd/string.test.cpp44
21 files changed, 455 insertions, 113 deletions
diff --git a/arch/x86_64/scripts/kernel.ld b/arch/x86_64/scripts/kernel.ld
index a429570..dbb0f8f 100644
--- a/arch/x86_64/scripts/kernel.ld
+++ b/arch/x86_64/scripts/kernel.ld
@@ -72,6 +72,12 @@ SECTIONS
.kernel_rodata ALIGN(4K) : AT (ADDR (.kernel_rodata) - TEACHOS_VMA)
{
*(.rodata*)
+
+ . = ALIGN(8);
+
+ PROVIDE(__start_fs_types = .);
+ KEEP(*(fs_types));
+ PROVIDE(__stop_fs_types = .);
} :kernel_rodata
.kernel_data ALIGN(4K) : AT (ADDR (.kernel_data) - TEACHOS_VMA)
diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt
index cbc7fa5..2388370 100644
--- a/kernel/CMakeLists.txt
+++ b/kernel/CMakeLists.txt
@@ -53,6 +53,7 @@ target_sources("kernel_lib" PRIVATE
"src/filesystem/mount.cpp"
"src/filesystem/open_file_descriptor.cpp"
"src/filesystem/open_file_table.cpp"
+ "src/filesystem/type_registry.cpp"
"src/filesystem/vfs.cpp"
# DevFS Filesystem
@@ -200,6 +201,7 @@ if(BUILD_TESTING)
"src/filesystem/mount.tests.cpp"
"src/filesystem/open_file_descriptor.tests.cpp"
"src/filesystem/open_file_table.tests.cpp"
+ "src/filesystem/type_registry.tests.cpp"
"src/filesystem/vfs.tests.cpp"
# Storage Subsystem Tests
diff --git a/kernel/include/kernel/filesystem/type.hpp b/kernel/include/kernel/filesystem/type.hpp
new file mode 100644
index 0000000..0948e54
--- /dev/null
+++ b/kernel/include/kernel/filesystem/type.hpp
@@ -0,0 +1,42 @@
+#ifndef TEACH_OS_KERNEL_FILESYSTEM_TYPE_HPP
+#define TEACH_OS_KERNEL_FILESYSTEM_TYPE_HPP
+
+#include <kernel/filesystem/filesystem.hpp>
+
+#include <kstd/memory>
+
+#include <string_view>
+
+namespace kernel::filesystem
+{
+
+ //! A type descriptor for a filesystem driver.
+ //!
+ //! Each filesystem must expose an instance of a class derived from this type in order to be registered with the vfs
+ //! filesystem registry.
+ struct type
+ {
+ virtual ~type() = default;
+
+ //! Get the name of the filesystem represented by this descriptor.
+ [[nodiscard]] virtual auto name() const noexcept -> std::string_view = 0;
+
+ //! Check if filesystems of this type require a device to back them.
+ [[nodiscard]] virtual auto requires_device() const noexcept -> bool = 0;
+
+ //! Create a new instance of the filesytem represented by this descriptor.
+ [[nodiscard]] virtual auto make_instance() const -> kstd::shared_ptr<filesystem> = 0;
+ };
+
+ template<typename Type>
+ struct type_registration
+ {
+ constexpr auto static instance = Type{};
+ [[using gnu: section("fs_types"), used, visibility("hidden")]] constexpr auto static pointer{
+ kstd::make_observer<type const>(&instance),
+ };
+ };
+
+} // namespace kernel::filesystem
+
+#endif
diff --git a/kernel/include/kernel/filesystem/type_registry.hpp b/kernel/include/kernel/filesystem/type_registry.hpp
new file mode 100644
index 0000000..3be7295
--- /dev/null
+++ b/kernel/include/kernel/filesystem/type_registry.hpp
@@ -0,0 +1,53 @@
+#ifndef TEACH_OS_KERNEL_TYPE_REGISRY_HPP
+#define TEACH_OS_KERNEL_TYPE_REGISRY_HPP
+
+#include <kernel/filesystem/type.hpp>
+
+#include <kstd/flat_map>
+#include <kstd/memory>
+#include <kstd/string>
+
+#include <cstddef>
+#include <span>
+#include <string_view>
+
+namespace kernel::filesystem
+{
+
+ struct type_registry
+ {
+ using value_type = type;
+ using pointer = kstd::observer_ptr<value_type const>;
+
+ auto static init() -> void;
+ auto static get() -> type_registry &;
+
+ constexpr type_registry() noexcept = default;
+
+ //! Add a type descriptor to this registry.
+ //!
+ //! This function will register the given descriptor with this registry, given that no descriptor for a filesystem
+ //! with the same name exists in this registry already.
+ //!
+ //! @param descriptor The filesystem type descriptor to add to the registry.
+ //! @return @p true iff. the descriptor was successfully added, @p false if not.
+ auto add(pointer descriptor) -> bool;
+
+ //! Get all currently registered type descriptors.
+ //!
+ //! @return A span containing all currently registered filesystem type descriptors.
+ [[nodiscard]] auto all() const noexcept -> std::span<pointer const>;
+
+ //! Get the number of registered filesystem types.
+ //!
+ //! @return The number of filesystem descriptors currently registered with this registry.
+ [[nodiscard]] auto size() const noexcept -> std::size_t;
+
+ private:
+ //! A map from filesystem names (identifiers) to filesystem type descriptors.
+ kstd::flat_map<std::string_view, pointer> m_descriptors{};
+ };
+
+} // namespace kernel::filesystem
+
+#endif
diff --git a/kernel/include/kernel/filesystem/vfs.hpp b/kernel/include/kernel/filesystem/vfs.hpp
index e6f2327..ddc9a9b 100644
--- a/kernel/include/kernel/filesystem/vfs.hpp
+++ b/kernel/include/kernel/filesystem/vfs.hpp
@@ -35,6 +35,8 @@ namespace kernel::filesystem
invalid_filesystem = -5
};
+ vfs();
+
/**
@brief Initialize the virtual filesystem.
@warning Panics if the VFS has already been initialized.
@@ -83,9 +85,6 @@ namespace kernel::filesystem
auto unmount(std::string_view path) -> operation_result;
private:
- vfs() = default;
- auto init_internal() -> void;
-
/**
* Note: Resolving a dentry requires traversing mount points; since the
* associated 'mount' object is discovered as a byproduct of this
@@ -107,7 +106,7 @@ namespace kernel::filesystem
auto graft_persistent_device_fs(kstd::shared_ptr<devfs::filesystem> const & device_fs) -> void;
- mount_table m_mount_table;
+ mount_table m_mount_table{};
};
} // namespace kernel::filesystem
diff --git a/kernel/kapi/filesystem.cpp b/kernel/kapi/filesystem.cpp
index 838d2cb..68b51c9 100644
--- a/kernel/kapi/filesystem.cpp
+++ b/kernel/kapi/filesystem.cpp
@@ -45,7 +45,7 @@ namespace kapi::filesystem
{
if (auto open_file_descriptor = kernel::filesystem::open_file_table::get().file(file_descriptor))
{
- if (kernel::filesystem::vfs::get().close(open_file_descriptor->get_dentry()->absolute_path().view()) ==
+ if (kernel::filesystem::vfs::get().close(open_file_descriptor->get_dentry()->absolute_path()) ==
kernel::filesystem::vfs::operation_result::success)
{
return kernel::filesystem::open_file_table::get().remove_file(file_descriptor);
diff --git a/kernel/src/filesystem/dentry.cpp b/kernel/src/filesystem/dentry.cpp
index 14de875..3d8e01a 100644
--- a/kernel/src/filesystem/dentry.cpp
+++ b/kernel/src/filesystem/dentry.cpp
@@ -41,7 +41,7 @@ namespace kernel::filesystem
auto dentry::name() const -> std::string_view
{
- return m_name.view();
+ return m_name;
}
auto dentry::absolute_path() const -> kstd::string
diff --git a/kernel/src/filesystem/devfs/filesystem.cpp b/kernel/src/filesystem/devfs/filesystem.cpp
index f0d8bf7..ce887ff 100644
--- a/kernel/src/filesystem/devfs/filesystem.cpp
+++ b/kernel/src/filesystem/devfs/filesystem.cpp
@@ -5,6 +5,7 @@
#include <kernel/filesystem/devfs/inode.hpp>
#include <kernel/filesystem/device_inode.hpp>
#include <kernel/filesystem/inode.hpp>
+#include <kernel/filesystem/type.hpp>
#include <kapi/devices/device.hpp>
@@ -15,6 +16,27 @@
namespace kernel::filesystem::devfs
{
+ struct type final : kernel::filesystem::type
+ {
+ [[nodiscard]] auto name() const noexcept -> std::string_view override
+ {
+ return "devfs";
+ }
+
+ [[nodiscard]] auto requires_device() const noexcept -> bool override
+ {
+ return false;
+ }
+
+ [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override
+ {
+ return kstd::make_shared<filesystem>();
+ }
+ };
+
+ [[gnu::used]]
+ constexpr auto registration = type_registration<type>{};
+
auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> operation_result
{
m_root_inode = kstd::make_shared<inode>();
diff --git a/kernel/src/filesystem/ext2/filesystem.cpp b/kernel/src/filesystem/ext2/filesystem.cpp
index 12aeaaa..3180a19 100644
--- a/kernel/src/filesystem/ext2/filesystem.cpp
+++ b/kernel/src/filesystem/ext2/filesystem.cpp
@@ -6,6 +6,7 @@
#include <kernel/filesystem/ext2/superblock.hpp>
#include <kernel/filesystem/filesystem.hpp>
#include <kernel/filesystem/inode.hpp>
+#include <kernel/filesystem/type.hpp>
#include <kstd/memory>
#include <kstd/unikstd.h>
@@ -18,6 +19,28 @@
namespace kernel::filesystem::ext2
{
+
+ struct type final : kernel::filesystem::type
+ {
+ [[nodiscard]] auto name() const noexcept -> std::string_view override
+ {
+ return "ext2";
+ }
+
+ [[nodiscard]] auto requires_device() const noexcept -> bool override
+ {
+ return true;
+ }
+
+ [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override
+ {
+ return kstd::make_shared<filesystem>();
+ }
+ };
+
+ [[gnu::used]]
+ constexpr auto registration = type_registration<type>{};
+
auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> operation_result
{
kernel::filesystem::filesystem::mount(backing_inode);
diff --git a/kernel/src/filesystem/rootfs/filesystem.cpp b/kernel/src/filesystem/rootfs/filesystem.cpp
index 0ba2936..7fe5c1e 100644
--- a/kernel/src/filesystem/rootfs/filesystem.cpp
+++ b/kernel/src/filesystem/rootfs/filesystem.cpp
@@ -1,8 +1,9 @@
#include <kernel/filesystem/rootfs/filesystem.hpp>
-#include "kernel/filesystem/filesystem.hpp"
+#include <kernel/filesystem/filesystem.hpp>
#include <kernel/filesystem/inode.hpp>
#include <kernel/filesystem/rootfs/inode.hpp>
+#include <kernel/filesystem/type.hpp>
#include <kstd/memory>
@@ -10,6 +11,28 @@
namespace kernel::filesystem::rootfs
{
+
+ struct type final : kernel::filesystem::type
+ {
+ [[nodiscard]] auto name() const noexcept -> std::string_view override
+ {
+ return "rootfs";
+ }
+
+ [[nodiscard]] auto requires_device() const noexcept -> bool override
+ {
+ return true;
+ }
+
+ [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override
+ {
+ return kstd::make_shared<filesystem>();
+ }
+ };
+
+ [[gnu::used]]
+ constexpr auto registration = type_registration<type>{};
+
auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> operation_result
{
m_root_inode = kstd::make_shared<inode>();
diff --git a/kernel/src/filesystem/type_registry.cpp b/kernel/src/filesystem/type_registry.cpp
new file mode 100644
index 0000000..d917c81
--- /dev/null
+++ b/kernel/src/filesystem/type_registry.cpp
@@ -0,0 +1,72 @@
+#include <kernel/filesystem/type_registry.hpp>
+
+#include <kapi/system.hpp>
+
+#include <kstd/memory>
+#include <kstd/print>
+
+#include <algorithm>
+#include <cstddef>
+#include <optional>
+#include <ranges>
+#include <span>
+
+namespace kernel::filesystem
+{
+
+ extern "C"
+ {
+ extern type_registry::pointer const __start_fs_types;
+ extern type_registry::pointer const __stop_fs_types;
+ }
+
+ namespace
+ {
+ auto constinit instance = std::optional<type_registry>{};
+ }
+
+ auto type_registry::init() -> void
+ {
+ if (instance)
+ {
+ kapi::system::panic("[FILESYSTEM] tried to initialize type registry more than once!");
+ }
+
+ instance.emplace();
+
+ auto type_descriptors = std::span{&__start_fs_types, &__stop_fs_types} | //
+ std::views::filter([](auto p) { return p != nullptr; });
+
+ std::ranges::for_each(type_descriptors, [](auto descriptor) {
+ kstd::println("[FILESYSTEM] registering '{}'", descriptor->name());
+ instance->add(descriptor);
+ });
+ }
+
+ auto type_registry::get() -> type_registry &
+ {
+ if (!instance)
+ {
+ kapi::system::panic("[FILESYSTEM] type registry has not been initialized!");
+ }
+
+ return *instance;
+ }
+
+ auto type_registry::add(pointer descriptor) -> bool
+ {
+ auto result = m_descriptors.emplace(descriptor->name(), descriptor);
+ return result.second;
+ }
+
+ auto type_registry::all() const noexcept -> std::span<pointer const>
+ {
+ return {m_descriptors.values().begin(), m_descriptors.values().end()};
+ }
+
+ auto type_registry::size() const noexcept -> std::size_t
+ {
+ return m_descriptors.size();
+ }
+
+} // namespace kernel::filesystem
diff --git a/kernel/src/filesystem/type_registry.tests.cpp b/kernel/src/filesystem/type_registry.tests.cpp
new file mode 100644
index 0000000..8382579
--- /dev/null
+++ b/kernel/src/filesystem/type_registry.tests.cpp
@@ -0,0 +1,77 @@
+#include <kernel/filesystem/type_registry.hpp>
+
+#include <kernel/filesystem/filesystem.hpp>
+#include <kernel/filesystem/type.hpp>
+
+#include <kstd/memory>
+
+#include <catch2/catch_test_macros.hpp>
+
+#include <iterator>
+#include <string_view>
+
+struct test_type final : kernel::filesystem::type
+{
+ [[nodiscard]] auto name() const noexcept -> std::string_view override
+ {
+ return "bht_testfs";
+ }
+
+ [[nodiscard]] auto requires_device() const noexcept -> bool override
+ {
+ return false;
+ }
+
+ [[nodiscard]] auto make_instance() const -> kstd::shared_ptr<kernel::filesystem::filesystem> override
+ {
+ return nullptr;
+ }
+};
+
+SCENARIO("Filesystem type registry initialization and construction", "[filesystem]")
+{
+ GIVEN("A default constructed type_registry")
+ {
+ auto instance = kernel::filesystem::type_registry{};
+
+ WHEN("getting the span of filesystem descriptors")
+ {
+ auto descriptors = instance.all();
+
+ THEN("the span is empty")
+ {
+ REQUIRE(descriptors.empty());
+ }
+ }
+ }
+}
+
+SCENARIO("Filesystem type registry modifiers", "[filesystem]")
+{
+ GIVEN("A default constructed type_registry")
+ {
+ auto instance = kernel::filesystem::type_registry{};
+
+ WHEN("adding a type descriptor")
+ {
+ auto descriptor = test_type{};
+
+ instance.add(kstd::make_observer(&descriptor));
+
+ THEN("the size of the registry is one")
+ {
+ REQUIRE(instance.size() == 1);
+ }
+
+ THEN("the span is not empty")
+ {
+ REQUIRE_FALSE(instance.all().empty());
+ }
+
+ THEN("the span's size is equal to the registry size")
+ {
+ REQUIRE(std::size(instance.all()) == std::size(instance));
+ }
+ }
+ }
+}
diff --git a/kernel/src/filesystem/vfs.cpp b/kernel/src/filesystem/vfs.cpp
index ae85291..e5dff8c 100644
--- a/kernel/src/filesystem/vfs.cpp
+++ b/kernel/src/filesystem/vfs.cpp
@@ -12,7 +12,6 @@
#include <kapi/system.hpp>
#include <kstd/memory>
-#include <kstd/string>
#include <kstd/vector>
#include <algorithm>
@@ -36,11 +35,10 @@ namespace kernel::filesystem
kapi::system::panic("[FILESYSTEM] vfs has already been initialized.");
}
- active_vfs.emplace(vfs{});
- active_vfs->init_internal();
+ active_vfs.emplace();
}
- auto vfs::init_internal() -> void
+ vfs::vfs()
{
// mount rootfs at /
auto root_fs = kstd::make_shared<rootfs::filesystem>();
@@ -226,22 +224,22 @@ namespace kernel::filesystem
continue;
}
- auto next_dentry = current_dentry->find_child(part.view());
+ auto next_dentry = current_dentry->find_child(part);
if (!next_dentry)
{
auto current_fs = current_mount->get_filesystem();
- auto found_inode = current_fs->lookup(current_dentry->get_inode(), part.view());
+ auto found_inode = current_fs->lookup(current_dentry->get_inode(), part);
if (!found_inode)
{
return {nullptr, nullptr};
}
- next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part.view());
+ next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part);
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->absolute_path().view());
+ current_mount = m_mount_table.find_mount(next_dentry->absolute_path());
if (!current_mount)
{
kapi::system::panic("[FILESYSTEM] mount for dentry with mounted flag not found.");
diff --git a/kernel/src/filesystem/vfs.tests.cpp b/kernel/src/filesystem/vfs.tests.cpp
index 962e067..f1d0df0 100644
--- a/kernel/src/filesystem/vfs.tests.cpp
+++ b/kernel/src/filesystem/vfs.tests.cpp
@@ -106,8 +106,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt");
REQUIRE(mounted_monkey_1 != nullptr);
- REQUIRE(vfs.close(mounted_monkey_1->absolute_path().view()) ==
- kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(mounted_monkey_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
auto unmounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt");
@@ -129,9 +128,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
REQUIRE(mounted_monkey_1 != nullptr);
REQUIRE(mounted_fish1 != nullptr);
- REQUIRE(vfs.close(mounted_monkey_1->absolute_path().view()) ==
- kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.close(mounted_fish1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(mounted_monkey_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(mounted_fish1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed);
REQUIRE(vfs.unmount("/information/monkey_house/infrastructure") ==
@@ -148,8 +146,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed);
- REQUIRE(vfs.close(mounted_monkey_1->absolute_path().view()) ==
- kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(mounted_monkey_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
}
@@ -165,8 +162,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto info_1 = vfs.open("/information/info_1.txt");
REQUIRE(info_1 != nullptr);
- REQUIRE(vfs.close(info_1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
- REQUIRE_THROWS_AS(vfs.close(info_1->absolute_path().view()), std::runtime_error);
+ REQUIRE(vfs.close(info_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE_THROWS_AS(vfs.close(info_1->absolute_path()), std::runtime_error);
}
THEN("images can be stacked mounted and correct file system is unmounted again")
@@ -177,7 +174,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto mounted_tickets = vfs.open("/information/entrance/tickets.txt");
REQUIRE(mounted_tickets != nullptr);
- REQUIRE(vfs.close(mounted_tickets->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(mounted_tickets->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
mounted_tickets = vfs.open("/information/entrance/tickets.txt");
@@ -200,7 +197,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto water = vfs.open("/monkey_house/infrastructure/water.txt");
REQUIRE(water != nullptr);
- REQUIRE(vfs.close(water->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(water->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success);
@@ -221,7 +218,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto water = vfs.open("/monkey_house/infrastructure/water.txt");
REQUIRE(water != nullptr);
- REQUIRE(vfs.close(water->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(water->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
auto dev_ram_16 = vfs.open("/dev/ram16");
REQUIRE(dev_ram_16 == nullptr);
@@ -239,7 +236,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto info_1 = vfs.open("/information/info_1.txt");
REQUIRE(info_1 != nullptr);
- REQUIRE(vfs.close(info_1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(info_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/dev") == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success);
@@ -362,7 +359,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), bytes_read};
REQUIRE(buffer_as_str == "sheep_1");
- REQUIRE(vfs.close(dentry->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(dentry->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
auto unmounted_sheep_1 = vfs.open("/information/sheep_1.txt");
@@ -395,8 +392,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
buffer_as_str = std::string_view{reinterpret_cast<char *>(goat_buffer.data()), bytes_read};
REQUIRE(buffer_as_str == "goat_1");
- REQUIRE(vfs.close(sheep_1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
- REQUIRE(vfs.close(goat_1->absolute_path().view()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(sheep_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(goat_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed);
@@ -407,8 +404,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS
auto still_mounted_sheep_1 = vfs.open("/information/sheep_1.txt");
REQUIRE(still_mounted_sheep_1 != nullptr);
- REQUIRE(vfs.close(still_mounted_sheep_1->absolute_path().view()) ==
- kernel::filesystem::vfs::operation_result::success);
+ REQUIRE(vfs.close(still_mounted_sheep_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success);
REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success);
auto unmounted_sheep_1 = vfs.open("/information/sheep_1.txt");
diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp
index 6985e94..8dc1349 100644
--- a/kernel/src/main.cpp
+++ b/kernel/src/main.cpp
@@ -1,3 +1,4 @@
+#include "kernel/filesystem/type_registry.hpp"
#include <kernel/devices/storage/management.hpp>
#include <kernel/filesystem/open_file_table.hpp>
#include <kernel/filesystem/vfs.hpp>
@@ -138,6 +139,9 @@ auto main() -> int
kernel::filesystem::open_file_table::init();
kstd::println("[OS] Global open file table initialized.");
+ kernel::filesystem::type_registry::init();
+ kstd::println("[OS] Builtin filesystems registered.");
+
kernel::filesystem::vfs::init();
kstd::println("[OS] Virtual filesystem initialized.");
diff --git a/libs/acpi/acpi/common/basic_table.hpp b/libs/acpi/acpi/common/basic_table.hpp
index 33f23d5..f5b5b27 100644
--- a/libs/acpi/acpi/common/basic_table.hpp
+++ b/libs/acpi/acpi/common/basic_table.hpp
@@ -28,6 +28,11 @@ namespace acpi
{
return signature() == table_signature_v<TableType> && validate_checksum();
}
+
+ private:
+ friend TableType;
+
+ constexpr basic_table() noexcept = default;
};
} // namespace acpi
diff --git a/libs/acpi/acpi/common/vla_table.hpp b/libs/acpi/acpi/common/vla_table.hpp
index a65a28e..d3f33a7 100644
--- a/libs/acpi/acpi/common/vla_table.hpp
+++ b/libs/acpi/acpi/common/vla_table.hpp
@@ -109,6 +109,11 @@ namespace acpi
{
return end();
}
+
+ private:
+ friend TableType;
+
+ constexpr vla_table() noexcept = default;
};
} // namespace acpi
diff --git a/libs/kstd/kstd/flat_map b/libs/kstd/kstd/flat_map
index f12b1b5..943e9fc 100644
--- a/libs/kstd/kstd/flat_map
+++ b/libs/kstd/kstd/flat_map
@@ -356,6 +356,22 @@ namespace kstd
return find(key) != cend();
}
+ //! Get a reference to the keys container.
+ //!
+ //! @return a reference to the keys container.
+ [[nodiscard]] constexpr auto keys() const noexcept -> key_container_type const &
+ {
+ return m_containers.keys;
+ }
+
+ //! Get a reference to the values container.
+ //!
+ //! @return a reference to the values container.
+ [[nodiscard]] constexpr auto values() const noexcept -> mapped_container_type const &
+ {
+ return m_containers.values;
+ }
+
private:
containers m_containers;
key_compare m_comparator;
diff --git a/libs/kstd/kstd/flat_map.test.cpp b/libs/kstd/kstd/flat_map.test.cpp
index 2e5a47c..6c57173 100644
--- a/libs/kstd/kstd/flat_map.test.cpp
+++ b/libs/kstd/kstd/flat_map.test.cpp
@@ -20,6 +20,16 @@ SCENARIO("Flat Map initialization and construction", "[flat_map]")
{
REQUIRE_FALSE(map.contains(1));
}
+
+ THEN("the keys container is empty")
+ {
+ REQUIRE(map.keys().empty());
+ }
+
+ THEN("the values container is empty")
+ {
+ REQUIRE(map.values().empty());
+ }
}
}
}
diff --git a/libs/kstd/kstd/string b/libs/kstd/kstd/string
index e228a04..9343b42 100644
--- a/libs/kstd/kstd/string
+++ b/libs/kstd/kstd/string
@@ -9,6 +9,7 @@
#include <kstd/vector>
#include <algorithm>
+#include <compare>
#include <concepts>
#include <cstddef>
#include <string_view>
@@ -52,7 +53,7 @@ namespace kstd
* @brief Constructs a string from a string view by copying the characters into owned storage.
* @param view The string view to copy the characters from.
*/
- string(std::string_view view)
+ explicit string(std::string_view view)
: string()
{
append(view);
@@ -101,6 +102,26 @@ namespace kstd
*/
constexpr auto operator=(string const & other) -> string & = default;
+ constexpr auto operator=(std::string_view const & other) -> string &
+ {
+ clear();
+ append(other);
+ return *this;
+ }
+
+ constexpr auto operator=(char const * other) -> string &
+ {
+ clear();
+ append(std::string_view{other});
+ return *this;
+ }
+
+ //! Create a string view from this string.
+ constexpr operator std::string_view() const noexcept
+ {
+ return {data(), size()};
+ }
+
/**
* @brief Returns the number of characters in this string, not including the null terminator.
*/
@@ -224,6 +245,7 @@ namespace kstd
{
if (!view.empty())
{
+ m_storage.reserve(size() + view.size() + 1);
std::ranges::for_each(view, [this](auto const ch) { push_back(ch); });
}
@@ -237,7 +259,7 @@ namespace kstd
*/
constexpr auto append(string const & other) -> string &
{
- return append(other.view());
+ return append(static_cast<std::string_view>(other));
}
/**
@@ -261,12 +283,29 @@ namespace kstd
return *this;
}
- /**
- * @brief Returns a string view of this string, which is a non-owning view into the characters of this string.
- */
- [[nodiscard]] constexpr auto view() const noexcept -> std::string_view
+ //! Compare this string lexicographically to another string.
+ //!
+ //! @param other The string to compare to this one.
+ [[nodiscard]] constexpr auto operator<=>(string const & other) const noexcept -> std::strong_ordering = default;
+
+ [[nodiscard]] constexpr auto operator==(string const & other) const noexcept -> bool = default;
+
+ //! Compare this string lexicographically to a C-style string.
+ //!
+ //! @param other The C-style string to compare to this one.
+ //! @return The result of the comparison.
+ [[nodiscard]] constexpr auto operator<=>(char const * other) const noexcept
+ {
+ return static_cast<std::string_view>(*this) <=> other;
+ }
+
+ //! Check if this string compares equal to a C-style string.
+ //!
+ //! @param other The C-style string to compare to this one.
+ //! @return @p true iff. this string compares equal to @p other, @p false otherwise.
+ [[nodiscard]] constexpr auto operator==(char const * other) const noexcept -> bool
{
- return std::string_view{data(), size()};
+ return static_cast<std::string_view>(*this) == other;
}
private:
@@ -316,62 +355,12 @@ namespace kstd
return result;
}
- [[nodiscard]] constexpr auto inline operator==(string const & lhs, string const & rhs) -> bool
- {
- return lhs.view() == rhs.view();
- }
-
- [[nodiscard]] constexpr auto inline operator!=(string const & lhs, string const & rhs) -> bool
- {
- return !(lhs == rhs);
- }
-
- [[nodiscard]] constexpr auto inline operator==(string const & lhs, std::string_view rhs) -> bool
- {
- return lhs.view() == rhs;
- }
-
- [[nodiscard]] constexpr auto inline operator!=(string const & lhs, std::string_view rhs) -> bool
- {
- return !(lhs == rhs);
- }
-
- [[nodiscard]] constexpr auto inline operator==(std::string_view lhs, string const & rhs) -> bool
- {
- return lhs == rhs.view();
- }
-
- [[nodiscard]] constexpr auto inline operator!=(std::string_view lhs, string const & rhs) -> bool
- {
- return !(lhs == rhs);
- }
-
- [[nodiscard]] constexpr auto inline operator==(string const & lhs, char const * rhs) -> bool
- {
- return lhs.view() == std::string_view{rhs};
- }
-
- [[nodiscard]] constexpr auto inline operator!=(string const & lhs, char const * rhs) -> bool
- {
- return !(lhs == rhs);
- }
-
- [[nodiscard]] constexpr auto inline operator==(char const * lhs, string const & rhs) -> bool
- {
- return std::string_view{lhs} == rhs.view();
- }
-
- [[nodiscard]] constexpr auto inline operator!=(char const * lhs, string const & rhs) -> bool
- {
- return !(lhs == rhs);
- }
-
template<>
struct formatter<string> : formatter<std::string_view>
{
auto format(string const & str, format_context & context) const -> void
{
- formatter<std::string_view>::format(str.view(), context);
+ formatter<std::string_view>::format(static_cast<std::string_view>(str), context);
}
};
diff --git a/libs/kstd/kstd/string.test.cpp b/libs/kstd/kstd/string.test.cpp
index 9755676..b81cd3a 100644
--- a/libs/kstd/kstd/string.test.cpp
+++ b/libs/kstd/kstd/string.test.cpp
@@ -22,7 +22,7 @@ SCENARIO("String initialization and construction", "[string]")
THEN("the string is empty")
{
- REQUIRE(str.view() == std::string_view{});
+ REQUIRE(str == std::string_view{});
}
}
}
@@ -43,7 +43,7 @@ SCENARIO("String initialization and construction", "[string]")
THEN("the string contains the same characters as the view")
{
- REQUIRE(str.view() == view);
+ REQUIRE(str == view);
}
}
}
@@ -64,7 +64,7 @@ SCENARIO("String initialization and construction", "[string]")
THEN("the string contains the same characters as the C-style string")
{
- REQUIRE(str.view() == c_str);
+ REQUIRE(str == c_str);
}
}
}
@@ -85,7 +85,7 @@ SCENARIO("String initialization and construction", "[string]")
THEN("the string contains the same character as the given character")
{
- REQUIRE(str.view() == std::string_view{&ch, 1});
+ REQUIRE(str == std::string_view{&ch, 1});
}
}
}
@@ -100,7 +100,7 @@ SCENARIO("String initialization and construction", "[string]")
THEN("the new string contains the same characters as the original")
{
- REQUIRE(str.view() == other.view());
+ REQUIRE(static_cast<std::string_view>(str) == static_cast<std::string_view>(other));
}
}
@@ -113,7 +113,7 @@ SCENARIO("String initialization and construction", "[string]")
THEN("the string contains the same characters as the assigned string")
{
- REQUIRE(str.view() == other.view());
+ REQUIRE(static_cast<std::string_view>(str) == static_cast<std::string_view>(other));
}
}
}
@@ -129,7 +129,7 @@ SCENARIO("String initialization and construction", "[string]")
THEN("the string contains the same characters as the assigned view")
{
- REQUIRE(str.view() == view);
+ REQUIRE(str == view);
}
}
}
@@ -145,7 +145,7 @@ SCENARIO("String initialization and construction", "[string]")
THEN("the string contains the same characters as the assigned C-style string")
{
- REQUIRE(str.view() == c_str);
+ REQUIRE(str == c_str);
}
}
}
@@ -164,7 +164,7 @@ SCENARIO("String concatenation", "[string]")
THEN("the first string contains the characters of both strings concatenated")
{
- REQUIRE(str1.view() == "Blub Blub");
+ REQUIRE(str1 == "Blub Blub");
}
THEN("the size of the first string is the sum of the sizes of both strings")
@@ -179,7 +179,7 @@ SCENARIO("String concatenation", "[string]")
THEN("the first string contains the characters of both strings concatenated")
{
- REQUIRE(str1.view() == "Blub Blub");
+ REQUIRE(str1 == "Blub Blub");
}
THEN("the size of the first string is the sum of the sizes of both strings")
@@ -194,7 +194,7 @@ SCENARIO("String concatenation", "[string]")
THEN("the new string contains the characters of both strings concatenated")
{
- REQUIRE(str3.view() == "Blub Blub");
+ REQUIRE(str3 == "Blub Blub");
}
THEN("the size of the new string is the sum of the sizes of both strings")
@@ -215,7 +215,7 @@ SCENARIO("String concatenation", "[string]")
THEN("the string contains the characters of both the original string and the appended view concatenated")
{
- REQUIRE(str.view() == "Blub Blub");
+ REQUIRE(str == "Blub Blub");
}
THEN("the size of the string is the sum of the sizes of the original string and the appended view")
@@ -236,7 +236,7 @@ SCENARIO("String concatenation", "[string]")
THEN("the string contains the original characters followed by the appended character")
{
- REQUIRE(str.view() == "Blub!");
+ REQUIRE(str == "Blub!");
}
THEN("the size of the string is one more than the original size")
@@ -251,7 +251,7 @@ SCENARIO("String concatenation", "[string]")
THEN("the string contains the original characters followed by the appended character")
{
- REQUIRE(str.view() == "Blub!");
+ REQUIRE(str == "Blub!");
}
THEN("the size of the string is one more than the original size")
@@ -276,8 +276,8 @@ SCENARIO("String conversion and comparison", "[string]")
THEN("the string contains the decimal representation of the unsigned integer")
{
- REQUIRE(str1.view() == "12345");
- REQUIRE(str2.view() == "0");
+ REQUIRE(str1 == "12345");
+ REQUIRE(str2 == "0");
}
}
}
@@ -335,7 +335,7 @@ SCENARIO("String clearing", "[string]")
THEN("the string contains no characters")
{
- REQUIRE(str.view() == std::string_view{});
+ REQUIRE(str == std::string_view{});
}
}
}
@@ -351,7 +351,7 @@ SCENARIO("String iteration", "[string]")
{
kstd::string result;
- for (auto ch : str.view())
+ for (auto ch : static_cast<std::string_view>(str))
{
result.push_back(ch);
}
@@ -396,14 +396,14 @@ SCENARIO("String iteration", "[string]")
{
kstd::string result;
- for (auto ch : str.view())
+ for (auto ch : static_cast<std::string_view>(str))
{
result.push_back(ch);
}
THEN("the iterated characters are the same as the characters in the string")
{
- REQUIRE(result == str.view());
+ REQUIRE(result == static_cast<std::string_view>(str));
}
}
@@ -429,7 +429,7 @@ SCENARIO("String iteration", "[string]")
{
kstd::string result;
- for (auto ch : str.view())
+ for (auto ch : static_cast<std::string_view>(str))
{
result.push_back(ch);
}
@@ -438,7 +438,7 @@ SCENARIO("String iteration", "[string]")
{
REQUIRE(result.empty());
REQUIRE(result.size() == 0);
- REQUIRE(result.view() == std::string_view{});
+ REQUIRE(static_cast<std::string_view>(result) == std::string_view{});
}
}
}