diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-07-14 19:30:03 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-07-14 19:30:03 +0200 |
| commit | d6735726d9cc6e98142e94001250076592279d36 (patch) | |
| tree | 95d308a027495790af57479cacb064badea334d0 | |
| parent | cdb8a0928ddfe626a1ac0acd1ae63bc8e5b77355 (diff) | |
| parent | 9558074af8ceef4dc2c3b168a0263775f8a377e0 (diff) | |
| download | kernel-d6735726d9cc6e98142e94001250076592279d36.tar.xz kernel-d6735726d9cc6e98142e94001250076592279d36.zip | |
Merge branch 'fmorgner/develop/kstd-system-error' into 'develop'
kstd: implement system_error infrastructure
See merge request teachos/kernel!54
188 files changed, 2230 insertions, 897 deletions
diff --git a/.clang-tidy b/.clang-tidy index 0be16fbd..e110ab1f 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -64,7 +64,7 @@ CheckOptions: modernize-use-std-print.ReplacementPrintFunction: "kstd::print" modernize-use-std-print.ReplacementPrintlnFunction: "kstd::println" - modernize-use-std-print.PrintHeader: "kstd/print" + modernize-use-std-print.PrintHeader: "kstd/print.hpp" modernize-use-std-ranges.UseReversePipe: true @@ -87,7 +87,7 @@ CheckOptions: readability-magic-numbers.IgnoreTypeAliases: true FormatStyle: file -HeaderFilterRegex: "(.*/kstd/kstd/.*)|(arch|kernel|kapi)/.*\\.hpp" +HeaderFilterRegex: "(arch|kernel|kapi|kstd)/.*\\.hpp" SystemHeaders: true RemovedArgs: - -fcondition-coverage diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 00000000..fd92c735 --- /dev/null +++ b/.gdbinit @@ -0,0 +1 @@ +skip -rfu Catch
\ No newline at end of file @@ -68,7 +68,11 @@ return { nesting_rules = { ['cpp_under_hpp'] = { pattern = "(.*).hpp", - files = { "%1.cpp", "%1.test.cpp", "%1.tests.cpp", "%1.S" } + files = { "%1.cpp", "%1.tests.cpp", "%1.S" } + }, + ['tests_under_cpp'] = { + pattern = "(.*).cpp", + files = { "%1.tests.cpp" } }, }, }, @@ -7,17 +7,6 @@ vim.opt.fixeol = false -- Enable Doxygen vim.g.load_doxygen_syntax = true --- C++ -vim.filetype.add({ - pattern = { - [".*/libs/kstd/kstd/.*"] = function(path, _) - if not path:match("%.[^/]+$") then - return "cpp" - end - end - } -}) - -- Debugging local dap = require("dap") local qemu_job_id = nil diff --git a/.vscode/settings.json b/.vscode/settings.json index 26154d1d..7b537ecb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,11 +14,8 @@ "explorer.fileNesting.enabled": true, "explorer.fileNesting.expand": false, "explorer.fileNesting.patterns": { - "*.hpp": "${capture}.cpp, ${capture}.test.cpp, ${capture}.S", - "*": "${capture}.cpp, ${capture}.test.cpp, ${capture}.S" - }, - "files.associations": { - "**/kstd/kstd/**": "cpp", + "*.hpp": "${capture}.cpp, ${capture}.tests.cpp, ${capture}.S", + "*.cpp": "${capture}.tests.cpp", }, "[cpp]": { "editor.formatOnSave": true, diff --git a/arch/x86_64/arch/cpu/control_register.hpp b/arch/x86_64/arch/cpu/control_register.hpp index 9cedc35a..ad307081 100644 --- a/arch/x86_64/arch/cpu/control_register.hpp +++ b/arch/x86_64/arch/cpu/control_register.hpp @@ -5,7 +5,7 @@ #include <kapi/memory.hpp> -#include <kstd/ext/bitfield_enum> +#include <kstd/ext/bitfield_enum.hpp> #include <cstdint> #include <string_view> diff --git a/arch/x86_64/arch/cpu/initialization.cpp b/arch/x86_64/arch/cpu/initialization.cpp index 1be9c821..49870eb7 100644 --- a/arch/x86_64/arch/cpu/initialization.cpp +++ b/arch/x86_64/arch/cpu/initialization.cpp @@ -6,7 +6,7 @@ #include <arch/cpu/segment_descriptor.hpp> #include <arch/cpu/task_state_segment.hpp> -#include <kstd/print> +#include <kstd/print.hpp> #include <bit> #include <cstdint> diff --git a/arch/x86_64/arch/cpu/interrupts.cpp b/arch/x86_64/arch/cpu/interrupts.cpp index f40422fc..99186e2d 100644 --- a/arch/x86_64/arch/cpu/interrupts.cpp +++ b/arch/x86_64/arch/cpu/interrupts.cpp @@ -7,7 +7,7 @@ #include <kapi/interrupts.hpp> #include <kapi/memory.hpp> -#include <kstd/print> +#include <kstd/print.hpp> #include <cstdint> diff --git a/arch/x86_64/arch/cpu/model_specific_register.hpp b/arch/x86_64/arch/cpu/model_specific_register.hpp index bd4aff9d..cf07737f 100644 --- a/arch/x86_64/arch/cpu/model_specific_register.hpp +++ b/arch/x86_64/arch/cpu/model_specific_register.hpp @@ -3,7 +3,7 @@ // IWYU pragma: private, include <x86_64/cpu/registers.hpp> -#include <kstd/ext/bitfield_enum> +#include <kstd/ext/bitfield_enum.hpp> #include <bit> #include <cstdint> diff --git a/arch/x86_64/arch/devices/init.cpp b/arch/x86_64/arch/devices/init.cpp index c30e8cf0..134d6dac 100644 --- a/arch/x86_64/arch/devices/init.cpp +++ b/arch/x86_64/arch/devices/init.cpp @@ -10,8 +10,8 @@ #include <acpi/acpi.hpp> -#include <kstd/memory> -#include <kstd/print> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> #include <cstdint> #include <utility> diff --git a/arch/x86_64/arch/devices/local_apic.cpp b/arch/x86_64/arch/devices/local_apic.cpp index 660921bd..b481a667 100644 --- a/arch/x86_64/arch/devices/local_apic.cpp +++ b/arch/x86_64/arch/devices/local_apic.cpp @@ -3,7 +3,7 @@ #include <kapi/devices.hpp> #include <kapi/memory.hpp> -#include <kstd/print> +#include <kstd/print.hpp> #include <cstddef> #include <cstdint> diff --git a/arch/x86_64/arch/memory/kernel_mapper.cpp b/arch/x86_64/arch/memory/kernel_mapper.cpp index 74272a0f..0ddf08dd 100644 --- a/arch/x86_64/arch/memory/kernel_mapper.cpp +++ b/arch/x86_64/arch/memory/kernel_mapper.cpp @@ -8,8 +8,8 @@ #include <elf/format.hpp> #include <elf/section_header.hpp> -#include <kstd/print> -#include <kstd/units> +#include <kstd/print.hpp> +#include <kstd/units.hpp> #include <multiboot2/information.hpp> diff --git a/arch/x86_64/arch/memory/page_table.hpp b/arch/x86_64/arch/memory/page_table.hpp index ce3d3a14..f288e3da 100644 --- a/arch/x86_64/arch/memory/page_table.hpp +++ b/arch/x86_64/arch/memory/page_table.hpp @@ -3,8 +3,8 @@ #include <kapi/memory.hpp> -#include <kstd/ext/bitfield_enum> -#include <kstd/units> +#include <kstd/ext/bitfield_enum.hpp> +#include <kstd/units.hpp> #include <array> #include <cstddef> diff --git a/arch/x86_64/kapi/boot_modules.cpp b/arch/x86_64/kapi/boot_modules.cpp index fb6bf465..9ca867a5 100644 --- a/arch/x86_64/kapi/boot_modules.cpp +++ b/arch/x86_64/kapi/boot_modules.cpp @@ -9,7 +9,7 @@ #include <kapi/memory.hpp> #include <kapi/system.hpp> -#include <kstd/print> +#include <kstd/print.hpp> #include <multiboot2/information.hpp> diff --git a/arch/x86_64/kapi/cpu.cpp b/arch/x86_64/kapi/cpu.cpp index 40dc2281..70cd3635 100644 --- a/arch/x86_64/kapi/cpu.cpp +++ b/arch/x86_64/kapi/cpu.cpp @@ -11,8 +11,8 @@ #include <acpi/acpi.hpp> -#include <kstd/memory> -#include <kstd/print> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> #include <atomic> #include <ranges> diff --git a/arch/x86_64/kapi/memory.cpp b/arch/x86_64/kapi/memory.cpp index 5b870d51..a6f84f07 100644 --- a/arch/x86_64/kapi/memory.cpp +++ b/arch/x86_64/kapi/memory.cpp @@ -12,8 +12,8 @@ #include <kapi/boot.hpp> #include <kapi/system.hpp> -#include <kstd/print> -#include <kstd/units> +#include <kstd/print.hpp> +#include <kstd/units.hpp> #include <multiboot2/constants.hpp> #include <multiboot2/information.hpp> diff --git a/cmake/Modules/BuildHostTests.cmake b/cmake/Modules/BuildHostTests.cmake new file mode 100644 index 00000000..aa3ae66d --- /dev/null +++ b/cmake/Modules/BuildHostTests.cmake @@ -0,0 +1,35 @@ +include_guard(GLOBAL) + +function("teachos_add_tests" NAME) + add_executable("${NAME}_tests") + add_executable("${NAME}::tests" ALIAS "${NAME}_tests") + + file(GLOB_RECURSE + TEST_SOURCES + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + CONFIGURE_DEPENDS + "*.tests.cpp" + ) + + target_sources("${NAME}_tests" PRIVATE + ${TEST_SOURCES} + ) + + target_link_libraries("${NAME}_tests" PRIVATE + "Catch2::Catch2WithMain" + "${NAME}::lib" + ) + + set_target_properties("${NAME}_tests" PROPERTIES + EXCLUDE_FROM_ALL NO + ) + + + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bht_results") + + catch_discover_tests("${NAME}::tests" + REPORTER junit + OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/bht_results" + OUTPUT_SUFFIX ".xml" + ) +endfunction()
\ No newline at end of file diff --git a/kapi/kapi/acpi.hpp b/kapi/kapi/acpi.hpp index 885fcde1..eb82c781 100644 --- a/kapi/kapi/acpi.hpp +++ b/kapi/kapi/acpi.hpp @@ -3,8 +3,8 @@ #include <acpi/acpi.hpp> -#include <kstd/memory> -#include <kstd/units> +#include <kstd/memory.hpp> +#include <kstd/units.hpp> #include <string_view> diff --git a/kapi/kapi/boot_module/boot_module_registry.hpp b/kapi/kapi/boot_module/boot_module_registry.hpp index fc3590fc..fdba0740 100644 --- a/kapi/kapi/boot_module/boot_module_registry.hpp +++ b/kapi/kapi/boot_module/boot_module_registry.hpp @@ -3,7 +3,7 @@ #include <kapi/boot_module/boot_module.hpp> -#include <kstd/vector> +#include <kstd/vector.hpp> #include <cstddef> diff --git a/kapi/kapi/cio.hpp b/kapi/kapi/cio.hpp index 9bbf7fa7..5c4cc8b7 100644 --- a/kapi/kapi/cio.hpp +++ b/kapi/kapi/cio.hpp @@ -3,7 +3,7 @@ #include <kapi/cio/output_device.hpp> // IWYU pragma: export -#include <kstd/format> +#include <kstd/format.hpp> #include <optional> #include <string_view> diff --git a/kapi/kapi/cpu.hpp b/kapi/kapi/cpu.hpp index deaf5cd7..41e00e40 100644 --- a/kapi/kapi/cpu.hpp +++ b/kapi/kapi/cpu.hpp @@ -3,8 +3,8 @@ #include <kapi/memory.hpp> -#include <kstd/format> -#include <kstd/memory> +#include <kstd/format.hpp> +#include <kstd/memory.hpp> #include <cstdint> diff --git a/kapi/kapi/devices/bus.hpp b/kapi/kapi/devices/bus.hpp index 59f49f73..8e2b5acf 100644 --- a/kapi/kapi/devices/bus.hpp +++ b/kapi/kapi/devices/bus.hpp @@ -5,10 +5,10 @@ #include <kapi/devices/device.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/string> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/string.hpp> +#include <kstd/vector.hpp> #include <atomic> #include <cstddef> diff --git a/kapi/kapi/devices/device.hpp b/kapi/kapi/devices/device.hpp index 70cf01f3..104d7b8e 100644 --- a/kapi/kapi/devices/device.hpp +++ b/kapi/kapi/devices/device.hpp @@ -3,8 +3,8 @@ // IWYU pragma: private, include <kapi/devices.hpp> -#include <kstd/memory> -#include <kstd/string> +#include <kstd/memory.hpp> +#include <kstd/string.hpp> #include <cstddef> diff --git a/kapi/kapi/devices/manager.hpp b/kapi/kapi/devices/manager.hpp index c9b90b4e..c317b61e 100644 --- a/kapi/kapi/devices/manager.hpp +++ b/kapi/kapi/devices/manager.hpp @@ -5,7 +5,7 @@ #include <kapi/devices/device.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> #include <cstddef> #include <string_view> diff --git a/kapi/kapi/filesystem.hpp b/kapi/kapi/filesystem.hpp index 3bd9aaf4..5346a96d 100644 --- a/kapi/kapi/filesystem.hpp +++ b/kapi/kapi/filesystem.hpp @@ -1,9 +1,10 @@ #ifndef TEACHOS_KAPI_FILESYSTEM_HPP #define TEACHOS_KAPI_FILESYSTEM_HPP -#include <kstd/unikstd.h> +#include <kstd/system_error.hpp> #include <cstddef> +#include <expected> #include <string_view> namespace kapi::filesystem @@ -20,54 +21,54 @@ namespace kapi::filesystem @brief Mounts a filesystem from the specified @p source at the specified @p target path. @param source The source device or filesystem to mount. @param target The target mount point. - @return 0 on success, -1 on failure. + @return Nothing on success, an error code otherwise. @qualifier kernel-defined */ - auto mount(std::string_view source, std::string_view target) -> kstd::ssize_t; + auto mount(std::string_view source, std::string_view target) -> std::expected<void, kstd::error_code>; /** @brief Unmounts a filesystem from the specified @p target path. @param target The target mount point to unmount. - @return 0 on success, -1 on failure. + @return Nothing on success, an error code otherwise. @qualifier kernel-defined */ - auto umount(std::string_view target) -> kstd::ssize_t; + auto umount(std::string_view target) -> std::expected<void, kstd::error_code>; /** @brief Opens a file at the specified @p path. @param path The path to the file to open. - @return A file descriptor on success, -1 on failure. + @return A file descriptor on success, an error code otherwise. @qualifier kernel-defined */ - auto open(std::string_view path) -> kstd::ssize_t; + auto open(std::string_view path) -> std::expected<std::size_t, kstd::error_code>; /** @brief Closes a @p file_descriptor. @param file_descriptor The file descriptor to close. - @return 0 on success, -1 on failure. + @return Nothing on success, an error code otherwise . @qualifier kernel-defined */ - auto close(size_t file_descriptor) -> kstd::ssize_t; + auto close(size_t file_descriptor) -> std::expected<void, kstd::error_code>; /** @brief Reads @p size bytes into @p buffer from a @p file_descriptor. @param file_descriptor The file descriptor to read from. @param buffer The buffer to store the read data. @param size The number of bytes to read. - @return The number of bytes read on success, -1 on failure. + @return The number of bytes read on success, an error code otherwise. @qualifier kernel-defined */ - auto read(size_t file_descriptor, void * buffer, size_t size) -> kstd::ssize_t; + auto read(size_t file_descriptor, void * buffer, size_t size) -> std::expected<std::size_t, kstd::error_code>; /** @brief Writes @p size bytes from @p buffer to a @p file_descriptor. @param file_descriptor The file descriptor to write to. @param buffer The buffer containing the data to write. @param size The number of bytes to write. - @return The number of bytes written on success, -1 on failure. + @return The number of bytes written on success, an error code otherwise. @qualifier kernel-defined */ - auto write(size_t file_descriptor, void const * buffer, size_t size) -> kstd::ssize_t; + auto write(size_t file_descriptor, void const * buffer, size_t size) -> std::expected<std::size_t, kstd::error_code>; } // namespace kapi::filesystem #endif // TEACHOS_KAPI_FILESYSTEM_HPP
\ No newline at end of file diff --git a/kapi/kapi/memory/address.hpp b/kapi/kapi/memory/address.hpp index 9231cfc6..d176d2b8 100644 --- a/kapi/kapi/memory/address.hpp +++ b/kapi/kapi/memory/address.hpp @@ -3,8 +3,8 @@ // IWYU pragma: private, include <kapi/memory.hpp> -#include <kstd/format> -#include <kstd/units> +#include <kstd/format.hpp> +#include <kstd/units.hpp> #include <bit> #include <compare> diff --git a/kapi/kapi/memory/chunk.hpp b/kapi/kapi/memory/chunk.hpp index 485a890d..36d83b2e 100644 --- a/kapi/kapi/memory/chunk.hpp +++ b/kapi/kapi/memory/chunk.hpp @@ -3,7 +3,7 @@ // IWYU pragma: private, include <kapi/memory.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <compare> #include <cstddef> diff --git a/kapi/kapi/memory/layout.hpp b/kapi/kapi/memory/layout.hpp index 733fa960..5f720a51 100644 --- a/kapi/kapi/memory/layout.hpp +++ b/kapi/kapi/memory/layout.hpp @@ -5,7 +5,7 @@ #include <kapi/memory/address.hpp> -#include <kstd/units> +#include <kstd/units.hpp> namespace kapi::memory { diff --git a/kapi/kapi/memory/page_mapper.hpp b/kapi/kapi/memory/page_mapper.hpp index fb600b2d..579c14fd 100644 --- a/kapi/kapi/memory/page_mapper.hpp +++ b/kapi/kapi/memory/page_mapper.hpp @@ -6,7 +6,7 @@ #include <kapi/memory/frame.hpp> #include <kapi/memory/page.hpp> -#include <kstd/ext/bitfield_enum> +#include <kstd/ext/bitfield_enum.hpp> #include <cstddef> #include <cstdint> diff --git a/kapi/kapi/system.hpp b/kapi/kapi/system.hpp index 8a20af94..f7dd4d7c 100644 --- a/kapi/kapi/system.hpp +++ b/kapi/kapi/system.hpp @@ -1,8 +1,15 @@ #ifndef TEACHOS_KAPI_SYSTEM_HPP #define TEACHOS_KAPI_SYSTEM_HPP +#include <kstd/format.hpp> +#include <kstd/system_error.hpp> + +#include <array> +#include <cstddef> #include <source_location> +#include <span> #include <string_view> +#include <type_traits> namespace kapi::system { @@ -10,6 +17,26 @@ namespace kapi::system //! @addtogroup kapi-system-kernel-defined //! @{ + template<typename... FormatArguments> + struct panic_format_string + { + kstd::format_string<FormatArguments...> format; + std::source_location location; + + template<std::size_t Size> + consteval panic_format_string(char const (&format)[Size], // NOLINT + std::source_location location = std::source_location::current()) + : format{format} + , location{location} + {} + + consteval panic_format_string(std::string_view const & format, + std::source_location location = std::source_location::current()) + : format{format} + , location{location} + {} + }; + //! Terminate kernel execution with the given error message. //! //! This function terminates the execution of the kernel and attempts to issue the given error message to the user. @@ -17,6 +44,14 @@ namespace kapi::system //! @param message The message associated with the panic [[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; + //! Termite kernel execution with the given error message and error code. + //! + //! This function terminates the execution of the kernel and attempts to issue the given error message to the user. + //! @param message The message associated with the panic. + //! @param error The erro code associated with the panic. + [[noreturn]] auto panic(std::string_view message, kstd::error_code error, + std::source_location = std::source_location::current()) -> void; + //! @} // end group kernel-defined //! @addtogroup kapi-system-platform-defined @@ -26,6 +61,15 @@ namespace kapi::system auto memory_initialized() -> void; //! @} // end group platform-defined + // + template<typename... FormatArguments> + [[noreturn]] auto panic(panic_format_string<std::type_identity_t<FormatArguments>...> format, + FormatArguments &&... arguments) + { + auto buffer = std::array<char, 512uz>{}; + auto [_, length] = kstd::format_to(std::span{buffer}, format.format, std::forward<FormatArguments>(arguments)...); + panic(std::string_view{buffer.data(), length}, format.location); + } } // namespace kapi::system diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index d50944e4..34d71de1 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -140,79 +140,32 @@ endif() if(BUILD_TESTING) find_package("Catch2") include("Catch") + include("BuildHostTests") - enable_coverage("kernel_lib") - - add_executable("kernel_tests") - add_executable("kernel::tests" ALIAS "kernel_tests") + teachos_add_tests("kernel") target_sources("kernel_tests" PRIVATE - # Platform-defined KAPI "kernel/test_support/kapi/cpu.cpp" "kernel/test_support/kapi/cio.cpp" "kernel/test_support/kapi/interrupts.cpp" "kernel/test_support/kapi/memory.cpp" - # Device Subsystem Support "kernel/test_support/devices/block_device.cpp" "kernel/test_support/devices/character_device.cpp" - # Filesystem Subsystem Support "kernel/test_support/filesystem/inode.cpp" "kernel/test_support/filesystem/filesystem.cpp" "kernel/test_support/filesystem/ext2.cpp" "kernel/test_support/filesystem/storage_boot_module_fixture.cpp" "kernel/test_support/filesystem/storage_boot_module_vfs_fixture.cpp" - # I/O Support "kernel/test_support/log_buffer.cpp" "kernel/test_support/output_device.cpp" - # Memory Support "kernel/test_support/page_mapper.cpp" "kernel/test_support/simulated_memory.cpp" - # Support System Listener "kernel/test_support/state_reset_listener.cpp" - - # KAPI Shim Tests - "kapi/cpu.tests.cpp" - "kapi/system.tests.cpp" - "kapi/filesystem.tests.cpp" - - # KSTD Shim Tests - "kstd/print.tests.cpp" - - # Memory Subsystem Tests - "kernel/memory/bitmap_allocator.tests.cpp" - "kernel/memory/block_list_allocator.tests.cpp" - - # Filesystem Subsystem Tests - "kernel/filesystem/devfs/filesystem.tests.cpp" - "kernel/filesystem/devfs/inode.tests.cpp" - "kernel/filesystem/ext2/filesystem.tests.cpp" - "kernel/filesystem/ext2/inode.tests.cpp" - "kernel/filesystem/path.tests.cpp" - "kernel/filesystem/rootfs/filesystem.tests.cpp" - "kernel/filesystem/rootfs/inode.tests.cpp" - "kernel/filesystem/dentry.tests.cpp" - "kernel/filesystem/device_inode.tests.cpp" - "kernel/filesystem/mount_table.tests.cpp" - "kernel/filesystem/mount.tests.cpp" - "kernel/filesystem/open_file_descriptor.tests.cpp" - "kernel/filesystem/open_file_table.tests.cpp" - "kernel/filesystem/type_registry.tests.cpp" - "kernel/filesystem/vfs.tests.cpp" - - # Storage Subsystem Tests - "kernel/devices/block_device_utils.tests.cpp" - "kernel/devices/block_device.tests.cpp" - "kernel/devices/storage/ram_disk/device.tests.cpp" - ) - - target_link_libraries("kernel_tests" PRIVATE - "kernel::lib" - "Catch2::Catch2WithMain" ) target_compile_definitions("kernel_tests" PRIVATE @@ -224,13 +177,8 @@ if(BUILD_TESTING) CXX_CLANG_TIDY "" ) - enable_coverage("kernel_tests") - - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bht_results") - - catch_discover_tests("kernel::tests" - REPORTER junit - OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/bht_results" - OUTPUT_SUFFIX ".xml" - ) + if(COMMAND "enable_coverage") + enable_coverage("kernel_lib") + enable_coverage("kernel_tests") + endif() endif() diff --git a/kernel/kapi/acpi.cpp b/kernel/kapi/acpi.cpp index b6d5cdf9..19188590 100644 --- a/kernel/kapi/acpi.cpp +++ b/kernel/kapi/acpi.cpp @@ -6,7 +6,7 @@ #include <acpi/acpi.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> #include <atomic> #include <optional> diff --git a/kernel/kapi/cpu.cpp b/kernel/kapi/cpu.cpp index 7b1a43b3..44331908 100644 --- a/kernel/kapi/cpu.cpp +++ b/kernel/kapi/cpu.cpp @@ -2,7 +2,7 @@ #include <kapi/system.hpp> -#include <kstd/print> +#include <kstd/print.hpp> namespace kapi::cpu { diff --git a/kernel/kapi/devices.cpp b/kernel/kapi/devices.cpp index 572227e6..577a8898 100644 --- a/kernel/kapi/devices.cpp +++ b/kernel/kapi/devices.cpp @@ -4,9 +4,9 @@ #include <kapi/system.hpp> -#include <kstd/flat_map> -#include <kstd/memory> -#include <kstd/print> +#include <kstd/flat_map.hpp> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> #include <atomic> #include <cstddef> diff --git a/kernel/kapi/devices/bus.cpp b/kernel/kapi/devices/bus.cpp index 59753f79..43310d2b 100644 --- a/kernel/kapi/devices/bus.cpp +++ b/kernel/kapi/devices/bus.cpp @@ -3,10 +3,10 @@ #include <kapi/devices.hpp> #include <kapi/system.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/string> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/string.hpp> +#include <kstd/vector.hpp> #include <algorithm> #include <cstddef> diff --git a/kernel/kapi/devices/device.cpp b/kernel/kapi/devices/device.cpp index 8b5d6b97..5dc59a27 100644 --- a/kernel/kapi/devices/device.cpp +++ b/kernel/kapi/devices/device.cpp @@ -2,8 +2,8 @@ #include <kapi/devices/bus.hpp> -#include <kstd/memory> -#include <kstd/string> +#include <kstd/memory.hpp> +#include <kstd/string.hpp> #include <cstddef> diff --git a/kernel/kapi/filesystem.cpp b/kernel/kapi/filesystem.cpp index 68b51c97..efde1336 100644 --- a/kernel/kapi/filesystem.cpp +++ b/kernel/kapi/filesystem.cpp @@ -4,73 +4,53 @@ #include <kernel/filesystem/open_file_table.hpp> #include <kernel/filesystem/vfs.hpp> -#include <kstd/memory> -#include <kstd/unikstd.h> +#include <kstd/memory.hpp> +#include <kstd/system_error.hpp> #include <cstddef> +#include <expected> #include <string_view> namespace kapi::filesystem { - auto mount(std::string_view source, std::string_view target) -> kstd::ssize_t + auto mount(std::string_view source, std::string_view target) -> std::expected<void, kstd::error_code> { - if (kernel::filesystem::vfs::get().do_mount(source, target) == kernel::filesystem::vfs::operation_result::success) - { - return 0; - } - return -1; + return kernel::filesystem::vfs::get().mount(source, target); } - auto umount(std::string_view target) -> kstd::ssize_t + auto umount(std::string_view target) -> std::expected<void, kstd::error_code> { - if (kernel::filesystem::vfs::get().unmount(target) == kernel::filesystem::vfs::operation_result::success) - { - return 0; - } - return -1; + return kernel::filesystem::vfs::get().unmount(target); } - auto open(std::string_view path) -> kstd::ssize_t + auto open(std::string_view path) -> std::expected<std::size_t, kstd::error_code> { - if (auto dentry = kernel::filesystem::vfs::get().open(path)) - { + return kernel::filesystem::vfs::get().open(path).and_then([](auto dentry) { auto open_file_descriptor = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry); return kernel::filesystem::open_file_table::get().add_file(open_file_descriptor); - } - - return -1; + }); } - auto close(size_t file_descriptor) -> kstd::ssize_t + auto close(size_t file_descriptor) -> std::expected<void, kstd::error_code> { - 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()) == - kernel::filesystem::vfs::operation_result::success) - { - return kernel::filesystem::open_file_table::get().remove_file(file_descriptor); - } - } - return -1; + return kernel::filesystem::open_file_table::get() + .file(file_descriptor) + .transform([](auto file) { return file->get_dentry()->absolute_path(); }) + .and_then([](auto path) { return kernel::filesystem::vfs::get().close(path); }) + .and_then([=]() { return kernel::filesystem::open_file_table::get().remove_file(file_descriptor); }); } - auto read(size_t file_descriptor, void * buffer, size_t size) -> kstd::ssize_t + auto read(size_t file_descriptor, void * buffer, size_t size) -> std::expected<std::size_t, kstd::error_code> { - if (auto open_file_descriptor = kernel::filesystem::open_file_table::get().file(file_descriptor)) - { - return open_file_descriptor->read(buffer, size); - } - - return -1; + return kernel::filesystem::open_file_table::get().file(file_descriptor).and_then([=](auto descriptor) { + return descriptor->read(buffer, size); + }); } - auto write(size_t file_descriptor, void const * buffer, size_t size) -> kstd::ssize_t + auto write(size_t file_descriptor, void const * buffer, size_t size) -> std::expected<std::size_t, kstd::error_code> { - if (auto open_file_descriptor = kernel::filesystem::open_file_table::get().file(file_descriptor)) - { - return open_file_descriptor->write(buffer, size); - } - - return -1; + return kernel::filesystem::open_file_table::get().file(file_descriptor).and_then([=](auto descriptor) { + return descriptor->write(buffer, size); + }); } } // namespace kapi::filesystem
\ No newline at end of file diff --git a/kernel/kapi/filesystem.tests.cpp b/kernel/kapi/filesystem.tests.cpp index d241afa8..d1e01db6 100644 --- a/kernel/kapi/filesystem.tests.cpp +++ b/kernel/kapi/filesystem.tests.cpp @@ -2,6 +2,8 @@ #include <kernel/test_support/filesystem/storage_boot_module_vfs_fixture.hpp> +#include <kstd/system_error.hpp> + #include <catch2/catch_test_macros.hpp> #include <algorithm> @@ -25,159 +27,149 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Kap THEN("files can be opened, read and closed again") { - auto fd = kapi::filesystem::open("/information/info_1.txt"); - REQUIRE(fd >= 0); + auto fd = kapi::filesystem::open("/information/info_1.txt").value(); auto buffer = std::vector<std::byte>(6); auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); - REQUIRE(bytes_read >= 0); + REQUIRE(bytes_read); - std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(*bytes_read)}; REQUIRE(buffer_as_str == "info_1"); - REQUIRE(kapi::filesystem::close(fd) == 0); + REQUIRE(kapi::filesystem::close(fd)); } THEN("files can be opened through absolute symbolic link, read and closed again") { - auto fd = kapi::filesystem::open("/symlinks/information_directory_absolute/info_1.txt"); - REQUIRE(fd >= 0); + auto fd = kapi::filesystem::open("/symlinks/information_directory_absolute/info_1.txt").value(); auto buffer = std::vector<std::byte>(6); auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); - REQUIRE(bytes_read >= 0); + REQUIRE(bytes_read); - std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(*bytes_read)}; REQUIRE(buffer_as_str == "info_1"); - REQUIRE(kapi::filesystem::close(fd) == 0); + REQUIRE(kapi::filesystem::close(fd)); } THEN("files can be opened through relative symbolic link, read and closed again") { - auto fd = kapi::filesystem::open("/symlinks/information_directory_relative/info_1.txt"); - REQUIRE(fd >= 0); + auto fd = kapi::filesystem::open("/symlinks/information_directory_relative/info_1.txt").value(); auto buffer = std::vector<std::byte>(6); auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); - REQUIRE(bytes_read >= 0); + REQUIRE(bytes_read); - std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(*bytes_read)}; REQUIRE(buffer_as_str == "info_1"); - REQUIRE(kapi::filesystem::close(fd) == 0); + REQUIRE(kapi::filesystem::close(fd)); } THEN("files can be opened through relative symbolic link over multiple mount points, read and closed again") { - kapi::filesystem::mount("/archiv/2024.img", "/information"); + CHECK(kapi::filesystem::mount("/archiv/2024.img", "/information")); - auto fd = kapi::filesystem::open("/information/symlinks/traverse_back_twice/information/sheep_1.txt"); - REQUIRE(fd >= 0); + auto fd = kapi::filesystem::open("/information/symlinks/traverse_back_twice/information/sheep_1.txt").value(); auto buffer = std::vector<std::byte>(7); auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); - REQUIRE(bytes_read >= 0); + REQUIRE(bytes_read); - std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(*bytes_read)}; REQUIRE(buffer_as_str == "sheep_1"); - REQUIRE(kapi::filesystem::close(fd) == 0); + REQUIRE(kapi::filesystem::close(fd)); } THEN("a filesystem can be mounted, files can be opened, read and closed again and unmounted") { - REQUIRE(kapi::filesystem::mount("/dev/ram16", "/information") == 0); + REQUIRE(kapi::filesystem::mount("/dev/ram16", "/information")); - auto fd = kapi::filesystem::open("/information/monkey_house/monkey_1.txt"); - REQUIRE(fd >= 0); + auto fd = kapi::filesystem::open("/information/monkey_house/monkey_1.txt").value(); auto buffer = std::vector<std::byte>(8); auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); - REQUIRE(bytes_read >= 0); + REQUIRE(bytes_read); - std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(*bytes_read)}; REQUIRE(buffer_as_str == "monkey_1"); - REQUIRE(kapi::filesystem::close(fd) == 0); - REQUIRE(kapi::filesystem::umount("/information") == 0); + REQUIRE(kapi::filesystem::close(fd)); + REQUIRE(kapi::filesystem::umount("/information")); } THEN("a filesystem cannot be unmounted if files are still open and can be unmounted after files are closed") { - REQUIRE(kapi::filesystem::mount("/dev/ram16", "/information") == 0); + REQUIRE(kapi::filesystem::mount("/dev/ram16", "/information")); - auto fd = kapi::filesystem::open("/information/monkey_house/monkey_1.txt"); - REQUIRE(fd >= 0); + auto fd = kapi::filesystem::open("/information/monkey_house/monkey_1.txt").value(); - REQUIRE(kapi::filesystem::umount("/information") < 0); + REQUIRE(!kapi::filesystem::umount("/information")); - REQUIRE(kapi::filesystem::close(fd) == 0); - REQUIRE(kapi::filesystem::umount("/information") == 0); + REQUIRE(kapi::filesystem::close(fd)); + REQUIRE(kapi::filesystem::umount("/information")); } THEN("device can be opened as file and read from") { - auto fd = kapi::filesystem::open("/dev/ram0"); - REQUIRE(fd >= 0); + auto fd = kapi::filesystem::open("/dev/ram0").value(); auto buffer = std::vector<std::byte>(512); auto bytes_read = kapi::filesystem::read(fd, buffer.data(), buffer.size()); - REQUIRE(bytes_read >= 0); + REQUIRE(bytes_read); - REQUIRE(kapi::filesystem::close(fd) == 0); + REQUIRE(kapi::filesystem::close(fd)); } THEN("device can be opened as file and written to and read from again") { - auto read_fd = kapi::filesystem::open("/dev/ram16"); - REQUIRE(read_fd >= 0); + auto read_fd = kapi::filesystem::open("/dev/ram16").value(); auto buffer = std::vector<std::byte>(512, std::byte{0xAB}); auto bytes_written = kapi::filesystem::write(read_fd, buffer.data(), buffer.size()); - REQUIRE(bytes_written >= 0); + REQUIRE(bytes_written); - auto write_fd = kapi::filesystem::open("/dev/ram16"); - REQUIRE(write_fd >= 0); + auto write_fd = kapi::filesystem::open("/dev/ram16").value(); auto read_buffer = std::vector<std::byte>(512); auto bytes_read = kapi::filesystem::read(write_fd, read_buffer.data(), read_buffer.size()); - REQUIRE(bytes_read >= 0); + REQUIRE(bytes_read); REQUIRE(std::equal(buffer.begin(), buffer.end(), read_buffer.begin())); - REQUIRE(kapi::filesystem::close(write_fd) == 0); - REQUIRE(kapi::filesystem::close(read_fd) == 0); + REQUIRE(kapi::filesystem::close(write_fd)); + REQUIRE(kapi::filesystem::close(read_fd)); } THEN("invalid paths cannot be mounted or unmounted") { - REQUIRE(kapi::filesystem::mount("/dev/ram16", "invalid_path") < 0); + REQUIRE(!kapi::filesystem::mount("/dev/ram16", "invalid_path")); } THEN("invalid paths cannot be unmounted") { - REQUIRE(kapi::filesystem::umount("invalid_path") < 0); + REQUIRE(!kapi::filesystem::umount("invalid_path")); } THEN("non existent files cannot be opened") { auto fd = kapi::filesystem::open("/information/non_existent.txt"); - REQUIRE(fd < 0); + REQUIRE(!fd); } THEN("not opened files cannot closed") { - REQUIRE(kapi::filesystem::close(999) < 0); + REQUIRE(!kapi::filesystem::close(999)); } THEN("same file cannot be closed twice") { - auto fd = kapi::filesystem::open("/information/info_1.txt"); - REQUIRE(fd >= 0); + auto fd = kapi::filesystem::open("/information/info_1.txt").value(); - REQUIRE(kapi::filesystem::close(fd) == 0); - REQUIRE(kapi::filesystem::close(fd) < 0); + REQUIRE(kapi::filesystem::close(fd)); + REQUIRE(!kapi::filesystem::close(fd)); } THEN("not opened files cannot be read from") @@ -185,7 +177,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Kap std::vector<std::byte> buffer(10); auto const invalid_fd = 999uz; auto bytes_read = kapi::filesystem::read(invalid_fd, buffer.data(), buffer.size()); - REQUIRE(bytes_read < 0); + REQUIRE(!bytes_read); } THEN("not opened files cannot be written to") @@ -193,7 +185,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Kap std::vector<std::byte> buffer(10); auto const invalid_fd = 999uz; auto bytes_written = kapi::filesystem::write(invalid_fd, buffer.data(), buffer.size()); - REQUIRE(bytes_written < 0); + REQUIRE(!bytes_written); } } } diff --git a/kernel/kapi/interrupts.cpp b/kernel/kapi/interrupts.cpp index 4efcaa37..18a1b29d 100644 --- a/kernel/kapi/interrupts.cpp +++ b/kernel/kapi/interrupts.cpp @@ -1,8 +1,8 @@ #include <kapi/interrupts.hpp> -#include <kstd/flat_map> -#include <kstd/print> -#include <kstd/vector> +#include <kstd/flat_map.hpp> +#include <kstd/print.hpp> +#include <kstd/vector.hpp> #include <algorithm> #include <cstdint> diff --git a/kernel/kapi/memory.cpp b/kernel/kapi/memory.cpp index 5ea08b16..91a6c2c7 100644 --- a/kernel/kapi/memory.cpp +++ b/kernel/kapi/memory.cpp @@ -5,8 +5,8 @@ #include <kapi/system.hpp> -#include <kstd/print> -#include <kstd/units> +#include <kstd/print.hpp> +#include <kstd/units.hpp> #include <algorithm> #include <cstddef> diff --git a/kernel/kapi/system.cpp b/kernel/kapi/system.cpp index 9819ceb7..629e5990 100644 --- a/kernel/kapi/system.cpp +++ b/kernel/kapi/system.cpp @@ -2,7 +2,8 @@ #include <kapi/cpu.hpp> -#include <kstd/print> +#include <kstd/print.hpp> +#include <kstd/system_error.hpp> #include <source_location> #include <string_view> @@ -18,4 +19,12 @@ namespace kapi::system cpu::halt(); } + [[gnu::weak]] + auto panic(std::string_view message, kstd::error_code error, std::source_location location) -> void + { + kstd::println(kstd::print_sink::stderr, "[PANIC] in {} : {} ({}) @ {}:{}", location.function_name(), message, error, + location.file_name(), location.line()); + cpu::halt(); + } + } // namespace kapi::system diff --git a/kernel/kapi/system.tests.cpp b/kernel/kapi/system.tests.cpp index 1e300316..a05e348b 100644 --- a/kernel/kapi/system.tests.cpp +++ b/kernel/kapi/system.tests.cpp @@ -3,7 +3,7 @@ #include <kernel/test_support/cio.hpp> #include <kernel/test_support/cpu.hpp> -#include <kstd/print> +#include <kstd/print.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/acpi/manager.cpp b/kernel/kernel/acpi/manager.cpp index bb895fda..e99baed8 100644 --- a/kernel/kernel/acpi/manager.cpp +++ b/kernel/kernel/acpi/manager.cpp @@ -5,8 +5,8 @@ #include <acpi/acpi.hpp> -#include <kstd/memory> -#include <kstd/print> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> #include <algorithm> #include <cstddef> diff --git a/kernel/kernel/acpi/manager.hpp b/kernel/kernel/acpi/manager.hpp index 1e8c1e85..ba05c682 100644 --- a/kernel/kernel/acpi/manager.hpp +++ b/kernel/kernel/acpi/manager.hpp @@ -3,9 +3,9 @@ #include <acpi/acpi.hpp> -#include <kstd/flat_map> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/flat_map.hpp> +#include <kstd/memory.hpp> +#include <kstd/vector.hpp> #include <string_view> diff --git a/kernel/kernel/devices/block_device.cpp b/kernel/kernel/devices/block_device.cpp index 13d73acd..a3531121 100644 --- a/kernel/kernel/devices/block_device.cpp +++ b/kernel/kernel/devices/block_device.cpp @@ -3,7 +3,7 @@ #include <kapi/devices/device.hpp> #include <kapi/system.hpp> -#include <kstd/string> +#include <kstd/string.hpp> #include <cstddef> diff --git a/kernel/kernel/devices/block_device.hpp b/kernel/kernel/devices/block_device.hpp index a6d68ee2..31599502 100644 --- a/kernel/kernel/devices/block_device.hpp +++ b/kernel/kernel/devices/block_device.hpp @@ -3,7 +3,7 @@ #include <kapi/devices/device.hpp> -#include <kstd/string> +#include <kstd/string.hpp> #include <cstddef> diff --git a/kernel/kernel/devices/block_device.tests.cpp b/kernel/kernel/devices/block_device.tests.cpp index a2ddd2bb..98722638 100644 --- a/kernel/kernel/devices/block_device.tests.cpp +++ b/kernel/kernel/devices/block_device.tests.cpp @@ -2,10 +2,10 @@ #include <kernel/test_support/cpu.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/string> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/string.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/devices/block_device_utils.cpp b/kernel/kernel/devices/block_device_utils.cpp index 18d1e9d7..68a0a306 100644 --- a/kernel/kernel/devices/block_device_utils.cpp +++ b/kernel/kernel/devices/block_device_utils.cpp @@ -5,9 +5,9 @@ #include <kapi/devices/device.hpp> #include <kapi/system.hpp> -#include <kstd/cstring> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/cstring.hpp> +#include <kstd/memory.hpp> +#include <kstd/vector.hpp> #include <algorithm> #include <cstddef> diff --git a/kernel/kernel/devices/block_device_utils.hpp b/kernel/kernel/devices/block_device_utils.hpp index 8be75b6f..88e23347 100644 --- a/kernel/kernel/devices/block_device_utils.hpp +++ b/kernel/kernel/devices/block_device_utils.hpp @@ -3,7 +3,7 @@ #include <kapi/devices/device.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> #include <cstddef> diff --git a/kernel/kernel/devices/block_device_utils.tests.cpp b/kernel/kernel/devices/block_device_utils.tests.cpp index e2e1e65e..c8c4acfb 100644 --- a/kernel/kernel/devices/block_device_utils.tests.cpp +++ b/kernel/kernel/devices/block_device_utils.tests.cpp @@ -4,9 +4,9 @@ #include <kernel/test_support/devices/block_device.hpp> #include <kernel/test_support/devices/character_device.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/devices/storage/controller.cpp b/kernel/kernel/devices/storage/controller.cpp index 171b918e..5ea9eb71 100644 --- a/kernel/kernel/devices/storage/controller.cpp +++ b/kernel/kernel/devices/storage/controller.cpp @@ -2,8 +2,8 @@ #include <kapi/devices/device.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/vector.hpp> #include <algorithm> #include <cstddef> diff --git a/kernel/kernel/devices/storage/controller.hpp b/kernel/kernel/devices/storage/controller.hpp index bea18f38..13494a52 100644 --- a/kernel/kernel/devices/storage/controller.hpp +++ b/kernel/kernel/devices/storage/controller.hpp @@ -3,8 +3,8 @@ #include <kapi/devices/device.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/vector.hpp> #include <cstddef> diff --git a/kernel/kernel/devices/storage/management.cpp b/kernel/kernel/devices/storage/management.cpp index 06efc27d..90c3696f 100644 --- a/kernel/kernel/devices/storage/management.cpp +++ b/kernel/kernel/devices/storage/management.cpp @@ -7,8 +7,8 @@ #include <kapi/devices/device.hpp> #include <kapi/system.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/vector.hpp> #include <algorithm> #include <cstddef> diff --git a/kernel/kernel/devices/storage/management.hpp b/kernel/kernel/devices/storage/management.hpp index 9a840875..a9704462 100644 --- a/kernel/kernel/devices/storage/management.hpp +++ b/kernel/kernel/devices/storage/management.hpp @@ -5,8 +5,8 @@ #include <kapi/devices/device.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/vector.hpp> #include <cstddef> diff --git a/kernel/kernel/devices/storage/ram_disk/controller.cpp b/kernel/kernel/devices/storage/ram_disk/controller.cpp index 30441fa5..c1075733 100644 --- a/kernel/kernel/devices/storage/ram_disk/controller.cpp +++ b/kernel/kernel/devices/storage/ram_disk/controller.cpp @@ -4,7 +4,7 @@ #include <kapi/boot_module/boot_module_registry.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> #include <algorithm> #include <cstddef> diff --git a/kernel/kernel/devices/storage/ram_disk/device.cpp b/kernel/kernel/devices/storage/ram_disk/device.cpp index 1557204b..1b53b0d3 100644 --- a/kernel/kernel/devices/storage/ram_disk/device.cpp +++ b/kernel/kernel/devices/storage/ram_disk/device.cpp @@ -5,8 +5,8 @@ #include <kapi/boot_module/boot_module.hpp> #include <kapi/system.hpp> -#include <kstd/cstring> -#include <kstd/string> +#include <kstd/cstring.hpp> +#include <kstd/string.hpp> #include <cstddef> diff --git a/kernel/kernel/filesystem/dentry.cpp b/kernel/kernel/filesystem/dentry.cpp index 01de276c..9321453a 100644 --- a/kernel/kernel/filesystem/dentry.cpp +++ b/kernel/kernel/filesystem/dentry.cpp @@ -4,8 +4,8 @@ #include <kapi/system.hpp> -#include <kstd/memory> -#include <kstd/string> +#include <kstd/memory.hpp> +#include <kstd/string.hpp> #include <algorithm> #include <cstdint> diff --git a/kernel/kernel/filesystem/dentry.hpp b/kernel/kernel/filesystem/dentry.hpp index 096a6bbb..ea689485 100644 --- a/kernel/kernel/filesystem/dentry.hpp +++ b/kernel/kernel/filesystem/dentry.hpp @@ -3,9 +3,9 @@ #include <kernel/filesystem/inode.hpp> -#include <kstd/memory> -#include <kstd/string> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/string.hpp> +#include <kstd/vector.hpp> #include <cstdint> #include <string_view> diff --git a/kernel/kernel/filesystem/dentry.tests.cpp b/kernel/kernel/filesystem/dentry.tests.cpp index b7690f57..55cdf21e 100644 --- a/kernel/kernel/filesystem/dentry.tests.cpp +++ b/kernel/kernel/filesystem/dentry.tests.cpp @@ -3,8 +3,8 @@ #include <kernel/test_support/cpu.hpp> #include <kernel/test_support/filesystem/inode.hpp> -#include <kstd/memory> -#include <kstd/print> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/filesystem/devfs/filesystem.cpp b/kernel/kernel/filesystem/devfs/filesystem.cpp index ce887ff3..7ffcb3c4 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.cpp @@ -4,12 +4,15 @@ #include <kernel/devices/storage/management.hpp> #include <kernel/filesystem/devfs/inode.hpp> #include <kernel/filesystem/device_inode.hpp> +#include <kernel/filesystem/error.hpp> #include <kernel/filesystem/inode.hpp> #include <kernel/filesystem/type.hpp> #include <kapi/devices/device.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> #include <algorithm> #include <string_view> @@ -37,25 +40,30 @@ namespace kernel::filesystem::devfs [[gnu::used]] constexpr auto registration = type_registration<type>{}; - auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> operation_result + auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> kstd::result<void> { m_root_inode = kstd::make_shared<inode>(); build_device_inode_table(); - return operation_result::success; + return kstd::success(); } auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name) const - -> kstd::shared_ptr<kernel::filesystem::inode> + -> kstd::result<kstd::shared_ptr<kernel::filesystem::inode>> { - if (!parent || !parent->is_directory()) + if (!parent) { - return nullptr; + return kstd::failure(vfs_errc::invalid_inode); + } + + if (!parent->is_directory()) + { + return kstd::failure(vfs_errc::not_a_directory); } if (parent.get() != m_root_inode.get()) { - return nullptr; + return kstd::failure(vfs_errc::invalid_inode); } auto it = std::ranges::find_if(m_inodes, [&](auto const & dev_node) { @@ -65,7 +73,13 @@ namespace kernel::filesystem::devfs } return false; }); - return (it != m_inodes.end()) ? *it : nullptr; + + if (it != m_inodes.end()) + { + return *it; + } + + return kstd::failure(vfs_errc::no_such_file_or_directory); } auto filesystem::build_device_inode_table() -> void diff --git a/kernel/kernel/filesystem/devfs/filesystem.hpp b/kernel/kernel/filesystem/devfs/filesystem.hpp index dbaa387b..dadeaf7d 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.hpp +++ b/kernel/kernel/filesystem/devfs/filesystem.hpp @@ -5,8 +5,10 @@ #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/inode.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> #include <string_view> @@ -25,7 +27,7 @@ namespace kernel::filesystem::devfs @param backing_inode Backing inode passed by the vfs (not required by devfs). @return The result of the mount operation. */ - auto mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> operation_result override; + auto mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> kstd::result<void> override; /** @brief Looks up an inode by @p name within a @p parent directory. @@ -34,7 +36,7 @@ namespace kernel::filesystem::devfs @return A pointer to the found inode, or a null pointer if not found. */ [[nodiscard]] auto lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name) const - -> kstd::shared_ptr<kernel::filesystem::inode> override; + -> kstd::result<kstd::shared_ptr<kernel::filesystem::inode>> override; private: auto build_device_inode_table() -> void; diff --git a/kernel/kernel/filesystem/devfs/filesystem.tests.cpp b/kernel/kernel/filesystem/devfs/filesystem.tests.cpp index 36cb4117..d5028231 100644 --- a/kernel/kernel/filesystem/devfs/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/devfs/filesystem.tests.cpp @@ -17,40 +17,40 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, THEN("mount succeeds") { - REQUIRE(result == kernel::filesystem::filesystem::operation_result::success); - REQUIRE(fs.root_inode() != nullptr); + REQUIRE(result); + REQUIRE(fs.root_inode()); } THEN("lookup on root finds ram0 device inode") { auto inode = fs.lookup(fs.root_inode(), "ram0"); - REQUIRE(inode != nullptr); - REQUIRE(inode->is_device()); + REQUIRE(inode); + REQUIRE(inode.value()->is_device()); } - THEN("lookup of an unknown device returns null") + THEN("lookup of an unknown device returns error") { auto inode = fs.lookup(fs.root_inode(), "ram99"); - REQUIRE(inode == nullptr); + REQUIRE(!inode); } - THEN("lookup with wrong parent returns null") + THEN("lookup with wrong parent returns error") { auto other_fs = kernel::filesystem::devfs::filesystem{}; - other_fs.mount(nullptr); + CHECK(other_fs.mount(nullptr)); auto inode = fs.lookup(other_fs.root_inode(), "ram0"); - REQUIRE(inode == nullptr); + REQUIRE(!inode); } - THEN("lookup with a non-directory parent returns null") + THEN("lookup with a non-directory parent returns error") { auto non_directory_inode = fs.lookup(fs.root_inode(), "ram0"); - REQUIRE(non_directory_inode != nullptr); - REQUIRE_FALSE(non_directory_inode->is_directory()); + REQUIRE(non_directory_inode); + REQUIRE_FALSE(non_directory_inode.value()->is_directory()); - auto result = fs.lookup(non_directory_inode, "anything"); - REQUIRE(result == nullptr); + auto result = fs.lookup(*non_directory_inode, "anything"); + REQUIRE(!result); } } @@ -60,13 +60,13 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto fs = kernel::filesystem::devfs::filesystem{}; auto result = fs.mount(nullptr); - REQUIRE(result == kernel::filesystem::filesystem::operation_result::success); + REQUIRE(result); THEN("lookup finds all generated RAM devices") { - REQUIRE(fs.lookup(fs.root_inode(), "ram0") != nullptr); - REQUIRE(fs.lookup(fs.root_inode(), "ram16") != nullptr); - REQUIRE(fs.lookup(fs.root_inode(), "ram32") != nullptr); + REQUIRE(fs.lookup(fs.root_inode(), "ram0")); + REQUIRE(fs.lookup(fs.root_inode(), "ram16")); + REQUIRE(fs.lookup(fs.root_inode(), "ram32")); } } } diff --git a/kernel/kernel/filesystem/devfs/inode.cpp b/kernel/kernel/filesystem/devfs/inode.cpp index 7bbfbbed..2e4ee7de 100644 --- a/kernel/kernel/filesystem/devfs/inode.cpp +++ b/kernel/kernel/filesystem/devfs/inode.cpp @@ -1,15 +1,17 @@ #include <kernel/filesystem/devfs/inode.hpp> +#include <kstd/result.hpp> + #include <cstddef> namespace kernel::filesystem::devfs { - auto inode::read(void *, size_t, size_t) const -> size_t + auto inode::read(void *, size_t, size_t) const -> kstd::result<size_t> { return 0; } - auto inode::write(void const *, size_t, size_t) -> size_t + auto inode::write(void const *, size_t, size_t) -> kstd::result<size_t> { return 0; } diff --git a/kernel/kernel/filesystem/devfs/inode.hpp b/kernel/kernel/filesystem/devfs/inode.hpp index e4288918..3472079f 100644 --- a/kernel/kernel/filesystem/devfs/inode.hpp +++ b/kernel/kernel/filesystem/devfs/inode.hpp @@ -3,6 +3,8 @@ #include <kernel/filesystem/inode.hpp> +#include <kstd/result.hpp> + #include <cstddef> namespace kernel::filesystem::devfs @@ -20,7 +22,7 @@ namespace kernel::filesystem::devfs @param size Number of bytes requested. @return Number of bytes read (always 0 because this inode does not expose file data). */ - auto read(void * buffer, size_t offset, size_t size) const -> size_t override; + auto read(void * buffer, size_t offset, size_t size) const -> kstd::result<size_t> override; /** @brief Writes to the devfs directory inode. @@ -29,7 +31,7 @@ namespace kernel::filesystem::devfs @param size Number of bytes requested. @return Number of bytes written (always 0 because writes are not supported for this inode). */ - auto write(void const * buffer, size_t offset, size_t size) -> size_t override; + auto write(void const * buffer, size_t offset, size_t size) -> kstd::result<size_t> override; /** @brief Check if this inode represents a directory. diff --git a/kernel/kernel/filesystem/devfs/inode.tests.cpp b/kernel/kernel/filesystem/devfs/inode.tests.cpp index ae26e742..ecf9a79b 100644 --- a/kernel/kernel/filesystem/devfs/inode.tests.cpp +++ b/kernel/kernel/filesystem/devfs/inode.tests.cpp @@ -1,8 +1,8 @@ #include <kernel/filesystem/devfs/inode.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/filesystem/device_inode.cpp b/kernel/kernel/filesystem/device_inode.cpp index 81a784cd..644e3df7 100644 --- a/kernel/kernel/filesystem/device_inode.cpp +++ b/kernel/kernel/filesystem/device_inode.cpp @@ -5,7 +5,8 @@ #include <kapi/devices/device.hpp> #include <kapi/system.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> #include <cstddef> @@ -20,7 +21,7 @@ namespace kernel::filesystem } } - auto device_inode::read(void * buffer, size_t offset, size_t size) const -> size_t + auto device_inode::read(void * buffer, size_t offset, size_t size) const -> kstd::result<size_t> { if (m_device->is_block_device()) { @@ -32,7 +33,7 @@ namespace kernel::filesystem } } - auto device_inode::write(void const * buffer, size_t offset, size_t size) -> size_t + auto device_inode::write(void const * buffer, size_t offset, size_t size) -> kstd::result<size_t> { if (m_device->is_block_device()) { diff --git a/kernel/kernel/filesystem/device_inode.hpp b/kernel/kernel/filesystem/device_inode.hpp index f4aa2d1e..5b22366a 100644 --- a/kernel/kernel/filesystem/device_inode.hpp +++ b/kernel/kernel/filesystem/device_inode.hpp @@ -5,7 +5,8 @@ #include <kapi/devices/device.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> #include <cstddef> @@ -32,7 +33,7 @@ namespace kernel::filesystem @param size The number of bytes to read. @return The number of bytes read. */ - auto read(void * buffer, size_t offset, size_t size) const -> size_t override; + auto read(void * buffer, size_t offset, size_t size) const -> kstd::result<size_t> override; /** @brief Write data to the device inode (and in the background from the associated device) from a @p buffer, starting @@ -42,7 +43,7 @@ namespace kernel::filesystem @param size The number of bytes to write. @return The number of bytes written. */ - auto write(void const * buffer, size_t offset, size_t size) -> size_t override; + auto write(void const * buffer, size_t offset, size_t size) -> kstd::result<size_t> override; /** @brief Get the associated device. @@ -52,7 +53,7 @@ namespace kernel::filesystem /** @brief Check if this inode represents a device. - @return returns true, since this indoe is a device inode and represents a device. + @return returns true, since this inode is a device inode and represents a device. */ [[nodiscard]] auto is_device() const -> bool override; diff --git a/kernel/kernel/filesystem/device_inode.tests.cpp b/kernel/kernel/filesystem/device_inode.tests.cpp index 025a22a2..d78d4a07 100644 --- a/kernel/kernel/filesystem/device_inode.tests.cpp +++ b/kernel/kernel/filesystem/device_inode.tests.cpp @@ -4,9 +4,9 @@ #include <kernel/test_support/devices/block_device.hpp> #include <kernel/test_support/devices/character_device.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/filesystem/error.hpp b/kernel/kernel/filesystem/error.hpp new file mode 100644 index 00000000..56f56ce4 --- /dev/null +++ b/kernel/kernel/filesystem/error.hpp @@ -0,0 +1,135 @@ +#ifndef TEACHOS_KERNEL_FILESYSTEM_ERROR_HPP +#define TEACHOS_KERNEL_FILESYSTEM_ERROR_HPP + +#include <kstd/system_error.hpp> + +#include <string_view> +#include <type_traits> + +namespace kernel::filesystem +{ + + enum struct vfs_errc : int + { + invalid_path = 1, + no_such_file_or_directory, + mount_point_not_found, + mount_busy, + has_child_mounts, + invalid_filesystem, + unmount_failed, + too_many_symbolic_link_levels, + unsupported_filesystem, + invalid_file_descriptor, + invalid_inode, + not_a_directory, + is_a_directory, + }; + + namespace detail + { + struct vfs_category_t final : kstd::error_category + { + [[nodiscard]] constexpr auto name() const noexcept -> std::string_view override + { + return "vfs"; + } + + [[nodiscard]] constexpr auto message(int value) const noexcept -> std::string_view override + { + switch (static_cast<vfs_errc>(value)) + { + case vfs_errc::invalid_path: + return "invalid path"; + case vfs_errc::no_such_file_or_directory: + return "no such file or directory"; + case vfs_errc::mount_point_not_found: + return "mount point not found"; + case vfs_errc::mount_busy: + return "mount point is busy"; + case vfs_errc::has_child_mounts: + return "mount point has child mounts"; + case vfs_errc::invalid_filesystem: + return "invalid filesystem"; + case vfs_errc::unmount_failed: + return "unmount failed"; + case vfs_errc::too_many_symbolic_link_levels: + return "too many symbolic link levels"; + case vfs_errc::unsupported_filesystem: + return "unsupported filesystem"; + case vfs_errc::invalid_file_descriptor: + return "invalid file descriptor"; + case vfs_errc::invalid_inode: + return "invalid inode"; + case vfs_errc::not_a_directory: + return "not a directory"; + case vfs_errc::is_a_directory: + return "is a directory"; + default: + return "unknown VFS error"; + } + } + + [[nodiscard]] constexpr auto default_error_condition(int value) const noexcept -> kstd::error_condition override + { + switch (static_cast<vfs_errc>(value)) + { + case vfs_errc::invalid_path: + case vfs_errc::invalid_filesystem: + case vfs_errc::invalid_inode: + return make_error_condition(kstd::errc::invalid_argument); + case vfs_errc::no_such_file_or_directory: + case vfs_errc::mount_point_not_found: + return make_error_condition(kstd::errc::no_such_file_or_directory); + case kernel::filesystem::vfs_errc::mount_busy: + case kernel::filesystem::vfs_errc::has_child_mounts: + case vfs_errc::unmount_failed: + return make_error_condition(kstd::errc::device_or_resource_busy); + case vfs_errc::too_many_symbolic_link_levels: + return make_error_condition(kstd::errc::too_many_symbolic_link_levels); + case vfs_errc::unsupported_filesystem: + return make_error_condition(kstd::errc::not_supported); + case vfs_errc::invalid_file_descriptor: + return make_error_condition(kstd::errc::bad_file_descriptor); + case vfs_errc::not_a_directory: + return make_error_condition(kstd::errc::not_a_directory); + case vfs_errc::is_a_directory: + return make_error_condition(kstd::errc::is_a_directory); + default: + return kstd::error_condition{value, *this}; + } + } + } constexpr inline vfs_category_instance{}; + } // namespace detail + + [[nodiscard]] constexpr auto inline vfs_category() noexcept -> kstd::error_category const & + { + return detail::vfs_category_instance; + } + + [[nodiscard]] constexpr auto inline make_error_code(vfs_errc error) noexcept -> kstd::error_code + { + return {static_cast<int>(error), vfs_category()}; + } + + [[nodiscard]] constexpr auto inline make_error_condition(vfs_errc error) noexcept -> kstd::error_condition + { + return {static_cast<int>(error), vfs_category()}; + } + +} // namespace kernel::filesystem + +namespace kstd +{ + template<> + struct is_error_code_enum<kernel::filesystem::vfs_errc> : std::true_type + { + }; + + template<> + struct is_error_condition_enum<kernel::filesystem::vfs_errc> : std::true_type + { + }; +} // namespace kstd + +#endif diff --git a/kernel/kernel/filesystem/ext2/error.hpp b/kernel/kernel/filesystem/ext2/error.hpp new file mode 100644 index 00000000..79f40517 --- /dev/null +++ b/kernel/kernel/filesystem/ext2/error.hpp @@ -0,0 +1,109 @@ +#ifndef TEACHOS_KERNEL_FILESYSTEM_EXT2_ERROR_HPP +#define TEACHOS_KERNEL_FILESYSTEM_EXT2_ERROR_HPP + +#include <kernel/filesystem/error.hpp> + +#include <kstd/system_error.hpp> + +#include <string_view> +#include <type_traits> + +namespace kernel::filesystem::ext2 +{ + + enum struct ext2_errc : int + { + invalid_magic_number = 1, + invalid_root_inode, + invalid_block_group_index, + invalid_block_index, + invalid_block_number, + failed_to_read_superblock, + failed_to_read_block_group_descriptors, + }; + + namespace detail + { + struct ext2_category_t final : kstd::error_category + { + [[nodiscard]] constexpr auto name() const noexcept -> std::string_view override + { + return "ext2"; + } + + [[nodiscard]] constexpr auto message(int value) const noexcept -> std::string_view override + { + switch (static_cast<ext2_errc>(value)) + { + case ext2_errc::invalid_magic_number: + return "invalid filesystem magic"; + case ext2_errc::invalid_root_inode: + return "invalid root inode"; + case ext2_errc::invalid_block_group_index: + return "block group index out of bounds"; + case ext2_errc::invalid_block_index: + return "block index out of bounds"; + case ext2_errc::invalid_block_number: + return "block number out of bounds"; + case ext2_errc::failed_to_read_superblock: + return "failed to read superblock"; + case ext2_errc::failed_to_read_block_group_descriptors: + return "failed to read block group descriptors"; + default: + return "unknown ext2 error"; + }; + } + + [[nodiscard]] constexpr auto equivalent(int code, kstd::error_condition const & condition) const noexcept + -> bool override + { + switch (static_cast<ext2_errc>(code)) + { + case ext2_errc::invalid_magic_number: + case ext2_errc::invalid_root_inode: + if (condition.category() == kernel::filesystem::vfs_category()) + { + return condition.value() == static_cast<int>(kernel::filesystem::vfs_errc::invalid_filesystem); + } + else if (condition.category() == kstd::generic_category()) + { + return condition.value() == static_cast<int>(kstd::errc::invalid_argument); + } + break; + case ext2_errc::invalid_block_group_index: + case ext2_errc::invalid_block_index: + case ext2_errc::invalid_block_number: + case ext2_errc::failed_to_read_superblock: + case ext2_errc::failed_to_read_block_group_descriptors: + if (condition.category() == kstd::generic_category()) + { + return condition.value() == static_cast<int>(kstd::errc::io_error); + } + break; + } + return kstd::error_category::equivalent(code, condition); + } + } constexpr inline ext2_category_instance{}; + } // namespace detail + + [[nodiscard]] constexpr auto inline ext2_category() noexcept -> kstd::error_category const & + { + return detail::ext2_category_instance; + } + + [[nodiscard]] constexpr auto inline make_error_code(ext2_errc error) noexcept -> kstd::error_code + { + return {static_cast<int>(error), ext2_category()}; + } + +} // namespace kernel::filesystem::ext2 + +namespace kstd +{ + template<> + struct is_error_code_enum<kernel::filesystem::ext2::ext2_errc> : std::true_type + { + }; +} // namespace kstd + +#endif diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp index 3180a19a..34ee1f75 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.cpp @@ -1,6 +1,8 @@ #include <kernel/filesystem/ext2/filesystem.hpp> +#include <kernel/filesystem/error.hpp> #include <kernel/filesystem/ext2/block_group_descriptor.hpp> +#include <kernel/filesystem/ext2/error.hpp> #include <kernel/filesystem/ext2/inode.hpp> #include <kernel/filesystem/ext2/linked_directory_entry.hpp> #include <kernel/filesystem/ext2/superblock.hpp> @@ -8,14 +10,17 @@ #include <kernel/filesystem/inode.hpp> #include <kernel/filesystem/type.hpp> -#include <kstd/memory> -#include <kstd/unikstd.h> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> #include <array> #include <cstddef> #include <cstdint> +#include <expected> #include <string_view> +#include <tuple> namespace kernel::filesystem::ext2 { @@ -41,15 +46,19 @@ namespace kernel::filesystem::ext2 [[gnu::used]] constexpr auto registration = type_registration<type>{}; - auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> operation_result + auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> kstd::result<void> { - kernel::filesystem::filesystem::mount(backing_inode); + std::ignore = kernel::filesystem::filesystem::mount(backing_inode); - m_backing_inode->read(&m_superblock, constants::superblock_offset, sizeof(m_superblock)); + if (auto read_result = m_backing_inode->read(&m_superblock, constants::superblock_offset, sizeof(m_superblock)); + !read_result) + { + return kstd::failure(read_result.error()); + } if (m_superblock.magic != constants::magic_number) { - return operation_result::invalid_magic_number; + return kstd::failure(ext2_errc::invalid_magic_number); } auto const blocks_per_group = m_superblock.blocks_per_group; @@ -57,40 +66,58 @@ namespace kernel::filesystem::ext2 m_block_group_descriptors = kstd::vector<block_group_descriptor>(num_block_groups); - m_backing_inode->read(m_block_group_descriptors.data(), block_group_descriptor_table_offset(), - num_block_groups * sizeof(block_group_descriptor)); + if (auto read_result = + m_backing_inode->read(m_block_group_descriptors.data(), block_group_descriptor_table_offset(), + num_block_groups * sizeof(block_group_descriptor)); + !read_result) + { + return kstd::failure(read_result.error()); + } - m_root_inode = read_inode(constants::root_inode_number); + if (auto root_inode = read_inode(constants::root_inode_number)) + { + m_root_inode = root_inode.value(); + } if (!m_root_inode || !m_root_inode->is_directory()) { - return operation_result::invalid_root_inode; + return kstd::failure(ext2_errc::invalid_root_inode); } - return operation_result::success; + + return {}; } auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name) const - -> kstd::shared_ptr<kernel::filesystem::inode> + -> kstd::result<kstd::shared_ptr<kernel::filesystem::inode>> { - if (!parent || !parent->is_directory()) + if (!parent) { - return nullptr; + return kstd::failure(vfs_errc::invalid_inode); } - auto * ext2_parent = static_cast<inode *>(parent.get()); - if (!ext2_parent) + if (!parent->is_directory()) { - return nullptr; + return kstd::failure(vfs_errc::not_a_directory); } + auto * ext2_parent = static_cast<inode *>(parent.get()); auto const & inode_data = ext2_parent->data(); kstd::vector<uint8_t> buffer(block_size()); for (uint32_t i = 0; i < inode_block_count(inode_data); ++i) { auto const global_block_number = map_inode_block_index_to_global_block_number(i, inode_data); - auto const block_offset = global_block_number * block_size(); - m_backing_inode->read(buffer.data(), block_offset, block_size()); + + if (!global_block_number) + { + return kstd::failure(global_block_number.error()); + } + + auto const block_offset = global_block_number.value() * block_size(); + if (auto read_result = m_backing_inode->read(buffer.data(), block_offset, block_size()); !read_result) + { + return kstd::failure(read_result.error()); + } auto const * entry = reinterpret_cast<linked_directory_entry const *>(buffer.data()); auto bytes_read = 0uz; @@ -108,10 +135,10 @@ namespace kernel::filesystem::ext2 } } - return nullptr; + return kstd::failure(vfs_errc::no_such_file_or_directory); } - auto filesystem::read_inode(uint32_t inode_number) const -> kstd::shared_ptr<inode> + auto filesystem::read_inode(uint32_t inode_number) const -> kstd::result<kstd::shared_ptr<inode>> { auto const inodes_per_group = m_superblock.inodes_per_group; auto const block_group_index = (inode_number - 1) / inodes_per_group; @@ -119,7 +146,7 @@ namespace kernel::filesystem::ext2 if (block_group_index >= m_block_group_descriptors.size()) { - return nullptr; + return kstd::failure(ext2_errc::invalid_block_group_index); } auto const & block_group_descriptor = m_block_group_descriptors.at(block_group_index); @@ -128,7 +155,10 @@ namespace kernel::filesystem::ext2 auto const inode_offset = inode_table_offset + inode_index_within_group * inode_size(); auto new_inode_data = inode_data{}; - m_backing_inode->read(&new_inode_data, inode_offset, sizeof(inode_data)); + if (auto read_result = m_backing_inode->read(&new_inode_data, inode_offset, sizeof(inode_data)); !read_result) + { + return kstd::failure(read_result.error()); + } return kstd::make_shared<inode>(this, new_inode_data); } @@ -143,7 +173,7 @@ namespace kernel::filesystem::ext2 } auto filesystem::map_inode_block_index_to_global_block_number(size_t inode_block_index, inode_data data) const - -> kstd::ssize_t + -> std::expected<std::size_t, kstd::error_code> { if (inode_block_index < constants::direct_block_count) { @@ -171,7 +201,15 @@ namespace kernel::filesystem::ext2 auto const idx = inode_block_index / stride; inode_block_index %= stride; - block_number = read_block_number_at_index(block_number, idx); + if (auto read_result = read_block_number_at_index(block_number, idx); !read_result) + { + return kstd::failure(read_result.error()); + } + else + { + block_number = read_result.value(); + } + if (block_number == 0) { return 0; @@ -186,16 +224,20 @@ namespace kernel::filesystem::ext2 return block_number; } - return -1; + return kstd::failure(ext2_errc::invalid_block_index); } - auto filesystem::read_block_number_at_index(uint32_t block_number, size_t index) const -> uint32_t + auto filesystem::read_block_number_at_index(uint32_t block_number, size_t index) const -> kstd::result<uint32_t> { uint32_t block_number_buffer = 0; auto const block_start_offset = block_number * block_size(); auto const number_start_address = block_start_offset + index * sizeof(uint32_t); - m_backing_inode->read(&block_number_buffer, number_start_address, sizeof(uint32_t)); + if (auto read_result = m_backing_inode->read(&block_number_buffer, number_start_address, sizeof(uint32_t)); + !read_result) + { + return kstd::failure(read_result.error()); + } return block_number_buffer; } diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp index 2284d7bf..5e5913bf 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.hpp +++ b/kernel/kernel/filesystem/ext2/filesystem.hpp @@ -7,9 +7,10 @@ #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/inode.hpp> -#include <kstd/memory> -#include <kstd/unikstd.h> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> #include <array> #include <cstddef> @@ -47,14 +48,14 @@ namespace kernel::filesystem::ext2 @brief A filesystem implementation for the ext2 filesystem format. This class provides methods for mounting an ext2 filesystem, and looking up inodes. */ - struct filesystem : kernel::filesystem::filesystem + struct filesystem final : kernel::filesystem::filesystem { /** @brief Initializes the ext2 filesystem with the given @p backing_inode. @param backing_inode The backing inode to mount. @return The result of the mount operation. */ - auto mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> operation_result override; + auto mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> kstd::result<void> override; /** @brief Looks up an inode by @p name within a @p parent directory. @@ -63,7 +64,7 @@ namespace kernel::filesystem::ext2 @return A pointer to the found inode, or a null pointer if not found. */ [[nodiscard]] auto lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name) const - -> kstd::shared_ptr<kernel::filesystem::inode> override; + -> kstd::result<kstd::shared_ptr<kernel::filesystem::inode>> override; /** @brief Gets the size of a block in the filesystem. @@ -81,10 +82,10 @@ namespace kernel::filesystem::ext2 @brief Maps an inode block index to a global block number. @param inode_block_index The index of the block within the inode. @param data The inode data. - @return The global block number. + @return The global block number on success, an error otherwise. */ [[nodiscard]] auto map_inode_block_index_to_global_block_number(size_t inode_block_index, inode_data data) const - -> kstd::ssize_t; + -> kstd::result<std::size_t>; private: struct indirect_level @@ -95,8 +96,8 @@ namespace kernel::filesystem::ext2 [[nodiscard]] auto indirect_levels() const -> std::array<indirect_level, 3>; - [[nodiscard]] auto read_inode(uint32_t inode_number) const -> kstd::shared_ptr<kernel::filesystem::ext2::inode>; - [[nodiscard]] auto read_block_number_at_index(uint32_t block_number, size_t index) const -> uint32_t; + [[nodiscard]] auto read_inode(uint32_t inode_number) const -> kstd::result<kstd::shared_ptr<inode>>; + [[nodiscard]] auto read_block_number_at_index(uint32_t block_number, size_t index) const -> kstd::result<uint32_t>; [[nodiscard]] auto inode_size() const -> uint16_t; [[nodiscard]] auto inode_block_count(inode_data const & data) const -> uint32_t; diff --git a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp index 83410702..1702526e 100644 --- a/kernel/kernel/filesystem/ext2/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/ext2/filesystem.tests.cpp @@ -2,14 +2,15 @@ #include <kernel/devices/storage/management.hpp> #include <kernel/filesystem/device_inode.hpp> +#include <kernel/filesystem/ext2/error.hpp> #include <kernel/filesystem/ext2/inode.hpp> #include <kernel/filesystem/filesystem.hpp> #include <kernel/test_support/devices/block_device.hpp> #include <kernel/test_support/filesystem/ext2.hpp> #include <kernel/test_support/filesystem/storage_boot_module_fixture.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> @@ -33,7 +34,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(boot_device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); + REQUIRE(fs.mount(dev_inode)); THEN("the root inode is available and is a directory") { @@ -44,25 +45,25 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, THEN("lookup resolves known entries from the image") { auto information = fs.lookup(fs.root_inode(), "information"); - REQUIRE(information != nullptr); - REQUIRE(information->is_directory()); + REQUIRE(information); + REQUIRE(information.value()->is_directory()); - auto info_1 = fs.lookup(information, "info_1.txt"); - REQUIRE(info_1 != nullptr); - REQUIRE(info_1->is_regular()); + auto info_1 = fs.lookup(*information, "info_1.txt"); + REQUIRE(info_1); + REQUIRE(info_1.value()->is_regular()); } THEN("lookup returns null for invalid inputs") { - REQUIRE(fs.lookup(nullptr, "information") == nullptr); + REQUIRE(!fs.lookup(nullptr, "information")); auto information = fs.lookup(fs.root_inode(), "information"); - REQUIRE(information != nullptr); - auto info_1 = fs.lookup(information, "info_1.txt"); - REQUIRE(info_1 != nullptr); + REQUIRE(information); + auto info_1 = fs.lookup(*information, "info_1.txt"); + REQUIRE(info_1); - REQUIRE(fs.lookup(info_1, "anything") == nullptr); - REQUIRE(fs.lookup(fs.root_inode(), "does_not_exist") == nullptr); + REQUIRE(!fs.lookup(*info_1, "anything")); + REQUIRE(!fs.lookup(fs.root_inode(), "does_not_exist")); } } } @@ -81,7 +82,7 @@ SCENARIO("Ext2 filesystem rejects invalid magic", "[filesystem][ext2][filesystem THEN("mount fails with invalid_magic_number") { - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::invalid_magic_number); + REQUIRE(fs.mount(dev_inode).error() == kernel::filesystem::ext2::ext2_errc::invalid_magic_number); } } } @@ -100,7 +101,7 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); + REQUIRE(fs.mount(dev_inode)); auto inode_data = kernel::filesystem::ext2::inode_data{}; inode_data.block[0] = 7; @@ -130,10 +131,10 @@ SCENARIO("Ext2 block mapping includes direct and all indirect levels", "[filesys REQUIRE(fs.map_inode_block_index_to_global_block_number(triply_start, inode_data) == 53); } - THEN("mapping returns zero for out-of-range indexes") + THEN("mapping returns error for out-of-range indexes") { auto const beyond_triply = triply_start + numbers_per_block * numbers_per_block * numbers_per_block; - REQUIRE(fs.map_inode_block_index_to_global_block_number(beyond_triply, inode_data) == -1); + REQUIRE(!fs.map_inode_block_index_to_global_block_number(beyond_triply, inode_data)); } } } diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp index 35a32ee4..6dadbec5 100644 --- a/kernel/kernel/filesystem/ext2/inode.cpp +++ b/kernel/kernel/filesystem/ext2/inode.cpp @@ -5,7 +5,8 @@ #include <kapi/system.hpp> -#include <kstd/cstring> +#include <kstd/cstring.hpp> +#include <kstd/result.hpp> #include <algorithm> #include <cstddef> @@ -23,7 +24,7 @@ namespace kernel::filesystem::ext2 } } - auto inode::read(void * buffer, size_t offset, size_t size) const -> size_t + auto inode::read(void * buffer, size_t offset, size_t size) const -> kstd::result<size_t> { auto const max_readable = this->size() - offset; auto const requested_size = std::min(size, max_readable); @@ -43,7 +44,7 @@ namespace kernel::filesystem::ext2 while (bytes_read < requested_size) { auto const block_number = m_filesystem->map_inode_block_index_to_global_block_number(block_index, m_data); - if (block_number == -1) + if (!block_number) { break; } @@ -56,11 +57,16 @@ namespace kernel::filesystem::ext2 } else { - auto const block_start_offset = block_number * m_filesystem->block_size(); + auto const block_start_offset = block_number.value() * m_filesystem->block_size(); auto const read_offset = block_start_offset + in_block_offset; - - bytes_read += m_filesystem->backing_inode()->read(static_cast<uint8_t *>(buffer) + bytes_read, read_offset, - bytes_to_read); + auto const read_result = m_filesystem->backing_inode()->read(static_cast<uint8_t *>(buffer) + bytes_read, + read_offset, bytes_to_read); + if (!read_result) + { + return kstd::failure(read_result.error()); + } + + bytes_read += read_result.value(); } block_index++; @@ -70,7 +76,7 @@ namespace kernel::filesystem::ext2 return bytes_read; } - auto inode::write(void const *, size_t, size_t) -> size_t + auto inode::write(void const *, size_t, size_t) -> kstd::result<size_t> { kapi::system::panic("[EXT2] inode::write is not implemented yet"); return 0; diff --git a/kernel/kernel/filesystem/ext2/inode.hpp b/kernel/kernel/filesystem/ext2/inode.hpp index f2496f0f..16cb04e0 100644 --- a/kernel/kernel/filesystem/ext2/inode.hpp +++ b/kernel/kernel/filesystem/ext2/inode.hpp @@ -3,7 +3,8 @@ #include <kernel/filesystem/inode.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> #include <array> #include <cstddef> @@ -54,7 +55,7 @@ namespace kernel::filesystem::ext2 @param size Number of bytes requested. @return Number of bytes read. */ - auto read(void * buffer, size_t offset, size_t size) const -> size_t override; + auto read(void * buffer, size_t offset, size_t size) const -> kstd::result<size_t> override; /** @brief Writes to the ext2 inode into a @p buffer, starting at the specified @p offset and for a given @p size. @@ -64,7 +65,7 @@ namespace kernel::filesystem::ext2 @param size Number of bytes requested. @return Number of bytes written. */ - auto write(void const * buffer, size_t offset, size_t size) -> size_t override; + auto write(void const * buffer, size_t offset, size_t size) -> kstd::result<size_t> override; /** @brief Get the data associated with this inode. diff --git a/kernel/kernel/filesystem/ext2/inode.tests.cpp b/kernel/kernel/filesystem/ext2/inode.tests.cpp index 4aecc04a..496e7c4f 100644 --- a/kernel/kernel/filesystem/ext2/inode.tests.cpp +++ b/kernel/kernel/filesystem/ext2/inode.tests.cpp @@ -10,8 +10,8 @@ #include <kernel/test_support/filesystem/ext2.hpp> #include <kernel/test_support/filesystem/storage_boot_module_fixture.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> @@ -20,6 +20,8 @@ #include <filesystem> #include <string_view> +// NOLINTBEGIN(readability-magic-numbers) + SCENARIO("Ext2 inode initialization and properties", "[filesystem][ext2][inode]") { GIVEN("an ext2 filesystem") @@ -97,29 +99,29 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_fixture, "Ext2 in auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(boot_device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); + REQUIRE(fs.mount(dev_inode)); auto information = fs.lookup(fs.root_inode(), "information"); - REQUIRE(information != nullptr); - auto file = fs.lookup(information, "info_1.txt"); - REQUIRE(file != nullptr); - REQUIRE(file->is_regular()); + REQUIRE(information); + auto file = fs.lookup(*information, "info_1.txt"); + REQUIRE(file); + REQUIRE(file.value()->is_regular()); THEN("reading from offset zero returns expected file prefix") { auto buffer = kstd::vector<std::byte>(6); - auto const bytes_read = file->read(buffer.data(), 0, buffer.size()); + auto const bytes_read = file.value()->read(buffer.data(), 0, buffer.size()); REQUIRE(bytes_read == 6); - auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read}; + auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), *bytes_read}; REQUIRE(text == "info_1"); } THEN("reading with an offset returns the expected byte") { auto buffer = kstd::vector<std::byte>(1); - auto const bytes_read = file->read(buffer.data(), 5, buffer.size()); + auto const bytes_read = file.value()->read(buffer.data(), 5, buffer.size()); REQUIRE(bytes_read == 1); REQUIRE(static_cast<char>(buffer[0]) == '1'); @@ -139,7 +141,7 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); + REQUIRE(fs.mount(dev_inode)); auto data = kernel::filesystem::ext2::inode_data{}; data.block[0] = 30; @@ -159,7 +161,7 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto const bytes_read = inode.read(buffer.data(), 0, buffer.size()); REQUIRE(bytes_read == data.size); - auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read}; + auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), *bytes_read}; REQUIRE(text.substr(0, 5) == "Hello"); REQUIRE(std::ranges::all_of(text.substr(5, block_size - 5), [](char c) { return c == '\0'; })); REQUIRE(text.substr(2 * block_size, 6) == "World!"); @@ -176,7 +178,7 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); + REQUIRE(fs.mount(dev_inode)); auto data = kernel::filesystem::ext2::inode_data{}; data.block[0] = 30; @@ -200,7 +202,7 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto const bytes_read = inode.read(buffer.data(), 0, buffer.size()); REQUIRE(bytes_read == data.size); - auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read}; + auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), *bytes_read}; REQUIRE(text.substr(0, 5) == "Hello"); REQUIRE(std::ranges::all_of(text.substr(5, 12 * block_size - 5), [](char c) { return c == '\0'; })); REQUIRE(text.substr(12 * block_size, 4) == "Blub"); @@ -221,7 +223,7 @@ SCENARIO("Ext2 inode handles zeros in block mappings as file holes", "[filesyste auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); + REQUIRE(fs.mount(dev_inode)); auto data = kernel::filesystem::ext2::inode_data{}; data.block[12] = 0; @@ -252,7 +254,7 @@ SCENARIO("Ext2 inode read across block boundaries", "[filesystem][ext2][inode]") auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); + REQUIRE(fs.mount(dev_inode)); auto inode_data = kernel::filesystem::ext2::inode_data{}; inode_data.size = block_size * 2; @@ -269,7 +271,7 @@ SCENARIO("Ext2 inode read across block boundaries", "[filesystem][ext2][inode]") auto const bytes_read = inode.read(buffer.data(), block_size - 6, buffer.size()); REQUIRE(bytes_read == 12); - auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), bytes_read}; + auto const text = std::string_view{reinterpret_cast<char const *>(buffer.data()), *bytes_read}; REQUIRE(text == "Hello World!"); } } @@ -313,7 +315,7 @@ SCENARIO("Ext2 inode get_size() correctly returns size depending on revision lev auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); + REQUIRE(fs.mount(dev_inode)); auto data = kernel::filesystem::ext2::inode_data{}; data.size = 256; @@ -349,7 +351,7 @@ SCENARIO("Ext2 inode get_size() correctly returns size depending on revision lev auto dev_inode = kstd::make_shared<kernel::filesystem::device_inode>(device); auto fs = kernel::filesystem::ext2::filesystem{}; - REQUIRE(fs.mount(dev_inode) == kernel::filesystem::filesystem::operation_result::success); + REQUIRE(fs.mount(dev_inode)); auto data = kernel::filesystem::ext2::inode_data{}; data.size = 256; @@ -373,4 +375,6 @@ SCENARIO("Ext2 inode get_size() correctly returns size depending on revision lev REQUIRE(inode.size() == 256); } } -}
\ No newline at end of file +} + +// NOLINTEND(readability-magic-numbers)
\ No newline at end of file diff --git a/kernel/kernel/filesystem/filesystem.cpp b/kernel/kernel/filesystem/filesystem.cpp index 24d0e229..ac0d0ebc 100644 --- a/kernel/kernel/filesystem/filesystem.cpp +++ b/kernel/kernel/filesystem/filesystem.cpp @@ -1,11 +1,14 @@ #include <kernel/filesystem/filesystem.hpp> +#include <kernel/filesystem/error.hpp> #include <kernel/filesystem/ext2/filesystem.hpp> #include <kernel/filesystem/inode.hpp> #include <kapi/system.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> #include <array> @@ -18,7 +21,8 @@ namespace kernel::filesystem }; } // namespace - auto filesystem::probe_and_mount(kstd::shared_ptr<inode> const & backing_inode) -> kstd::shared_ptr<filesystem> + auto filesystem::probe_and_mount(kstd::shared_ptr<inode> const & backing_inode) + -> kstd::result<kstd::shared_ptr<filesystem>> { if (!backing_inode) { @@ -28,16 +32,16 @@ namespace kernel::filesystem for (auto & factory : filesystem_factories) { auto fs = factory(); - if (fs->mount(backing_inode) == operation_result::success) + if (fs->mount(backing_inode)) { return fs; } } - return nullptr; + return kstd::failure(vfs_errc::unsupported_filesystem); } - auto filesystem::mount(kstd::shared_ptr<inode> const & backing_inode) -> operation_result + auto filesystem::mount(kstd::shared_ptr<inode> const & backing_inode) -> kstd::result<void> { if (!backing_inode) { @@ -45,7 +49,7 @@ namespace kernel::filesystem } m_backing_inode = backing_inode; - return operation_result::success; + return kstd::success(); } auto filesystem::root_inode() const -> kstd::shared_ptr<inode> const & diff --git a/kernel/kernel/filesystem/filesystem.hpp b/kernel/kernel/filesystem/filesystem.hpp index bec1b160..1264d00d 100644 --- a/kernel/kernel/filesystem/filesystem.hpp +++ b/kernel/kernel/filesystem/filesystem.hpp @@ -3,8 +3,10 @@ #include <kernel/filesystem/inode.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> #include <string_view> @@ -16,14 +18,6 @@ namespace kernel::filesystem */ struct filesystem { - enum class operation_result : int - { - success = 0, - invalid_magic_number = -1, - invalid_root_inode = -2, - unmount_failed = -3 - }; - /** @brief Virtual destructor for the filesystem. */ @@ -34,19 +28,19 @@ namespace kernel::filesystem and returns a pointer to the mounted filesystem instance. This method iterates through known filesystem types and attempts to initialize it with the backing inode until the mount was successful or all types have been tried. @param backing_inode The inode to probe and mount. - @return A pointer to the mounted filesystem instance if successful, or a null pointer if no recognizable filesystem - is found on the backing inode. + @return A pointer to the mounted filesystem instance if successful, an error otherwise. @warning Panics if @p backing_inode is null. */ - auto static probe_and_mount(kstd::shared_ptr<inode> const & backing_inode) -> kstd::shared_ptr<filesystem>; + auto static probe_and_mount(kstd::shared_ptr<inode> const & backing_inode) + -> kstd::result<kstd::shared_ptr<filesystem>>; /** @brief Initializes the filesystem with the given @p backing_inode. @param backing_inode The inode to use as the backing inode for the filesystem. (This is typically the inode representing the block device or another inode which contains the filesystem data.) - @return The result of the mount operation. + @return Nothing on success, and error otherwise. */ - virtual auto mount(kstd::shared_ptr<inode> const & backing_inode) -> operation_result; + virtual auto mount(kstd::shared_ptr<inode> const & backing_inode) -> kstd::result<void>; /** @brief Looks up a child inode within the given @p parent inode with the specified @p name. This method must be @@ -54,10 +48,10 @@ namespace kernel::filesystem finding the requested inode. @param parent The parent inode. @param name The name of the child inode to look up. - @return A pointer to the requested child inode, or a null pointer if not found. + @return A pointer to the requested child inode, an error otherwise. */ [[nodiscard]] virtual auto lookup(kstd::shared_ptr<inode> const & parent, std::string_view name) const - -> kstd::shared_ptr<inode> = 0; + -> kstd::result<kstd::shared_ptr<inode>> = 0; /** @brief Returns a reference to the root inode of the filesystem. diff --git a/kernel/kernel/filesystem/inode.hpp b/kernel/kernel/filesystem/inode.hpp index b34b921e..cfddebf6 100644 --- a/kernel/kernel/filesystem/inode.hpp +++ b/kernel/kernel/filesystem/inode.hpp @@ -1,6 +1,8 @@ #ifndef TEACH_OS_KERNEL_FILESYSTEM_INODE_HPP #define TEACH_OS_KERNEL_FILESYSTEM_INODE_HPP +#include <kstd/result.hpp> + #include <cstddef> namespace kernel::filesystem @@ -28,7 +30,7 @@ namespace kernel::filesystem @param size Number of bytes requested. @return Number of bytes read. */ - virtual auto read(void * buffer, size_t offset, size_t size) const -> size_t = 0; + virtual auto read(void * buffer, size_t offset, size_t size) const -> kstd::result<size_t> = 0; /** @brief Writes to the inode into a @p buffer, starting at the specified @p offset and for a given @p size. This @@ -38,7 +40,7 @@ namespace kernel::filesystem @param size Number of bytes to write. @return Number of bytes written. */ - virtual auto write(void const * buffer, size_t offset, size_t size) -> size_t = 0; + virtual auto write(void const * buffer, size_t offset, size_t size) -> kstd::result<size_t> = 0; /** @brief Returns whether the inode is a directory. diff --git a/kernel/kernel/filesystem/mount.cpp b/kernel/kernel/filesystem/mount.cpp index ead7479d..009ab230 100644 --- a/kernel/kernel/filesystem/mount.cpp +++ b/kernel/kernel/filesystem/mount.cpp @@ -5,8 +5,8 @@ #include <kapi/system.hpp> -#include <kstd/memory> -#include <kstd/string> +#include <kstd/memory.hpp> +#include <kstd/string.hpp> #include <cstddef> #include <string_view> diff --git a/kernel/kernel/filesystem/mount.hpp b/kernel/kernel/filesystem/mount.hpp index ced4f814..589094e0 100644 --- a/kernel/kernel/filesystem/mount.hpp +++ b/kernel/kernel/filesystem/mount.hpp @@ -4,8 +4,8 @@ #include <kernel/filesystem/dentry.hpp> #include <kernel/filesystem/filesystem.hpp> -#include <kstd/memory> -#include <kstd/string> +#include <kstd/memory.hpp> +#include <kstd/string.hpp> #include <atomic> #include <cstddef> diff --git a/kernel/kernel/filesystem/mount.tests.cpp b/kernel/kernel/filesystem/mount.tests.cpp index c9ff82e9..800a0cfc 100644 --- a/kernel/kernel/filesystem/mount.tests.cpp +++ b/kernel/kernel/filesystem/mount.tests.cpp @@ -5,9 +5,9 @@ #include <kernel/test_support/filesystem/filesystem.hpp> #include <kernel/test_support/filesystem/inode.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/filesystem/mount_table.cpp b/kernel/kernel/filesystem/mount_table.cpp index e4baac7a..d3f252b4 100644 --- a/kernel/kernel/filesystem/mount_table.cpp +++ b/kernel/kernel/filesystem/mount_table.cpp @@ -3,8 +3,8 @@ #include <kernel/filesystem/dentry.hpp> #include <kernel/filesystem/mount.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/vector.hpp> #include <algorithm> #include <ranges> diff --git a/kernel/kernel/filesystem/mount_table.hpp b/kernel/kernel/filesystem/mount_table.hpp index 4f2d1b7f..46e2a439 100644 --- a/kernel/kernel/filesystem/mount_table.hpp +++ b/kernel/kernel/filesystem/mount_table.hpp @@ -3,8 +3,8 @@ #include <kernel/filesystem/mount.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/vector.hpp> #include <string_view> diff --git a/kernel/kernel/filesystem/mount_table.tests.cpp b/kernel/kernel/filesystem/mount_table.tests.cpp index 19b47b23..39ad6b01 100644 --- a/kernel/kernel/filesystem/mount_table.tests.cpp +++ b/kernel/kernel/filesystem/mount_table.tests.cpp @@ -5,9 +5,9 @@ #include <kernel/test_support/filesystem/filesystem.hpp> #include <kernel/test_support/filesystem/inode.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/filesystem/open_file_descriptor.cpp b/kernel/kernel/filesystem/open_file_descriptor.cpp index a5567bf4..ecf3e725 100644 --- a/kernel/kernel/filesystem/open_file_descriptor.cpp +++ b/kernel/kernel/filesystem/open_file_descriptor.cpp @@ -2,8 +2,9 @@ #include <kernel/filesystem/dentry.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> #include <kstd/os/error.hpp> +#include <kstd/result.hpp> #include <cstddef> @@ -19,18 +20,32 @@ namespace kernel::filesystem } } - auto open_file_descriptor::read(void * buffer, size_t size) -> size_t + auto open_file_descriptor::read(void * buffer, size_t size) -> kstd::result<size_t> { - auto read_bytes = m_dentry->get_inode()->read(buffer, m_offset, size); - m_offset += read_bytes; - return read_bytes; + if (auto result = m_dentry->get_inode()->read(buffer, m_offset, size); !result) + { + return kstd::failure(result.error()); + } + else + { + auto read_bytes = result.value(); + m_offset += read_bytes; + return read_bytes; + } } - auto open_file_descriptor::write(void const * buffer, size_t size) -> size_t + auto open_file_descriptor::write(void const * buffer, size_t size) -> kstd::result<size_t> { - auto written_bytes = m_dentry->get_inode()->write(buffer, m_offset, size); - m_offset += written_bytes; - return written_bytes; + if (auto result = m_dentry->get_inode()->write(buffer, m_offset, size); !result) + { + return kstd::failure(result.error()); + } + else + { + auto written_bytes = result.value(); + m_offset += written_bytes; + return written_bytes; + } } auto open_file_descriptor::offset() const -> size_t diff --git a/kernel/kernel/filesystem/open_file_descriptor.hpp b/kernel/kernel/filesystem/open_file_descriptor.hpp index fd10e646..f6899a31 100644 --- a/kernel/kernel/filesystem/open_file_descriptor.hpp +++ b/kernel/kernel/filesystem/open_file_descriptor.hpp @@ -3,7 +3,8 @@ #include <kernel/filesystem/dentry.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> #include <cstddef> @@ -34,7 +35,7 @@ namespace kernel::filesystem @param size The number of bytes to read. @return The number of bytes read. */ - auto read(void * buffer, size_t size) -> size_t; + auto read(void * buffer, size_t size) -> kstd::result<size_t>; /** @brief Writes data to the open file descriptor from a @p buffer, starting at the current file offset and for a @@ -44,7 +45,7 @@ namespace kernel::filesystem @param size The number of bytes to write. @return The number of bytes written. */ - auto write(void const * buffer, size_t size) -> size_t; + auto write(void const * buffer, size_t size) -> kstd::result<size_t>; /** @brief Returns the current file offset for this open file descriptor. diff --git a/kernel/kernel/filesystem/open_file_descriptor.tests.cpp b/kernel/kernel/filesystem/open_file_descriptor.tests.cpp index 8c24cf0e..06488ba0 100644 --- a/kernel/kernel/filesystem/open_file_descriptor.tests.cpp +++ b/kernel/kernel/filesystem/open_file_descriptor.tests.cpp @@ -6,9 +6,9 @@ #include <kernel/test_support/filesystem/inode.hpp> #include <kernel/test_support/filesystem/storage_boot_module_vfs_fixture.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> @@ -81,8 +81,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Ope auto & vfs = kernel::filesystem::vfs::get(); auto dentry = vfs.open("/information/info_1.txt"); - REQUIRE(dentry != nullptr); - auto ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry); + REQUIRE(dentry); + auto ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry.value()); THEN("the file can be read and the offset is updated") { @@ -91,7 +91,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Ope REQUIRE(bytes_read == 7); REQUIRE(ofd->offset() == 7); - std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(bytes_read)}; + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), *bytes_read}; REQUIRE(buffer_as_str == "info_1\n"); } @@ -106,7 +106,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "Ope REQUIRE(bytes_read_2 == buffer.size() / 2); REQUIRE(ofd->offset() == buffer.size()); - std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), bytes_read_1 + bytes_read_2}; + std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), *bytes_read_1 + *bytes_read_2}; REQUIRE(buffer_as_str == "info"); } } diff --git a/kernel/kernel/filesystem/open_file_table.cpp b/kernel/kernel/filesystem/open_file_table.cpp index 2afe3aa4..dea504e4 100644 --- a/kernel/kernel/filesystem/open_file_table.cpp +++ b/kernel/kernel/filesystem/open_file_table.cpp @@ -1,11 +1,13 @@ #include <kernel/filesystem/open_file_table.hpp> +#include <kernel/filesystem/error.hpp> #include <kernel/filesystem/open_file_descriptor.hpp> #include <kapi/system.hpp> -#include <kstd/memory> -#include <kstd/unikstd.h> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> #include <algorithm> #include <cstddef> @@ -38,11 +40,12 @@ namespace kernel::filesystem return *global_open_file_table; } - auto open_file_table::add_file(kstd::shared_ptr<open_file_descriptor> const & file_descriptor) -> kstd::ssize_t + auto open_file_table::add_file(kstd::shared_ptr<open_file_descriptor> const & file_descriptor) + -> kstd::result<std::size_t> { if (!file_descriptor) { - return -1; + return kstd::failure(vfs_errc::invalid_file_descriptor); } auto it = std::ranges::find_if(m_open_files, [](auto const & open_file) { return open_file == nullptr; }); @@ -56,25 +59,25 @@ namespace kernel::filesystem return m_open_files.size() - 1; } - auto open_file_table::file(size_t fd) const -> kstd::shared_ptr<open_file_descriptor> + auto open_file_table::file(size_t fd) const -> kstd::result<kstd::shared_ptr<open_file_descriptor>> { - if (fd >= m_open_files.size()) + if (fd >= m_open_files.size() || m_open_files.at(fd) == nullptr) { - return nullptr; + return kstd::failure(vfs_errc::invalid_file_descriptor); } - return m_open_files.at(fd); + return kstd::success(m_open_files.at(fd)); } - auto open_file_table::remove_file(size_t fd) -> kstd::ssize_t + auto open_file_table::remove_file(size_t fd) -> kstd::result<void> { - if (fd >= m_open_files.size()) + if (fd >= m_open_files.size() || m_open_files.at(fd) == nullptr) { - return -1; + return kstd::failure(vfs_errc::invalid_file_descriptor); } m_open_files.at(fd) = nullptr; - return 0; + return kstd::success(); } } // namespace kernel::filesystem diff --git a/kernel/kernel/filesystem/open_file_table.hpp b/kernel/kernel/filesystem/open_file_table.hpp index 7e754ac1..7c9a0c0c 100644 --- a/kernel/kernel/filesystem/open_file_table.hpp +++ b/kernel/kernel/filesystem/open_file_table.hpp @@ -3,9 +3,10 @@ #include <kernel/filesystem/open_file_descriptor.hpp> -#include <kstd/memory> -#include <kstd/unikstd.h> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> #include <cstddef> @@ -40,21 +41,21 @@ namespace kernel::filesystem @param fd The file descriptor to add. @return The file descriptor index assigned to the file, or -1 on failure. */ - auto add_file(kstd::shared_ptr<open_file_descriptor> const & fd) -> kstd::ssize_t; + auto add_file(kstd::shared_ptr<open_file_descriptor> const & fd) -> kstd::result<std::size_t>; /** @brief Get a file from the open file table. @param fd The file descriptor index to retrieve. @return A pointer to the requested file descriptor, or a null pointer if not found. */ - [[nodiscard]] auto file(size_t fd) const -> kstd::shared_ptr<open_file_descriptor>; + [[nodiscard]] auto file(size_t fd) const -> kstd::result<kstd::shared_ptr<open_file_descriptor>>; /** @brief Remove a file from the open file table. @param fd The file descriptor index to remove. @return 0 on success, or -1 on failure. */ - auto remove_file(size_t fd) -> kstd::ssize_t; + auto remove_file(size_t fd) -> kstd::result<void>; private: open_file_table() = default; diff --git a/kernel/kernel/filesystem/open_file_table.tests.cpp b/kernel/kernel/filesystem/open_file_table.tests.cpp index 3e91111d..69188528 100644 --- a/kernel/kernel/filesystem/open_file_table.tests.cpp +++ b/kernel/kernel/filesystem/open_file_table.tests.cpp @@ -4,9 +4,10 @@ #include <kernel/filesystem/open_file_descriptor.hpp> #include <kernel/test_support/filesystem/inode.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> @@ -36,7 +37,7 @@ SCENARIO("Open file table add/get file", "[filesystem][open_file_table]") THEN("the file descriptor can be retrieved using the returned file descriptor") { - auto retrieved_descriptor = table.file(fd_1); + auto retrieved_descriptor = table.file(*fd_1); REQUIRE(retrieved_descriptor == file_descriptor_1); } } @@ -46,16 +47,16 @@ SCENARIO("Open file table add/get file", "[filesystem][open_file_table]") { auto & table = kernel::filesystem::open_file_table::get(); - THEN("adding a null file descriptor returns an error code") + THEN("adding a null file descriptor returns an error") { auto fd = table.add_file(nullptr); - REQUIRE(fd == -1); + REQUIRE(fd.error() == kstd::errc::bad_file_descriptor); } - THEN("retrieving a file descriptor with an out-of-bounds file descriptor returns a null pointer") + THEN("retrieving a file descriptor with an out-of-bounds file descriptor returns an error") { auto retrieved_descriptor = table.file(1000); - REQUIRE(retrieved_descriptor == nullptr); + REQUIRE(retrieved_descriptor.error() == kstd::errc::bad_file_descriptor); } } } @@ -72,23 +73,23 @@ SCENARIO("Open file table remove file", "[filesystem][open_file_table]") WHEN("removing the file descriptor using the file descriptor") { - table.remove_file(fd); + CHECK(table.remove_file(*fd)); THEN("the file descriptor can no longer be retrieved using the file descriptor") { - auto retrieved_descriptor = table.file(fd); - REQUIRE(retrieved_descriptor == nullptr); + auto retrieved_descriptor = table.file(*fd); + REQUIRE(retrieved_descriptor.error() == kstd::errc::bad_file_descriptor); } } WHEN("removing a file descriptor the other file descriptor keep the same index") { auto fd2 = table.add_file(file_descriptor); - table.remove_file(fd); + CHECK(table.remove_file(*fd)); THEN("the second file descriptor can still be retrieved using its file descriptor") { - auto retrieved_descriptor = table.file(fd2); + auto retrieved_descriptor = table.file(*fd2); REQUIRE(retrieved_descriptor == file_descriptor); } } diff --git a/kernel/kernel/filesystem/path.hpp b/kernel/kernel/filesystem/path.hpp index 4845bf1a..438c22f3 100644 --- a/kernel/kernel/filesystem/path.hpp +++ b/kernel/kernel/filesystem/path.hpp @@ -3,7 +3,7 @@ #include <kernel/filesystem/constants.hpp> -#include <kstd/string> +#include <kstd/string.hpp> #include <ranges> #include <string_view> diff --git a/kernel/kernel/filesystem/rootfs/filesystem.cpp b/kernel/kernel/filesystem/rootfs/filesystem.cpp index 7fe5c1ea..fef43e28 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.cpp @@ -1,11 +1,14 @@ #include <kernel/filesystem/rootfs/filesystem.hpp> +#include <kernel/filesystem/error.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> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> #include <string_view> @@ -33,15 +36,15 @@ namespace kernel::filesystem::rootfs [[gnu::used]] constexpr auto registration = type_registration<type>{}; - auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> operation_result + auto filesystem::mount(kstd::shared_ptr<kernel::filesystem::inode> const &) -> kstd::result<void> { m_root_inode = kstd::make_shared<inode>(); - return operation_result::success; + return kstd::success(); } auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const &, std::string_view) const - -> kstd::shared_ptr<kernel::filesystem::inode> + -> kstd::result<kstd::shared_ptr<kernel::filesystem::inode>> { - return nullptr; + return kstd::failure(vfs_errc::no_such_file_or_directory); } } // namespace kernel::filesystem::rootfs diff --git a/kernel/kernel/filesystem/rootfs/filesystem.hpp b/kernel/kernel/filesystem/rootfs/filesystem.hpp index 3c2dcb1c..8507d8b8 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.hpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.hpp @@ -4,9 +4,11 @@ #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/inode.hpp> -#include <kstd/memory> -#include <kstd/string> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/string.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> #include <string_view> @@ -25,7 +27,7 @@ namespace kernel::filesystem::rootfs @param backing_inode The backing inode to mount (not required by rootfs). @return The result of the mount operation. */ - auto mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> operation_result override; + auto mount(kstd::shared_ptr<kernel::filesystem::inode> const & backing_inode) -> kstd::result<void> override; /** @brief Looks up an inode by @p name within a @p parent directory. @@ -34,7 +36,7 @@ namespace kernel::filesystem::rootfs @return Always returns nullptr. */ [[nodiscard]] auto lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name) const - -> kstd::shared_ptr<kernel::filesystem::inode> override; + -> kstd::result<kstd::shared_ptr<kernel::filesystem::inode>> override; }; } // namespace kernel::filesystem::rootfs diff --git a/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp b/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp index ae320e95..347502ca 100644 --- a/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp +++ b/kernel/kernel/filesystem/rootfs/filesystem.tests.cpp @@ -2,9 +2,9 @@ #include <kernel/filesystem/filesystem.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> @@ -17,22 +17,22 @@ SCENARIO("Rootfs filesystem mount and lookup", "[filesystem][rootfs][filesystem] THEN("the filesystem can be mounted successfully") { - REQUIRE(result == kernel::filesystem::filesystem::operation_result::success); - REQUIRE(fs.root_inode() != nullptr); + REQUIRE(result); + REQUIRE(fs.root_inode()); } - THEN("looking up a non-existent directory returns null") + THEN("looking up a non-existent directory returns an error") { auto non_existent_inode_1 = fs.lookup(fs.root_inode(), ""); - REQUIRE(non_existent_inode_1 == nullptr); + REQUIRE(!non_existent_inode_1); auto non_existent_inode_2 = fs.lookup(fs.root_inode(), "nonexistent"); - REQUIRE(non_existent_inode_2 == nullptr); + REQUIRE(!non_existent_inode_2); } - THEN("looking up with a null parent inode returns null") + THEN("looking up with a null parent inode returns an error") { auto result = fs.lookup(nullptr, "dev"); - REQUIRE(result == nullptr); + REQUIRE(!result); } } } diff --git a/kernel/kernel/filesystem/rootfs/inode.cpp b/kernel/kernel/filesystem/rootfs/inode.cpp index f64fb87c..e3e9d641 100644 --- a/kernel/kernel/filesystem/rootfs/inode.cpp +++ b/kernel/kernel/filesystem/rootfs/inode.cpp @@ -2,16 +2,18 @@ #include <kernel/filesystem/rootfs/inode.hpp> +#include <kstd/result.hpp> + #include <cstddef> namespace kernel::filesystem::rootfs { - auto inode::read(void *, size_t, size_t) const -> size_t + auto inode::read(void *, size_t, size_t) const -> kstd::result<size_t> { return 0; } - auto inode::write(void const *, size_t, size_t) -> size_t + auto inode::write(void const *, size_t, size_t) -> kstd::result<size_t> { return 0; } diff --git a/kernel/kernel/filesystem/rootfs/inode.hpp b/kernel/kernel/filesystem/rootfs/inode.hpp index 0f21eaa0..777f13f9 100644 --- a/kernel/kernel/filesystem/rootfs/inode.hpp +++ b/kernel/kernel/filesystem/rootfs/inode.hpp @@ -3,9 +3,10 @@ #include <kernel/filesystem/inode.hpp> -#include <kstd/memory> -#include <kstd/string> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/string.hpp> +#include <kstd/vector.hpp> #include <cstddef> @@ -23,7 +24,7 @@ namespace kernel::filesystem::rootfs @param size Number of bytes requested. @return Number of bytes read (always 0 because this inode does not expose file data). */ - auto read(void * buffer, size_t offset, size_t size) const -> size_t override; + auto read(void * buffer, size_t offset, size_t size) const -> kstd::result<size_t> override; /** @brief Writes to the rootfs directory inode. @@ -32,7 +33,7 @@ namespace kernel::filesystem::rootfs @param size Number of bytes requested. @return Number of bytes written (always 0 because writes are not supported for this inode). */ - auto write(void const * buffer, size_t offset, size_t size) -> size_t override; + auto write(void const * buffer, size_t offset, size_t size) -> kstd::result<size_t> override; /** @brief Check if this inode represents a directory. diff --git a/kernel/kernel/filesystem/rootfs/inode.tests.cpp b/kernel/kernel/filesystem/rootfs/inode.tests.cpp index f4b634fa..0b48ca71 100644 --- a/kernel/kernel/filesystem/rootfs/inode.tests.cpp +++ b/kernel/kernel/filesystem/rootfs/inode.tests.cpp @@ -1,8 +1,8 @@ #include <kernel/filesystem/rootfs/inode.hpp> -#include <kstd/memory> -#include <kstd/print> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/filesystem/type.hpp b/kernel/kernel/filesystem/type.hpp index 0948e549..ebf43176 100644 --- a/kernel/kernel/filesystem/type.hpp +++ b/kernel/kernel/filesystem/type.hpp @@ -3,7 +3,7 @@ #include <kernel/filesystem/filesystem.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> #include <string_view> diff --git a/kernel/kernel/filesystem/type_registry.cpp b/kernel/kernel/filesystem/type_registry.cpp index 74b12090..6850090a 100644 --- a/kernel/kernel/filesystem/type_registry.cpp +++ b/kernel/kernel/filesystem/type_registry.cpp @@ -2,8 +2,8 @@ #include <kapi/system.hpp> -#include <kstd/memory> -#include <kstd/print> +#include <kstd/memory.hpp> +#include <kstd/print.hpp> #include <algorithm> #include <cstddef> diff --git a/kernel/kernel/filesystem/type_registry.hpp b/kernel/kernel/filesystem/type_registry.hpp index 3be72950..bda2326b 100644 --- a/kernel/kernel/filesystem/type_registry.hpp +++ b/kernel/kernel/filesystem/type_registry.hpp @@ -3,9 +3,9 @@ #include <kernel/filesystem/type.hpp> -#include <kstd/flat_map> -#include <kstd/memory> -#include <kstd/string> +#include <kstd/flat_map.hpp> +#include <kstd/memory.hpp> +#include <kstd/string.hpp> #include <cstddef> #include <span> diff --git a/kernel/kernel/filesystem/type_registry.tests.cpp b/kernel/kernel/filesystem/type_registry.tests.cpp index 8382579f..dbd3cdfd 100644 --- a/kernel/kernel/filesystem/type_registry.tests.cpp +++ b/kernel/kernel/filesystem/type_registry.tests.cpp @@ -3,7 +3,7 @@ #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/type.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/filesystem/vfs.cpp b/kernel/kernel/filesystem/vfs.cpp index e5dff8c4..d128bbf5 100644 --- a/kernel/kernel/filesystem/vfs.cpp +++ b/kernel/kernel/filesystem/vfs.cpp @@ -3,6 +3,7 @@ #include <kernel/filesystem/constants.hpp> #include <kernel/filesystem/dentry.hpp> #include <kernel/filesystem/devfs/filesystem.hpp> +#include <kernel/filesystem/error.hpp> #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/mount.hpp> #include <kernel/filesystem/mount_table.hpp> @@ -11,11 +12,14 @@ #include <kapi/system.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> #include <algorithm> #include <cstdint> +#include <expected> #include <optional> #include <ranges> #include <string_view> @@ -42,26 +46,33 @@ namespace kernel::filesystem { // mount rootfs at / auto root_fs = kstd::make_shared<rootfs::filesystem>(); - root_fs->mount(nullptr); + if (auto result = root_fs->mount(nullptr); !result) + { + kapi::system::panic("[FILESYSTEM] failed to mount root FS", result.error()); + } auto root_fs_root_dentry = kstd::make_shared<dentry>(nullptr, root_fs->root_inode(), "/"); - auto root_mount = kstd::make_shared<mount>(nullptr, root_fs_root_dentry, root_fs, nullptr, nullptr); + auto root_mount = kstd::make_shared<struct mount>(nullptr, root_fs_root_dentry, root_fs, nullptr, nullptr); m_mount_table.add_mount(root_mount); // mount devfs at /dev (inside rootfs, temporary, will be shadowed) auto device_fs = kstd::make_shared<devfs::filesystem>(); - device_fs->mount(nullptr); + if (auto result = device_fs->mount(nullptr); !result) + { + kapi::system::panic("[FILESYSTEM] failed to mount device FS", result.error()); + } graft_persistent_device_fs(device_fs); // mount boot fs at / (shadows rootfs), re-graft devfs - auto [boot_device_dentry, boot_device_mount_context] = resolve_path_internal("/dev/ram0"); + auto [boot_device_dentry, boot_device_mount_context] = + resolve_path_internal("/dev/ram0").value_or(std::pair{nullptr, nullptr}); if (boot_device_dentry && boot_device_mount_context) { if (auto boot_root_fs = kernel::filesystem::filesystem::probe_and_mount(boot_device_dentry->get_inode())) { if (auto root_dentry = resolve_path("/")) { - do_mount_internal(root_dentry, root_mount, boot_root_fs, boot_device_mount_context); + do_mount_internal(*root_dentry, root_mount, *boot_root_fs, boot_device_mount_context); graft_persistent_device_fs(device_fs); } } @@ -78,85 +89,100 @@ namespace kernel::filesystem return *active_vfs; } - auto vfs::open(std::string_view path) -> kstd::shared_ptr<dentry> + auto vfs::open(std::string_view path) -> kstd::result<dentry_ptr> { - auto [dentry, mount] = resolve_path_internal(path); - if (!dentry || !mount) + auto resolved_path = resolve_path_internal(path); + if (!resolved_path) { - return nullptr; + return kstd::failure(resolved_path.error()); } + + auto [dentry, mount] = resolved_path.value(); mount->increment_ref_count(); return dentry; } - auto vfs::close(std::string_view path) -> operation_result + auto vfs::close(std::string_view path) -> kstd::result<void> { if (auto mount = find_mount(path)) { - mount->decrement_ref_count(); - return operation_result::success; + mount.value()->decrement_ref_count(); + return kstd::success(); } - return operation_result::invalid_path; + return kstd::failure(vfs_errc::invalid_path); } - auto vfs::do_mount(std::string_view source, std::string_view target) -> operation_result + auto vfs::mount(std::string_view source, std::string_view target) -> kstd::result<void> { if (!path::is_valid_path(source) || !path::is_valid_path(target)) { - return operation_result::invalid_path; + return kstd::failure(vfs_errc::invalid_path); } - auto [mount_point_dentry, mount_context] = resolve_path_internal(target); - if (mount_point_dentry && mount_context) + auto resolved_target = resolve_path_internal(target); + if (!resolved_target) { - auto [source_dentry, source_mount_context] = resolve_path_internal(source); - if (source_dentry && source_mount_context) - { - if (auto fs = kernel::filesystem::filesystem::probe_and_mount(source_dentry->get_inode())) - { - do_mount_internal(mount_point_dentry, mount_context, fs, source_mount_context); - return operation_result::success; - } - return operation_result::invalid_filesystem; - } - return operation_result::non_existent_path; + return kstd::failure(resolved_target.error()); + } + auto [mount_point_dentry, mount_context] = *resolved_target; + + auto resolved_source = resolve_path_internal(source); + if (!resolved_source) + { + return kstd::failure(resolved_source.error()); + } + auto [source_dentry, source_mount_context] = *resolved_source; + + auto fs = kernel::filesystem::filesystem::probe_and_mount(source_dentry->get_inode()); + if (!fs) + { + return kstd::failure(fs.error()); } - return operation_result::mount_point_not_found; + + do_mount_internal(mount_point_dentry, mount_context, *fs, source_mount_context); + return kstd::success(); } - auto vfs::unmount(std::string_view path) -> operation_result + auto vfs::unmount(std::string_view path) -> kstd::result<void> { if (!path::is_valid_path(path)) { - return operation_result::invalid_path; + return kstd::failure(vfs_errc::invalid_path); } auto remove_result = m_mount_table.remove_mount(path); if (remove_result == mount_table::operation_result::removed) { - return operation_result::success; + return kstd::success(); } else if (remove_result == mount_table::operation_result::mount_not_found) { - return operation_result::mount_point_not_found; + return kstd::failure(vfs_errc::mount_point_not_found); + } + else if (remove_result == mount_table::operation_result::cannot_be_unmounted) + { + return kstd::failure(vfs_errc::mount_busy); + } + else if (remove_result == mount_table::operation_result::has_child_mounts) + { + return kstd::failure(vfs_errc::has_child_mounts); } - return operation_result::unmount_failed; + return kstd::failure(vfs_errc::unmount_failed); } - auto vfs::do_mount_internal(kstd::shared_ptr<dentry> const & mount_point_dentry, - kstd::shared_ptr<mount> const & parent_mount, kstd::shared_ptr<filesystem> const & fs, - kstd::shared_ptr<mount> const & source_mount) -> void + 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 { auto new_fs_root = kstd::make_shared<dentry>(mount_point_dentry->parent(), fs->root_inode(), mount_point_dentry->name()); - auto new_mount = kstd::make_shared<mount>(mount_point_dentry, new_fs_root, fs, parent_mount, source_mount); + auto new_mount = kstd::make_shared<struct mount>(mount_point_dentry, new_fs_root, fs, parent_mount, source_mount); m_mount_table.add_mount(new_mount); } auto vfs::graft_persistent_device_fs(kstd::shared_ptr<devfs::filesystem> const & device_fs) -> void { - auto [root_mount_point_dentry, root_mount] = resolve_path_internal("/"); + auto [root_mount_point_dentry, root_mount] = resolve_path_internal("/").value_or(std::pair{nullptr, nullptr}); if (root_mount_point_dentry && root_mount) { auto dev_dentry = root_mount_point_dentry->find_child("dev"); @@ -170,12 +196,11 @@ namespace kernel::filesystem } } - auto vfs::resolve_path_internal(std::string_view path) const - -> std::pair<kstd::shared_ptr<dentry>, kstd::shared_ptr<mount>> + auto vfs::resolve_path_internal(std::string_view path) const -> kstd::result<std::pair<dentry_ptr, mount_ptr>> { if (!path::is_valid_absolute_path(path)) { - return {nullptr, nullptr}; + return kstd::failure(vfs_errc::invalid_path); } auto current_mount = m_mount_table.find_mount("/"); @@ -197,6 +222,11 @@ namespace kernel::filesystem auto part = path_parts_vector.back(); path_parts_vector.pop_back(); + if (!current_dentry->get_inode()->is_directory()) + { + return kstd::failure(vfs_errc::not_a_directory); + } + if (part == ".") { continue; @@ -231,10 +261,10 @@ namespace kernel::filesystem auto found_inode = current_fs->lookup(current_dentry->get_inode(), part); if (!found_inode) { - return {nullptr, nullptr}; + return kstd::failure(found_inode.error()); } - next_dentry = kstd::make_shared<dentry>(current_dentry, found_inode, part); + 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)) @@ -252,12 +282,17 @@ namespace kernel::filesystem { if (symlink_counter++ > constants::symloop_max) { - return {nullptr, nullptr}; + return kstd::failure(vfs_errc::too_many_symbolic_link_levels); } 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}; + if (!bytes_read) + { + return kstd::failure(bytes_read.error()); + } + + 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()); @@ -275,17 +310,17 @@ namespace kernel::filesystem current_dentry = next_dentry; } - return {current_dentry, current_mount}; + return std::pair{current_dentry, current_mount}; } - auto vfs::resolve_path(std::string_view path) const -> kstd::shared_ptr<dentry> + auto vfs::resolve_path(std::string_view path) const -> kstd::result<dentry_ptr> { - return resolve_path_internal(path).first; + return resolve_path_internal(path).transform([](auto result) { return result.first; }); } - auto vfs::find_mount(std::string_view path) const -> kstd::shared_ptr<mount> + auto vfs::find_mount(std::string_view path) const -> kstd::result<mount_ptr> { - return resolve_path_internal(path).second; + return resolve_path_internal(path).transform([](auto result) { return result.second; }); } } // namespace kernel::filesystem diff --git a/kernel/kernel/filesystem/vfs.hpp b/kernel/kernel/filesystem/vfs.hpp index ddc9a9bc..9dfd3637 100644 --- a/kernel/kernel/filesystem/vfs.hpp +++ b/kernel/kernel/filesystem/vfs.hpp @@ -7,7 +7,9 @@ #include <kernel/filesystem/mount.hpp> #include <kernel/filesystem/mount_table.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> +#include <kstd/result.hpp> +#include <kstd/system_error.hpp> #include <string_view> #include <utility> @@ -17,23 +19,14 @@ namespace kernel::filesystem /** @brief The virtual filesystem (VFS) is responsible for managing mounted filesystems and providing a unified interface for file operations across different filesystem types. The VFS maintains a mount table to keep track of mounted - filesystems and their associated mount points. It provides methods for opening files by path, which involvesresolving + filesystems and their associated mount points. It provides methods for opening files by path, which involves resolving the path to the appropriate mounted filesystem and delegating the file operation to that filesystem's implementation. */ struct vfs { - /** - @brief Results for VFS operations. - */ - enum class operation_result : int - { - success = 0, - invalid_path = -1, - non_existent_path = -2, - mount_point_not_found = -3, - unmount_failed = -4, - invalid_filesystem = -5 - }; + using dentry_ptr = kstd::shared_ptr<dentry>; + using mount_ptr = kstd::shared_ptr<struct mount>; + using fs_ptr = kstd::shared_ptr<filesystem>; vfs(); @@ -58,31 +51,31 @@ namespace kernel::filesystem /** @brief Open a file by its @p path. This method resolves the path and returns the corresponding dentry. @param path The path to the file to open. - @return A shared pointer to the dentry or a null pointer if the file could not be opened. + @return A shared pointer to the dentry on success or an error code on failure. */ - auto open(std::string_view path) -> kstd::shared_ptr<dentry>; + auto open(std::string_view path) -> kstd::result<dentry_ptr>; /** @brief Close a file by its associated @p path. @param path The path to the file to close. - @return The result of the close operation. + @return Nothing on success or an error code on failure. */ - auto close(std::string_view path) -> operation_result; + auto close(std::string_view path) -> kstd::result<void>; /** @brief Mount a @p source path to a specific @p target path. @param source The source of the filesystem to mount. @param target The path where the filesystem should be mounted. - @return The result of the mount operation. + @return Nothing on success or an error code on failure. */ - auto do_mount(std::string_view source, std::string_view target) -> operation_result; + auto mount(std::string_view source, std::string_view target) -> kstd::result<void>; /** @brief Unmount the filesystem mounted at the specified @p path. @param path The path where the filesystem is mounted. - @return The result of the unmount operation. + @return Nothing on success or an error code on failure. */ - auto unmount(std::string_view path) -> operation_result; + auto unmount(std::string_view path) -> kstd::result<void>; private: /** @@ -96,13 +89,14 @@ namespace kernel::filesystem * - find_mount() for the mount context only. */ [[nodiscard]] auto resolve_path_internal(std::string_view path) const - -> std::pair<kstd::shared_ptr<dentry>, kstd::shared_ptr<mount>>; - [[nodiscard]] auto resolve_path(std::string_view path) const -> kstd::shared_ptr<dentry>; - [[nodiscard]] auto find_mount(std::string_view path) const -> kstd::shared_ptr<mount>; + -> kstd::result<std::pair<dentry_ptr, mount_ptr>>; + + [[nodiscard]] auto resolve_path(std::string_view path) const -> kstd::result<dentry_ptr>; + + [[nodiscard]] auto find_mount(std::string_view path) const -> kstd::result<mount_ptr>; - auto do_mount_internal(kstd::shared_ptr<dentry> const & mount_point_dentry, - kstd::shared_ptr<mount> const & parent_mount, kstd::shared_ptr<filesystem> const & fs, - kstd::shared_ptr<mount> const & source_mount = nullptr) -> void; + auto do_mount_internal(dentry_ptr const & mount_point_dentry, mount_ptr const & parent_mount, fs_ptr const & fs, + mount_ptr const & source_mount = nullptr) -> void; auto graft_persistent_device_fs(kstd::shared_ptr<devfs::filesystem> const & device_fs) -> void; diff --git a/kernel/kernel/filesystem/vfs.tests.cpp b/kernel/kernel/filesystem/vfs.tests.cpp index f1d0df0d..c99cea90 100644 --- a/kernel/kernel/filesystem/vfs.tests.cpp +++ b/kernel/kernel/filesystem/vfs.tests.cpp @@ -1,10 +1,12 @@ #include <kernel/filesystem/vfs.hpp> +#include <kernel/filesystem/error.hpp> #include <kernel/filesystem/open_file_descriptor.hpp> #include <kernel/test_support/filesystem/storage_boot_module_vfs_fixture.hpp> -#include <kstd/memory> -#include <kstd/vector> +#include <kstd/memory.hpp> +#include <kstd/system_error.hpp> +#include <kstd/vector.hpp> #include <catch2/catch_test_macros.hpp> @@ -73,7 +75,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS auto & vfs = kernel::filesystem::vfs::get(); auto image_1 = vfs.open("/dev/image_1.txt"); - REQUIRE(image_1 == nullptr); + REQUIRE(image_1.error() == kstd::errc::no_such_file_or_directory); auto dev = vfs.open("/dev/ram0"); REQUIRE(dev != nullptr); @@ -102,15 +104,15 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS THEN("second image can be mounted, data retrieved and unmounted again") { - REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram16", "/information")); 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()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(mounted_monkey_1); + REQUIRE(vfs.close(mounted_monkey_1.value()->absolute_path())); - REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/information")); auto unmounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt"); - REQUIRE(unmounted_monkey_1 == nullptr); + REQUIRE(unmounted_monkey_1.error() == kstd::errc::no_such_file_or_directory); auto info_1 = vfs.open("/information/info_1.txt"); REQUIRE(info_1 != nullptr); @@ -118,70 +120,68 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS THEN("third image can be mounted in a mounted file system, unmount only if no child mount exists") { - REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.do_mount("/dev/ram32", "/information/monkey_house/infrastructure") == - kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram16", "/information")); + REQUIRE(vfs.mount("/dev/ram32", "/information/monkey_house/infrastructure")); auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt"); auto mounted_fish1 = vfs.open("/information/monkey_house/infrastructure/enclosures/aquarium/tank_1/fish_1.txt"); - REQUIRE(mounted_monkey_1 != nullptr); - REQUIRE(mounted_fish1 != nullptr); + REQUIRE(mounted_monkey_1); + REQUIRE(mounted_fish1); - 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.close(mounted_monkey_1.value()->absolute_path())); + REQUIRE(vfs.close(mounted_fish1.value()->absolute_path())); - REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed); - REQUIRE(vfs.unmount("/information/monkey_house/infrastructure") == - kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(!vfs.unmount("/information")); + REQUIRE(vfs.unmount("/information/monkey_house/infrastructure")); + REQUIRE(vfs.unmount("/information")); } THEN("image can be mounted, unmount only if no files are open") { - REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram16", "/information")); auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt"); - REQUIRE(mounted_monkey_1 != nullptr); + REQUIRE(mounted_monkey_1); - REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed); + REQUIRE(!vfs.unmount("/information")); - REQUIRE(vfs.close(mounted_monkey_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(mounted_monkey_1.value()->absolute_path())); - REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/information")); } THEN("file with invalid path or not opened file cannot be closed") { - REQUIRE(vfs.close("invalid_path") == kernel::filesystem::vfs::operation_result::invalid_path); + REQUIRE(!vfs.close("invalid_path")); REQUIRE_THROWS_AS(vfs.close("/information/info_1.txt"), std::runtime_error); } THEN("file cannot be closed twice") { auto info_1 = vfs.open("/information/info_1.txt"); - REQUIRE(info_1 != nullptr); + REQUIRE(info_1); - 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); + REQUIRE(vfs.close(info_1.value()->absolute_path())); + REQUIRE_THROWS_AS(vfs.close(info_1.value()->absolute_path()), std::runtime_error); } THEN("images can be stacked mounted and correct file system is unmounted again") { - REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.do_mount("/dev/ram32", "/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram16", "/information")); + REQUIRE(vfs.mount("/dev/ram32", "/information")); auto mounted_tickets = vfs.open("/information/entrance/tickets.txt"); - REQUIRE(mounted_tickets != nullptr); + REQUIRE(mounted_tickets); - REQUIRE(vfs.close(mounted_tickets->absolute_path()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(mounted_tickets.value()->absolute_path())); - REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/information")); mounted_tickets = vfs.open("/information/entrance/tickets.txt"); - REQUIRE(mounted_tickets == nullptr); + REQUIRE(mounted_tickets.error() == kstd::errc::no_such_file_or_directory); auto mounted_monkey = vfs.open("/information/monkey_house/monkey_1.txt"); - REQUIRE(mounted_monkey != nullptr); + REQUIRE(mounted_monkey); } THEN("image can be mounted on / file opened and unmounted again") @@ -189,17 +189,17 @@ 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.do_mount("/dev/ram16", "/") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram16", "/")); info_1 = vfs.open("/information/info_1.txt"); - REQUIRE(info_1 == nullptr); + REQUIRE(info_1.error() == kstd::errc::no_such_file_or_directory); auto water = vfs.open("/monkey_house/infrastructure/water.txt"); REQUIRE(water != nullptr); - REQUIRE(vfs.close(water->absolute_path()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(water.value()->absolute_path())); - REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/")); info_1 = vfs.open("/information/info_1.txt"); REQUIRE(info_1 != nullptr); @@ -210,22 +210,22 @@ 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.do_mount("/dev/ram16", "/") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram16", "/")); info_1 = vfs.open("/information/info_1.txt"); - REQUIRE(info_1 == nullptr); + REQUIRE(info_1.error() == kstd::errc::no_such_file_or_directory); auto water = vfs.open("/monkey_house/infrastructure/water.txt"); REQUIRE(water != nullptr); - REQUIRE(vfs.close(water->absolute_path()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(water.value()->absolute_path())); auto dev_ram_16 = vfs.open("/dev/ram16"); - REQUIRE(dev_ram_16 == nullptr); + REQUIRE(dev_ram_16.error() == kstd::errc::no_such_file_or_directory); - REQUIRE(vfs.do_mount("/dev/ram32", "/") == kernel::filesystem::vfs::operation_result::non_existent_path); + REQUIRE(vfs.mount("/dev/ram32", "/").error() == kstd::errc::no_such_file_or_directory); - REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/")); auto dev_ram_32 = vfs.open("/dev/ram32"); REQUIRE(dev_ram_32 != nullptr); @@ -236,58 +236,53 @@ 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()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(info_1.value()->absolute_path())); - REQUIRE(vfs.unmount("/dev") == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.unmount("/") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/dev")); + REQUIRE(vfs.unmount("/")); info_1 = vfs.open("/information/info_1.txt"); - REQUIRE(info_1 == nullptr); + REQUIRE(info_1.error() == kstd::errc::no_such_file_or_directory); - REQUIRE(vfs.do_mount("/dev/ram0", "/") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram0", "/")); info_1 = vfs.open("/information/info_1.txt"); REQUIRE(info_1 != nullptr); auto dev_ram_0 = vfs.open("/dev/ram0"); - REQUIRE(dev_ram_0 == nullptr); + REQUIRE(dev_ram_0.error() == kstd::errc::no_such_file_or_directory); } THEN("mount with null file system fails") { - REQUIRE(vfs.do_mount("/closed.txt", "/information") == - kernel::filesystem::vfs::operation_result::invalid_filesystem); + REQUIRE(vfs.mount("/closed.txt", "/information").error() == kstd::errc::not_supported); } THEN("mount with invalid path fails") { - REQUIRE(vfs.do_mount("/dev/ram16", "") == kernel::filesystem::vfs::operation_result::invalid_path); - REQUIRE(vfs.do_mount("/dev/ram16", "information") == - kernel::filesystem::vfs::operation_result::mount_point_not_found); + REQUIRE(vfs.mount("/dev/ram16", "").error() == kstd::errc::invalid_argument); + REQUIRE(vfs.mount("/dev/ram16", "information").error() == kstd::errc::invalid_argument); } THEN("mount with non-existent source path fails") { - REQUIRE(vfs.do_mount("/dev/nonexistent", "/information") == - kernel::filesystem::vfs::operation_result::non_existent_path); + REQUIRE(vfs.mount("/dev/nonexistent", "/information").error() == kstd::errc::no_such_file_or_directory); } THEN("mount with non-existent mount point fails") { - REQUIRE(vfs.do_mount("/dev/ram16", "/information/nonexistent") == - kernel::filesystem::vfs::operation_result::mount_point_not_found); + REQUIRE(vfs.mount("/dev/ram16", "/information/nonexistent").error() == kstd::errc::no_such_file_or_directory); } THEN("unmount with invalid path fails") { - REQUIRE(vfs.unmount("") == kernel::filesystem::vfs::operation_result::invalid_path); - REQUIRE(vfs.unmount("information") == kernel::filesystem::vfs::operation_result::mount_point_not_found); + REQUIRE(vfs.unmount("").error() == kstd::errc::invalid_argument); + REQUIRE(vfs.unmount("information").error() == kstd::errc::no_such_file_or_directory); } THEN("unmounting non-existent mount point returns expected error code") { - REQUIRE(vfs.unmount("/information/nonexistent") == - kernel::filesystem::vfs::operation_result::mount_point_not_found); + REQUIRE(vfs.unmount("/information/nonexistent").error() == kstd::errc::no_such_file_or_directory); } THEN("a file can be access if . in the path") @@ -307,7 +302,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS THEN("a file can be accessed over multiple mounts if path contains .. or . ") { - REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram16", "/information")); auto img = vfs.open("/information/monkey_house/caretaker/../../../../../../archiv/2024.img"); REQUIRE(img != nullptr); @@ -321,9 +316,8 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS THEN("a file can be accessed over multiple mounts (device and file) if path contains .. ") { - REQUIRE(vfs.do_mount("/dev/ram16", "/information") == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.do_mount("/archiv/2024.img", "/information/monkey_house/infrastructure") == - kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram16", "/information")); + REQUIRE(vfs.mount("/archiv/2024.img", "/information/monkey_house/infrastructure")); auto pig_1 = vfs.open("/information/monkey_house/infrastructure/stable/pig_1.txt"); REQUIRE(pig_1 != nullptr); @@ -345,70 +339,69 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS THEN("the file-filesystem in the image can be mounted, files can be read and unmounted again") { auto & vfs = kernel::filesystem::vfs::get(); - REQUIRE(vfs.do_mount("/archiv/2024.img", "/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/archiv/2024.img", "/information")); auto info_1 = vfs.open("/information/info_1.txt"); - REQUIRE(info_1 == nullptr); + REQUIRE(info_1.error() == kstd::errc::no_such_file_or_directory); auto dentry = vfs.open("/information/sheep_1.txt"); REQUIRE(dentry != nullptr); - auto sheep_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry); + auto sheep_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(dentry.value()); kstd::vector<std::byte> buffer(7); auto bytes_read = sheep_1_ofd->read(buffer.data(), buffer.size()); - std::string_view buffer_as_str{reinterpret_cast<char *>(buffer.data()), bytes_read}; + 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()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(dentry.value()->absolute_path())); - REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/information")); auto unmounted_sheep_1 = vfs.open("/information/sheep_1.txt"); - REQUIRE(unmounted_sheep_1 == nullptr); + REQUIRE(unmounted_sheep_1.error() == kstd::errc::no_such_file_or_directory); } THEN("the file-filesystem in the image can be mounted and in this filesystem can another file-filesystem be " "mounted, files can be read and unmounted again") { auto & vfs = kernel::filesystem::vfs::get(); - REQUIRE(vfs.do_mount("/archiv/2024.img", "/information") == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.do_mount("/archiv/2025.img", "/information/stable") == - kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/archiv/2024.img", "/information")); + REQUIRE(vfs.mount("/archiv/2025.img", "/information/stable")); auto sheep_1 = vfs.open("/information/sheep_1.txt"); auto goat_1 = vfs.open("/information/stable/petting_zoo/goat_1.txt"); REQUIRE(sheep_1 != nullptr); REQUIRE(goat_1 != nullptr); - auto sheep_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(sheep_1); - auto goat_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(goat_1); + auto sheep_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(sheep_1.value()); + auto goat_1_ofd = kstd::make_shared<kernel::filesystem::open_file_descriptor>(goat_1.value()); kstd::vector<std::byte> sheep_buffer(7); auto bytes_read = sheep_1_ofd->read(sheep_buffer.data(), sheep_buffer.size()); - std::string_view buffer_as_str{reinterpret_cast<char *>(sheep_buffer.data()), bytes_read}; + std::string_view buffer_as_str{reinterpret_cast<char *>(sheep_buffer.data()), *bytes_read}; REQUIRE(buffer_as_str == "sheep_1"); kstd::vector<std::byte> goat_buffer(6); bytes_read = goat_1_ofd->read(goat_buffer.data(), goat_buffer.size()); - buffer_as_str = std::string_view{reinterpret_cast<char *>(goat_buffer.data()), bytes_read}; + 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()) == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.close(goat_1->absolute_path()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(sheep_1.value()->absolute_path())); + REQUIRE(vfs.close(goat_1.value()->absolute_path())); - REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed); + REQUIRE(vfs.unmount("/information").error() == kstd::errc::device_or_resource_busy); - REQUIRE(vfs.unmount("/information/stable") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/information/stable")); auto unmounted_goat_1 = vfs.open("/information/stable/petting_zoo/goat_1.txt"); - REQUIRE(unmounted_goat_1 == nullptr); + REQUIRE(unmounted_goat_1.error() == kstd::errc::no_such_file_or_directory); 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()) == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.close(still_mounted_sheep_1.value()->absolute_path())); - REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/information")); auto unmounted_sheep_1 = vfs.open("/information/sheep_1.txt"); - REQUIRE(unmounted_sheep_1 == nullptr); + REQUIRE(unmounted_sheep_1.error() == kstd::errc::no_such_file_or_directory); } } @@ -423,23 +416,21 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS THEN("cannot unmount a filesystem if files are mounted") { - REQUIRE(vfs.do_mount("/dev/ram16", "/entrance") == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.do_mount("/entrance/archiv/2024.img", "/enclosures") == - kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram16", "/entrance")); + REQUIRE(vfs.mount("/entrance/archiv/2024.img", "/enclosures")); - REQUIRE(vfs.unmount("/entrance") == kernel::filesystem::vfs::operation_result::unmount_failed); - REQUIRE(vfs.unmount("/enclosures") == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.unmount("/entrance") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/entrance").error() == kstd::errc::device_or_resource_busy); + REQUIRE(vfs.unmount("/enclosures")); + REQUIRE(vfs.unmount("/entrance")); } THEN("can mount filesystem onto the directory that contains it") { - REQUIRE(vfs.do_mount("/dev/ram16", "/entrance") == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.do_mount("/entrance/archiv/2024.img", "/entrance") == - kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.mount("/dev/ram16", "/entrance")); + REQUIRE(vfs.mount("/entrance/archiv/2024.img", "/entrance")); - REQUIRE(vfs.unmount("/entrance") == kernel::filesystem::vfs::operation_result::success); - REQUIRE(vfs.unmount("/entrance") == kernel::filesystem::vfs::operation_result::success); + REQUIRE(vfs.unmount("/entrance")); + REQUIRE(vfs.unmount("/entrance")); } } @@ -487,21 +478,21 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS { auto & vfs = kernel::filesystem::vfs::get(); auto invalid_symlink = vfs.open("/symlinks/invalid_absolute"); - REQUIRE(invalid_symlink == nullptr); + REQUIRE(invalid_symlink.error() == kstd::errc::no_such_file_or_directory); } THEN("symbolic link containing an invalid relative path is handled correctly") { auto & vfs = kernel::filesystem::vfs::get(); auto invalid_symlink = vfs.open("/symlinks/invalid_relative"); - REQUIRE(invalid_symlink == nullptr); + REQUIRE(invalid_symlink.error() == kstd::errc::no_such_file_or_directory); } THEN("circular symbolic links are detected and handled correctly") { auto & vfs = kernel::filesystem::vfs::get(); auto circular_symlink = vfs.open("/symlinks/symloop_a"); - REQUIRE(circular_symlink == nullptr); + REQUIRE(circular_symlink.error() == kstd::errc::too_many_symbolic_link_levels); } } @@ -511,7 +502,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_1"}, {image_path_1})); auto & vfs = kernel::filesystem::vfs::get(); - vfs.do_mount("/archiv/2024.img", "/information"); + REQUIRE(vfs.mount("/archiv/2024.img", "/information")); THEN("file can be opened through symbolic link pointing to the parent filesystem") { @@ -528,7 +519,7 @@ SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS setup_modules_from_img_and_init_vfs({"test_img_module_1", "test_img_module_2"}, {image_path_1, image_path_2})); auto & vfs = kernel::filesystem::vfs::get(); - vfs.do_mount("/dev/ram16", "/information"); + REQUIRE(vfs.mount("/dev/ram16", "/information")); THEN("file can be opened through symbolic link pointing to the parent filesystem and back into the mounted " "filesystem again") diff --git a/kernel/kernel/main.cpp b/kernel/kernel/main.cpp index 8dc13490..8dce5143 100644 --- a/kernel/kernel/main.cpp +++ b/kernel/kernel/main.cpp @@ -13,10 +13,11 @@ #include <kapi/memory.hpp> #include <kapi/system.hpp> -#include <kstd/format> -#include <kstd/print> -#include <kstd/units> -#include <kstd/vector> +#include <kstd/format.hpp> +#include <kstd/print.hpp> +#include <kstd/system_error.hpp> +#include <kstd/units.hpp> +#include <kstd/vector.hpp> #include <cstddef> #include <string_view> @@ -28,33 +29,33 @@ auto run_demo() -> void // 1) open a file kstd::println("attempting to open /entrance/tickets.txt"); auto fd_1 = kapi::filesystem::open("/entrance/tickets.txt"); - if (fd_1 == -1) + if (!fd_1) { kapi::system::panic("demo failed"); } else { - kstd::println("--> successfully opened /entrance/tickets.txt with file descriptor {}", fd_1); + kstd::println("--> successfully opened /entrance/tickets.txt with file descriptor {}", fd_1.value()); } // 2) read from the file kstd::vector<std::byte> buffer_1{10}; - auto bytes_read = kapi::filesystem::read(fd_1, buffer_1.data(), buffer_1.size()); - auto buffer_as_str = std::string_view{reinterpret_cast<char *>(buffer_1.data()), static_cast<size_t>(bytes_read)}; + auto bytes_read = *kapi::filesystem::read(fd_1.value(), buffer_1.data(), buffer_1.size()); + auto buffer_as_str = std::string_view{reinterpret_cast<char *>(buffer_1.data()), bytes_read}; kstd::println("--> read {} bytes from /entrance/tickets.txt: {}", bytes_read, buffer_as_str); kstd::println(""); // 3) show that /entrance/information/info_1.txt is not accessible before mounting kstd::println("attempting to open /entrance/information/info_1.txt before mounting"); auto fd_before_mount = kapi::filesystem::open("/entrance/information/info_1.txt"); - if (fd_before_mount == -1) + if (!fd_before_mount && fd_before_mount.error() == kstd::errc::no_such_file_or_directory) { kstd::println("--> as expected the file could not be opened before mounting"); } // 4) mount a new filesystem on top of /entrance kstd::println("mount /dev/ram16 to /entrance"); - if (kapi::filesystem::mount("/dev/ram16", "/entrance") == 0) + if (kapi::filesystem::mount("/dev/ram16", "/entrance")) { kstd::println("--> successfully mounted /dev/ram16 to /entrance"); } @@ -67,9 +68,9 @@ auto run_demo() -> void // 5) open a file from the new filesystem kstd::println("attempting to open /entrance/information/info_1.txt"); auto fd_2 = kapi::filesystem::open("/entrance/information/info_1.txt"); - if (fd_2 != -1) + if (fd_2) { - kstd::println("--> successfully opened /entrance/information/info_1.txt with file descriptor {}", fd_2); + kstd::println("--> successfully opened /entrance/information/info_1.txt with file descriptor {}", fd_2.value()); } else { @@ -78,16 +79,16 @@ auto run_demo() -> void // 6) read from the new file kstd::vector<std::byte> buffer_2{10}; - bytes_read = kapi::filesystem::read(fd_2, buffer_2.data(), buffer_2.size()); + bytes_read = *kapi::filesystem::read(fd_2.value(), buffer_2.data(), buffer_2.size()); buffer_as_str = std::string_view{reinterpret_cast<char *>(buffer_2.data()), static_cast<size_t>(bytes_read)}; kstd::println("--> read {} bytes from /entrance/information/info_1.txt: {} ", bytes_read, buffer_as_str); // 7) open device as file kstd::println("attempting to open /dev/ram32 as a file"); auto fd_3 = kapi::filesystem::open("/dev/ram32"); - if (fd_3 != -1) + if (fd_3) { - kstd::println("--> successfully opened /dev/ram32 as a file with file descriptor {}", fd_3); + kstd::println("--> successfully opened /dev/ram32 as a file with file descriptor {}", fd_3.value()); } else { @@ -96,13 +97,13 @@ auto run_demo() -> void // 8) read from the device file kstd::vector<std::byte> buffer_3{2}; - bytes_read = kapi::filesystem::read(fd_3, buffer_3.data(), buffer_3.size()); + bytes_read = *kapi::filesystem::read(fd_3.value(), buffer_3.data(), buffer_3.size()); kstd::println("--> read {} bytes from /dev/ram32: {::#04x} ", bytes_read, buffer_3); // 9) write to the device file auto const default_buffer_value = std::byte{0xAA}; kstd::vector<std::byte> write_buffer{default_buffer_value, default_buffer_value}; - auto bytes_written = kapi::filesystem::write(fd_3, write_buffer.data(), write_buffer.size()); + auto bytes_written = *kapi::filesystem::write(fd_3.value(), write_buffer.data(), write_buffer.size()); kstd::println("--> written {} bytes to /dev/ram32: {::#04x}", bytes_written, write_buffer); // 10) do memory dump to show that the write to the device file had an effect @@ -146,7 +147,7 @@ auto main() -> int kstd::println("[OS] Virtual filesystem initialized."); // TODO BA-FS26 remove demo code? - // run_demo(); + run_demo(); kapi::system::panic("Returning from kernel main!"); } diff --git a/kernel/kernel/memory.cpp b/kernel/kernel/memory.cpp index 6a85c0e7..663137eb 100644 --- a/kernel/kernel/memory.cpp +++ b/kernel/kernel/memory.cpp @@ -6,8 +6,8 @@ #include <kapi/memory.hpp> #include <kapi/system.hpp> -#include <kstd/print> -#include <kstd/units> +#include <kstd/print.hpp> +#include <kstd/units.hpp> #include <atomic> #include <optional> diff --git a/kernel/kernel/memory/block_list_allocator.cpp b/kernel/kernel/memory/block_list_allocator.cpp index 6e68ada7..a682051f 100644 --- a/kernel/kernel/memory/block_list_allocator.cpp +++ b/kernel/kernel/memory/block_list_allocator.cpp @@ -5,8 +5,8 @@ #include <kapi/memory.hpp> #include <kapi/system.hpp> -#include <kstd/mutex> -#include <kstd/units> +#include <kstd/mutex.hpp> +#include <kstd/units.hpp> #include <bit> #include <cstddef> diff --git a/kernel/kernel/memory/block_list_allocator.hpp b/kernel/kernel/memory/block_list_allocator.hpp index 51b226ee..ac6257c0 100644 --- a/kernel/kernel/memory/block_list_allocator.hpp +++ b/kernel/kernel/memory/block_list_allocator.hpp @@ -5,8 +5,8 @@ #include <kapi/memory.hpp> -#include <kstd/mutex> -#include <kstd/units> +#include <kstd/mutex.hpp> +#include <kstd/units.hpp> #include <cstddef> #include <new> diff --git a/kernel/kernel/memory/block_list_allocator.tests.cpp b/kernel/kernel/memory/block_list_allocator.tests.cpp index c5f84c52..6efcd31a 100644 --- a/kernel/kernel/memory/block_list_allocator.tests.cpp +++ b/kernel/kernel/memory/block_list_allocator.tests.cpp @@ -4,7 +4,7 @@ #include <kapi/memory.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/kernel/kernel/memory/heap_allocator.hpp b/kernel/kernel/memory/heap_allocator.hpp index fd39bef8..59fa98b0 100644 --- a/kernel/kernel/memory/heap_allocator.hpp +++ b/kernel/kernel/memory/heap_allocator.hpp @@ -1,7 +1,7 @@ #ifndef TEACHOS_KERNEL_MEMORY_HEAP_ALLOCATOR_HPP #define TEACHOS_KERNEL_MEMORY_HEAP_ALLOCATOR_HPP -#include <kstd/units> +#include <kstd/units.hpp> namespace kernel::memory { diff --git a/kernel/kernel/memory/mmio_allocator.cpp b/kernel/kernel/memory/mmio_allocator.cpp index ba23dbde..17f436f8 100644 --- a/kernel/kernel/memory/mmio_allocator.cpp +++ b/kernel/kernel/memory/mmio_allocator.cpp @@ -3,7 +3,7 @@ #include <kapi/memory.hpp> #include <kapi/system.hpp> -#include <kstd/allocator> +#include <kstd/allocator.hpp> #include <cstddef> #include <memory> diff --git a/kernel/kernel/memory/mmio_allocator.hpp b/kernel/kernel/memory/mmio_allocator.hpp index c7a8ed0c..862188fa 100644 --- a/kernel/kernel/memory/mmio_allocator.hpp +++ b/kernel/kernel/memory/mmio_allocator.hpp @@ -3,8 +3,8 @@ #include <kapi/memory.hpp> -#include <kstd/allocator> -#include <kstd/memory> +#include <kstd/allocator.hpp> +#include <kstd/memory.hpp> #include <cstddef> diff --git a/kernel/kernel/memory/operators.cpp b/kernel/kernel/memory/operators.cpp index 5673d680..5de5101d 100644 --- a/kernel/kernel/memory/operators.cpp +++ b/kernel/kernel/memory/operators.cpp @@ -2,7 +2,7 @@ #include <kapi/system.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <cstddef> #include <new> diff --git a/kernel/kernel/test_support/devices/block_device.cpp b/kernel/kernel/test_support/devices/block_device.cpp index 9a9e544d..2dda5dec 100644 --- a/kernel/kernel/test_support/devices/block_device.cpp +++ b/kernel/kernel/test_support/devices/block_device.cpp @@ -2,8 +2,8 @@ #include <kernel/devices/block_device.hpp> -#include <kstd/string> -#include <kstd/vector> +#include <kstd/string.hpp> +#include <kstd/vector.hpp> #include <algorithm> #include <cstddef> diff --git a/kernel/kernel/test_support/devices/block_device.hpp b/kernel/kernel/test_support/devices/block_device.hpp index 89a2bf15..d83dddd1 100644 --- a/kernel/kernel/test_support/devices/block_device.hpp +++ b/kernel/kernel/test_support/devices/block_device.hpp @@ -3,8 +3,8 @@ #include <kernel/devices/block_device.hpp> -#include <kstd/string> -#include <kstd/vector> +#include <kstd/string.hpp> +#include <kstd/vector.hpp> #include <cstddef> #include <cstdint> diff --git a/kernel/kernel/test_support/devices/character_device.cpp b/kernel/kernel/test_support/devices/character_device.cpp index 3806654f..fef5baf5 100644 --- a/kernel/kernel/test_support/devices/character_device.cpp +++ b/kernel/kernel/test_support/devices/character_device.cpp @@ -2,7 +2,7 @@ #include <kapi/devices.hpp> -#include <kstd/string> +#include <kstd/string.hpp> #include <cstddef> diff --git a/kernel/kernel/test_support/devices/character_device.hpp b/kernel/kernel/test_support/devices/character_device.hpp index aba183a1..5790a561 100644 --- a/kernel/kernel/test_support/devices/character_device.hpp +++ b/kernel/kernel/test_support/devices/character_device.hpp @@ -3,8 +3,8 @@ #include <kapi/devices/device.hpp> -#include <kstd/string> -#include <kstd/vector> +#include <kstd/string.hpp> +#include <kstd/vector.hpp> #include <cstddef> diff --git a/kernel/kernel/test_support/filesystem/filesystem.cpp b/kernel/kernel/test_support/filesystem/filesystem.cpp index ec706077..38cea2f1 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.cpp +++ b/kernel/kernel/test_support/filesystem/filesystem.cpp @@ -3,14 +3,16 @@ #include <kernel/filesystem/inode.hpp> #include <kernel/test_support/filesystem/inode.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> +#include <kstd/system_error.hpp> +#include <expected> #include <string_view> namespace kernel::tests::filesystem { auto filesystem::lookup(kstd::shared_ptr<kernel::filesystem::inode> const &, std::string_view) const - -> kstd::shared_ptr<kernel::filesystem::inode> + -> std::expected<kstd::shared_ptr<kernel::filesystem::inode>, kstd::error_code> { return kstd::make_shared<inode>(); } diff --git a/kernel/kernel/test_support/filesystem/filesystem.hpp b/kernel/kernel/test_support/filesystem/filesystem.hpp index 5f260220..e6e0f416 100644 --- a/kernel/kernel/test_support/filesystem/filesystem.hpp +++ b/kernel/kernel/test_support/filesystem/filesystem.hpp @@ -4,8 +4,10 @@ #include <kernel/filesystem/filesystem.hpp> #include <kernel/filesystem/inode.hpp> -#include <kstd/memory> +#include <kstd/memory.hpp> +#include <kstd/system_error.hpp> +#include <expected> #include <string_view> namespace kernel::tests::filesystem @@ -15,7 +17,7 @@ namespace kernel::tests::filesystem filesystem() = default; [[nodiscard]] auto lookup(kstd::shared_ptr<kernel::filesystem::inode> const & parent, std::string_view name) const - -> kstd::shared_ptr<kernel::filesystem::inode> override; + -> std::expected<kstd::shared_ptr<kernel::filesystem::inode>, kstd::error_code> override; }; } // namespace kernel::tests::filesystem diff --git a/kernel/kernel/test_support/filesystem/inode.cpp b/kernel/kernel/test_support/filesystem/inode.cpp index 0c8d9563..fd8e4d69 100644 --- a/kernel/kernel/test_support/filesystem/inode.cpp +++ b/kernel/kernel/test_support/filesystem/inode.cpp @@ -2,16 +2,18 @@ #include <kernel/filesystem/inode.hpp> +#include <kstd/result.hpp> + #include <cstddef> namespace kernel::tests::filesystem { - auto inode::read(void *, size_t, size_t size) const -> size_t + auto inode::read(void *, size_t, size_t size) const -> kstd::result<size_t> { return size; } - auto inode::write(void const *, size_t, size_t size) -> size_t + auto inode::write(void const *, size_t, size_t size) -> kstd::result<size_t> { return size; } diff --git a/kernel/kernel/test_support/filesystem/inode.hpp b/kernel/kernel/test_support/filesystem/inode.hpp index 8a764375..da2e3e21 100644 --- a/kernel/kernel/test_support/filesystem/inode.hpp +++ b/kernel/kernel/test_support/filesystem/inode.hpp @@ -3,14 +3,16 @@ #include <kernel/filesystem/inode.hpp> +#include <kstd/result.hpp> + #include <cstddef> namespace kernel::tests::filesystem { struct inode : kernel::filesystem::inode { - auto read(void * buffer, size_t offset, size_t size) const -> size_t override; - auto write(void const * buffer, size_t offset, size_t size) -> size_t override; + auto read(void * buffer, size_t offset, size_t size) const -> kstd::result<size_t> override; + auto write(void const * buffer, size_t offset, size_t size) -> kstd::result<size_t> override; [[nodiscard]] auto is_regular() const -> bool override; }; diff --git a/kernel/kernel/test_support/kapi/memory.cpp b/kernel/kernel/test_support/kapi/memory.cpp index 7fc95cb0..33b725bd 100644 --- a/kernel/kernel/test_support/kapi/memory.cpp +++ b/kernel/kernel/test_support/kapi/memory.cpp @@ -5,7 +5,7 @@ #include <kapi/memory.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <optional> diff --git a/kernel/kernel/test_support/page_mapper.cpp b/kernel/kernel/test_support/page_mapper.cpp index 3d50ff1a..b1a6f92b 100644 --- a/kernel/kernel/test_support/page_mapper.cpp +++ b/kernel/kernel/test_support/page_mapper.cpp @@ -2,7 +2,7 @@ #include <kapi/memory.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <cstddef> #include <format> diff --git a/kernel/kernel/test_support/page_mapper.hpp b/kernel/kernel/test_support/page_mapper.hpp index be4403b0..a9985393 100644 --- a/kernel/kernel/test_support/page_mapper.hpp +++ b/kernel/kernel/test_support/page_mapper.hpp @@ -5,7 +5,7 @@ #include <kapi/memory.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <cstddef> #include <cstdint> diff --git a/kernel/kernel/test_support/simulated_memory.cpp b/kernel/kernel/test_support/simulated_memory.cpp index 074e6b10..07adab17 100644 --- a/kernel/kernel/test_support/simulated_memory.cpp +++ b/kernel/kernel/test_support/simulated_memory.cpp @@ -2,7 +2,7 @@ #include <kapi/memory.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <cerrno> #include <cstddef> diff --git a/kernel/kernel/test_support/simulated_memory.hpp b/kernel/kernel/test_support/simulated_memory.hpp index a201c3d7..e7ca9f6c 100644 --- a/kernel/kernel/test_support/simulated_memory.hpp +++ b/kernel/kernel/test_support/simulated_memory.hpp @@ -3,7 +3,7 @@ #include <kapi/memory.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <cstddef> diff --git a/kernel/kstd/print.cpp b/kernel/kstd/print.cpp index d0611b21..cff1ea34 100644 --- a/kernel/kstd/print.cpp +++ b/kernel/kstd/print.cpp @@ -3,8 +3,8 @@ #include <kapi/cio.hpp> #include <kstd/bits/format/output_buffer.hpp> -#include <kstd/format> -#include <kstd/print> +#include <kstd/format.hpp> +#include <kstd/print.hpp> #include <algorithm> #include <array> diff --git a/kernel/kstd/print.tests.cpp b/kernel/kstd/print.tests.cpp index 4963f46e..a8c4ae25 100644 --- a/kernel/kstd/print.tests.cpp +++ b/kernel/kstd/print.tests.cpp @@ -1,4 +1,4 @@ -#include <kstd/print> +#include <kstd/print.hpp> #include <kernel/test_support/cio.hpp> diff --git a/libs/acpi/CMakeLists.txt b/libs/acpi/CMakeLists.txt index 58661c5e..caffa1c9 100644 --- a/libs/acpi/CMakeLists.txt +++ b/libs/acpi/CMakeLists.txt @@ -56,6 +56,7 @@ set_target_properties("acpi" PROPERTIES if(BUILD_TESTING) find_package("Catch2") include("Catch") + include("BuildHostTests") find_program(IASL_EXE NAMES "iasl" REQUIRED) @@ -88,37 +89,13 @@ if(BUILD_TESTING) enable_coverage("acpi") endif() - add_executable("acpi_tests") - add_executable("acpi::tests" ALIAS "acpi_tests") + teachos_add_tests("acpi") target_sources("acpi_tests" PRIVATE - "acpi/common/table_header.test.cpp" - "acpi/data/madt.test.cpp" - "acpi/data/rsdt.test.cpp" - "acpi/data/xsdt.test.cpp" - "acpi/pointers.test.cpp" - "acpi/test_data/tables.S" ) target_include_directories("acpi_tests" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/test_data" ) - - target_link_libraries("acpi_tests" PRIVATE - "Catch2::Catch2WithMain" - "acpi::lib" - ) - - set_target_properties("acpi_tests" PROPERTIES - EXCLUDE_FROM_ALL NO - ) - - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bht_results") - - catch_discover_tests("acpi::tests" - REPORTER junit - OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/bht_results" - OUTPUT_SUFFIX ".xml" - ) endif() diff --git a/libs/acpi/acpi/common/table_header.cpp b/libs/acpi/acpi/common/table_header.cpp index 6a7a4dc3..ebceca1d 100644 --- a/libs/acpi/acpi/common/table_header.cpp +++ b/libs/acpi/acpi/common/table_header.cpp @@ -1,7 +1,7 @@ #include <acpi/common/table_header.hpp> -#include <kstd/cstring> -#include <kstd/units> +#include <kstd/cstring.hpp> +#include <kstd/units.hpp> #include <array> #include <cstddef> diff --git a/libs/acpi/acpi/common/table_header.hpp b/libs/acpi/acpi/common/table_header.hpp index 471fed87..8e1d7c59 100644 --- a/libs/acpi/acpi/common/table_header.hpp +++ b/libs/acpi/acpi/common/table_header.hpp @@ -3,7 +3,7 @@ // IWYU pragma: private, include <acpi/acpi.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <array> #include <cstddef> diff --git a/libs/acpi/acpi/common/table_header.test.cpp b/libs/acpi/acpi/common/table_header.tests.cpp index ddc879ed..bbd42bd6 100644 --- a/libs/acpi/acpi/common/table_header.test.cpp +++ b/libs/acpi/acpi/common/table_header.tests.cpp @@ -2,7 +2,7 @@ #include <acpi/test_data/tables.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/libs/acpi/acpi/data/madt.cpp b/libs/acpi/acpi/data/madt.cpp index 1a8b6d3a..fe6bae16 100644 --- a/libs/acpi/acpi/data/madt.cpp +++ b/libs/acpi/acpi/data/madt.cpp @@ -1,6 +1,6 @@ #include <acpi/data/madt.hpp> -#include <kstd/cstring> +#include <kstd/cstring.hpp> #include <bit> #include <cstddef> diff --git a/libs/acpi/acpi/data/madt.hpp b/libs/acpi/acpi/data/madt.hpp index b76daa4f..4d992613 100644 --- a/libs/acpi/acpi/data/madt.hpp +++ b/libs/acpi/acpi/data/madt.hpp @@ -7,9 +7,9 @@ #include <acpi/common/table_type.hpp> #include <acpi/common/vla_table.hpp> -#include <kstd/ext/bitfield_enum> +#include <kstd/ext/bitfield_enum.hpp> #include <kstd/os/error.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <array> #include <cstddef> diff --git a/libs/acpi/acpi/data/madt.test.cpp b/libs/acpi/acpi/data/madt.tests.cpp index 1b95a74b..9ec0180a 100644 --- a/libs/acpi/acpi/data/madt.test.cpp +++ b/libs/acpi/acpi/data/madt.tests.cpp @@ -2,7 +2,7 @@ #include <acpi/test_data/tables.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/libs/acpi/acpi/data/rsdt.cpp b/libs/acpi/acpi/data/rsdt.cpp index 80e209db..a8626742 100644 --- a/libs/acpi/acpi/data/rsdt.cpp +++ b/libs/acpi/acpi/data/rsdt.cpp @@ -2,7 +2,7 @@ #include <acpi/common/table_header.hpp> -#include <kstd/cstring> +#include <kstd/cstring.hpp> #include <cstddef> #include <cstdint> diff --git a/libs/acpi/acpi/data/rsdt.test.cpp b/libs/acpi/acpi/data/rsdt.tests.cpp index 47992ce6..826d0b4f 100644 --- a/libs/acpi/acpi/data/rsdt.test.cpp +++ b/libs/acpi/acpi/data/rsdt.tests.cpp @@ -3,7 +3,7 @@ #include <acpi/acpi.hpp> #include <acpi/test_data/tables.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/libs/acpi/acpi/data/xsdt.cpp b/libs/acpi/acpi/data/xsdt.cpp index b77aeab7..c4b109b8 100644 --- a/libs/acpi/acpi/data/xsdt.cpp +++ b/libs/acpi/acpi/data/xsdt.cpp @@ -2,7 +2,7 @@ #include <acpi/common/table_header.hpp> -#include <kstd/cstring> +#include <kstd/cstring.hpp> #include <cstddef> #include <cstdint> diff --git a/libs/acpi/acpi/data/xsdt.test.cpp b/libs/acpi/acpi/data/xsdt.tests.cpp index 77a53408..19d9bcdb 100644 --- a/libs/acpi/acpi/data/xsdt.test.cpp +++ b/libs/acpi/acpi/data/xsdt.tests.cpp @@ -3,7 +3,7 @@ #include <acpi/acpi.hpp> #include <acpi/test_data/tables.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/libs/acpi/acpi/pointers.cpp b/libs/acpi/acpi/pointers.cpp index 2ac8d319..0393292c 100644 --- a/libs/acpi/acpi/pointers.cpp +++ b/libs/acpi/acpi/pointers.cpp @@ -2,7 +2,7 @@ #include <acpi/common/checksum.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <bit> #include <cstddef> diff --git a/libs/acpi/acpi/pointers.hpp b/libs/acpi/acpi/pointers.hpp index 5771e7df..310447f5 100644 --- a/libs/acpi/acpi/pointers.hpp +++ b/libs/acpi/acpi/pointers.hpp @@ -3,7 +3,7 @@ // IWYU pragma: private, include <acpi/acpi.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <array> #include <cstddef> diff --git a/libs/acpi/acpi/pointers.test.cpp b/libs/acpi/acpi/pointers.tests.cpp index d7b700d6..d7b700d6 100644 --- a/libs/acpi/acpi/pointers.test.cpp +++ b/libs/acpi/acpi/pointers.tests.cpp diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt index 002fb548..9c68feed 100644 --- a/libs/kstd/CMakeLists.txt +++ b/libs/kstd/CMakeLists.txt @@ -69,38 +69,12 @@ endif() if(BUILD_TESTING) find_package("Catch2") include("Catch") + include("BuildHostTests") - add_executable("kstd_tests") - add_executable("kstd::tests" ALIAS "kstd_tests") - - target_sources("kstd_tests" PRIVATE - "kstd/flat_map.test.cpp" - "kstd/format.test.cpp" - "kstd/vector.test.cpp" - "kstd/bits/observer_ptr.test.cpp" - "kstd/test_support/os_panic.test.cpp" - "kstd/string.test.cpp" - ) - - target_link_libraries("kstd_tests" PRIVATE - "Catch2::Catch2WithMain" - "kstd::lib" - ) - - set_target_properties("kstd_tests" PROPERTIES - EXCLUDE_FROM_ALL NO - ) + teachos_add_tests("kstd") if(COMMAND "enable_coverage") enable_coverage("kstd") enable_coverage("kstd_tests") endif() - - file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bht_results") - - catch_discover_tests("kstd::tests" - REPORTER junit - OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/bht_results" - OUTPUT_SUFFIX ".xml" - ) endif()
\ No newline at end of file diff --git a/libs/kstd/kstd/allocator b/libs/kstd/kstd/allocator.hpp index 0de0e10d..0de0e10d 100644 --- a/libs/kstd/kstd/allocator +++ b/libs/kstd/kstd/allocator.hpp diff --git a/libs/kstd/kstd/asm_ptr b/libs/kstd/kstd/asm_ptr.hpp index c06a8b52..c06a8b52 100644 --- a/libs/kstd/kstd/asm_ptr +++ b/libs/kstd/kstd/asm_ptr.hpp diff --git a/libs/kstd/kstd/bits/basic_string.hpp b/libs/kstd/kstd/bits/basic_string.hpp index 1675434c..a718bccc 100644 --- a/libs/kstd/kstd/bits/basic_string.hpp +++ b/libs/kstd/kstd/bits/basic_string.hpp @@ -1,10 +1,10 @@ #ifndef KSTD_BITS_BASIC_STRING_HPP #define KSTD_BITS_BASIC_STRING_HPP -#include <kstd/allocator> +#include <kstd/allocator.hpp> #include <kstd/bits/concepts.hpp> #include <kstd/os/error.hpp> -#include <kstd/ranges> +#include <kstd/ranges.hpp> #include <algorithm> #include <array> diff --git a/libs/kstd/kstd/bits/format/arg.hpp b/libs/kstd/kstd/bits/format/arg.hpp index e65b26fa..8271ca3d 100644 --- a/libs/kstd/kstd/bits/format/arg.hpp +++ b/libs/kstd/kstd/bits/format/arg.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_BITS_FORMAT_ARG_HPP #define KSTD_BITS_FORMAT_ARG_HPP -// IWYU pragma: private, include <kstd/format> +// IWYU pragma: private, include <kstd/format.hpp> #include <kstd/bits/format/error.hpp> #include <kstd/bits/format/fwd.hpp> diff --git a/libs/kstd/kstd/bits/format/args.hpp b/libs/kstd/kstd/bits/format/args.hpp index e8e31145..01735011 100644 --- a/libs/kstd/kstd/bits/format/args.hpp +++ b/libs/kstd/kstd/bits/format/args.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_BITS_FORMAT_ARGS_HPP #define KSTD_BITS_FORMAT_ARGS_HPP -// IWYU pragma: private, include <kstd/format> +// IWYU pragma: private, include <kstd/format.hpp> #include <kstd/bits/format/arg.hpp> #include <kstd/bits/format/context.hpp> diff --git a/libs/kstd/kstd/bits/format/context.hpp b/libs/kstd/kstd/bits/format/context.hpp index c166ba9c..d5f2f4d9 100644 --- a/libs/kstd/kstd/bits/format/context.hpp +++ b/libs/kstd/kstd/bits/format/context.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_BITS_FORMAT_CONTEXT_HPP #define KSTD_BITS_FORMAT_CONTEXT_HPP -// IWYU pragma: private, include <kstd/format> +// IWYU pragma: private, include <kstd/format.hpp> #include <kstd/bits/format/arg.hpp> #include <kstd/bits/format/output_buffer.hpp> diff --git a/libs/kstd/kstd/bits/format/formatter.hpp b/libs/kstd/kstd/bits/format/formatter.hpp index eb288294..c26907b2 100644 --- a/libs/kstd/kstd/bits/format/formatter.hpp +++ b/libs/kstd/kstd/bits/format/formatter.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_BITS_FORMATTER_HPP #define KSTD_BITS_FORMATTER_HPP -// IWYU pragma: private, include <kstd/format> +// IWYU pragma: private, include <kstd/format.hpp> #include <kstd/bits/format/context.hpp> #include <kstd/bits/format/error.hpp> diff --git a/libs/kstd/kstd/bits/format/formatter/cstring.hpp b/libs/kstd/kstd/bits/format/formatter/cstring.hpp index 553c8caf..12cb9c6f 100644 --- a/libs/kstd/kstd/bits/format/formatter/cstring.hpp +++ b/libs/kstd/kstd/bits/format/formatter/cstring.hpp @@ -5,6 +5,7 @@ #include <kstd/bits/format/formatter.hpp> #include <kstd/bits/format/formatter/string_view.hpp> +#include <cstddef> #include <string_view> namespace kstd @@ -24,6 +25,11 @@ namespace kstd { }; + template<std::size_t Size> + struct formatter<char[Size]> : formatter<char const *> // NOLINT + { + }; + } // namespace kstd #endif
\ No newline at end of file diff --git a/libs/kstd/kstd/bits/format/output_buffer.hpp b/libs/kstd/kstd/bits/format/output_buffer.hpp index fd7a2b4c..7e6f0575 100644 --- a/libs/kstd/kstd/bits/format/output_buffer.hpp +++ b/libs/kstd/kstd/bits/format/output_buffer.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_BITS_FORMAT_OUTPUT_BUFFER_HPP #define KSTD_BITS_FORMAT_OUTPUT_BUFFER_HPP -// IWYU pragma: private, include <kstd/format> +// IWYU pragma: private, include <kstd/format.hpp> #include <string_view> diff --git a/libs/kstd/kstd/bits/format/parse_context.hpp b/libs/kstd/kstd/bits/format/parse_context.hpp index cab8d726..81ed52cf 100644 --- a/libs/kstd/kstd/bits/format/parse_context.hpp +++ b/libs/kstd/kstd/bits/format/parse_context.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_BITS_FORMAT_PARSE_CONTEXT_HPP #define KSTD_BITS_FORMAT_PARSE_CONTEXT_HPP -// IWYU pragma: private, include <kstd/format> +// IWYU pragma: private, include <kstd/format.hpp> #include <kstd/bits/format/error.hpp> diff --git a/libs/kstd/kstd/bits/format/string.hpp b/libs/kstd/kstd/bits/format/string.hpp index a2b298d4..ab034e7c 100644 --- a/libs/kstd/kstd/bits/format/string.hpp +++ b/libs/kstd/kstd/bits/format/string.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_BITS_FORMAT_STRING_HPP #define KSTD_BITS_FORMAT_STRING_HPP -// IWYU pragma: private, include <kstd/format> +// IWYU pragma: private, include <kstd/format.hpp> #include <kstd/bits/format/context.hpp> #include <kstd/bits/format/error.hpp> diff --git a/libs/kstd/kstd/bits/format/vformat.cpp b/libs/kstd/kstd/bits/format/vformat.cpp index 1bf293a4..7210a0b6 100644 --- a/libs/kstd/kstd/bits/format/vformat.cpp +++ b/libs/kstd/kstd/bits/format/vformat.cpp @@ -1,6 +1,7 @@ -#include <kstd/format> -#include <kstd/string> +#include <kstd/format.hpp> +#include <kstd/string.hpp> +#include <algorithm> #include <cstddef> #include <iterator> #include <string_view> @@ -221,4 +222,23 @@ namespace kstd::bits::format return m_size; } + auto span_writer::push(std::string_view text) -> void + { + if (m_position < m_span.size() - 1) + { + auto space_left = m_span.size() - m_position; + auto to_copy = std::min(space_left, text.size()); + std::ranges::copy_n(text.begin(), to_copy, m_span.subspan(m_position).begin()); + m_position += to_copy; + } + } + + auto span_writer::push(char character) -> void + { + if (m_position < m_span.size() - 1) + { + m_span[m_position++] = character; + } + } + } // namespace kstd::bits::format
\ No newline at end of file diff --git a/libs/kstd/kstd/bits/format/vformat.hpp b/libs/kstd/kstd/bits/format/vformat.hpp index 2db56d17..63b41ab6 100644 --- a/libs/kstd/kstd/bits/format/vformat.hpp +++ b/libs/kstd/kstd/bits/format/vformat.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_BITS_FORMAT_VFORMAT_HPP #define KSTD_BITS_FORMAT_VFORMAT_HPP -// IWYU pragma: private, include <kstd/format> +// IWYU pragma: private, include <kstd/format.hpp> #include <kstd/bits/basic_string.hpp> #include <kstd/bits/format/args.hpp> @@ -11,8 +11,10 @@ #include <algorithm> #include <cstddef> #include <iterator> +#include <span> #include <string_view> #include <type_traits> +#include <utility> namespace kstd { @@ -28,7 +30,7 @@ namespace kstd //! @param args The arguments for the format string. auto vformat_to(output_buffer & buffer, std::string_view format, format_args args) -> void; - struct string_writer : output_buffer + struct string_writer final : output_buffer { auto push(std::string_view text) -> void final; auto push(char character) -> void final; @@ -40,7 +42,7 @@ namespace kstd }; //! A buffer that merely records the size of the output written to it. - struct size_recorder : output_buffer + struct size_recorder final : output_buffer { auto push(std::string_view text) -> void final; auto push(char character) -> void final; @@ -52,9 +54,9 @@ namespace kstd }; template<std::output_iterator<char> Output> - struct iterator_writer : output_buffer + struct iterator_writer final : output_buffer { - explicit iterator_writer(Output iterator) + constexpr explicit iterator_writer(Output iterator) : m_output{iterator} {} @@ -77,6 +79,25 @@ namespace kstd Output m_output{}; }; + struct span_writer final : output_buffer + { + constexpr explicit span_writer(std::span<char> span) + : m_span{span} + {} + + auto push(std::string_view text) -> void override; + auto push(char character) -> void override; + + [[nodiscard]] constexpr auto position() const noexcept -> std::size_t + { + return m_position; + } + + private: + std::size_t m_position{}; + std::span<char> m_span{}; + }; + } // namespace bits::format //! Format a given string with the provided arguments. @@ -108,6 +129,21 @@ namespace kstd return buffer.iterator(); } + //! Format a given string with the provided arguments. + //! + //! @param span The span to write to. + //! @param format The format string. + //! @param args The arguments for the format string. + //! @return A pair of the span written to and the next position to write to. + template<typename... ArgumentTypes> + auto format_to(std::span<char> span, format_string<std::type_identity_t<ArgumentTypes>...> format, + ArgumentTypes &&... args) -> std::pair<std::span<char>, std::size_t> + { + auto buffer = bits::format::span_writer{span}; + bits::format::vformat_to(buffer, format.str_view, make_format_args(std::forward<ArgumentTypes>(args)...).args); + return {span, buffer.position()}; + } + //! Determine the number of characters required to format the format string with the given arguments. //! //! @param format The format string. diff --git a/libs/kstd/kstd/bits/observer_ptr.hpp b/libs/kstd/kstd/bits/observer_ptr.hpp index 2593d7a4..e63e5d77 100644 --- a/libs/kstd/kstd/bits/observer_ptr.hpp +++ b/libs/kstd/kstd/bits/observer_ptr.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_OBSERVER_PTR_HPP #define KSTD_OBSERVER_PTR_HPP -// IWYU pragma: private, include <kstd/memory> +// IWYU pragma: private, include <kstd/memory.hpp> #include <kstd/os/error.hpp> diff --git a/libs/kstd/kstd/bits/observer_ptr.test.cpp b/libs/kstd/kstd/bits/observer_ptr.tests.cpp index f26fc09a..eca14ccd 100644 --- a/libs/kstd/kstd/bits/observer_ptr.test.cpp +++ b/libs/kstd/kstd/bits/observer_ptr.tests.cpp @@ -1,4 +1,4 @@ -#include <kstd/memory> +#include <kstd/memory.hpp> #include <kstd/test_support/os_panic.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/libs/kstd/kstd/bits/print_sink.hpp b/libs/kstd/kstd/bits/print_sink.hpp index af765e06..a1e9b0d4 100644 --- a/libs/kstd/kstd/bits/print_sink.hpp +++ b/libs/kstd/kstd/bits/print_sink.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_BITS_PRINT_SINK_HPP #define KSTD_BITS_PRINT_SINK_HPP -// IWYU pragma: private, include <kstd/print> +// IWYU pragma: private, include <kstd/print.hpp> namespace kstd { diff --git a/libs/kstd/kstd/bits/shared_ptr.hpp b/libs/kstd/kstd/bits/shared_ptr.hpp index 57a89c0d..ce4bfb7f 100644 --- a/libs/kstd/kstd/bits/shared_ptr.hpp +++ b/libs/kstd/kstd/bits/shared_ptr.hpp @@ -6,7 +6,7 @@ #include <type_traits> #include <utility> -// IWYU pragma: private, include <kstd/memory> +// IWYU pragma: private, include <kstd/memory.hpp> namespace kstd { diff --git a/libs/kstd/kstd/bits/unique_ptr.hpp b/libs/kstd/kstd/bits/unique_ptr.hpp index 3d803b4a..1df18cf2 100644 --- a/libs/kstd/kstd/bits/unique_ptr.hpp +++ b/libs/kstd/kstd/bits/unique_ptr.hpp @@ -3,7 +3,7 @@ #include <utility> -// IWYU pragma: private, include <kstd/memory> +// IWYU pragma: private, include <kstd/memory.hpp> namespace kstd { diff --git a/libs/kstd/kstd/cstring b/libs/kstd/kstd/cstring.hpp index bd8b28d8..bd8b28d8 100644 --- a/libs/kstd/kstd/cstring +++ b/libs/kstd/kstd/cstring.hpp diff --git a/libs/kstd/kstd/ext/bitfield_enum b/libs/kstd/kstd/ext/bitfield_enum.hpp index 80fe9d29..80fe9d29 100644 --- a/libs/kstd/kstd/ext/bitfield_enum +++ b/libs/kstd/kstd/ext/bitfield_enum.hpp diff --git a/libs/kstd/kstd/flat_map b/libs/kstd/kstd/flat_map.hpp index e51eb918..31557760 100644 --- a/libs/kstd/kstd/flat_map +++ b/libs/kstd/kstd/flat_map.hpp @@ -3,7 +3,7 @@ #include <kstd/bits/flat_map.hpp> #include <kstd/os/error.hpp> -#include <kstd/vector> +#include <kstd/vector.hpp> #include <algorithm> #include <concepts> diff --git a/libs/kstd/kstd/flat_map.test.cpp b/libs/kstd/kstd/flat_map.tests.cpp index 9df03bb4..bfd02303 100644 --- a/libs/kstd/kstd/flat_map.test.cpp +++ b/libs/kstd/kstd/flat_map.tests.cpp @@ -1,4 +1,4 @@ -#include <kstd/flat_map> +#include <kstd/flat_map.hpp> #include <kstd/test_support/os_panic.hpp> diff --git a/libs/kstd/kstd/format b/libs/kstd/kstd/format.hpp index 5ed798db..5d7f4ae6 100644 --- a/libs/kstd/kstd/format +++ b/libs/kstd/kstd/format.hpp @@ -5,6 +5,7 @@ #include <kstd/bits/format/arg.hpp> #include <kstd/bits/format/args.hpp> #include <kstd/bits/format/context.hpp> +#include <kstd/bits/format/error.hpp> #include <kstd/bits/format/formatter.hpp> #include <kstd/bits/format/formatter/bool.hpp> #include <kstd/bits/format/formatter/byte.hpp> diff --git a/libs/kstd/kstd/format.test.cpp b/libs/kstd/kstd/format.tests.cpp index 6126605f..a34cf063 100644 --- a/libs/kstd/kstd/format.test.cpp +++ b/libs/kstd/kstd/format.tests.cpp @@ -1,7 +1,8 @@ -#include <kstd/format> +#include <kstd/format.hpp> #include <catch2/catch_test_macros.hpp> +#include <array> #include <iterator> #include <sstream> #include <string_view> @@ -116,6 +117,95 @@ SCENARIO("Formatting to an output iterator", "[format]") } } +SCENARIO("Formatting to a span", "[format]") +{ + GIVEN("a format string without any placeholders") + { + constexpr auto fmt = "This is a test"sv; + + WHEN("calling format without any arguments.") + { + auto buffer = std::array<char, 100>{}; + auto [span, length] = kstd::format_to(buffer, fmt); + + THEN("the unmodified string is written to the span") + { + REQUIRE(std::string_view{span.data(), length} == "This is a test"); + } + } + + WHEN("calling format with additional arguments") + { + auto buffer = std::array<char, 100>{}; + auto [span, length] = kstd::format_to(buffer, fmt, 1, 2, 3); + + THEN("the unmodified string is written to the span") + { + REQUIRE(std::string_view(span.data(), length) == "This is a test"); + } + } + + WHEN("the span is too small") + { + auto buffer = std::array<char, 4>{}; + auto [span, length] = kstd::format_to(buffer, fmt, 1, 2, 3); + + THEN("the written length is equal to the span size") + { + REQUIRE(length == span.size()); + } + + THEN("only part of the unmodified string is written to the span") + { + REQUIRE(std::string_view(span.data(), length) == "This"); + } + } + } + + GIVEN("a format string with placeholders") + { + constexpr auto fmt = "Here are some placeholders: {} {} {}"sv; + + WHEN("calling format with the same number of arguments as there are placeholders") + { + auto buffer = std::array<char, 100>{}; + auto [span, length] = kstd::format_to(buffer, fmt, 1, true, -100); + + THEN("the formatted string is written to the span") + { + REQUIRE(std::string_view{span.data(), length} == "Here are some placeholders: 1 true -100"); + } + } + + WHEN("calling format with too many arguments") + { + auto buffer = std::array<char, 100>{}; + auto [span, length] = kstd::format_to(buffer, fmt, 2, false, -200, 4, 5, 6); + + THEN("the formatted string is written to the span") + { + REQUIRE(std::string_view{span.data(), length} == "Here are some placeholders: 2 false -200"); + } + } + + WHEN("the span is too small") + { + auto buffer = std::array<char, 4>{}; + auto [span, length] = kstd::format_to(buffer, fmt, 2, false, -200, 4, 5, 6); + + THEN("the written length is equal to the span size") + { + REQUIRE(length == span.size()); + } + + THEN("only part of the unmodified string is written to the span") + { + REQUIRE(std::string_view(span.data(), length) == "Here"); + } + } + } +} + SCENARIO("Determining formatted size") { GIVEN("a format string without any placeholders") diff --git a/libs/kstd/kstd/libc/string.cpp b/libs/kstd/kstd/libc/string.cpp index b7cdb82e..15ecc70f 100644 --- a/libs/kstd/kstd/libc/string.cpp +++ b/libs/kstd/kstd/libc/string.cpp @@ -1,4 +1,4 @@ -#include <kstd/cstring> +#include <kstd/cstring.hpp> #include <algorithm> #include <bit> diff --git a/libs/kstd/kstd/memory b/libs/kstd/kstd/memory.hpp index f108c6d6..f108c6d6 100644 --- a/libs/kstd/kstd/memory +++ b/libs/kstd/kstd/memory.hpp diff --git a/libs/kstd/kstd/mutex.cpp b/libs/kstd/kstd/mutex.cpp index 73876572..c1c5b190 100644 --- a/libs/kstd/kstd/mutex.cpp +++ b/libs/kstd/kstd/mutex.cpp @@ -1,4 +1,4 @@ -#include <kstd/mutex> +#include <kstd/mutex.hpp> #include <kstd/os/error.hpp> diff --git a/libs/kstd/kstd/mutex b/libs/kstd/kstd/mutex.hpp index b2a31aa9..b2a31aa9 100644 --- a/libs/kstd/kstd/mutex +++ b/libs/kstd/kstd/mutex.hpp diff --git a/libs/kstd/kstd/posix.hpp b/libs/kstd/kstd/posix.hpp new file mode 100644 index 00000000..12bd5ec0 --- /dev/null +++ b/libs/kstd/kstd/posix.hpp @@ -0,0 +1,85 @@ +#ifndef KSTD_CERRNO_HPP +#define KSTD_CERRNO_HPP + +namespace kstd::posix +{ + + constexpr auto static inline eafnosupport = 1; + constexpr auto static inline eaddrinuse = 2; + constexpr auto static inline eaddrnotavail = 3; + constexpr auto static inline eisconn = 4; + constexpr auto static inline e2big = 5; + constexpr auto static inline edom = 6; + constexpr auto static inline efault = 7; + constexpr auto static inline ebadf = 8; + constexpr auto static inline ebadmsg = 9; + constexpr auto static inline epipe = 10; + constexpr auto static inline econnaborted = 11; + constexpr auto static inline ealready = 12; + constexpr auto static inline econnrefused = 13; + constexpr auto static inline econnreset = 14; + constexpr auto static inline exdev = 15; + constexpr auto static inline edestaddrreq = 16; + constexpr auto static inline ebusy = 17; + constexpr auto static inline enotempty = 18; + constexpr auto static inline enoexec = 19; + constexpr auto static inline eexist = 20; + constexpr auto static inline efbig = 21; + constexpr auto static inline enametoolong = 22; + constexpr auto static inline enosys = 23; + constexpr auto static inline ehostunreach = 24; + constexpr auto static inline eidrm = 25; + constexpr auto static inline eilseq = 26; + constexpr auto static inline enotty = 27; + constexpr auto static inline eintr = 28; + constexpr auto static inline einval = 29; + constexpr auto static inline espipe = 30; + constexpr auto static inline eio = 31; + constexpr auto static inline eisdir = 32; + constexpr auto static inline emsgsize = 33; + constexpr auto static inline enetdown = 34; + constexpr auto static inline enetreset = 35; + constexpr auto static inline enetunreach = 36; + constexpr auto static inline enobufs = 37; + constexpr auto static inline echild = 38; + constexpr auto static inline enolink = 39; + constexpr auto static inline enolck = 40; + constexpr auto static inline enomsg = 41; + constexpr auto static inline enoprotoopt = 42; + constexpr auto static inline enospc = 43; + constexpr auto static inline enodev = 44; + constexpr auto static inline enxio = 45; + constexpr auto static inline enoent = 46; + constexpr auto static inline esrch = 47; + constexpr auto static inline enotdir = 48; + constexpr auto static inline enotsock = 49; + constexpr auto static inline enotconn = 50; + constexpr auto static inline enomem = 51; + constexpr auto static inline enotsup = 52; + constexpr auto static inline ecanceled = 53; + constexpr auto static inline einprogress = 54; + constexpr auto static inline eperm = 55; + constexpr auto static inline eopnotsupp = 56; + constexpr auto static inline ewouldblock = 57; + constexpr auto static inline eownerdead = 58; + constexpr auto static inline eacces = 59; + constexpr auto static inline eproto = 60; + constexpr auto static inline eprotonosupport = 61; + constexpr auto static inline erofs = 62; + constexpr auto static inline edeadlk = 63; + constexpr auto static inline eagain = 64; + constexpr auto static inline erange = 65; + constexpr auto static inline esocktnosupport = 66; + constexpr auto static inline enotrecoverable = 67; + constexpr auto static inline etxtbsy = 68; + constexpr auto static inline etimedout = 69; + constexpr auto static inline emfile = 70; + constexpr auto static inline enfile = 71; + constexpr auto static inline emlink = 72; + constexpr auto static inline eloop = 73; + constexpr auto static inline eoverflow = 74; + constexpr auto static inline eprototype = 75; + +} // namespace kstd::posix + +#endif
\ No newline at end of file diff --git a/libs/kstd/kstd/print b/libs/kstd/kstd/print.hpp index 1033f722..0d37efbe 100644 --- a/libs/kstd/kstd/print +++ b/libs/kstd/kstd/print.hpp @@ -2,7 +2,7 @@ #define KSTD_PRINT #include <kstd/bits/print_sink.hpp> // IWYU pragma: export -#include <kstd/format> +#include <kstd/format.hpp> #include <kstd/os/print.hpp> #include <type_traits> @@ -26,6 +26,7 @@ namespace kstd //! @qualifier kernel-defined //! Format the given error string using the given arguments and print it to the currently active output device. //! + //! @param sink The output sink to print to. //! @param format The format string //! @param args The arguments to use to place in the format string's placeholders. template<typename... Args> @@ -54,6 +55,7 @@ namespace kstd //! Format the given error string using the given arguments and print it, including a newline, to the currently active //! output device. //! + //! @param sink The output sink to print to. //! @param format The format string //! @param args The arguments template<typename... Args> diff --git a/libs/kstd/kstd/ranges b/libs/kstd/kstd/ranges.hpp index 78c3adbf..78c3adbf 100644 --- a/libs/kstd/kstd/ranges +++ b/libs/kstd/kstd/ranges.hpp diff --git a/libs/kstd/kstd/result.hpp b/libs/kstd/kstd/result.hpp new file mode 100644 index 00000000..7b027a8d --- /dev/null +++ b/libs/kstd/kstd/result.hpp @@ -0,0 +1,35 @@ +#ifndef KSTD_RESULT_HPP +#define KSTD_RESULT_HPP + +#include <kstd/system_error.hpp> + +#include <expected> +#include <type_traits> +#include <utility> + +namespace kstd +{ + + template<typename SuccessType> + using result = std::expected<SuccessType, error_code>; + + template<typename SuccessType> + requires(!std::is_void_v<SuccessType>) + constexpr auto inline success(SuccessType && value) -> result<std::remove_cvref_t<SuccessType>> + { + return result<std::remove_cvref_t<SuccessType>>{std::in_place, std::forward<SuccessType>(value)}; + } + + constexpr auto inline success() -> result<void> + { + return result<void>{std::in_place}; + } + + constexpr auto inline failure(error_code error) -> std::unexpected<error_code> + { + return std::unexpected(error); + } + +} // namespace kstd + +#endif
\ No newline at end of file diff --git a/libs/kstd/kstd/stack b/libs/kstd/kstd/stack.hpp index 02e44ea4..27e693f2 100644 --- a/libs/kstd/kstd/stack +++ b/libs/kstd/kstd/stack.hpp @@ -1,7 +1,7 @@ #ifndef KSTD_STACK_HPP #define KSTD_STACK_HPP -#include <kstd/vector> +#include <kstd/vector.hpp> #include <initializer_list> #include <utility> diff --git a/libs/kstd/kstd/string b/libs/kstd/kstd/string.hpp index 4a67a3a4..9978affc 100644 --- a/libs/kstd/kstd/string +++ b/libs/kstd/kstd/string.hpp @@ -7,9 +7,9 @@ #include <kstd/bits/format/formatter/cstring.hpp> #include <kstd/bits/format/formatter/integral.hpp> #include <kstd/bits/format/vformat.hpp> -#include <kstd/cstring> +#include <kstd/cstring.hpp> #include <kstd/os/error.hpp> -#include <kstd/vector> +#include <kstd/vector.hpp> #include <concepts> #include <cstddef> diff --git a/libs/kstd/kstd/string.test.cpp b/libs/kstd/kstd/string.tests.cpp index e11877e5..b8fa1139 100644 --- a/libs/kstd/kstd/string.test.cpp +++ b/libs/kstd/kstd/string.tests.cpp @@ -1,6 +1,6 @@ -#include <kstd/string> +#include <kstd/string.hpp> -#include <kstd/allocator> +#include <kstd/allocator.hpp> #include <kstd/test_support/os_panic.hpp> #include <catch2/catch_test_macros.hpp> diff --git a/libs/kstd/kstd/system_error.hpp b/libs/kstd/kstd/system_error.hpp new file mode 100644 index 00000000..09efb097 --- /dev/null +++ b/libs/kstd/kstd/system_error.hpp @@ -0,0 +1,636 @@ +#ifndef KSTD_SYSTEM_ERROR_HPP +#define KSTD_SYSTEM_ERROR_HPP + +#include <kstd/format.hpp> +#include <kstd/posix.hpp> // IWYU pragma: export + +#include <compare> +#include <cstdint> +#include <functional> +#include <string_view> +#include <type_traits> + +namespace kstd +{ + + struct error_condition; + struct error_code; + + //! Determine if a given enumeration type is an error condition enumeration. + //! + //! An enumeration type is an error condition enumeration if it defines generic, system-level error conditions. + //! Specific subsystem error enumerations on the other hand are not generic enough to be considered error conditions + //! and are thus called error codes. + //! + //! @note Types may opt in to being an error condition enumeration by specializing this class template. + //! + //! @tparam CandidateType The type to check. + template<typename CandidateType> + requires(std::is_enum_v<CandidateType>) + struct is_error_condition_enum : std::false_type + { + }; + + //! Determine if a given enumeration type is an error condition enumeration. + //! + //! @see is_error_condition_enum + //! + //! @tparam CandidateType The type to check. + template<typename CandidateType> + constexpr auto inline is_error_condition_enum_v = is_error_condition_enum<CandidateType>::value; + + //! Determine if a given enumeration type is an error condition enumeration. + //! + //! @see is_error_condition_enum + //! @tparam CandidateType The type to check. + template<typename CandidateType> + concept error_condition_enum = std::is_enum_v<CandidateType> && is_error_condition_enum_v<CandidateType>; + + //! Determine if a given enumeration type is an error code enumeration. + //! + //! An enumeration type is an error code enumeration if it defines specific, subsystem-level error codes. + //! Generic error conditions are not specific enough to be considered error codes and are thus called error + //! conditions. + //! + //! @note Types may opt in to being an error code enumeration by specializing this class template. + //! + //! @tparam CandidateType The type to check. + template<typename CandidateType> + requires(std::is_enum_v<CandidateType>) + struct is_error_code_enum : std::false_type + { + }; + + //! Determine if a given enumeration type is an error code enumeration. + //! + //! @see is_error_code_enum + //! + //! @tparam CandidateType The type to check. + template<typename CandidateType> + constexpr auto inline is_error_code_enum_v = is_error_code_enum<CandidateType>::value; + + //! Determine if a given enumeration type is an error code enumeration. + //! + //! @see is_error_code_enum + //! + //! @tparam CandidateType The type to check. + template<typename CandidateType> + concept error_code_enum = std::is_enum_v<CandidateType> && is_error_code_enum_v<CandidateType>; + + //! A category of error codes or conditions. + //! + //! An error category is a group of related error codes or conditions. Each error code or condition belongs to exactly + //! one error category. Error categories are used to provide additional context and information about the error codes + //! or conditions they contain. They can also be used to compare error codes or conditions from different categories. + //! + //! Subsystems shall defined their own error categories for their error codes, by inheriting from this class. + struct error_category + { + constexpr error_category() noexcept = default; + + error_category(error_category const &) = delete; + + constexpr virtual ~error_category() = default; + + auto operator=(error_category const &) -> error_category & = delete; + + //! Get the name of this error category. + [[nodiscard]] constexpr auto virtual name() const noexcept -> std::string_view = 0; + + //! Get the default error condition for a given error code value in this category. + //! + //! @param value The error code value to get the default error condition for. + //! @return The default error condition for the given error code value in this category. + [[nodiscard]] constexpr auto virtual default_error_condition(int value) const noexcept -> error_condition; + + //! Check if a given error code value is equivalent to a given error condition in this category. + //! + //! @param value The error code value to check. + //! @param other The error condition to compare against. + //! @return True if the error code value is equivalent to the error condition in this category, false otherwise. + [[nodiscard]] constexpr auto virtual equivalent(int value, error_condition const & other) const noexcept -> bool; + + //! Check if a given error code is equivalent to a given error condition in this category. + //! + //! @param code The error code to check. + //! @param condition The error condition to compare against. + //! @return True if the error code is equivalent to the error condition in this category, false otherwise. + [[nodiscard]] constexpr auto virtual equivalent(error_code const & code, int condition) const noexcept -> bool; + + //! Get the message for a given error code value in this category. + //! + //! @param value The error code value to get the message for. + //! @return The message for the given error code value in this category. + [[nodiscard]] constexpr auto virtual message(int value) const noexcept -> std::string_view = 0; + + //! Check if this error category is equal to another one. + [[nodiscard]] constexpr auto operator==(error_category const & other) const noexcept -> bool + { + return this == &other; + } + + //! Lexicographically compare this error category to a different one. + [[nodiscard]] constexpr auto operator<=>(error_category const & other) const noexcept -> std::strong_ordering + { + return std::compare_three_way{}(this, &other); + } + }; + + //! An error condition represents a generic, system-level error. + //! + //! Error conditions are used to represent errors to be tested for. + struct error_condition + { + //! Construct an error condition with a default value and category. + constexpr error_condition() noexcept; + + //! Construct an error condition with a specific value and category. + //! + //! @param value The error code value. + //! @param category The error category. + constexpr error_condition(int value, error_category const & category) noexcept + : m_value{value} + , m_category{&category} + {} + + //! Construct an error condition from an error condition enumeration value. + //! + //! @tparam Enum The error condition enumeration type. + //! @param value The error condition enumeration value. + template<error_condition_enum Enum> + constexpr error_condition(Enum value) noexcept + : error_condition{make_error_condition(value)} + {} + + //! Assign an error condition enumeration value to this error condition. + //! + //! @tparam Enum The error condition enumeration type. + //! @param value The error condition enumeration value. + template<error_condition_enum Enum> + constexpr auto operator=(Enum value) noexcept -> error_condition & + { + *this = make_error_condition(value); + } + + //! Assign a new value and category to this error condition. + //! + //! @param value The new error code value. + //! @param category The new error category. + constexpr auto assign(int value, error_category const & category) noexcept -> void + { + m_value = value; + m_category = &category; + } + + //! Clear this error condition. + //! + //! This sets the value to 0 and the category to the generic error category. + constexpr auto clear() noexcept -> void; + + //! Get the raw error code value of this error condition. + [[nodiscard]] constexpr auto value() const noexcept -> int + { + return m_value; + } + + //! Get the error category of this error condition. + [[nodiscard]] constexpr auto category() const noexcept -> error_category const & + { + return *m_category; + } + + //! Get the message associated with this error condition based on its value and category. + [[nodiscard]] constexpr auto message() const noexcept -> std::string_view + { + return m_category->message(m_value); + } + + //! Check if this error condition holds an error. + //! + //! @return @p true iff. this error condition holds a non-zero value, @p false otherwise. + [[nodiscard]] constexpr explicit operator bool() const noexcept + { + return m_value != 0; + } + + //! Check if two error conditions are equal. + //! + //! Error conditions are considered equal if they hold the same value and reference the same category. + [[nodiscard]] constexpr auto friend operator==(error_condition const & lhs, error_condition const & rhs) noexcept + -> bool + { + return lhs.category() == rhs.category() && lhs.value() == rhs.value(); + } + + //! Lexicographically compare two error conditions. + [[nodiscard]] constexpr auto friend operator<=>(error_condition const & lhs, error_condition const & rhs) noexcept + -> std::strong_ordering + { + if (auto result = lhs.category() <=> rhs.category(); result != std::strong_ordering::equal) + { + return result; + } + + return lhs.value() <=> rhs.value(); + } + + private: + int m_value{}; + error_category const * m_category{}; + }; + + //! An error code represents a specific, subsystem-level error. + //! + //! Error codes are used to represent errors that are specific to a subsystem. Equivalence between error codes and + //! error conditions can be defined per each error enumeration type. + struct error_code + { + //! Construct an error code with a default value and category. + constexpr error_code() noexcept; + + //! Construct an error code with a specific value and category. + constexpr error_code(int value, error_category const & category) noexcept + : m_value{value} + , m_category{&category} + {} + + //! Construct an error code from an error code enumeration value. + //! + //! @tparam Enum The error code enumeration type. + //! @param value The error code enumeration value. + template<error_code_enum Enum> + constexpr error_code(Enum value) noexcept + : error_code{make_error_code(value)} + {} + + //! Assign an error code enumeration value to this error code. + //! + //! The category is chosen based on the enumeration type of the value. + //! @tparam Enum The error code enumeration type. + //! @param value The error code enumeration value. + template<error_code_enum Enum> + constexpr auto operator=(Enum value) noexcept -> error_code & + { + return *this = make_error_code(value); + } + + //! Assign a new value and category to this error code. + //! + //! @param value The new error code value. + //! @param category The new error code category. + constexpr auto assign(int value, error_category const & category) noexcept -> void + { + m_value = value; + m_category = &category; + } + + //! Clear this error code. + constexpr auto clear() noexcept -> void; + + //! Get the raw error code value of this error code. + [[nodiscard]] constexpr auto value() const noexcept -> int + { + return m_value; + } + + //! Get the error category of this error code. + [[nodiscard]] constexpr auto category() const noexcept -> error_category const & + { + return *m_category; + } + + //! Get and error condition that is equivalent to this error code. + [[nodiscard]] constexpr auto default_error_condition() const noexcept -> error_condition + { + return m_category->default_error_condition(m_value); + } + + //! Get the message associated with this error code based on its value and category. + [[nodiscard]] constexpr auto message() const noexcept -> std::string_view + { + return m_category->message(m_value); + } + + //! Check if this error code holds an error. + //! + //! @return @p true iff. this error code holds a non-zero value, @p false otherwise. + [[nodiscard]] constexpr explicit operator bool() const noexcept + { + return m_value != 0; + } + + //! Check if two error codes are equal. + //! + //! Error codes are considered equal if they hold the same value and reference the same category. + [[nodiscard]] constexpr auto friend operator==(error_code const & lhs, error_code const & rhs) noexcept -> bool + { + return lhs.category() == rhs.category() && lhs.value() == rhs.value(); + } + + //! Lexicographically compare two error codes. + [[nodiscard]] constexpr auto friend operator<=>(error_code const & lhs, error_code const & rhs) noexcept + -> std::strong_ordering + { + if (auto result = lhs.category() <=> rhs.category(); result != std::strong_ordering::equal) + { + return result; + } + + return lhs.value() <=> rhs.value(); + } + + private: + int m_value{}; + error_category const * m_category{}; + }; + + enum struct errc : std::uint32_t + { + address_family_not_supported = posix::eafnosupport, + address_in_use = posix::eaddrinuse, + address_not_available = posix::eaddrnotavail, + already_connected = posix::eisconn, + argument_list_too_long = posix::e2big, + argument_out_of_domain = posix::edom, + bad_address = posix::efault, + bad_file_descriptor = posix::ebadf, + bad_message = posix::ebadmsg, + broken_pipe = posix::epipe, + connection_aborted = posix::econnaborted, + connection_already_in_progress = posix::ealready, + connection_refused = posix::econnrefused, + connection_reset = posix::econnreset, + cross_device_link = posix::exdev, + destination_address_required = posix::edestaddrreq, + device_or_resource_busy = posix::ebusy, + directory_not_empty = posix::enotempty, + executable_format_error = posix::enoexec, + file_exists = posix::eexist, + file_too_large = posix::efbig, + filename_too_long = posix::enametoolong, + function_not_supported = posix::enosys, + host_unreachable = posix::ehostunreach, + identifier_removed = posix::eidrm, + illegal_byte_sequence = posix::eilseq, + inappropriate_io_control_operation = posix::enotty, + interrupted = posix::eintr, + invalid_argument = posix::einval, + invalid_seek = posix::espipe, + io_error = posix::eio, + is_a_directory = posix::eisdir, + message_size = posix::emsgsize, + network_down = posix::enetdown, + network_reset = posix::enetreset, + network_unreachable = posix::enetunreach, + no_buffer_space = posix::enobufs, + no_child_process = posix::echild, + no_link = posix::enolink, + no_lock_available = posix::enolck, + no_message = posix::enomsg, + no_protocol_option = posix::enoprotoopt, + no_space_on_device = posix::enospc, + no_such_device_or_address = posix::enxio, + no_such_device = posix::enodev, + no_such_file_or_directory = posix::enoent, + no_such_process = posix::esrch, + not_a_directory = posix::enotdir, + not_a_socket = posix::enotsock, + not_connected = posix::enotconn, + not_enough_memory = posix::enomem, + not_supported = posix::enotsup, + operation_canceled = posix::ecanceled, + operation_in_progress = posix::einprogress, + operation_not_permitted = posix::eperm, + operation_not_supported = posix::eopnotsupp, + operation_would_block = posix::ewouldblock, + owner_dead = posix::eownerdead, + permission_denied = posix::eacces, + protocol_error = posix::eproto, + protocol_not_supported = posix::eprotonosupport, + read_only_file_system = posix::erofs, + resource_deadlock_would_occur = posix::edeadlk, + resource_unavailable_try_again = posix::eagain, + result_out_of_range = posix::erange, + state_not_recoverable = posix::enotrecoverable, + text_file_busy = posix::etxtbsy, + timed_out = posix::etimedout, + too_many_files_open_in_system = posix::enfile, + too_many_files_open = posix::emfile, + too_many_links = posix::emlink, + too_many_symbolic_link_levels = posix::eloop, + value_too_large = posix::eoverflow, + wrong_protocol_type = posix::eprototype, + }; + + //! Mark the kstd::errc enumeration as an error condition enumeration. + template<> + struct is_error_condition_enum<errc> : std::true_type + { + }; + + namespace bits + { + constexpr auto to_message(errc error) -> std::string_view + { + switch (error) + { + // clang-format off + case errc::address_family_not_supported: return "address family not supported"; + case errc::address_in_use: return "address in use"; + case errc::address_not_available: return "address not available"; + case errc::already_connected: return "already connected"; + case errc::argument_list_too_long: return "argument list too long"; + case errc::argument_out_of_domain: return "argument out of domain"; + case errc::bad_address: return "bad address"; + case errc::bad_file_descriptor: return "bad file descriptor"; + case errc::bad_message: return "bad message"; + case errc::broken_pipe: return "broken pipe"; + case errc::connection_aborted: return "connection aborted"; + case errc::connection_already_in_progress: return "connection already in progress"; + case errc::connection_refused: return "connection refused"; + case errc::connection_reset: return "connection reset"; + case errc::cross_device_link: return "cross device link"; + case errc::destination_address_required: return "destination address required"; + case errc::device_or_resource_busy: return "device or resource busy"; + case errc::directory_not_empty: return "directory not empty"; + case errc::executable_format_error: return "invalid executable format"; + case errc::file_exists: return "file exists"; + case errc::file_too_large: return "file too large"; + case errc::filename_too_long: return "filename too long"; + case errc::function_not_supported: return "function not supported"; + case errc::host_unreachable: return "host unreachable"; + case errc::identifier_removed: return "identifier removed"; + case errc::illegal_byte_sequence: return "illegal byte sequence"; + case errc::inappropriate_io_control_operation: return "inappropriate io control operation"; + case errc::interrupted: return "system call interrupted"; + case errc::invalid_argument: return "invalid argument"; + case errc::invalid_seek: return "invalid seek"; + case errc::io_error: return "input/output error"; + case errc::is_a_directory: return "is a directory"; + case errc::message_size: return "message size"; + case errc::network_down: return "network down"; + case errc::network_reset: return "network reset"; + case errc::network_unreachable: return "network unreachable"; + case errc::no_buffer_space: return "no buffer space"; + case errc::no_child_process: return "no child process"; + case errc::no_link: return "no link"; + case errc::no_lock_available: return "no lock available"; + case errc::no_message: return "no message"; + case errc::no_protocol_option: return "no protocol option"; + case errc::no_space_on_device: return "no space on device"; + case errc::no_such_device: return "no such device"; + case errc::no_such_device_or_address: return "no such device or address"; + case errc::no_such_file_or_directory: return "no such file or directory"; + case errc::no_such_process: return "no such process"; + case errc::not_a_directory: return "not a directory"; + case errc::not_a_socket: return "not a socket"; + case errc::not_connected: return "not connected"; + case errc::not_enough_memory: return "not enough memory"; + case errc::not_supported: return "not supported"; + case errc::operation_canceled: return "operation canceled"; + case errc::operation_in_progress: return "operation in progress"; + case errc::operation_not_permitted: return "operation not permitted"; + case errc::operation_not_supported: return "operation not supported"; + case errc::operation_would_block: return "operation would block"; + case errc::owner_dead: return "owner dead"; + case errc::permission_denied: return "permission denied"; + case errc::protocol_error: return "protocol error"; + case errc::protocol_not_supported: return "protocol not supported"; + case errc::read_only_file_system: return "read only file system"; + case errc::resource_deadlock_would_occur: return "resource deadlock would occur"; + case errc::resource_unavailable_try_again: return "resource unavailable, try again"; + case errc::result_out_of_range: return "result out of range"; + case errc::state_not_recoverable: return "state not recoverable"; + case errc::text_file_busy: return "text file busy"; + case errc::timed_out: return "timed out"; + case errc::too_many_files_open: return "too many files open"; + case errc::too_many_files_open_in_system: return "too many files open in system"; + case errc::too_many_links: return "too many links"; + case errc::too_many_symbolic_link_levels: return "too many symbolic link levels"; + case errc::value_too_large: return "value too large"; + case errc::wrong_protocol_type: return "wrong protocol type"; + default: return "unknown error"; + // clang-format on + } + } + + struct generic_category_t final : error_category + { + [[nodiscard]] constexpr auto name() const noexcept -> std::string_view override + { + return "generic"; + } + + [[nodiscard]] constexpr auto message(int value) const noexcept -> std::string_view override + { + return to_message(static_cast<errc>(value)); + } + } constexpr inline generic_category_instance{}; + + struct system_category_t final : error_category + { + [[nodiscard]] constexpr auto name() const noexcept -> std::string_view override + { + return "system"; + } + + [[nodiscard]] constexpr auto message(int value) const noexcept -> std::string_view override + { + return to_message(static_cast<errc>(value)); + } + } constexpr inline system_category_instance{}; + } // namespace bits + + //! Get a reference to the generic error category. + constexpr auto inline generic_category() noexcept -> error_category const & + { + return bits::generic_category_instance; + } + + //! Get a reference to the system error category. + constexpr auto inline system_category() noexcept -> error_category const & + { + return bits::system_category_instance; + } + + constexpr auto inline error_category::default_error_condition(int value) const noexcept -> error_condition + { + return error_condition{value, *this}; + } + + constexpr auto inline error_category::equivalent(int value, error_condition const & other) const noexcept -> bool + { + return default_error_condition(value) == other; + } + + constexpr auto error_category::equivalent(error_code const & code, int condition) const noexcept -> bool + { + return *this == code.category() && code.value() == condition; + } + + constexpr error_condition::error_condition() noexcept + : error_condition{0, generic_category()} + {} + + constexpr auto error_condition::clear() noexcept -> void + { + m_value = 0; + m_category = &generic_category(); + } + + constexpr auto operator==(error_code const & code, error_condition const & condition) noexcept -> bool + { + return code.category().equivalent(code.value(), condition) || + condition.category().equivalent(code, condition.value()); + } + + constexpr error_code::error_code() noexcept + : error_code{0, system_category()} {}; + + constexpr auto error_code::clear() noexcept -> void + { + m_value = 0; + m_category = &system_category(); + } + + //! Create an error code from an kstd::errc enumeration value. + [[nodiscard]] constexpr auto inline make_error_code(errc const value) noexcept -> error_code + { + return {static_cast<int>(value), generic_category()}; + } + + //! Create an error condition from an kstd::errc enumeration value. + [[nodiscard]] constexpr auto inline make_error_condition(errc const value) noexcept -> error_condition + { + return {static_cast<int>(value), generic_category()}; + } + + //! Enable formatting of kstd::error_code + //! + //! There are currently no valid format specifiers for error codes. + template<> + struct formatter<error_code> + { + constexpr auto parse(format_parse_context & context) -> format_parse_context::iterator + { + auto it = context.begin(); + if (it != context.end() && *it != '}') + { + bits::format::error("Invalid specifier for string_view."); + } + return it; + } + + auto format(error_code const & error, format_context & context) const -> void + { + context.push(error.category().name()); + context.push(':'); + formatter<int>{}.format(error.value(), context); + context.push(':'); + context.push(error.message()); + } + }; + +} // namespace kstd + +#endif diff --git a/libs/kstd/kstd/system_error.tests.cpp b/libs/kstd/kstd/system_error.tests.cpp new file mode 100644 index 00000000..59e11926 --- /dev/null +++ b/libs/kstd/kstd/system_error.tests.cpp @@ -0,0 +1,100 @@ +#include <kstd/system_error.hpp> + +#include <catch2/catch_test_macros.hpp> +#include <catch2/generators/catch_generators.hpp> + +SCENARIO("Error condition initialization and construction", "[kstd][system_error]") +{ + GIVEN("An empty context") + { + WHEN("constructing by default") + { + auto error = kstd::error_condition{}; + + THEN("the category is equal to generic_category") + { + REQUIRE(error.category() == kstd::generic_category()); + } + + THEN("the value is 0") + { + REQUIRE(error.value() == 0); + } + + THEN("conversion to bool yields false") + { + REQUIRE_FALSE(error); + } + } + } +} + +SCENARIO("Error code initialization and construction", "[kstd][system_error]") +{ + GIVEN("An empty context") + { + WHEN("constructing by default") + { + auto error = kstd::error_code{}; + + THEN("the category is equal to system_category") + { + REQUIRE(error.category() == kstd::system_category()); + } + + THEN("the value is 0") + { + REQUIRE(error.value() == 0); + } + + THEN("conversion to bool yields false") + { + REQUIRE_FALSE(error); + } + } + } +} + +SCENARIO("Error code messages", "[kstd][system_error]") +{ + GIVEN("An error code") + { + auto enumerator = GENERATE( + kstd::errc::address_family_not_supported, kstd::errc::address_in_use, kstd::errc::address_not_available, + kstd::errc::already_connected, kstd::errc::argument_list_too_long, kstd::errc::argument_out_of_domain, + kstd::errc::bad_address, kstd::errc::bad_file_descriptor, kstd::errc::bad_message, kstd::errc::broken_pipe, + kstd::errc::connection_aborted, kstd::errc::connection_already_in_progress, kstd::errc::connection_refused, + kstd::errc::connection_reset, kstd::errc::cross_device_link, kstd::errc::destination_address_required, + kstd::errc::device_or_resource_busy, kstd::errc::directory_not_empty, kstd::errc::executable_format_error, + kstd::errc::file_exists, kstd::errc::file_too_large, kstd::errc::filename_too_long, + kstd::errc::function_not_supported, kstd::errc::host_unreachable, kstd::errc::identifier_removed, + kstd::errc::illegal_byte_sequence, kstd::errc::inappropriate_io_control_operation, kstd::errc::interrupted, + kstd::errc::invalid_argument, kstd::errc::invalid_seek, kstd::errc::io_error, kstd::errc::is_a_directory, + kstd::errc::message_size, kstd::errc::network_down, kstd::errc::network_reset, kstd::errc::network_unreachable, + kstd::errc::no_buffer_space, kstd::errc::no_child_process, kstd::errc::no_link, kstd::errc::no_lock_available, + kstd::errc::no_message, kstd::errc::no_protocol_option, kstd::errc::no_space_on_device, + kstd::errc::no_such_device_or_address, kstd::errc::no_such_device, kstd::errc::no_such_file_or_directory, + kstd::errc::no_such_process, kstd::errc::not_a_directory, kstd::errc::not_a_socket, kstd::errc::not_connected, + kstd::errc::not_enough_memory, kstd::errc::not_supported, kstd::errc::operation_canceled, + kstd::errc::operation_in_progress, kstd::errc::operation_not_permitted, kstd::errc::operation_not_supported, + kstd::errc::operation_would_block, kstd::errc::owner_dead, kstd::errc::permission_denied, + kstd::errc::protocol_error, kstd::errc::protocol_not_supported, kstd::errc::read_only_file_system, + kstd::errc::resource_deadlock_would_occur, kstd::errc::resource_unavailable_try_again, + kstd::errc::result_out_of_range, kstd::errc::state_not_recoverable, kstd::errc::text_file_busy, + kstd::errc::timed_out, kstd::errc::too_many_files_open_in_system, kstd::errc::too_many_files_open, + kstd::errc::too_many_links, kstd::errc::too_many_symbolic_link_levels, kstd::errc::value_too_large, + kstd::errc::wrong_protocol_type); + + auto error = kstd::make_error_code(enumerator); + + WHEN("getting the message") + { + auto message = error.message(); + + THEN("the message is not 'unknown error'") + { + REQUIRE(message != "unknown error"); + } + } + } +} diff --git a/libs/kstd/kstd/test_support/os_panic.test.cpp b/libs/kstd/kstd/test_support/os_panic.tests.cpp index c30411aa..c30411aa 100644 --- a/libs/kstd/kstd/test_support/os_panic.test.cpp +++ b/libs/kstd/kstd/test_support/os_panic.tests.cpp diff --git a/libs/kstd/kstd/unikstd.h b/libs/kstd/kstd/unikstd.h deleted file mode 100644 index aa60be63..00000000 --- a/libs/kstd/kstd/unikstd.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef KSTD_UNIKSTD_HPP -#define KSTD_UNIKSTD_HPP - -#include <cstddef> -#include <type_traits> - -namespace kstd -{ - using ssize_t = std::make_signed_t<std::size_t>; -} // namespace kstd - -#endif
\ No newline at end of file diff --git a/libs/kstd/kstd/units b/libs/kstd/kstd/units.hpp index df5eb374..df5eb374 100644 --- a/libs/kstd/kstd/units +++ b/libs/kstd/kstd/units.hpp diff --git a/libs/kstd/kstd/vector b/libs/kstd/kstd/vector.hpp index 736b854d..d6ad232a 100644 --- a/libs/kstd/kstd/vector +++ b/libs/kstd/kstd/vector.hpp @@ -1,10 +1,10 @@ #ifndef KSTD_VECTOR_HPP #define KSTD_VECTOR_HPP -#include <kstd/allocator> +#include <kstd/allocator.hpp> #include <kstd/bits/concepts.hpp> #include <kstd/os/error.hpp> -#include <kstd/ranges> +#include <kstd/ranges.hpp> #include <algorithm> #include <concepts> @@ -107,6 +107,7 @@ namespace kstd //! @tparam ForwardIterator An iterator type used to describe the source range. //! @param first The start of the source range. //! @param last The end of the source range. + //! @param allocator The allocator to use in the vector. template<std::forward_iterator ForwardIterator> constexpr vector(ForwardIterator first, ForwardIterator last, allocator_type const & allocator = @@ -127,6 +128,7 @@ namespace kstd //! @tparam InputIterator An iterator type used to describe the source range. //! @param first The start of the source range. //! @param last The end of the source range. + //! @param allocator The allocator to use in the vector. template<std::input_iterator InputIterator> constexpr vector(InputIterator first, InputIterator last, allocator_type const & allocator = @@ -228,6 +230,7 @@ namespace kstd //! Construct a new vector and initialize it's content by copying all elements in the given initializer list. //! //! @param list The initializer list containing the source objects. + //! @param allocator The allocator to use in the vector. vector(std::initializer_list<value_type> list, allocator_type const & allocator = allocator_type{}) : vector{std::ranges::begin(list), std::ranges::end(list), allocator} {} @@ -639,6 +642,7 @@ namespace kstd //! Insert the element of a given range into the vector at a given position. //! + //! @param position The position where to insert the elements. //! @param range The source range to insert elements from. //! @tparam SourceRange A container compatible range type. template<typename SourceRange> diff --git a/libs/kstd/kstd/vector.test.cpp b/libs/kstd/kstd/vector.tests.cpp index 8bf8f79d..72c1127a 100644 --- a/libs/kstd/kstd/vector.test.cpp +++ b/libs/kstd/kstd/vector.tests.cpp @@ -1,6 +1,6 @@ -#include <kstd/vector> +#include <kstd/vector.hpp> -#include <kstd/ranges> +#include <kstd/ranges.hpp> #include <kstd/test_support/os_panic.hpp> #include <kstd/test_support/test_types.hpp> diff --git a/libs/multiboot2/multiboot2/information.hpp b/libs/multiboot2/multiboot2/information.hpp index f688fe5d..f12969e8 100644 --- a/libs/multiboot2/multiboot2/information.hpp +++ b/libs/multiboot2/multiboot2/information.hpp @@ -4,7 +4,7 @@ #include <elf/format.hpp> #include <elf/section_header.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <multiboot2/information/data.hpp> // IWYU pragma: export #include <multiboot2/information/iterator.hpp> // IWYU pragma: export diff --git a/libs/multiboot2/multiboot2/information/data.hpp b/libs/multiboot2/multiboot2/information/data.hpp index f39a6cb2..734bbc6f 100644 --- a/libs/multiboot2/multiboot2/information/data.hpp +++ b/libs/multiboot2/multiboot2/information/data.hpp @@ -3,7 +3,7 @@ // IWYU pragma: private, include <multiboot2/information.hpp> -#include <kstd/units> +#include <kstd/units.hpp> #include <multiboot2/constants/information_id.hpp> #include <multiboot2/constants/memory_type.hpp> |
