From d027d60f364e4e6345d26bc5f90eaedcc7793fc7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 22 Jul 2026 16:02:50 +0200 Subject: kapi/fs: implement status and raw_device --- kernel/kapi/filesystem.cpp | 5 +++ kernel/kernel/filesystem/device_inode.cpp | 15 +++++++ kernel/kernel/filesystem/device_inode.hpp | 5 +++ kernel/kernel/filesystem/device_inode.tests.cpp | 51 ++++++++++++++++++++++ kernel/kernel/filesystem/ext2/inode.cpp | 32 ++++++++++++++ kernel/kernel/filesystem/ext2/inode.hpp | 7 +++ kernel/kernel/filesystem/inode.cpp | 46 +++++++++++++++++++ kernel/kernel/filesystem/inode.hpp | 14 ++++++ kernel/kernel/filesystem/vfs.cpp | 11 +++++ kernel/kernel/filesystem/vfs.hpp | 5 +++ .../kernel/test_support/filesystem/filesystem.cpp | 5 ++- .../kernel/test_support/filesystem/filesystem.hpp | 5 ++- 12 files changed, 197 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/kapi/filesystem.cpp b/kernel/kapi/filesystem.cpp index b2f94747..10c9835a 100644 --- a/kernel/kapi/filesystem.cpp +++ b/kernel/kapi/filesystem.cpp @@ -68,4 +68,9 @@ namespace kapi::filesystem return kernel::filesystem::vfs::get().create(path); } + auto status(std::string_view path) -> kstd::result + { + return kernel::filesystem::vfs::get().status(path); + } + } // namespace kapi::filesystem \ No newline at end of file diff --git a/kernel/kernel/filesystem/device_inode.cpp b/kernel/kernel/filesystem/device_inode.cpp index 464c5ea9..5ac18019 100644 --- a/kernel/kernel/filesystem/device_inode.cpp +++ b/kernel/kernel/filesystem/device_inode.cpp @@ -1,16 +1,21 @@ #include #include +#include #include +#include #include #include +#include #include #include #include #include +#include + namespace kernel::filesystem { device_inode::device_inode(kstd::shared_ptr const & device) @@ -54,4 +59,14 @@ namespace kernel::filesystem return true; } + auto device_inode::raw_device() const -> std::optional + { + if (auto number = device_number_registry::get().number_of(*m_device)) + { + return *number; + } + + return std::nullopt; + } + } // namespace kernel::filesystem \ No newline at end of file diff --git a/kernel/kernel/filesystem/device_inode.hpp b/kernel/kernel/filesystem/device_inode.hpp index be9fc577..698124f2 100644 --- a/kernel/kernel/filesystem/device_inode.hpp +++ b/kernel/kernel/filesystem/device_inode.hpp @@ -4,11 +4,14 @@ #include #include +#include #include #include #include +#include + namespace kernel::filesystem { /** @@ -58,6 +61,8 @@ namespace kernel::filesystem */ [[nodiscard]] auto is_block_device() const -> bool override; + [[nodiscard]] auto raw_device() const -> std::optional override; + private: kstd::shared_ptr m_device; }; diff --git a/kernel/kernel/filesystem/device_inode.tests.cpp b/kernel/kernel/filesystem/device_inode.tests.cpp index e821ce1d..4c6e0338 100644 --- a/kernel/kernel/filesystem/device_inode.tests.cpp +++ b/kernel/kernel/filesystem/device_inode.tests.cpp @@ -1,11 +1,18 @@ #include +#include +#include #include #include #include +#include + +#include +#include #include #include +#include #include #include #include @@ -17,6 +24,17 @@ using namespace kstd::units_literals; +namespace +{ + struct registry_reset_guard + { + ~registry_reset_guard() + { + kernel::tests::filesystem::device_number_registry::deinit(); + } + }; +} // namespace + SCENARIO("Device inode construction", "[filesystem][device_inode]") { GIVEN("a block device") @@ -117,3 +135,36 @@ SCENARIO("Device inode read/write with a non-block device", "[filesystem][device } } } + +SCENARIO("Device inode raw_device()", "[filesystem][device-inode]") +{ + auto resetter = registry_reset_guard{}; + + GIVEN("A block device that has been published and numbered") + { + auto device = kstd::make_shared("ram0", 512_B); + REQUIRE(kapi::devices::interface_registry::get().publish(device, "ram0")); + + auto inode = kernel::filesystem::device_inode{device}; + + THEN("raw_device() return the number assigned to the device") + { + auto expected = kernel::filesystem::device_number_registry::get().number_of(*device); + REQUIRE(expected); + + auto actual = inode.raw_device(); + REQUIRE(actual == expected); + } + } + + GIVEN("a block device that has never been published") + { + auto device = kstd::make_shared("never_published", 512_B); + auto inode = kernel::filesystem::device_inode{device}; + + THEN("raw_device() is nullopt, not a stale or default number") + { + REQUIRE_FALSE(inode.raw_device()); + } + } +} diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index f42e2c0c..89e52232 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -12,6 +13,7 @@ #include #include #include +#include using namespace kstd::units_literals; @@ -201,6 +203,36 @@ namespace kernel::filesystem::ext2 return (m_data.mode & constants::mode_mask) == constants::mode_symbolic_link; } + auto inode::status() const -> kstd::result + { + auto result = kernel::filesystem::inode::status(); + if (!result) + { + return result; + } + + result->size = size(); + result->inode_number = m_inode_number; + result->link_count = m_data.links_count; + + return result; + } + + auto inode::raw_device() const -> std::optional + { + if (!is_device()) + { + return std::nullopt; + } + + auto const raw_device_number = m_data.block[0]; + + return kapi::filesystem::device_number{ + .major = static_cast((raw_device_number >> 8) & 0xff), + .minor = static_cast(raw_device_number & 0xff), + }; + } + auto inode::size() const -> kstd::units::bytes { uint64_t size = m_data.size; diff --git a/kernel/kernel/filesystem/ext2/inode.hpp b/kernel/kernel/filesystem/ext2/inode.hpp index 1d364a54..a15532b0 100644 --- a/kernel/kernel/filesystem/ext2/inode.hpp +++ b/kernel/kernel/filesystem/ext2/inode.hpp @@ -3,6 +3,8 @@ #include +#include + #include #include #include @@ -10,6 +12,7 @@ #include #include #include +#include namespace kernel::filesystem::ext2 { @@ -107,6 +110,10 @@ namespace kernel::filesystem::ext2 */ [[nodiscard]] auto is_symbolic_link() const -> bool override; + [[nodiscard]] auto status() const -> kstd::result override; + + [[nodiscard]] auto raw_device() const -> std::optional override; + /** @brief Get the size of the file represented by this inode. @return The size of the file in bytes. diff --git a/kernel/kernel/filesystem/inode.cpp b/kernel/kernel/filesystem/inode.cpp index e564ab38..d0762472 100644 --- a/kernel/kernel/filesystem/inode.cpp +++ b/kernel/kernel/filesystem/inode.cpp @@ -1,5 +1,12 @@ #include +#include + +#include + +#include +#include + namespace kernel::filesystem { auto inode::is_directory() const -> bool @@ -31,4 +38,43 @@ namespace kernel::filesystem { return false; } + + auto inode::status() const -> kstd::result + { + auto result = kapi::filesystem::file_status{}; + + if (is_directory()) + { + result.mode = std::to_underlying(kapi::filesystem::file_type::directory); + } + else if (is_regular()) + { + result.mode = std::to_underlying(kapi::filesystem::file_type::regular); + } + else if (is_block_device()) + { + result.mode = std::to_underlying(kapi::filesystem::file_type::block_device); + } + else if (is_character_device()) + { + result.mode = std::to_underlying(kapi::filesystem::file_type::character_device); + } + else if (is_symbolic_link()) + { + result.mode = std::to_underlying(kapi::filesystem::file_type::symbolic_link); + } + + if (auto const number = raw_device()) + { + result.raw_device = *number; + } + + return result; + } + + auto inode::raw_device() const -> std::optional + { + return std::nullopt; + } + } // namespace kernel::filesystem \ No newline at end of file diff --git a/kernel/kernel/filesystem/inode.hpp b/kernel/kernel/filesystem/inode.hpp index 005dc57b..25e5df31 100644 --- a/kernel/kernel/filesystem/inode.hpp +++ b/kernel/kernel/filesystem/inode.hpp @@ -1,9 +1,13 @@ #ifndef TEACH_OS_KERNEL_FILESYSTEM_INODE_HPP #define TEACH_OS_KERNEL_FILESYSTEM_INODE_HPP +#include + #include #include +#include + namespace kernel::filesystem { //! Represents an inode in the filesystem. @@ -62,6 +66,16 @@ namespace kernel::filesystem //! //! @return true iff. this inode is a symbolic link, false otherwise. [[nodiscard]] virtual auto is_symbolic_link() const -> bool; + + //! Get POSIX status information for this inode. + //! + //! @return a populated status information object, or an error or failure. + [[nodiscard]] virtual auto status() const -> kstd::result; + + //! Get the raw device, if any, this inode refers to. + //! + //! @return a device number if this inode refers to a device, an empty optional otherwise. + [[nodiscard]] virtual auto raw_device() const -> std::optional; }; } // namespace kernel::filesystem diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index 6533e027..c1a36856 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -186,6 +186,17 @@ namespace kernel::filesystem return create_inode(path, vfs_types::inode_type::regular); } + auto vfs::status(std::string_view path) const -> kstd::result + { + auto resolved = resolve_path(path); + if (!resolved) + { + return kstd::failure(resolved.error()); + } + + return (*resolved)->get_inode()->status(); + } + auto vfs::create_inode(std::string_view path, vfs_types::inode_type type, std::optional raw_device) -> kstd::result { diff --git a/kernel/kernel/filesystem/vfs.hpp b/kernel/kernel/filesystem/vfs.hpp index b965e426..6ab67ef8 100644 --- a/kernel/kernel/filesystem/vfs.hpp +++ b/kernel/kernel/filesystem/vfs.hpp @@ -96,6 +96,11 @@ namespace kernel::filesystem // TODO remove again after the open method supports an optional create flag auto create(std::string_view path) -> kstd::result; + //! Get the status of the file at a given path. + //! + //! @return A populated file status object on success, an error otherwise. + [[nodiscard]] auto status(std::string_view path) const -> kstd::result; + private: /** * Note: Resolving a dentry requires traversing mount points; since the diff --git a/kernel/kernel/test_support/filesystem/filesystem.cpp b/kernel/kernel/test_support/filesystem/filesystem.cpp index 4dd69668..3acedd5f 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.cpp +++ b/kernel/kernel/test_support/filesystem/filesystem.cpp @@ -1,10 +1,11 @@ #include -#include #include #include #include +#include + #include #include #include @@ -22,7 +23,7 @@ namespace kernel::tests::filesystem auto filesystem::create_inode(kstd::shared_ptr const &, std::string_view, kernel::filesystem::vfs_types::inode_type, - std::optional) + std::optional) -> kstd::result> { return kstd::make_shared(); diff --git a/kernel/kernel/test_support/filesystem/filesystem.hpp b/kernel/kernel/test_support/filesystem/filesystem.hpp index 0f51499e..2b61aea3 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.hpp +++ b/kernel/kernel/test_support/filesystem/filesystem.hpp @@ -1,11 +1,12 @@ #ifndef TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_FILESYSTEM_HPP #define TEACHOS_KERNEL_TEST_SUPPORT_FILESYSTEM_FILESYSTEM_HPP -#include #include #include #include +#include + #include #include #include @@ -24,7 +25,7 @@ namespace kernel::tests::filesystem [[nodiscard]] auto create_inode(kstd::shared_ptr const & parent, std::string_view name, kernel::filesystem::vfs_types::inode_type inode_type, - std::optional = std::nullopt) + std::optional = std::nullopt) -> kstd::result> override; }; } // namespace kernel::tests::filesystem -- cgit v1.2.3