From c09ef501e1baf293d92b166e5e38e29a41cf64c2 Mon Sep 17 00:00:00 2001 From: Lukas Oesch Date: Tue, 9 Jun 2026 11:06:25 +0200 Subject: implement mkdir and create function in kapi::filesystem that calls the vfs and then the underlying filesystem --- kapi/kapi/filesystem.hpp | 18 +++++++++ kernel/kapi/filesystem.cpp | 12 ++++++ kernel/kernel/filesystem/devfs/filesystem.cpp | 10 ++++- kernel/kernel/filesystem/devfs/filesystem.hpp | 12 ++++++ kernel/kernel/filesystem/error.hpp | 5 +++ kernel/kernel/filesystem/ext2/filesystem.hpp | 3 +- kernel/kernel/filesystem/filesystem.hpp | 12 ++++++ kernel/kernel/filesystem/path.hpp | 32 +++++++++++++++ kernel/kernel/filesystem/rootfs/filesystem.cpp | 9 ++++- kernel/kernel/filesystem/rootfs/filesystem.hpp | 12 ++++++ kernel/kernel/filesystem/vfs.cpp | 46 ++++++++++++++++++++++ kernel/kernel/filesystem/vfs.hpp | 18 +++++++++ .../kernel/test_support/filesystem/filesystem.cpp | 12 +++++- .../kernel/test_support/filesystem/filesystem.hpp | 9 ++++- 14 files changed, 202 insertions(+), 8 deletions(-) diff --git a/kapi/kapi/filesystem.hpp b/kapi/kapi/filesystem.hpp index 5346a96d..1656a17f 100644 --- a/kapi/kapi/filesystem.hpp +++ b/kapi/kapi/filesystem.hpp @@ -1,6 +1,7 @@ #ifndef TEACHOS_KAPI_FILESYSTEM_HPP #define TEACHOS_KAPI_FILESYSTEM_HPP +#include #include #include @@ -69,6 +70,23 @@ namespace kapi::filesystem @qualifier kernel-defined */ auto write(size_t file_descriptor, void const * buffer, size_t size) -> std::expected; + + /** + @brief Creates a new directory at the specified @p path. + @param path The path where the new directory should be created. + @return 0 on success, -1 on failure. + @qualifier kernel-defined + */ + auto mkdir(std::string_view path) -> kstd::result; + + /** + @brief Creates a new file at the specified @p path. + @param path The path where the new file should be created. + @return 0 on success, -1 on failure. + @qualifier kernel-defined + */ + // TODO remove again after the open method supports an optional create flag + auto create(std::string_view path) -> kstd::result; } // namespace kapi::filesystem #endif // TEACHOS_KAPI_FILESYSTEM_HPP \ No newline at end of file diff --git a/kernel/kapi/filesystem.cpp b/kernel/kapi/filesystem.cpp index efde1336..822095e6 100644 --- a/kernel/kapi/filesystem.cpp +++ b/kernel/kapi/filesystem.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -53,4 +54,15 @@ namespace kapi::filesystem return descriptor->write(buffer, size); }); } + + auto mkdir(std::string_view path) -> kstd::result + { + return kernel::filesystem::vfs::get().mkdir(path); + } + + auto create(std::string_view path) -> kstd::result + { + return kernel::filesystem::vfs::get().create(path); + } + } // namespace kapi::filesystem \ No newline at end of file diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index 7ffcb3c4..66799988 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -1,12 +1,13 @@ #include -#include "kernel/filesystem/filesystem.hpp" #include #include #include #include +#include #include #include +#include #include @@ -82,6 +83,13 @@ namespace kernel::filesystem::devfs return kstd::failure(vfs_errc::no_such_file_or_directory); } + auto filesystem::create_inode(kstd::shared_ptr const &, std::string_view, + kernel::filesystem::vfs_types::inode_type) + -> kstd::result> + { + return kstd::failure(vfs_errc::read_only_file_system); + } + auto filesystem::build_device_inode_table() -> void { m_inodes.clear(); diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index dadeaf7d..be3c119c 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,17 @@ namespace kernel::filesystem::devfs [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const -> kstd::result> override; + /** + @brief Creates a new inode with @p name within a @p parent directory. + @param parent The parent directory inode. + @param name The name of the inode to create. + @param inode_type The type of inode to be created. + @return Always returns nullptr, as creating new inodes is not supported in devfs. + */ + [[nodiscard]] auto create_inode(kstd::shared_ptr const & parent, std::string_view name, + kernel::filesystem::vfs_types::inode_type inode_type) + -> kstd::result> override; + private: auto build_device_inode_table() -> void; diff --git a/kernel/kernel/filesystem/error.hpp b/kernel/kernel/filesystem/error.hpp index 56f56ce4..82ba33b3 100644 --- a/kernel/kernel/filesystem/error.hpp +++ b/kernel/kernel/filesystem/error.hpp @@ -24,6 +24,7 @@ namespace kernel::filesystem invalid_inode, not_a_directory, is_a_directory, + read_only_file_system, }; namespace detail @@ -65,6 +66,8 @@ namespace kernel::filesystem return "not a directory"; case vfs_errc::is_a_directory: return "is a directory"; + case vfs_errc::read_only_file_system: + return "readonly filesystem"; default: return "unknown VFS error"; } @@ -95,6 +98,8 @@ namespace kernel::filesystem return make_error_condition(kstd::errc::not_a_directory); case vfs_errc::is_a_directory: return make_error_condition(kstd::errc::is_a_directory); + case vfs_errc::read_only_file_system: + return make_error_condition(kstd::errc::read_only_file_system); default: return kstd::error_condition{value, *this}; } diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 03398f00..9af9aeb1 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -16,7 +16,6 @@ #include #include #include -#include #include namespace kernel::filesystem::ext2 @@ -77,7 +76,7 @@ namespace kernel::filesystem::ext2 */ [[nodiscard]] auto create_inode(kstd::shared_ptr const & parent, std::string_view name, kernel::filesystem::vfs_types::inode_type inode_type) - -> kstd::result>; // TODO move into base class and override + -> kstd::result> override; /** @brief Gets the size of a block in the filesystem. diff --git a/kernel/kernel/filesystem/filesystem.hpp b/kernel/kernel/filesystem/filesystem.hpp index 1264d00d..aa6286bf 100644 --- a/kernel/kernel/filesystem/filesystem.hpp +++ b/kernel/kernel/filesystem/filesystem.hpp @@ -2,6 +2,7 @@ #define TEACH_OS_KERNEL_FILESYSTEM_FILESYSTEM_HPP #include +#include #include #include @@ -53,6 +54,17 @@ namespace kernel::filesystem [[nodiscard]] virtual auto lookup(kstd::shared_ptr const & parent, std::string_view name) const -> kstd::result> = 0; + /** + @brief Creates a new inode with @p name within a @p parent directory. + @param parent The parent directory inode. + @param name The name of the inode to create. + @param inode_type The type of inode to be created. + @return A pointer to the created inode, or a null pointer if creation failed. + */ + [[nodiscard]] virtual auto create_inode(kstd::shared_ptr const & parent, std::string_view name, + vfs_types::inode_type inode_type) + -> kstd::result> = 0; + /** @brief Returns a reference to the root inode of the filesystem. */ diff --git a/kernel/kernel/filesystem/path.hpp b/kernel/kernel/filesystem/path.hpp index 438c22f3..c2d8e588 100644 --- a/kernel/kernel/filesystem/path.hpp +++ b/kernel/kernel/filesystem/path.hpp @@ -7,6 +7,7 @@ #include #include +#include namespace kernel::filesystem::path { @@ -66,6 +67,37 @@ namespace kernel::filesystem::path [](auto const & part) { return kstd::string(std::string_view(part.begin(), part.end())); }); } + /** + @brief Splits the given path into its parent path and filename components. + @param path The path to split. + @return A pair of string views representing the parent path and filename. + */ + auto inline split_into_path_and_filename(std::string_view path) -> std::pair + { + if (path.empty()) + { + return {"", ""}; + } + + auto search_from = path.length() > 1 ? path.length() - 2 : 0; + auto last_separator_index = path.rfind('/', search_from); + + if (last_separator_index == std::string_view::npos) + { + return {"", path}; + } + else + { + auto parent_path = path.substr(0, last_separator_index); + if (parent_path.empty()) + { + parent_path = "/"; + } + auto filename = path.substr(last_separator_index + 1); + return {parent_path, filename}; + } + } + } // namespace kernel::filesystem::path #endif // TEACH_OS_KERNEL_FILESYSTEM_PATH_HPP \ No newline at end of file diff --git a/kernel/kernel/filesystem/rootfs/filesystem.cpp b/kernel/kernel/filesystem/rootfs/filesystem.cpp index fef43e28..5ff56547 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -14,7 +15,6 @@ namespace kernel::filesystem::rootfs { - struct type final : kernel::filesystem::type { [[nodiscard]] auto name() const noexcept -> std::string_view override @@ -47,4 +47,11 @@ namespace kernel::filesystem::rootfs { return kstd::failure(vfs_errc::no_such_file_or_directory); } + + auto filesystem::create_inode(kstd::shared_ptr const &, std::string_view, + kernel::filesystem::vfs_types::inode_type) + -> kstd::result> + { + return kstd::failure(vfs_errc::read_only_file_system); + } } // namespace kernel::filesystem::rootfs diff --git a/kernel/kernel/filesystem/rootfs/filesystem.hpp b/kernel/kernel/filesystem/rootfs/filesystem.hpp index 8507d8b8..498503c5 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.hpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -37,6 +38,17 @@ namespace kernel::filesystem::rootfs */ [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const -> kstd::result> override; + + /** + @brief Creates a new inode with @p name within a @p parent directory. + @param parent The parent directory inode. + @param name The name of the inode to create. + @param inode_type The type of inode to be created. + @return Always returns nullptr, as creating new inodes is not supported in devfs. + */ + [[nodiscard]] auto create_inode(kstd::shared_ptr const & parent, std::string_view name, + kernel::filesystem::vfs_types::inode_type inode_type) + -> kstd::result> override; }; } // namespace kernel::filesystem::rootfs diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index d128bbf5..2e4145db 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -171,6 +172,51 @@ namespace kernel::filesystem return kstd::failure(vfs_errc::unmount_failed); } + auto vfs::mkdir(std::string_view path) -> kstd::result + { + return create_inode(path, vfs_types::inode_type::directory); + } + + auto vfs::create(std::string_view path) -> kstd::result + { + return create_inode(path, vfs_types::inode_type::regular); + } + + auto vfs::create_inode(std::string_view path, vfs_types::inode_type type) -> kstd::result + { + if (!path::is_valid_path(path)) + { + return kstd::failure(vfs_errc::invalid_path); + } + + auto [parent_path, name] = path::split_into_path_and_filename(path); + if (name.empty()) + { + return kstd::failure(vfs_errc::invalid_path); + } + + auto resolved_parent = resolve_path_internal(parent_path); + if (!resolved_parent) + { + return kstd::failure(resolved_parent.error()); + } + + auto [parent_dentry, mount_context] = *resolved_parent; + + if (auto fs = mount_context->get_filesystem()) + { + if (auto new_inode = fs->create_inode(parent_dentry->get_inode(), name, type)) + { + auto new_dentry = kstd::make_shared(parent_dentry, *new_inode, name); + parent_dentry->add_child(new_dentry); + + return kstd::success(); + } + } + + return kstd::failure(vfs_errc::no_such_file_or_directory); + } + auto vfs::do_mount_internal(dentry_ptr const & mount_point_dentry, mount_ptr const & parent_mount, fs_ptr const & fs, mount_ptr const & source_mount) -> void { diff --git a/kernel/kernel/filesystem/vfs.hpp b/kernel/kernel/filesystem/vfs.hpp index 9dfd3637..beb336a4 100644 --- a/kernel/kernel/filesystem/vfs.hpp +++ b/kernel/kernel/filesystem/vfs.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -77,6 +78,21 @@ namespace kernel::filesystem */ auto unmount(std::string_view path) -> kstd::result; + /** + @brief Create a new directory at the specified @p path. + @param path The path where the new directory should be created. + @return The result of the mkdir operation. + */ + auto mkdir(std::string_view path) -> kstd::result; + + /** + @brief Create a new file at the specified @p path. + @param path The path where the new file should be created. + @return The result of the create operation. + */ + // TODO remove again after the open method supports an optional create flag + auto create(std::string_view path) -> kstd::result; + private: /** * Note: Resolving a dentry requires traversing mount points; since the @@ -100,6 +116,8 @@ namespace kernel::filesystem auto graft_persistent_device_fs(kstd::shared_ptr const & device_fs) -> void; + auto create_inode(std::string_view path, vfs_types::inode_type type) -> kstd::result; + mount_table m_mount_table{}; }; } // namespace kernel::filesystem diff --git a/kernel/kernel/test_support/filesystem/filesystem.cpp b/kernel/kernel/test_support/filesystem/filesystem.cpp index 38cea2f1..b48c7935 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.cpp +++ b/kernel/kernel/test_support/filesystem/filesystem.cpp @@ -1,18 +1,26 @@ #include #include +#include #include #include +#include #include -#include #include namespace kernel::tests::filesystem { auto filesystem::lookup(kstd::shared_ptr const &, std::string_view) const - -> std::expected, kstd::error_code> + -> kstd::result> + { + return kstd::make_shared(); + } + + auto filesystem::create_inode(kstd::shared_ptr const &, std::string_view, + kernel::filesystem::vfs_types::inode_type) + -> 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 e6e0f416..17edd079 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.hpp +++ b/kernel/kernel/test_support/filesystem/filesystem.hpp @@ -3,11 +3,12 @@ #include #include +#include #include +#include #include -#include #include namespace kernel::tests::filesystem @@ -17,7 +18,11 @@ namespace kernel::tests::filesystem filesystem() = default; [[nodiscard]] auto lookup(kstd::shared_ptr const & parent, std::string_view name) const - -> std::expected, kstd::error_code> override; + -> kstd::result> override; + + [[nodiscard]] auto create_inode(kstd::shared_ptr const & parent, std::string_view name, + kernel::filesystem::vfs_types::inode_type inode_type) + -> kstd::result> override; }; } // namespace kernel::tests::filesystem -- cgit v1.2.3