From ee64ca1014ee2bdf07bd5011f6aa9f77da104a4d Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sat, 4 Oct 2025 02:47:12 +0200 Subject: feat: kernel: new `kernel` process type, and usage of `explicit operator bool` feat: libSystem: minor tweaks. feat: indexer: important fixes in `RemoveFlag` Signed-off-by: Amlal El Mahrouss --- dev/kernel/FSKit/Ext2+IFS.h | 4 +- dev/kernel/KernelKit/CodeMgr.h | 3 +- dev/kernel/KernelKit/CoreProcessScheduler.h | 3 +- dev/kernel/KernelKit/KernelTaskScheduler.h | 4 +- dev/kernel/KernelKit/PECodeMgr.h | 77 ----------------------------- dev/kernel/KernelKit/UserProcessScheduler.h | 4 +- dev/kernel/amd64-desktop.make | 2 +- dev/kernel/src/FS/Ext2+FileMgr.cc | 16 +++--- dev/kernel/src/IndexableProperty.cc | 3 +- 9 files changed, 22 insertions(+), 94 deletions(-) delete mode 100644 dev/kernel/KernelKit/PECodeMgr.h (limited to 'dev/kernel') diff --git a/dev/kernel/FSKit/Ext2+IFS.h b/dev/kernel/FSKit/Ext2+IFS.h index 661c8d5f..72e01ecd 100644 --- a/dev/kernel/FSKit/Ext2+IFS.h +++ b/dev/kernel/FSKit/Ext2+IFS.h @@ -144,7 +144,7 @@ inline Kernel::ErrorOr ext2_load_inode(Ext2Context* ctx, Kernel::UInt * * Provides high-level interface for EXT2 filesystem operations */ -class Ext2FileSystemParser { +class Ext2FileSystemParser final { private: Ext2Context ctx; // Internal EXT2 context @@ -157,6 +157,8 @@ class Ext2FileSystemParser { */ explicit Ext2FileSystemParser(DriveTrait* drive); + NE_COPY_DELETE(Ext2FileSystemParser) + /* * Open a file or directory by path * diff --git a/dev/kernel/KernelKit/CodeMgr.h b/dev/kernel/KernelKit/CodeMgr.h index c733bc47..fc737a90 100644 --- a/dev/kernel/KernelKit/CodeMgr.h +++ b/dev/kernel/KernelKit/CodeMgr.h @@ -14,9 +14,10 @@ #pragma once +#ifdef __NE_USE_PEF__ #include -#include #include +#endif /// @file CodeMgr.h /// @brief Code Manager header file. diff --git a/dev/kernel/KernelKit/CoreProcessScheduler.h b/dev/kernel/KernelKit/CoreProcessScheduler.h index f40ffc81..49e9363e 100644 --- a/dev/kernel/KernelKit/CoreProcessScheduler.h +++ b/dev/kernel/KernelKit/CoreProcessScheduler.h @@ -147,7 +147,8 @@ enum class ProcessSubsystem : Int32 { kProcessSubsystemUser, kProcessSubsystemService, kProcessSubsystemDriver, - kProcessSubsystemCount = kProcessSubsystemDriver - kProcessSubsystemSecurity + 1, + kProcessSubsystemKernel, + kProcessSubsystemCount = kProcessSubsystemKernel - kProcessSubsystemSecurity + 1, kProcessSubsystemInvalid = 0xFFFFFFF, }; diff --git a/dev/kernel/KernelKit/KernelTaskScheduler.h b/dev/kernel/KernelKit/KernelTaskScheduler.h index ce0ff30d..1bc8975a 100644 --- a/dev/kernel/KernelKit/KernelTaskScheduler.h +++ b/dev/kernel/KernelKit/KernelTaskScheduler.h @@ -24,7 +24,7 @@ typedef ProcessID KID; class KERNEL_TASK final { public: Char Name[kSchedNameLen] = {"KERNEL_TASK"}; - ProcessSubsystem SubSystem{ProcessSubsystem::kProcessSubsystemDriver}; + ProcessSubsystem SubSystem{ProcessSubsystem::kProcessSubsystemKernel}; HAL::StackFramePtr StackFrame{nullptr}; UInt8* StackReserve{nullptr}; SizeT StackSize{kSchedMaxStackSz}; @@ -40,7 +40,7 @@ class KernelTaskHelper final { public: STATIC Bool Switch(HAL::StackFramePtr frame_ptr, ProcessID new_kid); STATIC Bool CanBeScheduled(const KERNEL_TASK& process); - STATIC ErrorOr TheCurrentKID(); + STATIC ErrorOr TheCurrentKID(); STATIC SizeT StartScheduling(); }; } // namespace Kernel \ No newline at end of file diff --git a/dev/kernel/KernelKit/PECodeMgr.h b/dev/kernel/KernelKit/PECodeMgr.h deleted file mode 100644 index 15c2b7ee..00000000 --- a/dev/kernel/KernelKit/PECodeMgr.h +++ /dev/null @@ -1,77 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - - File: PECodeMgr.h - Purpose: PE32+ Code Mgr and Dylib mgr. - - Revision History: - - 12/02/24: Added file (amlel) - -------------------------------------------- */ - -#pragma once - -//////////////////////////////////////////////////// - -// LAST REV: Mon Feb 12 13:52:01 CET 2024 - -//////////////////////////////////////////////////// - -#include -#include -#include -#include -#include - -#ifndef INC_PROCESS_SCHEDULER_H -#include -#endif - -#define kPeApplicationMime "application/vnd-portable-executable" - -namespace Kernel { -/// -/// \name PE32Loader -/// \brief PE32+ loader class. -/// -class PE32Loader : public LoaderInterface { - private: - explicit PE32Loader() = delete; - - public: - explicit PE32Loader(const VoidPtr blob); - explicit PE32Loader(const Char* path); - ~PE32Loader() override; - - public: - NE_COPY_DEFAULT(PE32Loader) - - public: - const Char* Path() override; - const Char* AsString() override; - const Char* MIME() override; - - public: - ErrorOr FindStart() override; - ErrorOr FindSymbol(const Char* name, Int32 kind) override; - ErrorOr GetBlob() override; - - public: - bool IsLoaded() noexcept; - - private: -#ifdef __FSKIT_INCLUDES_NEFS__ - OwnPtr> fFile; -#elif defined(__FSKIT_INCLUDES_HEFS__) - OwnPtr> fFile; -#else - OwnPtr> fFile; -#endif // __FSKIT_INCLUDES_NEFS__ - - Ref fPath; - VoidPtr fCachedBlob; - bool fBad; -}; -} // namespace Kernel \ No newline at end of file diff --git a/dev/kernel/KernelKit/UserProcessScheduler.h b/dev/kernel/KernelKit/UserProcessScheduler.h index e5b81f76..d106e511 100644 --- a/dev/kernel/KernelKit/UserProcessScheduler.h +++ b/dev/kernel/KernelKit/UserProcessScheduler.h @@ -86,7 +86,7 @@ class USER_PROCESS final { /***********************************************************************************/ //! @brief boolean operator, check status. /***********************************************************************************/ - operator bool(); + explicit operator bool(); /***********************************************************************************/ ///! @brief Crashes the app, exits with code ~0. @@ -192,7 +192,7 @@ class UserProcessScheduler final : public ISchedulable { NE_MOVE_DELETE(UserProcessScheduler) public: - operator bool(); + explicit operator bool(); bool operator!(); public: diff --git a/dev/kernel/amd64-desktop.make b/dev/kernel/amd64-desktop.make index bfcca16b..a3040c89 100644 --- a/dev/kernel/amd64-desktop.make +++ b/dev/kernel/amd64-desktop.make @@ -5,7 +5,7 @@ CXX = x86_64-w64-mingw32-g++ LD = x86_64-w64-mingw32-ld -CCFLAGS = -fshort-wchar -c -D__NE_AMD64__ -D__NE_VEPM__ -Wall -Wpedantic -Wextra -mno-red-zone -fno-rtti -fno-exceptions -std=c++20 -D__FSKIT_INCLUDES_HEFS__ -D__FSKIT_INCLUDES_EXT2__ -D__NE_SUPPORT_NX__ -O0 -I../vendor -D__NEOSKRNL__ -D__HAVE_NE_APIS__ -D__FREESTANDING__ -D__NE_VIRTUAL_MEMORY_SUPPORT__ -D__NE_AUTO_FORMAT__ -D__NE__ -I./ -I../ -I../boot +CCFLAGS = -fshort-wchar -c -D__NE_AMD64__ -D__NE_USE_PEF__ -D__NE_VEPM__ -Wall -Wpedantic -Wextra -mno-red-zone -fno-rtti -fno-exceptions -std=c++20 -D__FSKIT_INCLUDES_HEFS__ -D__FSKIT_INCLUDES_EXT2__ -D__NE_SUPPORT_NX__ -O0 -I../vendor -D__NEOSKRNL__ -D__HAVE_NE_APIS__ -D__FREESTANDING__ -D__NE_VIRTUAL_MEMORY_SUPPORT__ -D__NE_AUTO_FORMAT__ -D__NE__ -I./ -I../ -I../boot ASM = nasm diff --git a/dev/kernel/src/FS/Ext2+FileMgr.cc b/dev/kernel/src/FS/Ext2+FileMgr.cc index 7c28c0c9..c0c9c84e 100644 --- a/dev/kernel/src/FS/Ext2+FileMgr.cc +++ b/dev/kernel/src/FS/Ext2+FileMgr.cc @@ -17,14 +17,14 @@ #include #include -constexpr UInt32 EXT2_DIRECT_BLOCKS = 12; -constexpr UInt32 EXT2_SINGLE_INDIRECT_INDEX = 12; -constexpr UInt32 EXT2_DOUBLE_INDIRECT_INDEX = 13; -constexpr UInt32 EXT2_TRIPLE_INDIRECT_INDEX = 14; -constexpr UInt32 EXT2_ROOT_INODE = 2; -constexpr UInt32 EXT2_SUPERBLOCK_BLOCK = 1; -constexpr UInt32 EXT2_GROUP_DESC_BLOCK_SMALL = 2; -constexpr UInt32 EXT2_GROUP_DESC_BLOCK_LARGE = 1; +constexpr static UInt32 EXT2_DIRECT_BLOCKS = 12; +constexpr static UInt32 EXT2_SINGLE_INDIRECT_INDEX = 12; +constexpr static UInt32 EXT2_DOUBLE_INDIRECT_INDEX = 13; +constexpr ATTRIBUTE(unused) static UInt32 EXT2_TRIPLE_INDIRECT_INDEX = 14; +constexpr static UInt32 EXT2_ROOT_INODE = 2; +constexpr ATTRIBUTE(unused) static UInt32 EXT2_SUPERBLOCK_BLOCK = 1; +constexpr static UInt32 EXT2_GROUP_DESC_BLOCK_SMALL = 2; +constexpr static UInt32 EXT2_GROUP_DESC_BLOCK_LARGE = 1; static inline SizeT ext2_min(SizeT a, SizeT b) { return a < b ? a : b; diff --git a/dev/kernel/src/IndexableProperty.cc b/dev/kernel/src/IndexableProperty.cc index c11e328d..56143607 100644 --- a/dev/kernel/src/IndexableProperty.cc +++ b/dev/kernel/src/IndexableProperty.cc @@ -22,7 +22,7 @@ namespace Indexer { Void IndexableProperty::AddFlag(Int16 flag) { fFlags |= flag; } - Void IndexableProperty::RemoveFlag(Int16 flag) { fFlags &= flag; } + Void IndexableProperty::RemoveFlag(Int16 flag) { fFlags &= ~(flag); } Int16 IndexableProperty::HasFlag(Int16 flag) { return fFlags & flag; } @@ -33,6 +33,7 @@ namespace Indexer { /// @return none, check before if indexer can be claimed (using indexer.HasFlag(kIndexerClaimed)). Void fs_index_file(const Char* filename, SizeT filenameLen, IndexableProperty& indexer) { if (!indexer.HasFlag(kIndexerClaimed)) { + indexer.RemoveFlag(kIndexerUnclaimed); indexer.AddFlag(kIndexerClaimed); rt_copy_memory_safe(reinterpret_cast(const_cast(filename)), (VoidPtr) indexer.Leak().Path, filenameLen, kIndexerCatalogNameLength); -- cgit v1.2.3 From d8de88f25cfa7cc7a46ee8913ba1338f67aaeac5 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sat, 4 Oct 2025 02:55:38 +0200 Subject: feat: kernel: codebase improvements. Signed-off-by: Amlal El Mahrouss --- dev/kernel/NeKit/Defines.h | 4 ++-- dev/kernel/NeKit/ErrorOr.h | 4 ++-- dev/kernel/NeKit/Ref.h | 6 +++--- public/frameworks/CoreFoundation.fwrk/headers/Ref.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'dev/kernel') diff --git a/dev/kernel/NeKit/Defines.h b/dev/kernel/NeKit/Defines.h index 0f9a7c4a..27f4f127 100644 --- a/dev/kernel/NeKit/Defines.h +++ b/dev/kernel/NeKit/Defines.h @@ -8,8 +8,8 @@ #include -#define NEWKIT_VERSION_STR "0.0.1" -#define NEWKIT_VERSION_BCD 0x0001 +#define NEKIT_VERSION_STR "0.0.1" +#define NEKIT_VERSION_BCD 0x0001 #ifndef __cplusplus #error Kernel compiles with a C++ compiler. diff --git a/dev/kernel/NeKit/ErrorOr.h b/dev/kernel/NeKit/ErrorOr.h index e8b3b6fc..09f0cad5 100644 --- a/dev/kernel/NeKit/ErrorOr.h +++ b/dev/kernel/NeKit/ErrorOr.h @@ -13,7 +13,7 @@ #include namespace Kernel { -using ErrorT = UInt; +using ErrorT = UInt32; template class ErrorOr final { @@ -50,7 +50,7 @@ class ErrorOr final { private: Ref mRef; - Int32 mId{0}; + ErrorT mId{0}; }; using ErrorOrAny = ErrorOr; diff --git a/dev/kernel/NeKit/Ref.h b/dev/kernel/NeKit/Ref.h index a791ee1a..6f7eca21 100644 --- a/dev/kernel/NeKit/Ref.h +++ b/dev/kernel/NeKit/Ref.h @@ -5,8 +5,8 @@ ------------------------------------------- */ -#ifndef _NEWKIT_REF_H_ -#define _NEWKIT_REF_H_ +#ifndef _NEKIT_REF_H_ +#define _NEKIT_REF_H_ #include #include @@ -67,4 +67,4 @@ class NonNullRef final { }; } // namespace Kernel -#endif // ifndef _NEWKIT_REF_H_ +#endif // ifndef _NEKIT_REF_H_ diff --git a/public/frameworks/CoreFoundation.fwrk/headers/Ref.h b/public/frameworks/CoreFoundation.fwrk/headers/Ref.h index 87005db1..c8d1ba69 100644 --- a/public/frameworks/CoreFoundation.fwrk/headers/Ref.h +++ b/public/frameworks/CoreFoundation.fwrk/headers/Ref.h @@ -78,4 +78,4 @@ class CFNonNullRef final { }; } // namespace CF -#endif // ifndef _NEWKIT_REF_H_ +#endif // ifndef _NEKIT_REF_H_ -- cgit v1.2.3 From abff64f38c988a5350cbeb243896c0ee30401058 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sun, 5 Oct 2025 09:46:50 +0200 Subject: feat: launch: reworking launch program. feat: boot: Use NB prefix instead of CB. feat: kernel: Use more portable types. Signed-off-by: Amlal El Mahrouss --- compile_flags.txt | 2 +- dev/boot/src/HEL/ARM64/BootCB.S | 40 ---------------------------------------- dev/boot/src/HEL/ARM64/BootNB.S | 40 ++++++++++++++++++++++++++++++++++++++++ dev/boot/src/HEL/POWER/BootCB.S | 34 ---------------------------------- dev/boot/src/HEL/POWER/BootNB.S | 34 ++++++++++++++++++++++++++++++++++ dev/kernel/NeKit/Defines.h | 14 +++++++------- dev/launch/LaunchKit/LaunchKit.h | 4 ++-- dev/launch/src/LaunchSrv.cc | 2 +- 8 files changed, 85 insertions(+), 85 deletions(-) delete mode 100644 dev/boot/src/HEL/ARM64/BootCB.S create mode 100644 dev/boot/src/HEL/ARM64/BootNB.S delete mode 100644 dev/boot/src/HEL/POWER/BootCB.S create mode 100644 dev/boot/src/HEL/POWER/BootNB.S (limited to 'dev/kernel') diff --git a/compile_flags.txt b/compile_flags.txt index 8f006960..384cd84e 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -2,7 +2,7 @@ -Idev/ -Idev/user -Idev/boot --Idev/system_sdk +-Idev/launch -Idev/misc -Idev/ddk -Ipublic/tools diff --git a/dev/boot/src/HEL/ARM64/BootCB.S b/dev/boot/src/HEL/ARM64/BootCB.S deleted file mode 100644 index d52c1dcf..00000000 --- a/dev/boot/src/HEL/ARM64/BootCB.S +++ /dev/null @@ -1,40 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#ifdef __NE_NEBOOT__ - -.section .boot_hdr -.align 4 - -/* BootZ boot header begin */ - -boot_hdr_mag: - .ascii "CB" -boot_hdr_name: - // it has to match ten bytes. - .asciz "bootz\0\0\0" -boot_hdr_ver: - .word 0x101 -boot_hdr_proc: - .long bootloader_start - -/* BootZ boot header end */ - -.extern bootloader_main -.extern bootloader_stack - -.globl bootloader_start -bootloader_start: - adr x0, bootloader_stack - ldr x1, =bootloader_start - sub x0, x0, x1 - ldr x0, [x0] - mov sp, x0 - - bl bootloader_main - ret - -#endif // __NE_NEBOOT__ \ No newline at end of file diff --git a/dev/boot/src/HEL/ARM64/BootNB.S b/dev/boot/src/HEL/ARM64/BootNB.S new file mode 100644 index 00000000..d52c1dcf --- /dev/null +++ b/dev/boot/src/HEL/ARM64/BootNB.S @@ -0,0 +1,40 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __NE_NEBOOT__ + +.section .boot_hdr +.align 4 + +/* BootZ boot header begin */ + +boot_hdr_mag: + .ascii "CB" +boot_hdr_name: + // it has to match ten bytes. + .asciz "bootz\0\0\0" +boot_hdr_ver: + .word 0x101 +boot_hdr_proc: + .long bootloader_start + +/* BootZ boot header end */ + +.extern bootloader_main +.extern bootloader_stack + +.globl bootloader_start +bootloader_start: + adr x0, bootloader_stack + ldr x1, =bootloader_start + sub x0, x0, x1 + ldr x0, [x0] + mov sp, x0 + + bl bootloader_main + ret + +#endif // __NE_NEBOOT__ \ No newline at end of file diff --git a/dev/boot/src/HEL/POWER/BootCB.S b/dev/boot/src/HEL/POWER/BootCB.S deleted file mode 100644 index 3887ff10..00000000 --- a/dev/boot/src/HEL/POWER/BootCB.S +++ /dev/null @@ -1,34 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -.section .boot_hdr -.align 4 - -/* BootZ boot header begin */ - -boot_hdr_mag: - .ascii "CB" -boot_hdr_name: - // it has to match ten bytes. - .asciz "bootz\0\0\0" -boot_hdr_ver: - .word 0x101 -boot_hdr_proc: - .long bootloader_start - -/* BootZ boot header end */ - -.extern bootloader_main -.extern bootloader_stack - -.globl bootloader_start -bootloader_start: - mflr 4 /* real address of .Laddr */ - lwz 0,(bootloader_stack-bootloader_start)(4) /* stack address location */ - mr 1,0 /* use user defined stack */ - - bl bootloader_main - blr diff --git a/dev/boot/src/HEL/POWER/BootNB.S b/dev/boot/src/HEL/POWER/BootNB.S new file mode 100644 index 00000000..3887ff10 --- /dev/null +++ b/dev/boot/src/HEL/POWER/BootNB.S @@ -0,0 +1,34 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +.section .boot_hdr +.align 4 + +/* BootZ boot header begin */ + +boot_hdr_mag: + .ascii "CB" +boot_hdr_name: + // it has to match ten bytes. + .asciz "bootz\0\0\0" +boot_hdr_ver: + .word 0x101 +boot_hdr_proc: + .long bootloader_start + +/* BootZ boot header end */ + +.extern bootloader_main +.extern bootloader_stack + +.globl bootloader_start +bootloader_start: + mflr 4 /* real address of .Laddr */ + lwz 0,(bootloader_stack-bootloader_start)(4) /* stack address location */ + mr 1,0 /* use user defined stack */ + + bl bootloader_main + blr diff --git a/dev/kernel/NeKit/Defines.h b/dev/kernel/NeKit/Defines.h index 27f4f127..c5f02e0a 100644 --- a/dev/kernel/NeKit/Defines.h +++ b/dev/kernel/NeKit/Defines.h @@ -35,13 +35,13 @@ using nullPtr = decltype(nullptr); using NullPtr = decltype(nullptr); using Int = int; -using Int32 = int; -using UShort = unsigned short; -using UInt16 = unsigned short; +using Int32 = __INT32_TYPE__; +using UShort = __UINT16_TYPE__; +using UInt16 = __UINT16_TYPE__; using Short = short; using Int16 = short; -using UInt = unsigned int; -using UInt32 = unsigned int; +using UInt = __UINT32_TYPE__; +using UInt32 = __UINT32_TYPE__; using Long = __INT64_TYPE__; using Int64 = __INT64_TYPE__; using ULong = __UINT64_TYPE__; @@ -49,8 +49,8 @@ using UInt64 = __UINT64_TYPE__; using Boolean = bool; using Bool = bool; using Char = char; -using UChar = unsigned char; -using UInt8 = unsigned char; +using UChar = __UINT8_TYPE__; +using UInt8 = __UINT8_TYPE__; using SSize = Int64; using SSizeT = Int64; diff --git a/dev/launch/LaunchKit/LaunchKit.h b/dev/launch/LaunchKit/LaunchKit.h index 2fa9607b..2efa7806 100644 --- a/dev/launch/LaunchKit/LaunchKit.h +++ b/dev/launch/LaunchKit/LaunchKit.h @@ -15,6 +15,6 @@ #define NELAUNCH_WARN(MSG) PrintOut(nullptr, "WARN: [LAUNCH] %s\n", MSG) namespace Launch { -using LaunchHandle = VoidPtr; -using KernelStatus = SInt32; +using LaunchAny = VoidPtr; +using LaunchStatus = SInt32; } // namespace Launch diff --git a/dev/launch/src/LaunchSrv.cc b/dev/launch/src/LaunchSrv.cc index f5c9ee3c..b79fedf5 100644 --- a/dev/launch/src/LaunchSrv.cc +++ b/dev/launch/src/LaunchSrv.cc @@ -11,7 +11,7 @@ extern "C" SInt32 nelaunch_startup_fn(Void) { /// @todo Start LaunchServices.fwrk services, make the launcher manageable too (via mgmt.launch) - NELAUNCH_INFO("Starting NeKernel services..."); + NELAUNCH_INFO("Registering NeKernel Launcher..."); return kErrorSuccess; } -- cgit v1.2.3 From 3b6a7e8c87f94391f92b55f20b9ba3e560ef280e Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 7 Oct 2025 09:24:56 +0200 Subject: feat: kernel & libSystem: improvements and tweaks. feat: docs: wip design of Launch. Signed-off-by: Amlal El Mahrouss --- dev/kernel/CFKit/GUIDWizard.h | 10 +- dev/kernel/CFKit/GUIDWrapper.h | 6 +- dev/kernel/CFKit/Property.h | 8 +- dev/kernel/CFKit/Utils.h | 6 +- dev/kernel/FSKit/Ext2+IFS.h | 2 +- dev/kernel/FSKit/HeFS.h | 8 + dev/kernel/KernelKit/FileMgr.h | 4 +- dev/kernel/KernelKit/KernelTaskScheduler.h | 2 +- dev/kernel/KernelKit/UserProcessScheduler.h | 4 +- dev/kernel/NeKit/ErrorOr.h | 2 +- dev/kernel/NeKit/Pair.h | 38 + dev/kernel/src/FS/Ext2+FileMgr.cc | 1561 --------------------------- dev/kernel/src/FS/Ext2+FileSystemParser.cc | 21 - dev/kernel/src/FS/Ext2+IFS.cc | 1555 ++++++++++++++++++++++++++ dev/kernel/src/FS/HeFS+FileMgr.cc | 152 +++ dev/kernel/src/GUIDWizard.cc | 4 +- dev/kernel/src/GUIDWrapper.cc | 2 +- dev/kernel/src/PEFCodeMgr.cc | 54 +- dev/kernel/src/Property.cc | 4 +- dev/launch/LaunchKit/LaunchKit.h | 2 +- dev/libSystem/SystemKit/Verify.h | 2 +- docs/drawio/LAUNCH_DESIGN.drawio | 0 22 files changed, 1822 insertions(+), 1625 deletions(-) delete mode 100644 dev/kernel/src/FS/Ext2+FileMgr.cc delete mode 100644 dev/kernel/src/FS/Ext2+FileSystemParser.cc create mode 100644 dev/kernel/src/FS/Ext2+IFS.cc create mode 100644 docs/drawio/LAUNCH_DESIGN.drawio (limited to 'dev/kernel') diff --git a/dev/kernel/CFKit/GUIDWizard.h b/dev/kernel/CFKit/GUIDWizard.h index c7cb18ac..e2d9bcb1 100644 --- a/dev/kernel/CFKit/GUIDWizard.h +++ b/dev/kernel/CFKit/GUIDWizard.h @@ -15,9 +15,7 @@ #include #include -namespace CF::XRN::Version1 { -using namespace Kernel; - -Ref cf_make_sequence(const ArrayList& seq); -ErrorOr> cf_try_guid_to_string(Ref& guid); -} // namespace CF::XRN::Version1 +namespace Kernel::CF::XRN::Version1 { +Ref cf_make_sequence(const ArrayList& seq); +ErrorOr> cf_try_guid_to_string(Ref& guid); +} // namespace Kernel::CF::XRN::Version1 diff --git a/dev/kernel/CFKit/GUIDWrapper.h b/dev/kernel/CFKit/GUIDWrapper.h index a3920357..05cb4754 100644 --- a/dev/kernel/CFKit/GUIDWrapper.h +++ b/dev/kernel/CFKit/GUIDWrapper.h @@ -15,9 +15,7 @@ #define kXRNNil "@{........-....-M...-N...-............}" /// @brief eXtended Resource Namespace -namespace CF::XRN { -using namespace Kernel; - +namespace Kernel::CF::XRN { union GUIDSequence { alignas(8) UShort fU8[16]; alignas(8) UShort fU16[8]; @@ -48,4 +46,4 @@ class GUID final { private: GUIDSequence fUUID; }; -} // namespace CF::XRN +} // namespace Kernel::CF::XRN diff --git a/dev/kernel/CFKit/Property.h b/dev/kernel/CFKit/Property.h index 7fc9bf07..17246a63 100644 --- a/dev/kernel/CFKit/Property.h +++ b/dev/kernel/CFKit/Property.h @@ -15,9 +15,7 @@ #define kMaxPropLen (256U) -namespace CF { -using namespace Kernel; - +namespace Kernel::CF { /// @brief handle to anything (number, ptr, string...) using PropertyId = UIntPtr; @@ -44,10 +42,10 @@ class Property { template using PropertyArray = Array; -} // namespace CF +} // namespace Kernel::CF namespace Kernel { -using namespace CF; +using namespace Kernel::CF; } #endif // !CFKIT_PROPS_H diff --git a/dev/kernel/CFKit/Utils.h b/dev/kernel/CFKit/Utils.h index 97b0ee53..247ad5fb 100644 --- a/dev/kernel/CFKit/Utils.h +++ b/dev/kernel/CFKit/Utils.h @@ -5,9 +5,7 @@ #include /// @brief CFKit -namespace CF { -using namespace Kernel; - +namespace Kernel::CF { /// @brief Finds the PE header inside the blob. inline auto ldr_find_exec_header(DosHeaderPtr ptrDos) -> LDR_EXEC_HEADER_PTR { if (!ptrDos) return nullptr; @@ -45,6 +43,6 @@ inline auto ldr_find_exec_header(const Char* ptrDos) -> LDR_EXEC_HEADER_PTR { inline auto ldr_find_opt_exec_header(const Char* ptrDos) -> LDR_OPTIONAL_HEADER_PTR { return ldr_find_opt_exec_header((DosHeaderPtr) ptrDos); } -} // namespace CF +} // namespace Kernel::CF #endif // ifndef CFKIT_UTILS_H diff --git a/dev/kernel/FSKit/Ext2+IFS.h b/dev/kernel/FSKit/Ext2+IFS.h index 72e01ecd..44435a29 100644 --- a/dev/kernel/FSKit/Ext2+IFS.h +++ b/dev/kernel/FSKit/Ext2+IFS.h @@ -146,7 +146,7 @@ inline Kernel::ErrorOr ext2_load_inode(Ext2Context* ctx, Kernel::UInt */ class Ext2FileSystemParser final { private: - Ext2Context ctx; // Internal EXT2 context + Ext2Context fCtx; // Internal EXT2 context public: /* diff --git a/dev/kernel/FSKit/HeFS.h b/dev/kernel/FSKit/HeFS.h index 845ef467..51ec7648 100644 --- a/dev/kernel/FSKit/HeFS.h +++ b/dev/kernel/FSKit/HeFS.h @@ -32,6 +32,14 @@ #define kHeFSINDStartOffset (sizeof(HEFS_BOOT_NODE)) #define kHeFSINStartOffset (sizeof(HEFS_INDEX_NODE_DIRECTORY)) +#define kHeFSRootDirectory "/" +#define kHeFSRootDirectoryU8 u8"/" + +#define kHeFSSeparator '/' +#define kHeFSUpDir ".." + +#define kHeFSRootDirectoryLen (2U) + #define kHeFSSearchAllStr u8"*" struct HEFS_BOOT_NODE; diff --git a/dev/kernel/KernelKit/FileMgr.h b/dev/kernel/KernelKit/FileMgr.h index bad6cf85..cc2feeb8 100644 --- a/dev/kernel/KernelKit/FileMgr.h +++ b/dev/kernel/KernelKit/FileMgr.h @@ -298,7 +298,7 @@ class FileStream final { if (man) { man->Write(offset, fFile, data, len); - return ErrorOr(0); + return ErrorOr(kErrorSuccess); } return ErrorOr(kErrorInvalidData); @@ -317,7 +317,7 @@ class FileStream final { if (man) { man->Write(name, fFile, data, 0, len); - return ErrorOr(0); + return ErrorOr(kErrorSuccess); } return ErrorOr(kErrorInvalidData); diff --git a/dev/kernel/KernelKit/KernelTaskScheduler.h b/dev/kernel/KernelKit/KernelTaskScheduler.h index 1bc8975a..2029ae7b 100644 --- a/dev/kernel/KernelKit/KernelTaskScheduler.h +++ b/dev/kernel/KernelKit/KernelTaskScheduler.h @@ -41,6 +41,6 @@ class KernelTaskHelper final { STATIC Bool Switch(HAL::StackFramePtr frame_ptr, ProcessID new_kid); STATIC Bool CanBeScheduled(const KERNEL_TASK& process); STATIC ErrorOr TheCurrentKID(); - STATIC SizeT StartScheduling(); + STATIC SizeT StartScheduling(); }; } // namespace Kernel \ No newline at end of file diff --git a/dev/kernel/KernelKit/UserProcessScheduler.h b/dev/kernel/KernelKit/UserProcessScheduler.h index d106e511..2cf65fe0 100644 --- a/dev/kernel/KernelKit/UserProcessScheduler.h +++ b/dev/kernel/KernelKit/UserProcessScheduler.h @@ -192,8 +192,8 @@ class UserProcessScheduler final : public ISchedulable { NE_MOVE_DELETE(UserProcessScheduler) public: - explicit operator bool(); - bool operator!(); + explicit operator bool(); + bool operator!(); public: UserProcessTeam& TheCurrentTeam(); diff --git a/dev/kernel/NeKit/ErrorOr.h b/dev/kernel/NeKit/ErrorOr.h index 09f0cad5..3351c65d 100644 --- a/dev/kernel/NeKit/ErrorOr.h +++ b/dev/kernel/NeKit/ErrorOr.h @@ -50,7 +50,7 @@ class ErrorOr final { private: Ref mRef; - ErrorT mId{0}; + ErrorT mId{0}; }; using ErrorOrAny = ErrorOr; diff --git a/dev/kernel/NeKit/Pair.h b/dev/kernel/NeKit/Pair.h index aeeeb8a2..61668f5a 100644 --- a/dev/kernel/NeKit/Pair.h +++ b/dev/kernel/NeKit/Pair.h @@ -6,8 +6,46 @@ #pragma once +#include #include +#include namespace Kernel { +template class Pair; + +class PairBuilder; + +template +class Pair final { + T1 fFirst{nullptr}; + T2 fSecond{nullptr}; + + friend PairBuilder; + + public: + explicit Pair() = default; + ~Pair() = default; + + NE_COPY_DEFAULT(Pair) + + T1& First() { return fFirst; } + T2& Second() { return fSecond; } + + const T1& First() const { return *fFirst; } + const T2& Second() const { return *fSecond; } + + private: + Pair(T1 first, T2 second) : fFirst(first), fSecond(second) {} +}; + +class PairBuilder final { + template + STATIC Pair Construct(T1 first, T2 second) { + return Pair(first, second); + } +}; + +template +using PairOr = ErrorOr>; } // namespace Kernel diff --git a/dev/kernel/src/FS/Ext2+FileMgr.cc b/dev/kernel/src/FS/Ext2+FileMgr.cc deleted file mode 100644 index c0c9c84e..00000000 --- a/dev/kernel/src/FS/Ext2+FileMgr.cc +++ /dev/null @@ -1,1561 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#ifndef __NE_MINIMAL_OS__ -#ifdef __FSKIT_INCLUDES_EXT2__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -constexpr static UInt32 EXT2_DIRECT_BLOCKS = 12; -constexpr static UInt32 EXT2_SINGLE_INDIRECT_INDEX = 12; -constexpr static UInt32 EXT2_DOUBLE_INDIRECT_INDEX = 13; -constexpr ATTRIBUTE(unused) static UInt32 EXT2_TRIPLE_INDIRECT_INDEX = 14; -constexpr static UInt32 EXT2_ROOT_INODE = 2; -constexpr ATTRIBUTE(unused) static UInt32 EXT2_SUPERBLOCK_BLOCK = 1; -constexpr static UInt32 EXT2_GROUP_DESC_BLOCK_SMALL = 2; -constexpr static UInt32 EXT2_GROUP_DESC_BLOCK_LARGE = 1; - -static inline SizeT ext2_min(SizeT a, SizeT b) { - return a < b ? a : b; -} - -struct Ext2GroupInfo { - EXT2_GROUP_DESCRIPTOR* groupDesc; - UInt32 groupDescriptorBlock; - UInt32 offsetInGroupDescBlock; - UInt8* blockBuffer; -}; - -// Convert EXT2 block number -> LBA (sector index) for Drive I/O. -static inline UInt32 ext2_block_to_lba(Ext2Context* ctx, - UInt32 blockNumber) { - if (!ctx || !ctx->drive) return 0; - UInt32 blockSize = ctx->BlockSize(); - UInt32 sectorSize = ctx->drive->fSectorSz; - UInt32 sectorsPerBlock = blockSize / sectorSize; - return blockNumber * sectorsPerBlock; -} - -// Read a block and return a pointer to its content -static ErrorOr ext2_read_block_ptr(Ext2Context* ctx, - UInt32 blockNumber) { - if (!ctx || !ctx->drive || !ctx->superblock) - return ErrorOr(kErrorInvalidData); - - UInt32 blockSize = ctx->BlockSize(); - auto buf = (UInt32*) mm_alloc_ptr(blockSize, true, false); - if (!buf) return ErrorOr(kErrorHeapOutOfMemory); - - UInt32 lba = ext2_block_to_lba(ctx, blockNumber); - if (!ext2_read_block(ctx->drive, lba, buf, blockSize)) { - mm_free_ptr(buf); - return ErrorOr(kErrorDisk); - } - return ErrorOr(buf); -} - -// Get the block address for a given logical block index -static ErrorOr ext2_get_block_address(Ext2Context* ctx, Ext2Node* node, - UInt32 logicalIndex) { - if (!ctx || !node || !ctx->drive) return ErrorOr(kErrorInvalidData); - - UInt32 blockSize = ctx->BlockSize(); - UInt32 pointersPerBlock = blockSize / sizeof(UInt32); - - // Direct blocks - if (logicalIndex < EXT2_DIRECT_BLOCKS) { - UInt32 bn = node->inode.fBlock[logicalIndex]; - if (bn == 0) return ErrorOr(kErrorInvalidData); - return ErrorOr(bn); - } - - // Single indirect blocks - if (logicalIndex < (EXT2_DIRECT_BLOCKS + pointersPerBlock)) { - UInt32 iblock = node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX]; - if (iblock == 0) return ErrorOr(kErrorInvalidData); - - auto res = ext2_read_block_ptr(ctx, iblock); - if (!res) return ErrorOr(res.Error()); - - // Using dereference operator - UInt32* ptr = *res.Leak(); // operator* returns T (UInt32*) - - UInt32 val = ptr[logicalIndex - EXT2_DIRECT_BLOCKS]; - mm_free_ptr(ptr); - - if (val == 0) return ErrorOr(kErrorInvalidData); - return ErrorOr(val); - } - - // Double indirect blocks - UInt32 doubleStart = EXT2_DIRECT_BLOCKS + pointersPerBlock; - UInt32 doubleSpan = pointersPerBlock * pointersPerBlock; - if (logicalIndex < (doubleStart + doubleSpan)) { - UInt32 db = node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX]; - if (db == 0) return ErrorOr(kErrorInvalidData); - - auto dblRes = ext2_read_block_ptr(ctx, db); - if (!dblRes) return ErrorOr(dblRes.Error()); - - UInt32* dblPtr = *dblRes.Leak(); - - UInt32 idxWithin = logicalIndex - doubleStart; - UInt32 firstIdx = idxWithin / pointersPerBlock; - UInt32 secondIdx = idxWithin % pointersPerBlock; - UInt32 singleBlockNum = dblPtr[firstIdx]; - - mm_free_ptr(dblPtr); - if (singleBlockNum == 0) return ErrorOr(kErrorInvalidData); - - auto singleRes = ext2_read_block_ptr(ctx, singleBlockNum); - if (!singleRes) return ErrorOr(singleRes.Error()); - - UInt32* singlePtr = *singleRes.Leak(); - UInt32 val = singlePtr[secondIdx]; - mm_free_ptr(singlePtr); - - if (val == 0) return ErrorOr(kErrorInvalidData); - return ErrorOr(val); - } - - return ErrorOr(kErrorUnimplemented); -} - -static ErrorOr ext2_read_inode_data(Ext2Context* ctx, Ext2Node* node, - SizeT size) { - if (!ctx || !ctx->drive || !node || size == 0) return ErrorOr(1); - - auto blockSize = ctx->BlockSize(); - SizeT available = (node->inode.fSize > node->cursor) ? (node->inode.fSize - node->cursor) : 0; - SizeT bytesToRead = (size < available) ? size : available; - if (bytesToRead == 0) return ErrorOr(2); // nothing to read - - auto buffer = mm_alloc_ptr(bytesToRead, true, false); - if (!buffer) return ErrorOr(3); // allocation failed - - UInt32 currentOffset = node->cursor; - SizeT remaining = bytesToRead; - UInt8* dest = reinterpret_cast(buffer); - - while (remaining > 0) { - UInt32 logicalIndex = currentOffset / blockSize; - UInt32 offsetInBlock = currentOffset % blockSize; - - auto phys = ext2_get_block_address(ctx, node, logicalIndex); - if (phys.HasError()) { - mm_free_ptr(buffer); - return ErrorOr(phys.Error()); - } - - auto blockNumber = phys.Value(); - UInt32 lba = ext2_block_to_lba(ctx, blockNumber); - - auto blockBuf = mm_alloc_ptr(blockSize, true, false); - if (!blockBuf) { - mm_free_ptr(buffer); - return ErrorOr(4); // block buffer allocation failed - } - - if (!ext2_read_block(ctx->drive, lba, blockBuf, blockSize)) { - mm_free_ptr(blockBuf); - mm_free_ptr(buffer); - return ErrorOr(5); // block read failed - } - - SizeT chunk = ext2_min(remaining, blockSize - offsetInBlock); - rt_copy_memory_safe(static_cast(static_cast(blockBuf) + offsetInBlock), - static_cast(dest), chunk, chunk); - - mm_free_ptr(blockBuf); - - currentOffset += static_cast(chunk); - dest += chunk; - remaining -= chunk; - } - - node->cursor += static_cast(bytesToRead); - return ErrorOr(buffer); -} - -// Get group descriptor information for a given block/inode number -static ErrorOr ext2_get_group_descriptor_info(Ext2Context* ctx, - UInt32 targetBlockOrInode) { - if (!ctx || !ctx->superblock || !ctx->drive) return ErrorOr(kErrorInvalidData); - - UInt32 blockSize = ctx->BlockSize(); - UInt32 blocksPerGroup = ctx->superblock->fBlocksPerGroup; - UInt32 inodesPerGroup = ctx->superblock->fInodesPerGroup; - UInt32 totalBlocks = ctx->superblock->fBlockCount; - UInt32 totalInodes = ctx->superblock->fInodeCount; - - if (blocksPerGroup == 0 || inodesPerGroup == 0) return ErrorOr(kErrorInvalidData); - - // block group index - UInt32 groupIndex = 0; - if (targetBlockOrInode == 0) { - groupIndex = 0; - } else if (targetBlockOrInode <= totalInodes) { - // 1-based - groupIndex = (targetBlockOrInode - 1) / inodesPerGroup; - } else { - // EXT2 block number - if (targetBlockOrInode < ctx->superblock->fFirstDataBlock) { - groupIndex = 0; - } else { - groupIndex = (targetBlockOrInode - ctx->superblock->fFirstDataBlock) / blocksPerGroup; - } - } - - // Calculate number of block groups - UInt32 groupsCount = static_cast((totalBlocks + blocksPerGroup - 1) / blocksPerGroup); - if (groupIndex >= groupsCount) return ErrorOr(kErrorInvalidData); - - // Determine GDT start block - UInt32 gdtStartBlock = - (blockSize == 1024) ? EXT2_GROUP_DESC_BLOCK_SMALL : EXT2_GROUP_DESC_BLOCK_LARGE; - - // Compute byte offset of descriptor within the GDT - const UInt32 descSize = sizeof(EXT2_GROUP_DESCRIPTOR); - UInt64 descByteOffset = static_cast(groupIndex) * descSize; - - // Which EXT2 block contains that descriptor? - UInt32 blockOffsetWithinGdt = static_cast(descByteOffset / blockSize); - UInt32 offsetInGroupDescBlock = static_cast(descByteOffset % blockSize); - UInt32 groupDescriptorBlock = gdtStartBlock + blockOffsetWithinGdt; - - // Allocate buffer and read the block containing the descriptor - auto blockBuffer = mm_alloc_ptr(blockSize, true, false); - if (!blockBuffer) return ErrorOr(kErrorHeapOutOfMemory); - - UInt32 groupDescriptorLba = ext2_block_to_lba(ctx, groupDescriptorBlock); - if (!ext2_read_block(ctx->drive, groupDescriptorLba, blockBuffer, blockSize)) { - mm_free_ptr(blockBuffer); - return ErrorOr(kErrorDisk); - } - - auto groupInfo = (Ext2GroupInfo*) mm_alloc_ptr(sizeof(Ext2GroupInfo), true, false); - if (!groupInfo) { - mm_free_ptr(blockBuffer); - return ErrorOr(kErrorHeapOutOfMemory); - } - - groupInfo->groupDesc = reinterpret_cast( - reinterpret_cast(blockBuffer) + offsetInGroupDescBlock); - groupInfo->groupDescriptorBlock = groupDescriptorBlock; - groupInfo->offsetInGroupDescBlock = offsetInGroupDescBlock; - groupInfo->blockBuffer = reinterpret_cast(blockBuffer); - - return ErrorOr(groupInfo); -} - -// Allocate a new block -inline ErrorOr ext2_alloc_block(Ext2Context* ctx, - EXT2_GROUP_DESCRIPTOR* groupDesc) { - if (!ctx || !ctx->superblock || !groupDesc) return ErrorOr(kErrorInvalidData); - - UInt32 blockSize = ctx->BlockSize(); - - // for the bitmap - auto bitmap = mm_alloc_ptr(blockSize, true, false); - if (!bitmap) return ErrorOr(kErrorHeapOutOfMemory); - - // Read block bitmap - if (!ext2_read_block(ctx->drive, groupDesc->fBlockBitmap, bitmap, blockSize)) { - mm_free_ptr(bitmap); - return ErrorOr(kErrorDisk); - } - - // bit = 0 - for (UInt32 byteIdx = 0; byteIdx < blockSize; ++byteIdx) { - auto byte = reinterpret_cast(bitmap)[byteIdx]; - if (byte != 0xFF) { - for (int bit = 0; bit < 8; ++bit) { - if (!(byte & (1 << bit))) { - // Mark bit as used - reinterpret_cast(bitmap)[byteIdx] |= (1 << bit); - - // Compute block number - UInt32 blockNumber = byteIdx * 8 + bit; - - // Write bitmap back - if (!ext2_write_block(ctx->drive, groupDesc->fBlockBitmap, bitmap, blockSize)) { - mm_free_ptr(bitmap); - return ErrorOr(kErrorDisk); - } - - // Update group descriptor free count - groupDesc->fFreeBlocksCount--; - mm_free_ptr(bitmap); - return ErrorOr(blockNumber); - } - } - } - } - - mm_free_ptr(bitmap); - return ErrorOr(kErrorDiskIsFull); -} - -// Indirect blocks -static ErrorOr ext2_set_block_address(Ext2Context* ctx, - Ext2Node* node, - UInt32 logicalBlockIndex, - UInt32 physicalBlockNumber) { - using namespace Kernel; - - if (!ctx || !ctx->drive || !node) return ErrorOr(kErrorInvalidData); - - auto blockSize = ctx->BlockSize(); - UInt32 blocksPerPointerBlock = blockSize / sizeof(UInt32); - - // Direct blocks - if (logicalBlockIndex < EXT2_DIRECT_BLOCKS) { - node->inode.fBlock[logicalBlockIndex] = physicalBlockNumber; - return ErrorOr(nullptr); - } - - // Single indirect blocks - if (logicalBlockIndex < EXT2_DIRECT_BLOCKS + blocksPerPointerBlock) { - if (node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX] == 0) { - auto groupInfoRes = ext2_get_group_descriptor_info(ctx, node->inodeNumber); - if (groupInfoRes.HasError()) return ErrorOr(groupInfoRes.Error()); - - auto groupInfo = groupInfoRes.Leak().Leak(); // Ref - auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc); - if (newBlockRes.HasError()) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return ErrorOr(newBlockRes.Error()); - } - - node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX] = newBlockRes.Leak(); - - UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock); - if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - - // Zero out new indirect block - auto zeroBuf = mm_alloc_ptr(blockSize, true, false); - if (!zeroBuf) return ErrorOr(kErrorHeapOutOfMemory); - - rt_zero_memory(zeroBuf, blockSize); - UInt32 indirectLba = ext2_block_to_lba(ctx, node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX]); - if (!ext2_write_block(ctx->drive, indirectLba, zeroBuf, blockSize)) { - mm_free_ptr(zeroBuf); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(zeroBuf); - } - - // Read, modify, and write single indirect block - auto indirectRes = ext2_read_block_ptr(ctx, node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX]); - if (indirectRes.HasError()) return ErrorOr(indirectRes.Error()); - - UInt32* indirectPtr = indirectRes.Leak().Leak(); // Ref - indirectPtr[logicalBlockIndex - EXT2_DIRECT_BLOCKS] = physicalBlockNumber; - - UInt32 indirectLba = ext2_block_to_lba(ctx, node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX]); - if (!ext2_write_block(ctx->drive, indirectLba, indirectPtr, blockSize)) { - mm_free_ptr(indirectPtr); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(indirectPtr); - return ErrorOr(nullptr); - } - - // Double - UInt32 doubleStart = EXT2_DIRECT_BLOCKS + blocksPerPointerBlock; - UInt32 doubleSpan = blocksPerPointerBlock * blocksPerPointerBlock; - if (logicalBlockIndex < doubleStart + doubleSpan) { - if (node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX] == 0) { - auto groupInfoRes = ext2_get_group_descriptor_info(ctx, node->inodeNumber); - if (groupInfoRes.HasError()) return ErrorOr(groupInfoRes.Error()); - - auto groupInfo = groupInfoRes.Leak().Leak(); - auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc); - if (newBlockRes.HasError()) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return ErrorOr(newBlockRes.Error()); - } - - node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX] = newBlockRes.Leak(); - - UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock); - if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - - // Zero new double-indirect block - auto zeroBuf = mm_alloc_ptr(blockSize, true, false); - if (!zeroBuf) return ErrorOr(kErrorHeapOutOfMemory); - - rt_zero_memory(zeroBuf, blockSize); - UInt32 dblLba = ext2_block_to_lba(ctx, node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX]); - if (!ext2_write_block(ctx->drive, dblLba, zeroBuf, blockSize)) { - mm_free_ptr(zeroBuf); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(zeroBuf); - } - - // Compute indices - UInt32 idxWithin = logicalBlockIndex - doubleStart; - UInt32 firstIdx = idxWithin / blocksPerPointerBlock; - UInt32 secondIdx = idxWithin % blocksPerPointerBlock; - - auto doubleRes = ext2_read_block_ptr(ctx, node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX]); - if (doubleRes.HasError()) return ErrorOr(doubleRes.Error()); - - UInt32* doublePtr = doubleRes.Leak().Leak(); - UInt32 singleIndirectBlock = doublePtr[firstIdx]; - - // Allocate single-indirect if missing - if (singleIndirectBlock == 0) { - auto groupInfoRes = ext2_get_group_descriptor_info(ctx, node->inodeNumber); - if (groupInfoRes.HasError()) { - mm_free_ptr(doublePtr); - return ErrorOr(groupInfoRes.Error()); - } - - auto groupInfo = groupInfoRes.Leak().Leak(); - auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc); - if (newBlockRes.HasError()) { - mm_free_ptr(doublePtr); - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return ErrorOr(newBlockRes.Error()); - } - - singleIndirectBlock = newBlockRes.Leak(); - doublePtr[firstIdx] = singleIndirectBlock; - - // Write back GDT - UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock); - if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) { - mm_free_ptr(doublePtr); - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - - // Zero single-indirect block - auto zeroBuf = mm_alloc_ptr(blockSize, true, false); - if (!zeroBuf) { - mm_free_ptr(doublePtr); - return ErrorOr(kErrorHeapOutOfMemory); - } - - rt_zero_memory(zeroBuf, blockSize); - UInt32 singleLba = ext2_block_to_lba(ctx, singleIndirectBlock); - if (!ext2_write_block(ctx->drive, singleLba, zeroBuf, blockSize)) { - mm_free_ptr(zeroBuf); - mm_free_ptr(doublePtr); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(zeroBuf); - - // Write double-indirect back to disk - UInt32 dblLba = ext2_block_to_lba(ctx, node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX]); - if (!ext2_write_block(ctx->drive, dblLba, doublePtr, blockSize)) { - mm_free_ptr(doublePtr); - return ErrorOr(kErrorDisk); - } - } - - mm_free_ptr(doublePtr); - - // Write to single-indirect block - auto singleRes = ext2_read_block_ptr(ctx, singleIndirectBlock); - if (singleRes.HasError()) return ErrorOr(singleRes.Error()); - - UInt32* singlePtr = singleRes.Leak().Leak(); - singlePtr[secondIdx] = physicalBlockNumber; - - UInt32 singleLba = ext2_block_to_lba(ctx, singleIndirectBlock); - if (!ext2_write_block(ctx->drive, singleLba, singlePtr, blockSize)) { - mm_free_ptr(singlePtr); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(singlePtr); - return ErrorOr(nullptr); - } - - // Triple indirect blocks not implemented - return ErrorOr(kErrorUnimplemented); -} - -// Find a directory entry by name within a directory inode -static ErrorOr ext2_find_dir_entry(Ext2Context* ctx, Ext2Node* dirNode, - const char* name) { - if (!ctx || !ctx->drive || !dirNode || !name) - return ErrorOr(kErrorInvalidData); - - // Check directory type - auto type = (dirNode->inode.fMode >> 12) & 0xF; - if (type != kExt2FileTypeDirectory) return ErrorOr(kErrorInvalidData); - - UInt32 blockSize = ctx->BlockSize(); - auto blockBuf = mm_alloc_ptr(blockSize, true, false); - if (!blockBuf) return ErrorOr(kErrorHeapOutOfMemory); - - SizeT nameLen = rt_string_len(name); - for (UInt32 i = 0; i < EXT2_DIRECT_BLOCKS; ++i) { - UInt32 blockNum = dirNode->inode.fBlock[i]; - if (blockNum == 0) continue; - - UInt32 lba = ext2_block_to_lba(ctx, blockNum); - if (!ext2_read_block(ctx->drive, lba, blockBuf, blockSize)) { - mm_free_ptr(blockBuf); - return ErrorOr(kErrorDisk); - } - - UInt32 offset = 0; - while (offset + sizeof(UInt32) + sizeof(UInt16) <= blockSize) { - auto onDiskEntry = reinterpret_cast((UInt8*) blockBuf + offset); - if (onDiskEntry->fRecordLength == 0) break; // corrupted - - if (onDiskEntry->fInode != 0 && onDiskEntry->fNameLength == nameLen) { - // Compare names - if (rt_string_cmp(name, onDiskEntry->fName, nameLen) == 0) { - // Allocate a result sized to hold the name + metadata - SizeT recSize = sizeof(EXT2_DIR_ENTRY); - auto found = (EXT2_DIR_ENTRY*) mm_alloc_ptr(recSize, true, false); - if (!found) { - mm_free_ptr(blockBuf); - return ErrorOr(kErrorHeapOutOfMemory); - } - - // Copy only record-length bytes - rt_copy_memory_safe(onDiskEntry, found, onDiskEntry->fRecordLength, recSize); - mm_free_ptr(blockBuf); - return ErrorOr(found); - } - } - offset += onDiskEntry->fRecordLength; - } - } - - mm_free_ptr(blockBuf); - return ErrorOr(kErrorFileNotFound); -} - -// Compute ideal record length for a directory name -static inline UInt16 ext2_dir_entry_ideal_len(UInt8 nameLen) { - UInt16 raw = - static_cast(8 + nameLen); // 8 = inode(4)+rec_len(2)+name_len(1)+file_type(1) - return static_cast((raw + 3) & ~3u); // align up to 4 -} - -static ErrorOr ext2_add_dir_entry(Ext2Context* ctx, Ext2Node* parentDirNode, - const char* name, UInt32 inodeNumber, - UInt8 fileType) { - using namespace Kernel; - - if (!ctx || !ctx->drive || !parentDirNode || !name) return ErrorOr(kErrorInvalidData); - - UInt32 blockSize = ctx->BlockSize(); - SizeT nameLen = rt_string_len(name); - if (nameLen == 0 || nameLen > 255) return ErrorOr(kErrorInvalidData); - - UInt16 newRecIdeal = ext2_dir_entry_ideal_len(static_cast(nameLen)); - - auto blockBuf = mm_alloc_ptr(blockSize, true, false); - if (!blockBuf) return ErrorOr(kErrorHeapOutOfMemory); - - for (UInt32 bi = 0; bi < EXT2_DIRECT_BLOCKS; ++bi) { - UInt32 blockNum = parentDirNode->inode.fBlock[bi]; - - if (blockNum == 0) { - // Allocate new block - auto groupInfoRes = ext2_get_group_descriptor_info(ctx, parentDirNode->inodeNumber); - if (!groupInfoRes) { - mm_free_ptr(blockBuf); - return ErrorOr(groupInfoRes.Error()); - } - - auto groupInfo = *groupInfoRes.Leak(); // Dereference to get Ext2GroupInfo* - auto allocBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc); - if (!allocBlockRes) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - mm_free_ptr(blockBuf); - return ErrorOr(allocBlockRes.Error()); - } - - UInt32 newBlock = *allocBlockRes.Leak(); // Dereference to get UInt32 - UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock); - - if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - mm_free_ptr(blockBuf); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - - // Zero block & insert entry - rt_zero_memory(blockBuf, blockSize); - auto entry = reinterpret_cast(blockBuf); - entry->fInode = inodeNumber; - entry->fNameLength = static_cast(nameLen); - entry->fFileType = fileType; - entry->fRecordLength = static_cast(blockSize); - rt_copy_memory_safe(const_cast(name), entry->fName, nameLen, blockSize); - - UInt32 blockLba = ext2_block_to_lba(ctx, newBlock); - if (!ext2_write_block(ctx->drive, blockLba, blockBuf, blockSize)) { - mm_free_ptr(blockBuf); - return ErrorOr(kErrorDisk); - } - - auto setRes = ext2_set_block_address(ctx, parentDirNode, bi, newBlock); - if (!setRes) { - mm_free_ptr(blockBuf); - return ErrorOr(setRes.Error()); - } - - mm_free_ptr(blockBuf); - return ErrorOr(nullptr); - } - - // read it - UInt32 blockLba = ext2_block_to_lba(ctx, blockNum); - if (!ext2_read_block(ctx->drive, blockLba, blockBuf, blockSize)) { - mm_free_ptr(blockBuf); - return ErrorOr(kErrorDisk); - } - - UInt32 offset = 0; - EXT2_DIR_ENTRY* lastEntry = nullptr; - UInt32 lastOffset = 0; - - while (offset < blockSize) { - if (offset + 8 > blockSize) break; - auto e = reinterpret_cast((UInt8*) blockBuf + offset); - if (e->fRecordLength == 0) break; - lastEntry = e; - lastOffset = offset; - offset += e->fRecordLength; - } - - if (!lastEntry) continue; - - UInt16 lastIdeal = ext2_dir_entry_ideal_len(lastEntry->fNameLength); - - if (lastEntry->fRecordLength >= (UInt16) (lastIdeal + newRecIdeal)) { - UInt16 origRec = lastEntry->fRecordLength; - lastEntry->fRecordLength = lastIdeal; - - UInt32 newOffset = lastOffset + lastIdeal; - auto newEntry = reinterpret_cast((UInt8*) blockBuf + newOffset); - newEntry->fInode = inodeNumber; - newEntry->fNameLength = static_cast(nameLen); - newEntry->fFileType = fileType; - newEntry->fRecordLength = static_cast(origRec - lastIdeal); - rt_copy_memory_safe(const_cast(name), newEntry->fName, nameLen, - newEntry->fRecordLength); - - if (!ext2_write_block(ctx->drive, blockLba, blockBuf, blockSize)) { - mm_free_ptr(blockBuf); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(blockBuf); - return ErrorOr(nullptr); - } - } - - // No space in direct blocks -> allocate new block - int targetIndex = -1; - for (UInt32 i = 0; i < EXT2_DIRECT_BLOCKS; ++i) { - if (parentDirNode->inode.fBlock[i] == 0) { - targetIndex = i; - break; - } - } - if (targetIndex == -1) { - mm_free_ptr(blockBuf); - return ErrorOr(kErrorUnimplemented); - } - - auto groupInfoResult = ext2_get_group_descriptor_info(ctx, parentDirNode->inodeNumber); - if (!groupInfoResult) { - mm_free_ptr(blockBuf); - return ErrorOr(groupInfoResult.Error()); - } - - auto groupInfo = *groupInfoResult.Leak(); // Dereference to get Ext2GroupInfo* - auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc); - if (!newBlockRes) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - mm_free_ptr(blockBuf); - return ErrorOr(newBlockRes.Error()); - } - - UInt32 newBlockNum = *newBlockRes.Leak(); // Dereference to get UInt32 - UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock); - if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - mm_free_ptr(blockBuf); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - - rt_zero_memory(blockBuf, blockSize); - auto entry = reinterpret_cast(blockBuf); - entry->fInode = inodeNumber; - entry->fNameLength = static_cast(nameLen); - entry->fFileType = fileType; - entry->fRecordLength = static_cast(blockSize); - rt_copy_memory_safe(const_cast(name), entry->fName, nameLen, blockSize); - - UInt32 newBlockLba = ext2_block_to_lba(ctx, newBlockNum); - if (!ext2_write_block(ctx->drive, newBlockLba, blockBuf, blockSize)) { - mm_free_ptr(blockBuf); - return ErrorOr(kErrorDisk); - } - - auto setRes = ext2_set_block_address(ctx, parentDirNode, targetIndex, newBlockNum); - if (!setRes) { - mm_free_ptr(blockBuf); - return ErrorOr(setRes.Error()); - } - - mm_free_ptr(blockBuf); - return ErrorOr(nullptr); -} - -// Soon -static ErrorOr ext2_alloc_inode(Ext2Context* ctx, - EXT2_GROUP_DESCRIPTOR* groupDesc) { - if (!ctx || !ctx->superblock || !groupDesc) return ErrorOr(kErrorInvalidData); - - UInt32 blockSize = ctx->BlockSize(); - - // buffer for the inode bitmap - auto bitmap = mm_alloc_ptr(blockSize, true, false); - if (!bitmap) return ErrorOr(kErrorHeapOutOfMemory); - - // Read inode bitmap - if (!ext2_read_block(ctx->drive, groupDesc->fInodeBitmap, bitmap, blockSize)) { - mm_free_ptr(bitmap); - return ErrorOr(kErrorDisk); - } - - // Find first free inode (bit = 0) - for (UInt32 byteIdx = 0; byteIdx < blockSize; ++byteIdx) { - auto byte = reinterpret_cast(bitmap)[byteIdx]; - if (byte != 0xFF) { - for (int bit = 0; bit < 8; ++bit) { - if (!(byte & (1 << bit))) { - // Mark bit as used - reinterpret_cast(bitmap)[byteIdx] |= (1 << bit); - - // Compute inode number - UInt32 inodeNumber = byteIdx * 8 + bit + 1; // Inodes are 1-based - - // Write bitmap back - if (!ext2_write_block(ctx->drive, groupDesc->fInodeBitmap, bitmap, blockSize)) { - mm_free_ptr(bitmap); - return ErrorOr(kErrorDisk); - } - - // Update group descriptor free count - groupDesc->fFreeInodesCount--; - mm_free_ptr(bitmap); - return ErrorOr(inodeNumber); - } - } - } - } - - mm_free_ptr(bitmap); - return ErrorOr(kErrorDiskIsFull); -} - -// to write an inode to its correct location on disk -static ErrorOr ext2_write_inode(Ext2Context* ctx, Ext2Node* node) { - using namespace Kernel; - - if (!ctx || !ctx->superblock || !ctx->drive || !node) return ErrorOr(kErrorInvalidData); - - auto blockSize = ctx->BlockSize(); - UInt32 inodesPerGroup = ctx->superblock->fInodesPerGroup; - - if (inodesPerGroup == 0) return ErrorOr(kErrorInvalidData); - - // Calculate which group this inode belongs to - UInt32 groupIndex = (node->inodeNumber - 1) / inodesPerGroup; - NE_UNUSED(groupIndex); - UInt32 inodeIndexInGroup = (node->inodeNumber - 1) % inodesPerGroup; - - // Get group descriptor - auto groupInfoResult = ext2_get_group_descriptor_info(ctx, node->inodeNumber); - if (!groupInfoResult) return ErrorOr(groupInfoResult.Error()); - - auto groupInfo = *groupInfoResult.Leak(); // Dereference to get Ext2GroupInfo* - - // Calculate inode table position - UInt32 inodeTableBlock = groupInfo->groupDesc->fInodeTable; - UInt32 inodeSize = ctx->superblock->fInodeSize; - UInt32 inodesPerBlock = blockSize / inodeSize; - - UInt32 blockOffset = inodeIndexInGroup / inodesPerBlock; - UInt32 offsetInBlock = (inodeIndexInGroup % inodesPerBlock) * inodeSize; - - UInt32 inodeBlock = inodeTableBlock + blockOffset; - UInt32 inodeLba = ext2_block_to_lba(ctx, inodeBlock); - - // Read the block containing the inode - auto blockBuf = mm_alloc_ptr(blockSize, true, false); - if (!blockBuf) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return ErrorOr(kErrorHeapOutOfMemory); - } - - if (!ext2_read_block(ctx->drive, inodeLba, blockBuf, blockSize)) { - mm_free_ptr(blockBuf); - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return ErrorOr(kErrorDisk); - } - - // Copy the updated inode into the block buffer - rt_copy_memory_safe(&node->inode, static_cast((UInt8*) blockBuf + offsetInBlock), - sizeof(EXT2_INODE), blockSize - offsetInBlock); - - // Write the block back - if (!ext2_write_block(ctx->drive, inodeLba, blockBuf, blockSize)) { - mm_free_ptr(blockBuf); - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return ErrorOr(kErrorDisk); - } - - mm_free_ptr(blockBuf); - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - - return ErrorOr(nullptr); -} - -namespace { -// new -struct PathComponents { - const char** components; - int count; - Char* buffer; - - PathComponents(const char* path) : components(nullptr), count(0), buffer(nullptr) { - if (!path || *path == '\0') return; - - SizeT pathLen = rt_string_len(path); - buffer = (Char*) mm_alloc_ptr(pathLen + 1, true, false); - if (!buffer) return; - - rt_copy_memory_safe((void*) path, buffer, pathLen, pathLen + 1); - buffer[pathLen] = '\0'; - - // temp array - const char** temp = (const char**) mm_alloc_ptr(sizeof(char*) * (pathLen + 1), true, false); - if (!temp) { - mm_free_ptr(buffer); - buffer = nullptr; - return; - } - - UInt32 compCount = 0; - Char* p = buffer; - - while (*p != '\0') { - // skip slashes - while (*p == '/') p++; - if (*p == '\0') break; - - Char* start = p; - while (*p != '/' && *p != '\0') p++; - Char saved = *p; - *p = '\0'; - - // handle ".", "..", or normal - if (rt_string_cmp(start, ".", 1) == 0) { - // ignore - } else if (rt_string_cmp(start, "..", 2) == 0) { - if (compCount > 0) compCount--; // go up one level - } else { - temp[compCount++] = start; - } - - *p = saved; - } - - if (compCount == 0) { - mm_free_ptr(temp); - return; - } - - components = (const char**) mm_alloc_ptr(sizeof(char*) * compCount, true, false); - if (!components) { - mm_free_ptr(temp); - return; - } - - for (UInt32 i = 0; i < compCount; i++) components[i] = temp[i]; - count = compCount; - - mm_free_ptr(temp); - } - - ~PathComponents() { - if (components) mm_free_ptr(components); - if (buffer) mm_free_ptr(buffer); - } -}; -} // anonymous namespace - -// The Ext2FileSystemParser (not manager!) -Ext2FileSystemParser::Ext2FileSystemParser(DriveTrait* drive) : ctx(drive) {} -NodePtr Ext2FileSystemParser::Open(const char* path, const char* restrict_type) { - NE_UNUSED(restrict_type); - if (!path || *path == '\0' || !this->ctx.drive) { - return nullptr; - } - - // Root ("/") - if (rt_string_len(path) == 1 && rt_string_cmp(path, "/", 1) == 0) { - auto inodeResult = ext2_load_inode(&this->ctx, EXT2_ROOT_INODE); - if (!inodeResult) { - return nullptr; - } - - auto heapNode = (Ext2Node*) mm_alloc_ptr(sizeof(Ext2Node), true, false); - if (!heapNode) return nullptr; - - *heapNode = *inodeResult.Leak().Leak(); - heapNode->cursor = 0; - return reinterpret_cast(heapNode); - } - - PathComponents pathComponents(path); - if (pathComponents.count == 0) { - return nullptr; - } - - UInt32 currentInodeNumber = EXT2_ROOT_INODE; - Ext2Node* currentDirNode = nullptr; - - for (UInt32 i = 0; i < (UInt32)pathComponents.count; ++i) { - auto inodeResult = ext2_load_inode(&this->ctx, currentInodeNumber); - if (!inodeResult) { - if (currentDirNode) mm_free_ptr(currentDirNode); - return nullptr; - } - - if (currentDirNode) { - mm_free_ptr(currentDirNode); - currentDirNode = nullptr; - } - - currentDirNode = (Ext2Node*) mm_alloc_ptr(sizeof(Ext2Node), true, false); - if (!currentDirNode) { - return nullptr; - } - - *currentDirNode = *inodeResult.Leak().Leak(); - currentDirNode->cursor = 0; - - if (i < pathComponents.count - 1U) { - UInt32 type = (currentDirNode->inode.fMode >> 12) & 0xF; - if (type != kExt2FileTypeDirectory) { - mm_free_ptr(currentDirNode); - return nullptr; - } - } - - auto dirEntryResult = - ext2_find_dir_entry(&this->ctx, currentDirNode, pathComponents.components[i]); - if (!dirEntryResult) { - mm_free_ptr(currentDirNode); - return nullptr; - } - - EXT2_DIR_ENTRY* entryPtr = *dirEntryResult.Leak(); - currentInodeNumber = entryPtr->fInode; - mm_free_ptr(entryPtr); - } - - auto finalInodeResult = ext2_load_inode(&this->ctx, currentInodeNumber); - if (!finalInodeResult) { - if (currentDirNode) mm_free_ptr(currentDirNode); - return nullptr; - } - - if (currentDirNode) { - mm_free_ptr(currentDirNode); - } - - auto resultNode = (Ext2Node*) mm_alloc_ptr(sizeof(Ext2Node), true, false); - if (!resultNode) { - return nullptr; - } - - *resultNode = *finalInodeResult.Leak().Leak(); - resultNode->cursor = 0; - return reinterpret_cast(resultNode); -} - -void* Ext2FileSystemParser::Read(NodePtr node, Int32 flags, SizeT size) { - if (!node) return nullptr; - - NE_UNUSED(flags); - - auto extNode = reinterpret_cast(node); - auto dataResult = ext2_read_inode_data(&this->ctx, extNode, size); - - if (!dataResult) { - return nullptr; // error, nothing to return - } - - void* data = *dataResult.Leak(); - if (data) { - extNode->cursor += static_cast(size); - } - - return data; -} - -void Ext2FileSystemParser::Write(NodePtr node, void* data, Int32 flags, SizeT size) { - if (!node || !data || size == 0) return; - - NE_UNUSED(flags); - - auto extNode = reinterpret_cast(node); - auto blockSize = this->ctx.BlockSize(); - SizeT bytesWritten = 0; - - UInt32 currentOffset = extNode->cursor; - UInt8* src = reinterpret_cast(data); - - while (bytesWritten < size) { - UInt32 logicalBlockIndex = currentOffset / blockSize; - UInt32 offsetInBlock = currentOffset % blockSize; - - auto physBlockResult = ext2_get_block_address(&this->ctx, extNode, logicalBlockIndex); - UInt32 physicalBlock = 0; - - if (!physBlockResult) { - auto err = physBlockResult.Error(); - if (err == kErrorInvalidData || err == kErrorUnimplemented) { - auto groupInfoResult = ext2_get_group_descriptor_info(&this->ctx, extNode->inodeNumber); - if (!groupInfoResult) { - return; - } - - auto groupInfo = *groupInfoResult.Leak(); - auto allocResult = ext2_alloc_block(&this->ctx, groupInfo->groupDesc); - if (!allocResult) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return; - } - - physicalBlock = *allocResult.Leak(); - - auto setRes = ext2_set_block_address(&this->ctx, extNode, logicalBlockIndex, physicalBlock); - if (!setRes) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return; - } - - UInt32 gdtLba = ext2_block_to_lba(&this->ctx, groupInfo->groupDescriptorBlock); - if (!ext2_write_block(this->ctx.drive, gdtLba, groupInfo->blockBuffer, blockSize)) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - return; - } - - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - } else { - return; - } - } else { - physicalBlock = physBlockResult.Value(); - } - - UInt32 physicalLba = ext2_block_to_lba(&this->ctx, physicalBlock); - - auto blockBuf = mm_alloc_ptr(blockSize, true, false); - if (!blockBuf) return; - - if (offsetInBlock > 0 || (size - bytesWritten) < blockSize) { - if (!ext2_read_block(this->ctx.drive, physicalLba, blockBuf, blockSize)) { - mm_free_ptr(blockBuf); - return; - } - } else { - rt_zero_memory(blockBuf, blockSize); - } - - UInt32 bytesInCurrentBlock = - static_cast(ext2_min(size - bytesWritten, blockSize - offsetInBlock)); - rt_copy_memory_safe(src, static_cast((UInt8*) blockBuf + offsetInBlock), - bytesInCurrentBlock, blockSize - offsetInBlock); - - if (!ext2_write_block(this->ctx.drive, physicalLba, blockBuf, blockSize)) { - mm_free_ptr(blockBuf); - return; - } - - mm_free_ptr(blockBuf); - - currentOffset += bytesInCurrentBlock; - src += bytesInCurrentBlock; - bytesWritten += bytesInCurrentBlock; - } - - if (currentOffset > extNode->inode.fSize) { - extNode->inode.fSize = currentOffset; - } - - extNode->inode.fBlocks = (extNode->inode.fSize + blockSize - 1) / blockSize; - extNode->inode.fModifyTime = 0; - - auto writeInodeRes = ext2_write_inode(&this->ctx, extNode); - if (!writeInodeRes) { - // Failed to persist inode - } - - extNode->cursor = currentOffset; -} - -bool Ext2FileSystemParser::Seek(NodePtr node, SizeT offset) { - if (!node) return false; - auto extNode = reinterpret_cast(node); - extNode->cursor = static_cast(offset); - return true; -} - -SizeT Ext2FileSystemParser::Tell(NodePtr node) { - if (!node) return 0; - auto extNode = reinterpret_cast(node); - return extNode->cursor; -} - -bool Ext2FileSystemParser::Rewind(NodePtr node) { - if (!node) return false; - auto extNode = reinterpret_cast(node); - extNode->cursor = 0; - return true; -} - -void* Ext2FileSystemParser::Read(const char* name, NodePtr node, Int32 flags, SizeT size) { - NE_UNUSED(name); - return Read(node, flags, size); -} - -void Ext2FileSystemParser::Write(const char* name, NodePtr node, void* data, Int32 flags, - SizeT size) { - NE_UNUSED(name); - Write(node, data, flags, size); -} - -NodePtr Ext2FileSystemParser::Create(const char* path) { - if (!path || *path == '\0') return nullptr; - - PathComponents pathComponents(path); - if (pathComponents.count == 0) return nullptr; - - const char* filename = pathComponents.components[pathComponents.count - 1]; - if (rt_string_len(filename) > kExt2FSMaxFileNameLen) return nullptr; - - // Build parent path - Char parentPathBuf[256] = {0}; - SizeT currentPathLen = 0; - for (UInt32 i = 0; (i < pathComponents.count - 1U); ++i) { - SizeT componentLen = rt_string_len(pathComponents.components[i]); - if (currentPathLen + componentLen + 1 >= sizeof(parentPathBuf)) return nullptr; - if (i > 0) parentPathBuf[currentPathLen++] = '/'; - rt_copy_memory_safe(const_cast(pathComponents.components[i]), - parentPathBuf + currentPathLen, componentLen, - sizeof(parentPathBuf) - currentPathLen); - currentPathLen += componentLen; - } - parentPathBuf[currentPathLen] = '\0'; - - // Open parent directory - NodePtr parentDirNodePtr = nullptr; - if (currentPathLen == 0) { - // root - auto inodeRes = ext2_load_inode(&this->ctx, EXT2_ROOT_INODE); - if (!inodeRes) return nullptr; - parentDirNodePtr = mm_alloc_ptr(sizeof(Ext2Node), true, false); - if (!parentDirNodePtr) return nullptr; - *reinterpret_cast(parentDirNodePtr) = *inodeRes.Leak().Leak(); - reinterpret_cast(parentDirNodePtr)->cursor = 0; - } else { - parentDirNodePtr = Open(parentPathBuf, "r"); - } - - if (!parentDirNodePtr) return nullptr; - - auto parentDirNode = reinterpret_cast(parentDirNodePtr); - - // Ensure parent is a directory - UInt32 type = (parentDirNode->inode.fMode >> 12) & 0xF; - if (type != kExt2FileTypeDirectory) { - mm_free_ptr(parentDirNode); - return nullptr; - } - - // Get group info for allocation - auto groupInfoResult = ext2_get_group_descriptor_info(&this->ctx, parentDirNode->inodeNumber); - if (!groupInfoResult) { - mm_free_ptr(parentDirNode); - return nullptr; - } - auto groupInfo = *groupInfoResult.Leak(); - - // Allocate new inode - auto newInodeRes = ext2_alloc_inode(&this->ctx, groupInfo->groupDesc); - if (!newInodeRes) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); // so this works - mm_free_ptr(parentDirNode); - return nullptr; - } - UInt32 newInodeNumber = newInodeRes.Value(); - - UInt32 gdtLba = ext2_block_to_lba(&this->ctx, groupInfo->groupDescriptorBlock); - if (!ext2_write_block(this->ctx.drive, gdtLba, groupInfo->blockBuffer, this->ctx.BlockSize())) { - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - mm_free_ptr(parentDirNode); - return nullptr; - } - - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - - // Create new Ext2Node - Ext2Node* newFileNode = reinterpret_cast(mm_alloc_ptr(sizeof(Ext2Node), true, false)); - if (!newFileNode) { - mm_free_ptr(parentDirNode); - return nullptr; - } - - newFileNode->inodeNumber = newInodeNumber; - rt_zero_memory(&newFileNode->inode, sizeof(EXT2_INODE)); - - newFileNode->inode.fMode = (kExt2FileTypeRegular << 12); - newFileNode->inode.fUID = 0; - newFileNode->inode.fGID = 0; - newFileNode->inode.fLinksCount = 1; - newFileNode->inode.fSize = 0; - newFileNode->inode.fBlocks = 0; - newFileNode->inode.fCreateTime = 0; - newFileNode->inode.fModifyTime = 0; - - // Persist new inode - auto writeInodeRes = ext2_write_inode(&this->ctx, newFileNode); - if (!writeInodeRes) { - mm_free_ptr(parentDirNode); - mm_free_ptr(newFileNode); - return nullptr; - } - - // Add directory entry - auto addRes = - ext2_add_dir_entry(&this->ctx, parentDirNode, filename, newInodeNumber, kExt2FileTypeRegular); - if (!addRes) { - mm_free_ptr(parentDirNode); - mm_free_ptr(newFileNode); - return nullptr; - } - - // Update parent inode - auto parentWriteRes = ext2_write_inode(&this->ctx, parentDirNode); - // ignore failure - - NE_UNUSED(parentWriteRes); - - mm_free_ptr(parentDirNode); - return reinterpret_cast(newFileNode); -} - -NodePtr Ext2FileSystemParser::CreateDirectory(const char* path) { - if (!path || *path == '\0') return nullptr; - - PathComponents pathComponents(path); - if (pathComponents.count == 0) { - kout << "EXT2: Failed to parse path for CreateDirectory.\n"; - return nullptr; - } - - const char* dirname = pathComponents.components[pathComponents.count - 1]; - if (rt_string_len(dirname) > kExt2FSMaxFileNameLen) { - kout << "EXT2: Directory name too long: " << dirname << ".\n"; - return nullptr; - } - - // Build parent path - Char parentPathBuf[256]; - SizeT currentPathLen = 0; - for (UInt32 i = 0; (i < pathComponents.count - 1U); ++i) { - SizeT componentLen = rt_string_len(pathComponents.components[i]); - if (currentPathLen + componentLen + 1 >= sizeof(parentPathBuf)) { - kout << "EXT2: Parent path too long for CreateDirectory.\n"; - return nullptr; - } - - if (i > 0) parentPathBuf[currentPathLen++] = '/'; - - rt_copy_memory_safe(static_cast(const_cast(pathComponents.components[i])), - static_cast(parentPathBuf + currentPathLen), componentLen, - sizeof(parentPathBuf) - currentPathLen); - currentPathLen += componentLen; - } - - parentPathBuf[currentPathLen] = '\0'; - - // Open parent directory node - NodePtr parentDirNodePtr = nullptr; - if (currentPathLen == 0) { - auto inodeRes = ext2_load_inode(&this->ctx, EXT2_ROOT_INODE); - if (!inodeRes) { - return nullptr; - } - - parentDirNodePtr = reinterpret_cast(mm_alloc_ptr(sizeof(Ext2Node), true, false)); - if (!parentDirNodePtr) return nullptr; - - *reinterpret_cast(parentDirNodePtr) = *inodeRes.Leak().Leak(); - reinterpret_cast(parentDirNodePtr)->cursor = 0; - } else { - parentDirNodePtr = Open(parentPathBuf, "r"); - } - - if (!parentDirNodePtr) { - kout << "EXT2: Failed to open parent directory for CreateDirectory: " << parentPathBuf << ".\n"; - return nullptr; - } - - auto parentDirNode = reinterpret_cast(parentDirNodePtr); - - // Check parent is a directory - UInt32 parentType = (parentDirNode->inode.fMode >> 12) & 0xF; - if (parentType != kExt2FileTypeDirectory) { - kout << "EXT2: Parent is not a directory: " << parentPathBuf << ".\n"; - mm_free_ptr(parentDirNode); - return nullptr; - } - - // Allocate inode - auto groupInfoResult = ext2_get_group_descriptor_info(&this->ctx, parentDirNode->inodeNumber); - if (!groupInfoResult) { - kout << "EXT2: Failed to get group descriptor info for new dir inode.\n"; - mm_free_ptr(parentDirNode); - return nullptr; - } - - auto groupInfo = *groupInfoResult.Leak(); - auto newInodeRes = ext2_alloc_inode(&this->ctx, groupInfo->groupDesc); - if (!newInodeRes) { - kout << "EXT2: Failed to allocate inode for new directory.\n"; - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - mm_free_ptr(parentDirNode); - return nullptr; - } - - UInt32 newInodeNumber = *newInodeRes.Leak(); - - // Write back group descriptor block - UInt32 gdtLba = ext2_block_to_lba(&this->ctx, groupInfo->groupDescriptorBlock); - if (!ext2_write_block(this->ctx.drive, gdtLba, groupInfo->blockBuffer, this->ctx.BlockSize())) { - kout << "EXT2: Failed to write group descriptor after inode allocation.\n"; - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - mm_free_ptr(parentDirNode); - return nullptr; - } - - mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); - mm_free_ptr(groupInfo); - - // Create new Ext2Node and initialize inode fields - Ext2Node* newDirNode = reinterpret_cast(mm_alloc_ptr(sizeof(Ext2Node), true, false)); - if (!newDirNode) { - kout << "EXT2: Out of memory for new directory node.\n"; - mm_free_ptr(parentDirNode); - return nullptr; - } - - newDirNode->inodeNumber = newInodeNumber; - rt_zero_memory(&newDirNode->inode, sizeof(EXT2_INODE)); - newDirNode->inode.fMode = (kExt2FileTypeDirectory << 12); - newDirNode->inode.fUID = 0; - newDirNode->inode.fGID = 0; - newDirNode->inode.fLinksCount = 2; // . and .. - newDirNode->inode.fSize = this->ctx.BlockSize(); - newDirNode->inode.fBlocks = 1; - newDirNode->inode.fCreateTime = 0; - newDirNode->inode.fModifyTime = 0; - - // Allocate a data block for the new directory - auto groupForBlockRes = ext2_get_group_descriptor_info(&this->ctx, newDirNode->inodeNumber); - if (!groupForBlockRes) { - kout << "EXT2: Failed to get group info for directory block allocation.\n"; - mm_free_ptr(parentDirNode); - mm_free_ptr(newDirNode); - return nullptr; - } - - auto groupForBlock = *groupForBlockRes.Leak(); - auto newBlockRes = ext2_alloc_block(&this->ctx, groupForBlock->groupDesc); - if (!newBlockRes) { - kout << "EXT2: Failed to allocate block for new directory contents.\n"; - mm_free_ptr(reinterpret_cast(groupForBlock->blockBuffer)); - mm_free_ptr(groupForBlock); - mm_free_ptr(parentDirNode); - mm_free_ptr(newDirNode); - return nullptr; - } - - UInt32 newDirBlockNum = *newBlockRes.Leak(); - - // Write back GDT - UInt32 gdtLba2 = ext2_block_to_lba(&this->ctx, groupForBlock->groupDescriptorBlock); - if (!ext2_write_block(this->ctx.drive, gdtLba2, groupForBlock->blockBuffer, - this->ctx.BlockSize())) { - kout << "EXT2: Failed to write GDT after directory block allocation.\n"; - mm_free_ptr(reinterpret_cast(groupForBlock->blockBuffer)); - mm_free_ptr(groupForBlock); - mm_free_ptr(parentDirNode); - mm_free_ptr(newDirNode); - return nullptr; - } - - mm_free_ptr(reinterpret_cast(groupForBlock->blockBuffer)); - mm_free_ptr(groupForBlock); - - // Set the block in newDirNode - auto setBlkRes = ext2_set_block_address(&this->ctx, newDirNode, 0, newDirBlockNum); - if (!setBlkRes) { - kout << "EXT2: Failed to set data block for new directory.\n"; - mm_free_ptr(parentDirNode); - mm_free_ptr(newDirNode); - return nullptr; - } - - // Prepare block with '.' and '..' - auto dirBlockBuf = mm_alloc_ptr(this->ctx.BlockSize(), true, false); - if (!dirBlockBuf) { - kout << "EXT2: Out of memory preparing directory block.\n"; - mm_free_ptr(parentDirNode); - mm_free_ptr(newDirNode); - return nullptr; - } - - rt_zero_memory(dirBlockBuf, this->ctx.BlockSize()); - - // '.' entry - auto dot = reinterpret_cast(dirBlockBuf); - dot->fInode = newInodeNumber; - dot->fNameLength = 1; - dot->fFileType = kExt2FileTypeDirectory; - dot->fRecordLength = ext2_dir_entry_ideal_len(dot->fNameLength); - dot->fName[0] = '.'; - - // '..' entry occupies rest of block - auto dotdot = reinterpret_cast((UInt8*) dirBlockBuf + dot->fRecordLength); - dotdot->fInode = parentDirNode->inodeNumber; - dotdot->fNameLength = 2; - dotdot->fFileType = kExt2FileTypeDirectory; - dotdot->fRecordLength = static_cast(this->ctx.BlockSize() - dot->fRecordLength); - dotdot->fName[0] = '.'; - dotdot->fName[1] = '.'; - - // Write dir block to disk - UInt32 newDirBlockLba = ext2_block_to_lba(&this->ctx, newDirBlockNum); - if (!ext2_write_block(this->ctx.drive, newDirBlockLba, dirBlockBuf, this->ctx.BlockSize())) { - kout << "EXT2: Failed to write directory block to disk.\n"; - mm_free_ptr(dirBlockBuf); - mm_free_ptr(parentDirNode); - mm_free_ptr(newDirNode); - return nullptr; - } - - mm_free_ptr(dirBlockBuf); - - // Persist new directory inode - auto writeInodeRes = ext2_write_inode(&this->ctx, newDirNode); - if (!writeInodeRes) { - kout << "EXT2: Failed to write new directory inode to disk.\n"; - mm_free_ptr(parentDirNode); - mm_free_ptr(newDirNode); - return nullptr; - } - - // Add directory entry into parent - auto addRes = ext2_add_dir_entry(&this->ctx, parentDirNode, dirname, newInodeNumber, - kExt2FileTypeDirectory); - if (!addRes) { - kout << "EXT2: Failed to add directory entry for '" << dirname << "' to parent.\n"; - mm_free_ptr(parentDirNode); - mm_free_ptr(newDirNode); - return nullptr; - } - - // Increment parent link count and persist parent inode - parentDirNode->inode.fLinksCount += 1; - auto parentWriteRes = ext2_write_inode(&this->ctx, parentDirNode); - if (!parentWriteRes) { - kout << "EXT2: Warning: failed to update parent inode after directory creation.\n"; - } - - mm_free_ptr(parentDirNode); - return reinterpret_cast(newDirNode); -} - -#endif -#endif diff --git a/dev/kernel/src/FS/Ext2+FileSystemParser.cc b/dev/kernel/src/FS/Ext2+FileSystemParser.cc deleted file mode 100644 index 318f83d6..00000000 --- a/dev/kernel/src/FS/Ext2+FileSystemParser.cc +++ /dev/null @@ -1,21 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#ifdef __FSKIT_INCLUDES_EXT2__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif // ifdef __FSKIT_INCLUDES_EXT2__ diff --git a/dev/kernel/src/FS/Ext2+IFS.cc b/dev/kernel/src/FS/Ext2+IFS.cc new file mode 100644 index 00000000..2c359197 --- /dev/null +++ b/dev/kernel/src/FS/Ext2+IFS.cc @@ -0,0 +1,1555 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef __NE_MINIMAL_OS__ +#ifdef __FSKIT_INCLUDES_EXT2__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr static UInt32 EXT2_DIRECT_BLOCKS = 12; +constexpr static UInt32 EXT2_SINGLE_INDIRECT_INDEX = 12; +constexpr static UInt32 EXT2_DOUBLE_INDIRECT_INDEX = 13; +constexpr ATTRIBUTE(unused) static UInt32 EXT2_TRIPLE_INDIRECT_INDEX = 14; +constexpr static UInt32 EXT2_ROOT_INODE = 2; +constexpr ATTRIBUTE(unused) static UInt32 EXT2_SUPERBLOCK_BLOCK = 1; +constexpr static UInt32 EXT2_GROUP_DESC_BLOCK_SMALL = 2; +constexpr static UInt32 EXT2_GROUP_DESC_BLOCK_LARGE = 1; + +static inline SizeT ext2_min(SizeT a, SizeT b) { + return a < b ? a : b; +} + +struct Ext2GroupInfo { + EXT2_GROUP_DESCRIPTOR* groupDesc; + UInt32 groupDescriptorBlock; + UInt32 offsetInGroupDescBlock; + UInt8* blockBuffer; +}; + +// Convert EXT2 block number -> LBA (sector index) for Drive I/O. +static inline UInt32 ext2_block_to_lba(Ext2Context* ctx, UInt32 blockNumber) { + if (!ctx || !ctx->drive) return 0; + UInt32 blockSize = ctx->BlockSize(); + UInt32 sectorSize = ctx->drive->fSectorSz; + UInt32 sectorsPerBlock = blockSize / sectorSize; + return blockNumber * sectorsPerBlock; +} + +// Read a block and return a pointer to its content +static ErrorOr ext2_read_block_ptr(Ext2Context* ctx, UInt32 blockNumber) { + if (!ctx || !ctx->drive || !ctx->superblock) return ErrorOr(kErrorInvalidData); + + UInt32 blockSize = ctx->BlockSize(); + auto buf = (UInt32*) mm_alloc_ptr(blockSize, true, false); + if (!buf) return ErrorOr(kErrorHeapOutOfMemory); + + UInt32 lba = ext2_block_to_lba(ctx, blockNumber); + if (!ext2_read_block(ctx->drive, lba, buf, blockSize)) { + mm_free_ptr(buf); + return ErrorOr(kErrorDisk); + } + return ErrorOr(buf); +} + +// Get the block address for a given logical block index +static ErrorOr ext2_get_block_address(Ext2Context* ctx, Ext2Node* node, + UInt32 logicalIndex) { + if (!ctx || !node || !ctx->drive) return ErrorOr(kErrorInvalidData); + + UInt32 blockSize = ctx->BlockSize(); + UInt32 pointersPerBlock = blockSize / sizeof(UInt32); + + // Direct blocks + if (logicalIndex < EXT2_DIRECT_BLOCKS) { + UInt32 bn = node->inode.fBlock[logicalIndex]; + if (bn == 0) return ErrorOr(kErrorInvalidData); + return ErrorOr(bn); + } + + // Single indirect blocks + if (logicalIndex < (EXT2_DIRECT_BLOCKS + pointersPerBlock)) { + UInt32 iblock = node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX]; + if (iblock == 0) return ErrorOr(kErrorInvalidData); + + auto res = ext2_read_block_ptr(ctx, iblock); + if (!res) return ErrorOr(res.Error()); + + // Using dereference operator + UInt32* ptr = *res.Leak(); // operator* returns T (UInt32*) + + UInt32 val = ptr[logicalIndex - EXT2_DIRECT_BLOCKS]; + mm_free_ptr(ptr); + + if (val == 0) return ErrorOr(kErrorInvalidData); + return ErrorOr(val); + } + + // Double indirect blocks + UInt32 doubleStart = EXT2_DIRECT_BLOCKS + pointersPerBlock; + UInt32 doubleSpan = pointersPerBlock * pointersPerBlock; + if (logicalIndex < (doubleStart + doubleSpan)) { + UInt32 db = node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX]; + if (db == 0) return ErrorOr(kErrorInvalidData); + + auto dblRes = ext2_read_block_ptr(ctx, db); + if (!dblRes) return ErrorOr(dblRes.Error()); + + UInt32* dblPtr = *dblRes.Leak(); + + UInt32 idxWithin = logicalIndex - doubleStart; + UInt32 firstIdx = idxWithin / pointersPerBlock; + UInt32 secondIdx = idxWithin % pointersPerBlock; + UInt32 singleBlockNum = dblPtr[firstIdx]; + + mm_free_ptr(dblPtr); + if (singleBlockNum == 0) return ErrorOr(kErrorInvalidData); + + auto singleRes = ext2_read_block_ptr(ctx, singleBlockNum); + if (!singleRes) return ErrorOr(singleRes.Error()); + + UInt32* singlePtr = *singleRes.Leak(); + UInt32 val = singlePtr[secondIdx]; + mm_free_ptr(singlePtr); + + if (val == 0) return ErrorOr(kErrorInvalidData); + return ErrorOr(val); + } + + return ErrorOr(kErrorUnimplemented); +} + +static ErrorOr ext2_read_inode_data(Ext2Context* ctx, Ext2Node* node, SizeT size) { + if (!ctx || !ctx->drive || !node || size == 0) return ErrorOr(1); + + auto blockSize = ctx->BlockSize(); + SizeT available = (node->inode.fSize > node->cursor) ? (node->inode.fSize - node->cursor) : 0; + SizeT bytesToRead = (size < available) ? size : available; + if (bytesToRead == 0) return ErrorOr(2); // nothing to read + + auto buffer = mm_alloc_ptr(bytesToRead, true, false); + if (!buffer) return ErrorOr(3); // allocation failed + + UInt32 currentOffset = node->cursor; + SizeT remaining = bytesToRead; + UInt8* dest = reinterpret_cast(buffer); + + while (remaining > 0) { + UInt32 logicalIndex = currentOffset / blockSize; + UInt32 offsetInBlock = currentOffset % blockSize; + + auto phys = ext2_get_block_address(ctx, node, logicalIndex); + if (phys.HasError()) { + mm_free_ptr(buffer); + return ErrorOr(phys.Error()); + } + + auto blockNumber = phys.Value(); + UInt32 lba = ext2_block_to_lba(ctx, blockNumber); + + auto blockBuf = mm_alloc_ptr(blockSize, true, false); + if (!blockBuf) { + mm_free_ptr(buffer); + return ErrorOr(4); // block buffer allocation failed + } + + if (!ext2_read_block(ctx->drive, lba, blockBuf, blockSize)) { + mm_free_ptr(blockBuf); + mm_free_ptr(buffer); + return ErrorOr(5); // block read failed + } + + SizeT chunk = ext2_min(remaining, blockSize - offsetInBlock); + rt_copy_memory_safe(static_cast(static_cast(blockBuf) + offsetInBlock), + static_cast(dest), chunk, chunk); + + mm_free_ptr(blockBuf); + + currentOffset += static_cast(chunk); + dest += chunk; + remaining -= chunk; + } + + node->cursor += static_cast(bytesToRead); + return ErrorOr(buffer); +} + +// Get group descriptor information for a given block/inode number +static ErrorOr ext2_get_group_descriptor_info(Ext2Context* ctx, + UInt32 targetBlockOrInode) { + if (!ctx || !ctx->superblock || !ctx->drive) return ErrorOr(kErrorInvalidData); + + UInt32 blockSize = ctx->BlockSize(); + UInt32 blocksPerGroup = ctx->superblock->fBlocksPerGroup; + UInt32 inodesPerGroup = ctx->superblock->fInodesPerGroup; + UInt32 totalBlocks = ctx->superblock->fBlockCount; + UInt32 totalInodes = ctx->superblock->fInodeCount; + + if (blocksPerGroup == 0 || inodesPerGroup == 0) return ErrorOr(kErrorInvalidData); + + // block group index + UInt32 groupIndex = 0; + if (targetBlockOrInode == 0) { + groupIndex = 0; + } else if (targetBlockOrInode <= totalInodes) { + // 1-based + groupIndex = (targetBlockOrInode - 1) / inodesPerGroup; + } else { + // EXT2 block number + if (targetBlockOrInode < ctx->superblock->fFirstDataBlock) { + groupIndex = 0; + } else { + groupIndex = (targetBlockOrInode - ctx->superblock->fFirstDataBlock) / blocksPerGroup; + } + } + + // Calculate number of block groups + UInt32 groupsCount = static_cast((totalBlocks + blocksPerGroup - 1) / blocksPerGroup); + if (groupIndex >= groupsCount) return ErrorOr(kErrorInvalidData); + + // Determine GDT start block + UInt32 gdtStartBlock = + (blockSize == 1024) ? EXT2_GROUP_DESC_BLOCK_SMALL : EXT2_GROUP_DESC_BLOCK_LARGE; + + // Compute byte offset of descriptor within the GDT + const UInt32 descSize = sizeof(EXT2_GROUP_DESCRIPTOR); + UInt64 descByteOffset = static_cast(groupIndex) * descSize; + + // Which EXT2 block contains that descriptor? + UInt32 blockOffsetWithinGdt = static_cast(descByteOffset / blockSize); + UInt32 offsetInGroupDescBlock = static_cast(descByteOffset % blockSize); + UInt32 groupDescriptorBlock = gdtStartBlock + blockOffsetWithinGdt; + + // Allocate buffer and read the block containing the descriptor + auto blockBuffer = mm_alloc_ptr(blockSize, true, false); + if (!blockBuffer) return ErrorOr(kErrorHeapOutOfMemory); + + UInt32 groupDescriptorLba = ext2_block_to_lba(ctx, groupDescriptorBlock); + if (!ext2_read_block(ctx->drive, groupDescriptorLba, blockBuffer, blockSize)) { + mm_free_ptr(blockBuffer); + return ErrorOr(kErrorDisk); + } + + auto groupInfo = (Ext2GroupInfo*) mm_alloc_ptr(sizeof(Ext2GroupInfo), true, false); + if (!groupInfo) { + mm_free_ptr(blockBuffer); + return ErrorOr(kErrorHeapOutOfMemory); + } + + groupInfo->groupDesc = reinterpret_cast( + reinterpret_cast(blockBuffer) + offsetInGroupDescBlock); + groupInfo->groupDescriptorBlock = groupDescriptorBlock; + groupInfo->offsetInGroupDescBlock = offsetInGroupDescBlock; + groupInfo->blockBuffer = reinterpret_cast(blockBuffer); + + return ErrorOr(groupInfo); +} + +// Allocate a new block +inline ErrorOr ext2_alloc_block(Ext2Context* ctx, EXT2_GROUP_DESCRIPTOR* groupDesc) { + if (!ctx || !ctx->superblock || !groupDesc) return ErrorOr(kErrorInvalidData); + + UInt32 blockSize = ctx->BlockSize(); + + // for the bitmap + auto bitmap = mm_alloc_ptr(blockSize, true, false); + if (!bitmap) return ErrorOr(kErrorHeapOutOfMemory); + + // Read block bitmap + if (!ext2_read_block(ctx->drive, groupDesc->fBlockBitmap, bitmap, blockSize)) { + mm_free_ptr(bitmap); + return ErrorOr(kErrorDisk); + } + + // bit = 0 + for (UInt32 byteIdx = 0; byteIdx < blockSize; ++byteIdx) { + auto byte = reinterpret_cast(bitmap)[byteIdx]; + if (byte != 0xFF) { + for (int bit = 0; bit < 8; ++bit) { + if (!(byte & (1 << bit))) { + // Mark bit as used + reinterpret_cast(bitmap)[byteIdx] |= (1 << bit); + + // Compute block number + UInt32 blockNumber = byteIdx * 8 + bit; + + // Write bitmap back + if (!ext2_write_block(ctx->drive, groupDesc->fBlockBitmap, bitmap, blockSize)) { + mm_free_ptr(bitmap); + return ErrorOr(kErrorDisk); + } + + // Update group descriptor free count + groupDesc->fFreeBlocksCount--; + mm_free_ptr(bitmap); + return ErrorOr(blockNumber); + } + } + } + } + + mm_free_ptr(bitmap); + return ErrorOr(kErrorDiskIsFull); +} + +// Indirect blocks +static ErrorOr ext2_set_block_address(Ext2Context* ctx, Ext2Node* node, + UInt32 logicalBlockIndex, UInt32 physicalBlockNumber) { + using namespace Kernel; + + if (!ctx || !ctx->drive || !node) return ErrorOr(kErrorInvalidData); + + auto blockSize = ctx->BlockSize(); + UInt32 blocksPerPointerBlock = blockSize / sizeof(UInt32); + + // Direct blocks + if (logicalBlockIndex < EXT2_DIRECT_BLOCKS) { + node->inode.fBlock[logicalBlockIndex] = physicalBlockNumber; + return ErrorOr(nullptr); + } + + // Single indirect blocks + if (logicalBlockIndex < EXT2_DIRECT_BLOCKS + blocksPerPointerBlock) { + if (node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX] == 0) { + auto groupInfoRes = ext2_get_group_descriptor_info(ctx, node->inodeNumber); + if (groupInfoRes.HasError()) return ErrorOr(groupInfoRes.Error()); + + auto groupInfo = groupInfoRes.Leak().Leak(); // Ref + auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc); + if (newBlockRes.HasError()) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return ErrorOr(newBlockRes.Error()); + } + + node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX] = newBlockRes.Leak(); + + UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock); + if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + + // Zero out new indirect block + auto zeroBuf = mm_alloc_ptr(blockSize, true, false); + if (!zeroBuf) return ErrorOr(kErrorHeapOutOfMemory); + + rt_zero_memory(zeroBuf, blockSize); + UInt32 indirectLba = ext2_block_to_lba(ctx, node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX]); + if (!ext2_write_block(ctx->drive, indirectLba, zeroBuf, blockSize)) { + mm_free_ptr(zeroBuf); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(zeroBuf); + } + + // Read, modify, and write single indirect block + auto indirectRes = ext2_read_block_ptr(ctx, node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX]); + if (indirectRes.HasError()) return ErrorOr(indirectRes.Error()); + + UInt32* indirectPtr = indirectRes.Leak().Leak(); // Ref + indirectPtr[logicalBlockIndex - EXT2_DIRECT_BLOCKS] = physicalBlockNumber; + + UInt32 indirectLba = ext2_block_to_lba(ctx, node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX]); + if (!ext2_write_block(ctx->drive, indirectLba, indirectPtr, blockSize)) { + mm_free_ptr(indirectPtr); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(indirectPtr); + return ErrorOr(nullptr); + } + + // Double + UInt32 doubleStart = EXT2_DIRECT_BLOCKS + blocksPerPointerBlock; + UInt32 doubleSpan = blocksPerPointerBlock * blocksPerPointerBlock; + if (logicalBlockIndex < doubleStart + doubleSpan) { + if (node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX] == 0) { + auto groupInfoRes = ext2_get_group_descriptor_info(ctx, node->inodeNumber); + if (groupInfoRes.HasError()) return ErrorOr(groupInfoRes.Error()); + + auto groupInfo = groupInfoRes.Leak().Leak(); + auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc); + if (newBlockRes.HasError()) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return ErrorOr(newBlockRes.Error()); + } + + node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX] = newBlockRes.Leak(); + + UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock); + if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + + // Zero new double-indirect block + auto zeroBuf = mm_alloc_ptr(blockSize, true, false); + if (!zeroBuf) return ErrorOr(kErrorHeapOutOfMemory); + + rt_zero_memory(zeroBuf, blockSize); + UInt32 dblLba = ext2_block_to_lba(ctx, node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX]); + if (!ext2_write_block(ctx->drive, dblLba, zeroBuf, blockSize)) { + mm_free_ptr(zeroBuf); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(zeroBuf); + } + + // Compute indices + UInt32 idxWithin = logicalBlockIndex - doubleStart; + UInt32 firstIdx = idxWithin / blocksPerPointerBlock; + UInt32 secondIdx = idxWithin % blocksPerPointerBlock; + + auto doubleRes = ext2_read_block_ptr(ctx, node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX]); + if (doubleRes.HasError()) return ErrorOr(doubleRes.Error()); + + UInt32* doublePtr = doubleRes.Leak().Leak(); + UInt32 singleIndirectBlock = doublePtr[firstIdx]; + + // Allocate single-indirect if missing + if (singleIndirectBlock == 0) { + auto groupInfoRes = ext2_get_group_descriptor_info(ctx, node->inodeNumber); + if (groupInfoRes.HasError()) { + mm_free_ptr(doublePtr); + return ErrorOr(groupInfoRes.Error()); + } + + auto groupInfo = groupInfoRes.Leak().Leak(); + auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc); + if (newBlockRes.HasError()) { + mm_free_ptr(doublePtr); + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return ErrorOr(newBlockRes.Error()); + } + + singleIndirectBlock = newBlockRes.Leak(); + doublePtr[firstIdx] = singleIndirectBlock; + + // Write back GDT + UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock); + if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) { + mm_free_ptr(doublePtr); + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + + // Zero single-indirect block + auto zeroBuf = mm_alloc_ptr(blockSize, true, false); + if (!zeroBuf) { + mm_free_ptr(doublePtr); + return ErrorOr(kErrorHeapOutOfMemory); + } + + rt_zero_memory(zeroBuf, blockSize); + UInt32 singleLba = ext2_block_to_lba(ctx, singleIndirectBlock); + if (!ext2_write_block(ctx->drive, singleLba, zeroBuf, blockSize)) { + mm_free_ptr(zeroBuf); + mm_free_ptr(doublePtr); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(zeroBuf); + + // Write double-indirect back to disk + UInt32 dblLba = ext2_block_to_lba(ctx, node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX]); + if (!ext2_write_block(ctx->drive, dblLba, doublePtr, blockSize)) { + mm_free_ptr(doublePtr); + return ErrorOr(kErrorDisk); + } + } + + mm_free_ptr(doublePtr); + + // Write to single-indirect block + auto singleRes = ext2_read_block_ptr(ctx, singleIndirectBlock); + if (singleRes.HasError()) return ErrorOr(singleRes.Error()); + + UInt32* singlePtr = singleRes.Leak().Leak(); + singlePtr[secondIdx] = physicalBlockNumber; + + UInt32 singleLba = ext2_block_to_lba(ctx, singleIndirectBlock); + if (!ext2_write_block(ctx->drive, singleLba, singlePtr, blockSize)) { + mm_free_ptr(singlePtr); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(singlePtr); + return ErrorOr(nullptr); + } + + // Triple indirect blocks not implemented + return ErrorOr(kErrorUnimplemented); +} + +// Find a directory entry by name within a directory inode +static ErrorOr ext2_find_dir_entry(Ext2Context* ctx, Ext2Node* dirNode, + const char* name) { + if (!ctx || !ctx->drive || !dirNode || !name) return ErrorOr(kErrorInvalidData); + + // Check directory type + auto type = (dirNode->inode.fMode >> 12) & 0xF; + if (type != kExt2FileTypeDirectory) return ErrorOr(kErrorInvalidData); + + UInt32 blockSize = ctx->BlockSize(); + auto blockBuf = mm_alloc_ptr(blockSize, true, false); + if (!blockBuf) return ErrorOr(kErrorHeapOutOfMemory); + + SizeT nameLen = rt_string_len(name); + for (UInt32 i = 0; i < EXT2_DIRECT_BLOCKS; ++i) { + UInt32 blockNum = dirNode->inode.fBlock[i]; + if (blockNum == 0) continue; + + UInt32 lba = ext2_block_to_lba(ctx, blockNum); + if (!ext2_read_block(ctx->drive, lba, blockBuf, blockSize)) { + mm_free_ptr(blockBuf); + return ErrorOr(kErrorDisk); + } + + UInt32 offset = 0; + while (offset + sizeof(UInt32) + sizeof(UInt16) <= blockSize) { + auto onDiskEntry = reinterpret_cast((UInt8*) blockBuf + offset); + if (onDiskEntry->fRecordLength == 0) break; // corrupted + + if (onDiskEntry->fInode != 0 && onDiskEntry->fNameLength == nameLen) { + // Compare names + if (rt_string_cmp(name, onDiskEntry->fName, nameLen) == 0) { + // Allocate a result sized to hold the name + metadata + SizeT recSize = sizeof(EXT2_DIR_ENTRY); + auto found = (EXT2_DIR_ENTRY*) mm_alloc_ptr(recSize, true, false); + if (!found) { + mm_free_ptr(blockBuf); + return ErrorOr(kErrorHeapOutOfMemory); + } + + // Copy only record-length bytes + rt_copy_memory_safe(onDiskEntry, found, onDiskEntry->fRecordLength, recSize); + mm_free_ptr(blockBuf); + return ErrorOr(found); + } + } + offset += onDiskEntry->fRecordLength; + } + } + + mm_free_ptr(blockBuf); + return ErrorOr(kErrorFileNotFound); +} + +// Compute ideal record length for a directory name +static inline UInt16 ext2_dir_entry_ideal_len(UInt8 nameLen) { + UInt16 raw = + static_cast(8 + nameLen); // 8 = inode(4)+rec_len(2)+name_len(1)+file_type(1) + return static_cast((raw + 3) & ~3u); // align up to 4 +} + +static ErrorOr ext2_add_dir_entry(Ext2Context* ctx, Ext2Node* parentDirNode, + const char* name, UInt32 inodeNumber, UInt8 fileType) { + using namespace Kernel; + + if (!ctx || !ctx->drive || !parentDirNode || !name) return ErrorOr(kErrorInvalidData); + + UInt32 blockSize = ctx->BlockSize(); + SizeT nameLen = rt_string_len(name); + if (nameLen == 0 || nameLen > 255) return ErrorOr(kErrorInvalidData); + + UInt16 newRecIdeal = ext2_dir_entry_ideal_len(static_cast(nameLen)); + + auto blockBuf = mm_alloc_ptr(blockSize, true, false); + if (!blockBuf) return ErrorOr(kErrorHeapOutOfMemory); + + for (UInt32 bi = 0; bi < EXT2_DIRECT_BLOCKS; ++bi) { + UInt32 blockNum = parentDirNode->inode.fBlock[bi]; + + if (blockNum == 0) { + // Allocate new block + auto groupInfoRes = ext2_get_group_descriptor_info(ctx, parentDirNode->inodeNumber); + if (!groupInfoRes) { + mm_free_ptr(blockBuf); + return ErrorOr(groupInfoRes.Error()); + } + + auto groupInfo = *groupInfoRes.Leak(); // Dereference to get Ext2GroupInfo* + auto allocBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc); + if (!allocBlockRes) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + mm_free_ptr(blockBuf); + return ErrorOr(allocBlockRes.Error()); + } + + UInt32 newBlock = *allocBlockRes.Leak(); // Dereference to get UInt32 + UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock); + + if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + mm_free_ptr(blockBuf); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + + // Zero block & insert entry + rt_zero_memory(blockBuf, blockSize); + auto entry = reinterpret_cast(blockBuf); + entry->fInode = inodeNumber; + entry->fNameLength = static_cast(nameLen); + entry->fFileType = fileType; + entry->fRecordLength = static_cast(blockSize); + rt_copy_memory_safe(const_cast(name), entry->fName, nameLen, blockSize); + + UInt32 blockLba = ext2_block_to_lba(ctx, newBlock); + if (!ext2_write_block(ctx->drive, blockLba, blockBuf, blockSize)) { + mm_free_ptr(blockBuf); + return ErrorOr(kErrorDisk); + } + + auto setRes = ext2_set_block_address(ctx, parentDirNode, bi, newBlock); + if (!setRes) { + mm_free_ptr(blockBuf); + return ErrorOr(setRes.Error()); + } + + mm_free_ptr(blockBuf); + return ErrorOr(nullptr); + } + + // read it + UInt32 blockLba = ext2_block_to_lba(ctx, blockNum); + if (!ext2_read_block(ctx->drive, blockLba, blockBuf, blockSize)) { + mm_free_ptr(blockBuf); + return ErrorOr(kErrorDisk); + } + + UInt32 offset = 0; + EXT2_DIR_ENTRY* lastEntry = nullptr; + UInt32 lastOffset = 0; + + while (offset < blockSize) { + if (offset + 8 > blockSize) break; + auto e = reinterpret_cast((UInt8*) blockBuf + offset); + if (e->fRecordLength == 0) break; + lastEntry = e; + lastOffset = offset; + offset += e->fRecordLength; + } + + if (!lastEntry) continue; + + UInt16 lastIdeal = ext2_dir_entry_ideal_len(lastEntry->fNameLength); + + if (lastEntry->fRecordLength >= (UInt16) (lastIdeal + newRecIdeal)) { + UInt16 origRec = lastEntry->fRecordLength; + lastEntry->fRecordLength = lastIdeal; + + UInt32 newOffset = lastOffset + lastIdeal; + auto newEntry = reinterpret_cast((UInt8*) blockBuf + newOffset); + newEntry->fInode = inodeNumber; + newEntry->fNameLength = static_cast(nameLen); + newEntry->fFileType = fileType; + newEntry->fRecordLength = static_cast(origRec - lastIdeal); + rt_copy_memory_safe(const_cast(name), newEntry->fName, nameLen, + newEntry->fRecordLength); + + if (!ext2_write_block(ctx->drive, blockLba, blockBuf, blockSize)) { + mm_free_ptr(blockBuf); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(blockBuf); + return ErrorOr(nullptr); + } + } + + // No space in direct blocks -> allocate new block + int targetIndex = -1; + for (UInt32 i = 0; i < EXT2_DIRECT_BLOCKS; ++i) { + if (parentDirNode->inode.fBlock[i] == 0) { + targetIndex = i; + break; + } + } + if (targetIndex == -1) { + mm_free_ptr(blockBuf); + return ErrorOr(kErrorUnimplemented); + } + + auto groupInfoResult = ext2_get_group_descriptor_info(ctx, parentDirNode->inodeNumber); + if (!groupInfoResult) { + mm_free_ptr(blockBuf); + return ErrorOr(groupInfoResult.Error()); + } + + auto groupInfo = *groupInfoResult.Leak(); // Dereference to get Ext2GroupInfo* + auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc); + if (!newBlockRes) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + mm_free_ptr(blockBuf); + return ErrorOr(newBlockRes.Error()); + } + + UInt32 newBlockNum = *newBlockRes.Leak(); // Dereference to get UInt32 + UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock); + if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + mm_free_ptr(blockBuf); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + + rt_zero_memory(blockBuf, blockSize); + auto entry = reinterpret_cast(blockBuf); + entry->fInode = inodeNumber; + entry->fNameLength = static_cast(nameLen); + entry->fFileType = fileType; + entry->fRecordLength = static_cast(blockSize); + rt_copy_memory_safe(const_cast(name), entry->fName, nameLen, blockSize); + + UInt32 newBlockLba = ext2_block_to_lba(ctx, newBlockNum); + if (!ext2_write_block(ctx->drive, newBlockLba, blockBuf, blockSize)) { + mm_free_ptr(blockBuf); + return ErrorOr(kErrorDisk); + } + + auto setRes = ext2_set_block_address(ctx, parentDirNode, targetIndex, newBlockNum); + if (!setRes) { + mm_free_ptr(blockBuf); + return ErrorOr(setRes.Error()); + } + + mm_free_ptr(blockBuf); + return ErrorOr(nullptr); +} + +// Soon +static ErrorOr ext2_alloc_inode(Ext2Context* ctx, EXT2_GROUP_DESCRIPTOR* groupDesc) { + if (!ctx || !ctx->superblock || !groupDesc) return ErrorOr(kErrorInvalidData); + + UInt32 blockSize = ctx->BlockSize(); + + // buffer for the inode bitmap + auto bitmap = mm_alloc_ptr(blockSize, true, false); + if (!bitmap) return ErrorOr(kErrorHeapOutOfMemory); + + // Read inode bitmap + if (!ext2_read_block(ctx->drive, groupDesc->fInodeBitmap, bitmap, blockSize)) { + mm_free_ptr(bitmap); + return ErrorOr(kErrorDisk); + } + + // Find first free inode (bit = 0) + for (UInt32 byteIdx = 0; byteIdx < blockSize; ++byteIdx) { + auto byte = reinterpret_cast(bitmap)[byteIdx]; + if (byte != 0xFF) { + for (int bit = 0; bit < 8; ++bit) { + if (!(byte & (1 << bit))) { + // Mark bit as used + reinterpret_cast(bitmap)[byteIdx] |= (1 << bit); + + // Compute inode number + UInt32 inodeNumber = byteIdx * 8 + bit + 1; // Inodes are 1-based + + // Write bitmap back + if (!ext2_write_block(ctx->drive, groupDesc->fInodeBitmap, bitmap, blockSize)) { + mm_free_ptr(bitmap); + return ErrorOr(kErrorDisk); + } + + // Update group descriptor free count + groupDesc->fFreeInodesCount--; + mm_free_ptr(bitmap); + return ErrorOr(inodeNumber); + } + } + } + } + + mm_free_ptr(bitmap); + return ErrorOr(kErrorDiskIsFull); +} + +// to write an inode to its correct location on disk +static ErrorOr ext2_write_inode(Ext2Context* ctx, Ext2Node* node) { + using namespace Kernel; + + if (!ctx || !ctx->superblock || !ctx->drive || !node) return ErrorOr(kErrorInvalidData); + + auto blockSize = ctx->BlockSize(); + UInt32 inodesPerGroup = ctx->superblock->fInodesPerGroup; + + if (inodesPerGroup == 0) return ErrorOr(kErrorInvalidData); + + // Calculate which group this inode belongs to + UInt32 groupIndex = (node->inodeNumber - 1) / inodesPerGroup; + NE_UNUSED(groupIndex); + UInt32 inodeIndexInGroup = (node->inodeNumber - 1) % inodesPerGroup; + + // Get group descriptor + auto groupInfoResult = ext2_get_group_descriptor_info(ctx, node->inodeNumber); + if (!groupInfoResult) return ErrorOr(groupInfoResult.Error()); + + auto groupInfo = *groupInfoResult.Leak(); // Dereference to get Ext2GroupInfo* + + // Calculate inode table position + UInt32 inodeTableBlock = groupInfo->groupDesc->fInodeTable; + UInt32 inodeSize = ctx->superblock->fInodeSize; + UInt32 inodesPerBlock = blockSize / inodeSize; + + UInt32 blockOffset = inodeIndexInGroup / inodesPerBlock; + UInt32 offsetInBlock = (inodeIndexInGroup % inodesPerBlock) * inodeSize; + + UInt32 inodeBlock = inodeTableBlock + blockOffset; + UInt32 inodeLba = ext2_block_to_lba(ctx, inodeBlock); + + // Read the block containing the inode + auto blockBuf = mm_alloc_ptr(blockSize, true, false); + if (!blockBuf) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return ErrorOr(kErrorHeapOutOfMemory); + } + + if (!ext2_read_block(ctx->drive, inodeLba, blockBuf, blockSize)) { + mm_free_ptr(blockBuf); + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return ErrorOr(kErrorDisk); + } + + // Copy the updated inode into the block buffer + rt_copy_memory_safe(&node->inode, static_cast((UInt8*) blockBuf + offsetInBlock), + sizeof(EXT2_INODE), blockSize - offsetInBlock); + + // Write the block back + if (!ext2_write_block(ctx->drive, inodeLba, blockBuf, blockSize)) { + mm_free_ptr(blockBuf); + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return ErrorOr(kErrorDisk); + } + + mm_free_ptr(blockBuf); + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + + return ErrorOr(nullptr); +} + +namespace { +// new +struct PathComponents { + const char** components; + int count; + Char* buffer; + + PathComponents(const char* path) : components(nullptr), count(0), buffer(nullptr) { + if (!path || *path == '\0') return; + + SizeT pathLen = rt_string_len(path); + buffer = (Char*) mm_alloc_ptr(pathLen + 1, true, false); + if (!buffer) return; + + rt_copy_memory_safe((void*) path, buffer, pathLen, pathLen + 1); + buffer[pathLen] = '\0'; + + // temp array + const char** temp = (const char**) mm_alloc_ptr(sizeof(char*) * (pathLen + 1), true, false); + if (!temp) { + mm_free_ptr(buffer); + buffer = nullptr; + return; + } + + UInt32 compCount = 0; + Char* p = buffer; + + while (*p != '\0') { + // skip slashes + while (*p == '/') p++; + if (*p == '\0') break; + + Char* start = p; + while (*p != '/' && *p != '\0') p++; + Char saved = *p; + *p = '\0'; + + // handle ".", "..", or normal + if (rt_string_cmp(start, ".", 1) == 0) { + // ignore + } else if (rt_string_cmp(start, "..", 2) == 0) { + if (compCount > 0) compCount--; // go up one level + } else { + temp[compCount++] = start; + } + + *p = saved; + } + + if (compCount == 0) { + mm_free_ptr(temp); + return; + } + + components = (const char**) mm_alloc_ptr(sizeof(char*) * compCount, true, false); + if (!components) { + mm_free_ptr(temp); + return; + } + + for (UInt32 i = 0; i < compCount; i++) components[i] = temp[i]; + count = compCount; + + mm_free_ptr(temp); + } + + ~PathComponents() { + if (components) mm_free_ptr(components); + if (buffer) mm_free_ptr(buffer); + } +}; +} // anonymous namespace + +// The Ext2FileSystemParser (not manager!) +Ext2FileSystemParser::Ext2FileSystemParser(DriveTrait* drive) : fCtx(drive) { + MUST_PASS(fCtx); +} + +NodePtr Ext2FileSystemParser::Open(const char* path, const char* restrict_type) { + NE_UNUSED(restrict_type); + if (!path || *path == '\0' || !this->fCtx.drive) { + return nullptr; + } + + // Root ("/") + if (rt_string_len(path) == 1 && rt_string_cmp(path, "/", 1) == 0) { + auto inodeResult = ext2_load_inode(&this->fCtx, EXT2_ROOT_INODE); + if (!inodeResult) { + return nullptr; + } + + auto heapNode = (Ext2Node*) mm_alloc_ptr(sizeof(Ext2Node), true, false); + if (!heapNode) return nullptr; + + *heapNode = *inodeResult.Leak().Leak(); + heapNode->cursor = 0; + return reinterpret_cast(heapNode); + } + + PathComponents pathComponents(path); + if (pathComponents.count == 0) { + return nullptr; + } + + UInt32 currentInodeNumber = EXT2_ROOT_INODE; + Ext2Node* currentDirNode = nullptr; + + for (UInt32 i = 0; i < (UInt32) pathComponents.count; ++i) { + auto inodeResult = ext2_load_inode(&this->fCtx, currentInodeNumber); + if (!inodeResult) { + if (currentDirNode) mm_free_ptr(currentDirNode); + return nullptr; + } + + if (currentDirNode) { + mm_free_ptr(currentDirNode); + currentDirNode = nullptr; + } + + currentDirNode = (Ext2Node*) mm_alloc_ptr(sizeof(Ext2Node), true, false); + if (!currentDirNode) { + return nullptr; + } + + *currentDirNode = *inodeResult.Leak().Leak(); + currentDirNode->cursor = 0; + + if (i < pathComponents.count - 1U) { + UInt32 type = (currentDirNode->inode.fMode >> 12) & 0xF; + if (type != kExt2FileTypeDirectory) { + mm_free_ptr(currentDirNode); + return nullptr; + } + } + + auto dirEntryResult = + ext2_find_dir_entry(&this->fCtx, currentDirNode, pathComponents.components[i]); + if (!dirEntryResult) { + mm_free_ptr(currentDirNode); + return nullptr; + } + + EXT2_DIR_ENTRY* entryPtr = *dirEntryResult.Leak(); + currentInodeNumber = entryPtr->fInode; + mm_free_ptr(entryPtr); + } + + auto finalInodeResult = ext2_load_inode(&this->fCtx, currentInodeNumber); + if (!finalInodeResult) { + if (currentDirNode) mm_free_ptr(currentDirNode); + return nullptr; + } + + if (currentDirNode) { + mm_free_ptr(currentDirNode); + } + + auto resultNode = (Ext2Node*) mm_alloc_ptr(sizeof(Ext2Node), true, false); + if (!resultNode) { + return nullptr; + } + + *resultNode = *finalInodeResult.Leak().Leak(); + resultNode->cursor = 0; + return reinterpret_cast(resultNode); +} + +void* Ext2FileSystemParser::Read(NodePtr node, Int32 flags, SizeT size) { + if (!node) return nullptr; + + NE_UNUSED(flags); + + auto extNode = reinterpret_cast(node); + auto dataResult = ext2_read_inode_data(&this->fCtx, extNode, size); + + if (!dataResult) { + return nullptr; // error, nothing to return + } + + void* data = *dataResult.Leak(); + if (data) { + extNode->cursor += static_cast(size); + } + + return data; +} + +void Ext2FileSystemParser::Write(NodePtr node, void* data, Int32 flags, SizeT size) { + if (!node || !data || size == 0) return; + + NE_UNUSED(flags); + + auto extNode = reinterpret_cast(node); + auto blockSize = this->fCtx.BlockSize(); + SizeT bytesWritten = 0; + + UInt32 currentOffset = extNode->cursor; + UInt8* src = reinterpret_cast(data); + + while (bytesWritten < size) { + UInt32 logicalBlockIndex = currentOffset / blockSize; + UInt32 offsetInBlock = currentOffset % blockSize; + + auto physBlockResult = ext2_get_block_address(&this->fCtx, extNode, logicalBlockIndex); + UInt32 physicalBlock = 0; + + if (!physBlockResult) { + auto err = physBlockResult.Error(); + if (err == kErrorInvalidData || err == kErrorUnimplemented) { + auto groupInfoResult = ext2_get_group_descriptor_info(&this->fCtx, extNode->inodeNumber); + if (!groupInfoResult) { + return; + } + + auto groupInfo = *groupInfoResult.Leak(); + auto allocResult = ext2_alloc_block(&this->fCtx, groupInfo->groupDesc); + if (!allocResult) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return; + } + + physicalBlock = *allocResult.Leak(); + + auto setRes = + ext2_set_block_address(&this->fCtx, extNode, logicalBlockIndex, physicalBlock); + if (!setRes) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return; + } + + UInt32 gdtLba = ext2_block_to_lba(&this->fCtx, groupInfo->groupDescriptorBlock); + if (!ext2_write_block(this->fCtx.drive, gdtLba, groupInfo->blockBuffer, blockSize)) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + return; + } + + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + } else { + return; + } + } else { + physicalBlock = physBlockResult.Value(); + } + + UInt32 physicalLba = ext2_block_to_lba(&this->fCtx, physicalBlock); + + auto blockBuf = mm_alloc_ptr(blockSize, true, false); + if (!blockBuf) return; + + if (offsetInBlock > 0 || (size - bytesWritten) < blockSize) { + if (!ext2_read_block(this->fCtx.drive, physicalLba, blockBuf, blockSize)) { + mm_free_ptr(blockBuf); + return; + } + } else { + rt_zero_memory(blockBuf, blockSize); + } + + UInt32 bytesInCurrentBlock = + static_cast(ext2_min(size - bytesWritten, blockSize - offsetInBlock)); + rt_copy_memory_safe(src, static_cast((UInt8*) blockBuf + offsetInBlock), + bytesInCurrentBlock, blockSize - offsetInBlock); + + if (!ext2_write_block(this->fCtx.drive, physicalLba, blockBuf, blockSize)) { + mm_free_ptr(blockBuf); + return; + } + + mm_free_ptr(blockBuf); + + currentOffset += bytesInCurrentBlock; + src += bytesInCurrentBlock; + bytesWritten += bytesInCurrentBlock; + } + + if (currentOffset > extNode->inode.fSize) { + extNode->inode.fSize = currentOffset; + } + + extNode->inode.fBlocks = (extNode->inode.fSize + blockSize - 1) / blockSize; + extNode->inode.fModifyTime = 0; + + auto writeInodeRes = ext2_write_inode(&this->fCtx, extNode); + if (!writeInodeRes) { + // Failed to persist inode + } + + extNode->cursor = currentOffset; +} + +bool Ext2FileSystemParser::Seek(NodePtr node, SizeT offset) { + if (!node) return false; + auto extNode = reinterpret_cast(node); + extNode->cursor = static_cast(offset); + return true; +} + +SizeT Ext2FileSystemParser::Tell(NodePtr node) { + if (!node) return 0; + auto extNode = reinterpret_cast(node); + return extNode->cursor; +} + +bool Ext2FileSystemParser::Rewind(NodePtr node) { + if (!node) return false; + auto extNode = reinterpret_cast(node); + extNode->cursor = 0; + return true; +} + +void* Ext2FileSystemParser::Read(const char* name, NodePtr node, Int32 flags, SizeT size) { + NE_UNUSED(name); + return Read(node, flags, size); +} + +void Ext2FileSystemParser::Write(const char* name, NodePtr node, void* data, Int32 flags, + SizeT size) { + NE_UNUSED(name); + Write(node, data, flags, size); +} + +NodePtr Ext2FileSystemParser::Create(const char* path) { + if (!path || *path == '\0') return nullptr; + + PathComponents pathComponents(path); + if (pathComponents.count == 0) return nullptr; + + const char* filename = pathComponents.components[pathComponents.count - 1]; + if (rt_string_len(filename) > kExt2FSMaxFileNameLen) return nullptr; + + // Build parent path + Char parentPathBuf[256] = {0}; + SizeT currentPathLen = 0; + for (UInt32 i = 0; (i < pathComponents.count - 1U); ++i) { + SizeT componentLen = rt_string_len(pathComponents.components[i]); + if (currentPathLen + componentLen + 1 >= sizeof(parentPathBuf)) return nullptr; + if (i > 0) parentPathBuf[currentPathLen++] = '/'; + rt_copy_memory_safe(const_cast(pathComponents.components[i]), + parentPathBuf + currentPathLen, componentLen, + sizeof(parentPathBuf) - currentPathLen); + currentPathLen += componentLen; + } + parentPathBuf[currentPathLen] = '\0'; + + // Open parent directory + NodePtr parentDirNodePtr = nullptr; + if (currentPathLen == 0) { + // root + auto inodeRes = ext2_load_inode(&this->fCtx, EXT2_ROOT_INODE); + if (!inodeRes) return nullptr; + parentDirNodePtr = mm_alloc_ptr(sizeof(Ext2Node), true, false); + if (!parentDirNodePtr) return nullptr; + *reinterpret_cast(parentDirNodePtr) = *inodeRes.Leak().Leak(); + reinterpret_cast(parentDirNodePtr)->cursor = 0; + } else { + parentDirNodePtr = Open(parentPathBuf, "r"); + } + + if (!parentDirNodePtr) return nullptr; + + auto parentDirNode = reinterpret_cast(parentDirNodePtr); + + // Ensure parent is a directory + UInt32 type = (parentDirNode->inode.fMode >> 12) & 0xF; + if (type != kExt2FileTypeDirectory) { + mm_free_ptr(parentDirNode); + return nullptr; + } + + // Get group info for allocation + auto groupInfoResult = ext2_get_group_descriptor_info(&this->fCtx, parentDirNode->inodeNumber); + if (!groupInfoResult) { + mm_free_ptr(parentDirNode); + return nullptr; + } + auto groupInfo = *groupInfoResult.Leak(); + + // Allocate new inode + auto newInodeRes = ext2_alloc_inode(&this->fCtx, groupInfo->groupDesc); + if (!newInodeRes) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); // so this works + mm_free_ptr(parentDirNode); + return nullptr; + } + UInt32 newInodeNumber = newInodeRes.Value(); + + UInt32 gdtLba = ext2_block_to_lba(&this->fCtx, groupInfo->groupDescriptorBlock); + if (!ext2_write_block(this->fCtx.drive, gdtLba, groupInfo->blockBuffer, this->fCtx.BlockSize())) { + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + mm_free_ptr(parentDirNode); + return nullptr; + } + + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + + // Create new Ext2Node + Ext2Node* newFileNode = reinterpret_cast(mm_alloc_ptr(sizeof(Ext2Node), true, false)); + if (!newFileNode) { + mm_free_ptr(parentDirNode); + return nullptr; + } + + newFileNode->inodeNumber = newInodeNumber; + rt_zero_memory(&newFileNode->inode, sizeof(EXT2_INODE)); + + newFileNode->inode.fMode = (kExt2FileTypeRegular << 12); + newFileNode->inode.fUID = 0; + newFileNode->inode.fGID = 0; + newFileNode->inode.fLinksCount = 1; + newFileNode->inode.fSize = 0; + newFileNode->inode.fBlocks = 0; + newFileNode->inode.fCreateTime = 0; + newFileNode->inode.fModifyTime = 0; + + // Persist new inode + auto writeInodeRes = ext2_write_inode(&this->fCtx, newFileNode); + if (!writeInodeRes) { + mm_free_ptr(parentDirNode); + mm_free_ptr(newFileNode); + return nullptr; + } + + // Add directory entry + auto addRes = ext2_add_dir_entry(&this->fCtx, parentDirNode, filename, newInodeNumber, + kExt2FileTypeRegular); + if (!addRes) { + mm_free_ptr(parentDirNode); + mm_free_ptr(newFileNode); + return nullptr; + } + + // Update parent inode + auto parentWriteRes = ext2_write_inode(&this->fCtx, parentDirNode); + // ignore failure + + NE_UNUSED(parentWriteRes); + + mm_free_ptr(parentDirNode); + return reinterpret_cast(newFileNode); +} + +NodePtr Ext2FileSystemParser::CreateDirectory(const char* path) { + if (!path || *path == '\0') return nullptr; + + PathComponents pathComponents(path); + if (pathComponents.count == 0) { + kout << "EXT2: Failed to parse path for CreateDirectory.\n"; + return nullptr; + } + + const char* dirname = pathComponents.components[pathComponents.count - 1]; + if (rt_string_len(dirname) > kExt2FSMaxFileNameLen) { + kout << "EXT2: Directory name too long: " << dirname << ".\n"; + return nullptr; + } + + // Build parent path + Char parentPathBuf[256]; + SizeT currentPathLen = 0; + for (UInt32 i = 0; (i < pathComponents.count - 1U); ++i) { + SizeT componentLen = rt_string_len(pathComponents.components[i]); + if (currentPathLen + componentLen + 1 >= sizeof(parentPathBuf)) { + kout << "EXT2: Parent path too long for CreateDirectory.\n"; + return nullptr; + } + + if (i > 0) parentPathBuf[currentPathLen++] = '/'; + + rt_copy_memory_safe(static_cast(const_cast(pathComponents.components[i])), + static_cast(parentPathBuf + currentPathLen), componentLen, + sizeof(parentPathBuf) - currentPathLen); + currentPathLen += componentLen; + } + + parentPathBuf[currentPathLen] = '\0'; + + // Open parent directory node + NodePtr parentDirNodePtr = nullptr; + if (currentPathLen == 0) { + auto inodeRes = ext2_load_inode(&this->fCtx, EXT2_ROOT_INODE); + if (!inodeRes) { + return nullptr; + } + + parentDirNodePtr = reinterpret_cast(mm_alloc_ptr(sizeof(Ext2Node), true, false)); + if (!parentDirNodePtr) return nullptr; + + *reinterpret_cast(parentDirNodePtr) = *inodeRes.Leak().Leak(); + reinterpret_cast(parentDirNodePtr)->cursor = 0; + } else { + parentDirNodePtr = Open(parentPathBuf, "r"); + } + + if (!parentDirNodePtr) { + kout << "EXT2: Failed to open parent directory for CreateDirectory: " << parentPathBuf << ".\n"; + return nullptr; + } + + auto parentDirNode = reinterpret_cast(parentDirNodePtr); + + // Check parent is a directory + UInt32 parentType = (parentDirNode->inode.fMode >> 12) & 0xF; + if (parentType != kExt2FileTypeDirectory) { + kout << "EXT2: Parent is not a directory: " << parentPathBuf << ".\n"; + mm_free_ptr(parentDirNode); + return nullptr; + } + + // Allocate inode + auto groupInfoResult = ext2_get_group_descriptor_info(&this->fCtx, parentDirNode->inodeNumber); + if (!groupInfoResult) { + kout << "EXT2: Failed to get group descriptor info for new dir inode.\n"; + mm_free_ptr(parentDirNode); + return nullptr; + } + + auto groupInfo = *groupInfoResult.Leak(); + auto newInodeRes = ext2_alloc_inode(&this->fCtx, groupInfo->groupDesc); + if (!newInodeRes) { + kout << "EXT2: Failed to allocate inode for new directory.\n"; + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + mm_free_ptr(parentDirNode); + return nullptr; + } + + UInt32 newInodeNumber = *newInodeRes.Leak(); + + // Write back group descriptor block + UInt32 gdtLba = ext2_block_to_lba(&this->fCtx, groupInfo->groupDescriptorBlock); + if (!ext2_write_block(this->fCtx.drive, gdtLba, groupInfo->blockBuffer, this->fCtx.BlockSize())) { + kout << "EXT2: Failed to write group descriptor after inode allocation.\n"; + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + mm_free_ptr(parentDirNode); + return nullptr; + } + + mm_free_ptr(reinterpret_cast(groupInfo->blockBuffer)); + mm_free_ptr(groupInfo); + + // Create new Ext2Node and initialize inode fields + Ext2Node* newDirNode = reinterpret_cast(mm_alloc_ptr(sizeof(Ext2Node), true, false)); + if (!newDirNode) { + kout << "EXT2: Out of memory for new directory node.\n"; + mm_free_ptr(parentDirNode); + return nullptr; + } + + newDirNode->inodeNumber = newInodeNumber; + rt_zero_memory(&newDirNode->inode, sizeof(EXT2_INODE)); + newDirNode->inode.fMode = (kExt2FileTypeDirectory << 12); + newDirNode->inode.fUID = 0; + newDirNode->inode.fGID = 0; + newDirNode->inode.fLinksCount = 2; // . and .. + newDirNode->inode.fSize = this->fCtx.BlockSize(); + newDirNode->inode.fBlocks = 1; + newDirNode->inode.fCreateTime = 0; + newDirNode->inode.fModifyTime = 0; + + // Allocate a data block for the new directory + auto groupForBlockRes = ext2_get_group_descriptor_info(&this->fCtx, newDirNode->inodeNumber); + if (!groupForBlockRes) { + kout << "EXT2: Failed to get group info for directory block allocation.\n"; + mm_free_ptr(parentDirNode); + mm_free_ptr(newDirNode); + return nullptr; + } + + auto groupForBlock = *groupForBlockRes.Leak(); + auto newBlockRes = ext2_alloc_block(&this->fCtx, groupForBlock->groupDesc); + if (!newBlockRes) { + kout << "EXT2: Failed to allocate block for new directory contents.\n"; + mm_free_ptr(reinterpret_cast(groupForBlock->blockBuffer)); + mm_free_ptr(groupForBlock); + mm_free_ptr(parentDirNode); + mm_free_ptr(newDirNode); + return nullptr; + } + + UInt32 newDirBlockNum = *newBlockRes.Leak(); + + // Write back GDT + UInt32 gdtLba2 = ext2_block_to_lba(&this->fCtx, groupForBlock->groupDescriptorBlock); + if (!ext2_write_block(this->fCtx.drive, gdtLba2, groupForBlock->blockBuffer, + this->fCtx.BlockSize())) { + kout << "EXT2: Failed to write GDT after directory block allocation.\n"; + mm_free_ptr(reinterpret_cast(groupForBlock->blockBuffer)); + mm_free_ptr(groupForBlock); + mm_free_ptr(parentDirNode); + mm_free_ptr(newDirNode); + return nullptr; + } + + mm_free_ptr(reinterpret_cast(groupForBlock->blockBuffer)); + mm_free_ptr(groupForBlock); + + // Set the block in newDirNode + auto setBlkRes = ext2_set_block_address(&this->fCtx, newDirNode, 0, newDirBlockNum); + if (!setBlkRes) { + kout << "EXT2: Failed to set data block for new directory.\n"; + mm_free_ptr(parentDirNode); + mm_free_ptr(newDirNode); + return nullptr; + } + + // Prepare block with '.' and '..' + auto dirBlockBuf = mm_alloc_ptr(this->fCtx.BlockSize(), true, false); + if (!dirBlockBuf) { + kout << "EXT2: Out of memory preparing directory block.\n"; + mm_free_ptr(parentDirNode); + mm_free_ptr(newDirNode); + return nullptr; + } + + rt_zero_memory(dirBlockBuf, this->fCtx.BlockSize()); + + // '.' entry + auto dot = reinterpret_cast(dirBlockBuf); + dot->fInode = newInodeNumber; + dot->fNameLength = 1; + dot->fFileType = kExt2FileTypeDirectory; + dot->fRecordLength = ext2_dir_entry_ideal_len(dot->fNameLength); + dot->fName[0] = '.'; + + // '..' entry occupies rest of block + auto dotdot = reinterpret_cast((UInt8*) dirBlockBuf + dot->fRecordLength); + dotdot->fInode = parentDirNode->inodeNumber; + dotdot->fNameLength = 2; + dotdot->fFileType = kExt2FileTypeDirectory; + dotdot->fRecordLength = static_cast(this->fCtx.BlockSize() - dot->fRecordLength); + dotdot->fName[0] = '.'; + dotdot->fName[1] = '.'; + + // Write dir block to disk + UInt32 newDirBlockLba = ext2_block_to_lba(&this->fCtx, newDirBlockNum); + if (!ext2_write_block(this->fCtx.drive, newDirBlockLba, dirBlockBuf, this->fCtx.BlockSize())) { + kout << "EXT2: Failed to write directory block to disk.\n"; + mm_free_ptr(dirBlockBuf); + mm_free_ptr(parentDirNode); + mm_free_ptr(newDirNode); + return nullptr; + } + + mm_free_ptr(dirBlockBuf); + + // Persist new directory inode + auto writeInodeRes = ext2_write_inode(&this->fCtx, newDirNode); + if (!writeInodeRes) { + kout << "EXT2: Failed to write new directory inode to disk.\n"; + mm_free_ptr(parentDirNode); + mm_free_ptr(newDirNode); + return nullptr; + } + + // Add directory entry into parent + auto addRes = ext2_add_dir_entry(&this->fCtx, parentDirNode, dirname, newInodeNumber, + kExt2FileTypeDirectory); + if (!addRes) { + kout << "EXT2: Failed to add directory entry for '" << dirname << "' to parent.\n"; + mm_free_ptr(parentDirNode); + mm_free_ptr(newDirNode); + return nullptr; + } + + // Increment parent link count and persist parent inode + parentDirNode->inode.fLinksCount += 1; + auto parentWriteRes = ext2_write_inode(&this->fCtx, parentDirNode); + if (!parentWriteRes) { + kout << "EXT2: Warning: failed to update parent inode after directory creation.\n"; + } + + mm_free_ptr(parentDirNode); + return reinterpret_cast(newDirNode); +} + +#endif +#endif diff --git a/dev/kernel/src/FS/HeFS+FileMgr.cc b/dev/kernel/src/FS/HeFS+FileMgr.cc index e4985a3b..6b559cf4 100644 --- a/dev/kernel/src/FS/HeFS+FileMgr.cc +++ b/dev/kernel/src/FS/HeFS+FileMgr.cc @@ -10,5 +10,157 @@ #include #include +/// @brief HeFS File System Manager. +/// BUGS: 0 + +namespace Kernel { +/// @brief C++ constructor +HeFileSystemMgr::HeFileSystemMgr() { + mParser = new HeFileSystemParser(); + MUST_PASS(mParser); + + kout << "We are done allocating NeFileSystemParser...\n"; +} + +HeFileSystemMgr::~HeFileSystemMgr() { + if (mParser) { + kout << "Destroying NeFileSystemParser...\n"; + delete mParser; + mParser = nullptr; + } +} + +/// @brief Removes a node from the filesystem. +/// @param path The filename +/// @return If it was deleted or not. +bool HeFileSystemMgr::Remove(_Input const Char* path) { + if (path == nullptr || *path == 0) { + kout << "HeFS: Remove called with null or empty path\n"; + return false; + } + + return NO; +} + +/// @brief Creates a node with the specified. +/// @param path The filename path. +/// @return The Node pointer. +NodePtr HeFileSystemMgr::Create(_Input const Char* path) { + if (!path || *path == 0) { + kout << "HeFS: Create called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +/// @brief Creates a node which is a directory. +/// @param path The filename path. +/// @return The Node pointer. +NodePtr HeFileSystemMgr::CreateDirectory(const Char* path) { + if (!path || *path == 0) { + kout << "HeFS: CreateDirectory called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +/// @brief Creates a node which is an alias. +/// @param path The filename path. +/// @return The Node pointer. +NodePtr HeFileSystemMgr::CreateAlias(const Char* path) { + if (!path || *path == 0) { + kout << "HeFS: CreateAlias called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +NodePtr HeFileSystemMgr::CreateSwapFile(const Char* path) { + if (!path || *path == 0) { + kout << "HeFS: CreateSwapFile called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +/// @brief Gets the root directory. +/// @return +const Char* NeFileSystemHelper::Root() { + return kHeFSRootDirectory; +} + +/// @brief Gets the up-dir directory. +/// @return +const Char* NeFileSystemHelper::UpDir() { + return kHeFSUpDir; +} + +/// @brief Gets the separator character. +/// @return +Char NeFileSystemHelper::Separator() { + return kHeFSSeparator; +} + +/// @brief Gets the metafile character. +/// @return +Char NeFileSystemHelper::MetaFile() { + return 0; +} + +/// @brief Opens a new file. +/// @param path +/// @param r +/// @return +_Output NodePtr HeFileSystemMgr::Open(_Input const Char* path, _Input const Char* r) { + if (!path || *path == 0) { + kout << "HeFS: Open called with null or empty path\n"; + return nullptr; + } + if (!r || *r == 0) { + kout << "HeFS: Open called with null or empty mode string\n"; + return nullptr; + } + return nullptr; +} + +Void HeFileSystemMgr::Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, + _Input SizeT size) {} + +_Output VoidPtr HeFileSystemMgr::Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT size) { + return nullptr; +} + +Void HeFileSystemMgr::Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, + _Input Int32 flags, _Input SizeT size) {} + +_Output VoidPtr HeFileSystemMgr::Read(_Input const Char* name, _Input NodePtr node, + _Input Int32 flags, _Input SizeT sz) { + return nullptr; +} + +_Output Bool HeFileSystemMgr::Seek(NodePtr node, SizeT off) { + return false; +} + +/// @brief Tell current offset within catalog. +/// @param node +/// @return kFileMgrNPos if invalid, else current offset. +_Output SizeT HeFileSystemMgr::Tell(NodePtr node) { + return kFileMgrNPos; +} + +/// @brief Rewinds the catalog +/// @param node +/// @return False if invalid, nah? calls Seek(node, 0). +_Output Bool HeFileSystemMgr::Rewind(NodePtr node) { + return kFileMgrNPos; +} + +/// @brief Returns the parser of HeFS. +_Output HeFileSystemParser* HeFileSystemMgr::GetParser() noexcept { + return mParser; +} +} // namespace Kernel + #endif // ifdef __FSKIT_INCLUDES_HEFS__ #endif // ifndef __NE_MINIMAL_OS__ diff --git a/dev/kernel/src/GUIDWizard.cc b/dev/kernel/src/GUIDWizard.cc index 46915ace..b3120179 100644 --- a/dev/kernel/src/GUIDWizard.cc +++ b/dev/kernel/src/GUIDWizard.cc @@ -17,7 +17,7 @@ // @brief Size of UUID. #define kUUIDSize 37 -namespace CF::XRN::Version1 { +namespace Kernel::CF::XRN::Version1 { auto cf_make_sequence(const ArrayList& uuidSeq) -> Ref { GUIDSequence* seq = new GUIDSequence(); MUST_PASS(seq); @@ -62,4 +62,4 @@ auto cf_try_guid_to_string(Ref& seq) -> ErrorOr> { return ErrorOr>{-1}; } -} // namespace CF::XRN::Version1 +} // namespace Kernel::CF::XRN::Version1 diff --git a/dev/kernel/src/GUIDWrapper.cc b/dev/kernel/src/GUIDWrapper.cc index f87a1bdd..d5ab6bb8 100644 --- a/dev/kernel/src/GUIDWrapper.cc +++ b/dev/kernel/src/GUIDWrapper.cc @@ -6,4 +6,4 @@ #include -namespace CF::XRN {} +namespace Kernel::CF::XRN {} diff --git a/dev/kernel/src/PEFCodeMgr.cc b/dev/kernel/src/PEFCodeMgr.cc index c0caeb5b..a0d0a6af 100644 --- a/dev/kernel/src/PEFCodeMgr.cc +++ b/dev/kernel/src/PEFCodeMgr.cc @@ -53,7 +53,37 @@ namespace Detail { /***********************************************************************************/ PEFLoader::PEFLoader(const VoidPtr blob) : fCachedBlob(blob) { MUST_PASS(fCachedBlob); - fBad = false; + + if (!fCachedBlob) { + this->fBad = YES; + return; + } + + PEFContainer* container = reinterpret_cast(fCachedBlob); + + if (container->Abi == kPefAbi && + container->Count >= + 3) { /* if same ABI, AND: .text, .bss, .data (or at least similar) exists */ + if (container->Cpu == Detail::ldr_get_platform() && container->Magic[0] == kPefMagic[0] && + container->Magic[1] == kPefMagic[1] && container->Magic[2] == kPefMagic[2] && + container->Magic[3] == kPefMagic[3] && container->Magic[4] == kPefMagic[4]) { + return; + } else if (container->Magic[0] == kPefMagicFat[0] && container->Magic[1] == kPefMagicFat[1] && + container->Magic[2] == kPefMagicFat[2] && container->Magic[3] == kPefMagicFat[3] && + container->Magic[4] == kPefMagicFat[4]) { + /// This is a fat binary. Treat it as such. + this->fFatBinary = YES; + return; + } + } + + kout << "PEFLoader: warning: Binary format error!\r"; + + this->fFatBinary = NO; + this->fBad = YES; + + if (this->fCachedBlob) mm_free_ptr(this->fCachedBlob); + this->fCachedBlob = nullptr; } /***********************************************************************************/ @@ -69,6 +99,11 @@ PEFLoader::PEFLoader(const Char* path) : fCachedBlob(nullptr), fFatBinary(false) /// @note zero here means that the FileMgr will read every container header inside the file. fCachedBlob = fFile->Read(kPefHeader, 0UL); + if (!fCachedBlob) { + this->fBad = YES; + return; + } + PEFContainer* container = reinterpret_cast(fCachedBlob); if (container->Abi == kPefAbi && @@ -82,18 +117,18 @@ PEFLoader::PEFLoader(const Char* path) : fCachedBlob(nullptr), fFatBinary(false) container->Magic[2] == kPefMagicFat[2] && container->Magic[3] == kPefMagicFat[3] && container->Magic[4] == kPefMagicFat[4]) { /// This is a fat binary, treat it as such. - this->fFatBinary = true; + this->fFatBinary = YES; return; } } - fBad = true; + kout << "PEFLoader: warning: Binary format error!\r"; - if (fCachedBlob) mm_free_ptr(fCachedBlob); - - kout << "PEFLoader: warning: exec format error!\r"; + this->fFatBinary = NO; + this->fBad = YES; - fCachedBlob = nullptr; + if (this->fCachedBlob) mm_free_ptr(this->fCachedBlob); + this->fCachedBlob = nullptr; } /***********************************************************************************/ @@ -127,9 +162,8 @@ ErrorOr PEFLoader::FindSymbol(const Char* name, Int32 kind) { return ErrorOr{kErrorInvalidData}; /// fat binary check. - if (command_header->Cpu != container->Cpu && !this->fFatBinary) { + if (command_header->Cpu != container->Cpu && !this->fFatBinary) return ErrorOr{kErrorInvalidData}; - } const auto kMangleCharacter = '$'; const Char* kContainerKinds[] = {".code64", ".data64", ".zero64", nullptr}; @@ -183,7 +217,7 @@ ErrorOr PEFLoader::FindSymbol(const Char* name, Int32 kind) { mm_free_ptr(blob); - kout << "PEFLoader: info: Loaded stub: " << command_header->Name << "!\r"; + kout << "PEFLoader: info: Load stub: " << command_header->Name << "!\r"; Int32 ret = 0; SizeT pages_count = (command_header->VMSize + kPageSize - 1) / kPageSize; diff --git a/dev/kernel/src/Property.cc b/dev/kernel/src/Property.cc index 581da501..1d01293f 100644 --- a/dev/kernel/src/Property.cc +++ b/dev/kernel/src/Property.cc @@ -6,7 +6,7 @@ #include -namespace CF { +namespace Kernel::CF { /***********************************************************************************/ /// @brief Destructor. /***********************************************************************************/ @@ -38,4 +38,4 @@ BasicKString<>& Property::GetKey() { PropertyId& Property::GetValue() { return fValue; } -} // namespace CF +} // namespace Kernel::CF diff --git a/dev/launch/LaunchKit/LaunchKit.h b/dev/launch/LaunchKit/LaunchKit.h index 2efa7806..34f7c223 100644 --- a/dev/launch/LaunchKit/LaunchKit.h +++ b/dev/launch/LaunchKit/LaunchKit.h @@ -15,6 +15,6 @@ #define NELAUNCH_WARN(MSG) PrintOut(nullptr, "WARN: [LAUNCH] %s\n", MSG) namespace Launch { -using LaunchAny = VoidPtr; +using LaunchAny = VoidPtr; using LaunchStatus = SInt32; } // namespace Launch diff --git a/dev/libSystem/SystemKit/Verify.h b/dev/libSystem/SystemKit/Verify.h index 5ad0dbff..bc0c8be3 100644 --- a/dev/libSystem/SystemKit/Verify.h +++ b/dev/libSystem/SystemKit/Verify.h @@ -37,4 +37,4 @@ inline constexpr R* sys_constexpr_cast(T* ptr) { static_assert(must_cast_traits::value, "constexpr cast failed! types are mismatching!"); return static_cast(ptr); } -} // namespace LibSystem::Detail +} // namespace LibSystem::Verify diff --git a/docs/drawio/LAUNCH_DESIGN.drawio b/docs/drawio/LAUNCH_DESIGN.drawio new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From 59f37ac002635171892925f163783689ec23c1fc Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Thu, 9 Oct 2025 12:00:49 +0200 Subject: feat: fixes and improvements of the kernel. Signed-off-by: Amlal El Mahrouss --- dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc | 2 +- dev/kernel/SignalKit/SignalGen.h | 4 ++-- dev/kernel/StorageKit/AHCI.h | 2 +- dev/kernel/src/Storage/AHCIDeviceInterface.cc | 2 +- dev/kernel/src/Storage/ATADeviceInterface.cc | 2 +- dev/kernel/src/UserMgr.cc | 12 ++++++------ dev/kernel/src/UserProcessScheduler.cc | 12 ++++-------- dev/kernel/src/UtfUtils.cc | 9 +++++++++ 8 files changed, 25 insertions(+), 20 deletions(-) (limited to 'dev/kernel') diff --git a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc index 77e3331d..0a465145 100644 --- a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc +++ b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc @@ -591,7 +591,7 @@ namespace Detail { /// @brief Acquires a new AHCI device with drv_index in mind. /// @param drv_index The drive index to assign. /// @return A wrapped device interface if successful, or error code. -ErrorOr sk_acquire_ahci_device(Int32 drv_index) { +ErrorOr sk_acquire_ahci_device(UInt32 drv_index) { if (!drv_std_detected_ahci()) return ErrorOr(kErrorDisk); AHCIDeviceInterface device(Detail::sk_io_read_ahci, Detail::sk_io_write_ahci); diff --git a/dev/kernel/SignalKit/SignalGen.h b/dev/kernel/SignalKit/SignalGen.h index 4be9452a..fdc27161 100644 --- a/dev/kernel/SignalKit/SignalGen.h +++ b/dev/kernel/SignalKit/SignalGen.h @@ -26,10 +26,10 @@ namespace Kernel { typedef SizeT rt_signal_kind; /// @brief Standard signal seed for general purpose usage. -inline static constexpr auto kUserSignalSeed = 0x0895034fUL; +inline constexpr auto kUserSignalSeed = 0x0895034fUL; /// @brief Special signal seed for kernel usage. -inline static constexpr auto kKernelSignalSeed = 0x0895034f9fUL; +inline constexpr auto kKernelSignalSeed = 0x0895034f9fUL; /// @brief Generate signal from **Sig** template diff --git a/dev/kernel/StorageKit/AHCI.h b/dev/kernel/StorageKit/AHCI.h index 3b9dac67..3605abe6 100644 --- a/dev/kernel/StorageKit/AHCI.h +++ b/dev/kernel/StorageKit/AHCI.h @@ -45,5 +45,5 @@ class AHCIDeviceInterface NE_DEVICE { }; UInt16 sk_init_ahci_device(BOOL atapi); -ErrorOr sk_acquire_ahci_device(Int32 drv_index); +ErrorOr sk_acquire_ahci_device(UInt32 drv_index); } // namespace Kernel diff --git a/dev/kernel/src/Storage/AHCIDeviceInterface.cc b/dev/kernel/src/Storage/AHCIDeviceInterface.cc index 39570665..182ed2b3 100644 --- a/dev/kernel/src/Storage/AHCIDeviceInterface.cc +++ b/dev/kernel/src/Storage/AHCIDeviceInterface.cc @@ -84,6 +84,6 @@ const UInt32& AHCIDeviceInterface::GetIndex() { } Void AHCIDeviceInterface::SetIndex(const UInt32& drv) { - MUST_PASS(MountpointInterface::kDriveIndexInvalid != drv); + MUST_PASS(MountpointInterface::kDriveIndexInvalid < drv); this->fDriveIndex = drv; } \ No newline at end of file diff --git a/dev/kernel/src/Storage/ATADeviceInterface.cc b/dev/kernel/src/Storage/ATADeviceInterface.cc index 609837af..e302d2cc 100644 --- a/dev/kernel/src/Storage/ATADeviceInterface.cc +++ b/dev/kernel/src/Storage/ATADeviceInterface.cc @@ -74,7 +74,7 @@ const UInt32& ATADeviceInterface::GetIndex() { } Void ATADeviceInterface::SetIndex(const UInt32& drv) { - MUST_PASS(MountpointInterface::kDriveIndexInvalid != drv); + MUST_PASS(MountpointInterface::kDriveIndexInvalid < drv); this->fDriveIndex = drv; } diff --git a/dev/kernel/src/UserMgr.cc b/dev/kernel/src/UserMgr.cc index 8e4ba540..9db1ca4d 100644 --- a/dev/kernel/src/UserMgr.cc +++ b/dev/kernel/src/UserMgr.cc @@ -22,7 +22,7 @@ #define kStdUserType (0xEE) #define kSuperUserType (0xEF) -/// @file User.cc +/// @file UserMgr.cc /// @brief Multi-user support. namespace Kernel { @@ -38,14 +38,14 @@ namespace Detail { kout << "user_fnv_generator: Hashing user password...\r"; - const UInt64 FNV_OFFSET_BASIS = 0xcbf29ce484222325ULL; - const UInt64 FNV_PRIME = 0x100000001b3ULL; + const UInt64 kFnvOffsetBasis = 0xcbf29ce484222325ULL; + const UInt64 fFnvPrime = 0x100000001b3ULL; - UInt64 hash = FNV_OFFSET_BASIS; + UInt64 hash = kFnvOffsetBasis; while (*password) { - hash ^= (Utf8Char) (*password++); - hash *= FNV_PRIME; + hash ^= (Char) (*password++); + hash *= fFnvPrime; } kout << "user_fnv_generator: Hashed user password.\r"; diff --git a/dev/kernel/src/UserProcessScheduler.cc b/dev/kernel/src/UserProcessScheduler.cc index 07c4a572..ad6263c8 100644 --- a/dev/kernel/src/UserProcessScheduler.cc +++ b/dev/kernel/src/UserProcessScheduler.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include ///! BUGS: 0 @@ -462,15 +463,10 @@ UserProcessScheduler& UserProcessScheduler::The() { /***********************************************************************************/ Void UserProcessScheduler::Remove(ProcessID process_id) { - if (process_id < 0 || process_id > kSchedProcessLimitPerTeam) { - return; - } - - if (this->mTeam.mProcessList[process_id].Status == ProcessStatusKind::kInvalid) { - return; - } + if (process_id < 0 || process_id > kSchedProcessLimitPerTeam) return; + if (this->mTeam.mProcessList[process_id].Status == ProcessStatusKind::kInvalid) return; - mTeam.mProcessList[process_id].Exit(0); + mTeam.mProcessList[process_id].Exit(kErrorSuccess); } /// @brief Is it a user scheduler? diff --git a/dev/kernel/src/UtfUtils.cc b/dev/kernel/src/UtfUtils.cc index e98b8306..d0523b96 100644 --- a/dev/kernel/src/UtfUtils.cc +++ b/dev/kernel/src/UtfUtils.cc @@ -10,6 +10,8 @@ namespace Kernel { Size urt_string_len(const Utf8Char* str) { + if (!str) return 0; + SizeT len{0}; while (str[len] != u8'\0') ++len; @@ -18,6 +20,8 @@ Size urt_string_len(const Utf8Char* str) { } Void urt_set_memory(const voidPtr src, UInt32 dst, Size len) { + if (!src) return; + Utf8Char* srcChr = reinterpret_cast(src); Size index = 0; @@ -28,6 +32,8 @@ Void urt_set_memory(const voidPtr src, UInt32 dst, Size len) { } Int32 urt_string_cmp(const Utf8Char* src, const Utf8Char* cmp, Size size) { + if (!src) return 0; + Int32 counter = 0; for (Size index = 0; index < size; ++index) { @@ -38,6 +44,9 @@ Int32 urt_string_cmp(const Utf8Char* src, const Utf8Char* cmp, Size size) { } Int32 urt_copy_memory(const VoidPtr src, VoidPtr dst, Size len) { + if (!src) return 0; + if (!dst) return 0; + Utf8Char* srcChr = reinterpret_cast(src); Utf8Char* dstChar = reinterpret_cast(dst); -- cgit v1.2.3 From 212c57ea05bf918dc26fe8864ad617f2f6259cea Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Fri, 10 Oct 2025 10:30:38 +0200 Subject: feat: kernel: dispatch structures have two new methods. Signed-off-by: Amlal El Mahrouss --- dev/kernel/ArchKit/ArchKit.h | 6 ++++++ dev/kernel/CFKit/GUIDWrapper.h | 5 ++--- dev/kernel/src/UserMgr.cc | 2 +- dev/kernel/src/UserProcessScheduler.cc | 1 - dev/libSystem/src/JailCalls.cc | 4 ++-- dev/libSystem/src/VerifyCalls.cc | 2 +- 6 files changed, 12 insertions(+), 8 deletions(-) (limited to 'dev/kernel') diff --git a/dev/kernel/ArchKit/ArchKit.h b/dev/kernel/ArchKit/ArchKit.h index 2042bded..9c45b6bb 100644 --- a/dev/kernel/ArchKit/ArchKit.h +++ b/dev/kernel/ArchKit/ArchKit.h @@ -75,6 +75,9 @@ struct HAL_DISPATCH_ENTRY final { Kernel::Bool fHooked; rt_syscall_proc fProc; + BOOL IsKernCall() { return NO; } + BOOL IsSysCall() { return YES; } + operator bool() { return fHooked; } }; @@ -86,6 +89,9 @@ struct HAL_KERNEL_DISPATCH_ENTRY final { Kernel::Bool fHooked; rt_kerncall_proc fProc; + BOOL IsKernCall() { return YES; } + BOOL IsSysCall() { return NO; } + operator bool() { return fHooked; } }; diff --git a/dev/kernel/CFKit/GUIDWrapper.h b/dev/kernel/CFKit/GUIDWrapper.h index 05cb4754..14a96fde 100644 --- a/dev/kernel/CFKit/GUIDWrapper.h +++ b/dev/kernel/CFKit/GUIDWrapper.h @@ -16,7 +16,7 @@ /// @brief eXtended Resource Namespace namespace Kernel::CF::XRN { -union GUIDSequence { +union GUIDSequence final { alignas(8) UShort fU8[16]; alignas(8) UShort fU16[8]; alignas(8) UInt fU32[4]; @@ -36,8 +36,7 @@ class GUID final { ~GUID() = default; public: - GUID& operator=(const GUID&) = default; - GUID(const GUID&) = default; + NE_COPY_DEFAULT(GUID) public: GUIDSequence& operator->() noexcept { return fUUID; } diff --git a/dev/kernel/src/UserMgr.cc b/dev/kernel/src/UserMgr.cc index 9db1ca4d..5ee2aa33 100644 --- a/dev/kernel/src/UserMgr.cc +++ b/dev/kernel/src/UserMgr.cc @@ -39,7 +39,7 @@ namespace Detail { kout << "user_fnv_generator: Hashing user password...\r"; const UInt64 kFnvOffsetBasis = 0xcbf29ce484222325ULL; - const UInt64 fFnvPrime = 0x100000001b3ULL; + const UInt64 fFnvPrime = 0x100000001b3ULL; UInt64 hash = kFnvOffsetBasis; diff --git a/dev/kernel/src/UserProcessScheduler.cc b/dev/kernel/src/UserProcessScheduler.cc index ad6263c8..af54799e 100644 --- a/dev/kernel/src/UserProcessScheduler.cc +++ b/dev/kernel/src/UserProcessScheduler.cc @@ -21,7 +21,6 @@ #include #include #include -#include #include ///! BUGS: 0 diff --git a/dev/libSystem/src/JailCalls.cc b/dev/libSystem/src/JailCalls.cc index 85796e9f..5cb47bb5 100644 --- a/dev/libSystem/src/JailCalls.cc +++ b/dev/libSystem/src/JailCalls.cc @@ -5,13 +5,13 @@ ------------------------------------------- */ #include +#include #include #include -#include #include using namespace LibSystem; IMPORT_C struct JAIL* JailGetCurrent(Void) { - return (struct JAIL*)libsys_syscall_arg_1(SYSCALL_HASH("JailGetCurrent")); + return (struct JAIL*) libsys_syscall_arg_1(SYSCALL_HASH("JailGetCurrent")); } \ No newline at end of file diff --git a/dev/libSystem/src/VerifyCalls.cc b/dev/libSystem/src/VerifyCalls.cc index 83617ae0..078f921b 100644 --- a/dev/libSystem/src/VerifyCalls.cc +++ b/dev/libSystem/src/VerifyCalls.cc @@ -5,8 +5,8 @@ ------------------------------------------- */ #include -#include #include +#include using namespace LibSystem; -- cgit v1.2.3 From faec0dd3a9eda081052753f260133d10b2cdbfe7 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Mon, 13 Oct 2025 10:40:14 +0200 Subject: feat: kernel: fix error code in `cf_try_guid_to_string` and `cf_make_sequence`. Signed-off-by: Amlal El Mahrouss --- dev/kernel/src/GUIDWizard.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'dev/kernel') diff --git a/dev/kernel/src/GUIDWizard.cc b/dev/kernel/src/GUIDWizard.cc index b3120179..b36fffc2 100644 --- a/dev/kernel/src/GUIDWizard.cc +++ b/dev/kernel/src/GUIDWizard.cc @@ -24,6 +24,8 @@ auto cf_make_sequence(const ArrayList& uuidSeq) -> Ref { Ref seq_ref{seq}; + if (!seq) return seq_ref; + seq_ref.Leak()->fUuid.fMs1 = uuidSeq[0]; seq_ref.Leak()->fUuid.fMs2 = uuidSeq[1]; seq_ref.Leak()->fUuid.fMs3 = uuidSeq[2]; @@ -60,6 +62,6 @@ auto cf_try_guid_to_string(Ref& seq) -> ErrorOr> { if (view) return ErrorOr>{view.Leak()}; - return ErrorOr>{-1}; + return ErrorOr>{kErrorInvalidData}; } } // namespace Kernel::CF::XRN::Version1 -- cgit v1.2.3 From 3d8a7b189d3deaaaab948fdb71ed7fedcc16e05c Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sun, 19 Oct 2025 18:08:04 +0200 Subject: feat: kernel: NetworkKit improvements and signal system refactors. Signed-off-by: Amlal El Mahrouss --- dev/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc | 2 +- dev/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc | 2 +- dev/kernel/NetworkKit/IPC.h | 19 ++++---- dev/kernel/NetworkKit/MAC.h | 2 +- dev/kernel/SignalKit/SignalGen.h | 51 ---------------------- dev/kernel/SignalKit/Signals.h | 51 ++++++++++++++++++++++ dev/kernel/src/UserProcessScheduler.cc | 2 +- 7 files changed, 63 insertions(+), 66 deletions(-) delete mode 100644 dev/kernel/SignalKit/SignalGen.h create mode 100644 dev/kernel/SignalKit/Signals.h (limited to 'dev/kernel') diff --git a/dev/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc b/dev/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc index 7408639c..0cb991f9 100644 --- a/dev/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc +++ b/dev/kernel/HALKit/AMD64/HalCoreInterruptHandler.cc @@ -8,7 +8,7 @@ #include #include #include -#include +#include EXTERN_C Kernel::Void idt_handle_breakpoint(Kernel::UIntPtr rip); diff --git a/dev/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc b/dev/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc index dd875c63..0c26f4cb 100644 --- a/dev/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc +++ b/dev/kernel/HALKit/ARM64/HalCoreInterruptHandler.cc @@ -8,7 +8,7 @@ #include #include #include -#include +#include EXTERN_C Kernel::Void int_handle_breakpoint(Kernel::UIntPtr rip); EXTERN_C BOOL mp_handle_gic_interrupt_el0(Void); diff --git a/dev/kernel/NetworkKit/IPC.h b/dev/kernel/NetworkKit/IPC.h index 223a112b..c65ec6fb 100644 --- a/dev/kernel/NetworkKit/IPC.h +++ b/dev/kernel/NetworkKit/IPC.h @@ -38,13 +38,10 @@ struct PACKED IPC_ADDR final { // some operators. //////////////////////////////////// - bool operator==(const IPC_ADDR& addr) noexcept; - - bool operator==(IPC_ADDR& addr) noexcept; - - bool operator!=(const IPC_ADDR& addr) noexcept; - - bool operator!=(IPC_ADDR& addr) noexcept; + BOOL operator==(const IPC_ADDR& addr) noexcept; + BOOL operator==(IPC_ADDR& addr) noexcept; + BOOL operator!=(const IPC_ADDR& addr) noexcept; + BOOL operator!=(IPC_ADDR& addr) noexcept; }; typedef struct IPC_ADDR IPC_ADDR; @@ -58,7 +55,7 @@ enum { constexpr inline auto kIPCMsgSize = 6094U; enum { - kIPCLockInvalid, + kIPCLockInvalid = 0, kIPCLockFree = 1, kIPCLockUsed = 2, }; @@ -77,17 +74,17 @@ typedef struct IPC_MSG final { UInt32 IpcLock; /// @brief Passes the message to target, could be anything, HTTP packet, JSON or whatever. static Bool Pass(IPC_MSG* self, IPC_MSG* target) noexcept; -} PACKED IPC_MSG; +} PACKED ALIGN(8) IPC_MSG; /// @brief Sanitize packet function /// @retval true packet is correct. /// @retval false packet is incorrect and process has crashed. -Bool ipc_sanitize_packet(_Input IPC_MSG* pckt_in); +BOOL ipc_sanitize_packet(_Input IPC_MSG* pckt_in); /// @brief Construct packet function /// @retval true packet is correct. /// @retval false packet is incorrect and process has crashed. -Bool ipc_construct_packet(_Output _Input IPC_MSG** pckt_in); +BOOL ipc_construct_packet(_Output _Input IPC_MSG** pckt_in); } // namespace Kernel #endif // INC_IPC_H diff --git a/dev/kernel/NetworkKit/MAC.h b/dev/kernel/NetworkKit/MAC.h index 805f7259..9cfd93c2 100644 --- a/dev/kernel/NetworkKit/MAC.h +++ b/dev/kernel/NetworkKit/MAC.h @@ -10,7 +10,7 @@ #include #include -#define kMACAddrLen (32) +#define kMACAddrLen (32U) namespace Kernel { class MacAddressGetter; diff --git a/dev/kernel/SignalKit/SignalGen.h b/dev/kernel/SignalKit/SignalGen.h deleted file mode 100644 index fdc27161..00000000 --- a/dev/kernel/SignalKit/SignalGen.h +++ /dev/null @@ -1,51 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#pragma once - -#include - -#define SIGKILL 1 /* kill */ -#define SIGPAUS 2 /* pause */ -#define SIGEXEC 3 /* execute */ -#define SIGTRAP 4 /* trap */ -#define SIGABRT 5 /* abort */ -#define SIGCONT 6 /* continue */ -#define SIGSEG 7 /* process fault */ -#define SIGBREK 8 -#define SIGATCH 9 -#define SIGDTCH 10 - -/// @author Amlal El Mahrouss -/// @brief Signal Generation API. - -namespace Kernel { -typedef SizeT rt_signal_kind; - -/// @brief Standard signal seed for general purpose usage. -inline constexpr auto kUserSignalSeed = 0x0895034fUL; - -/// @brief Special signal seed for kernel usage. -inline constexpr auto kKernelSignalSeed = 0x0895034f9fUL; - -/// @brief Generate signal from **Sig** -template -inline rt_signal_kind sig_generate_unique() { - static_assert(Sig > 0, "Signal is zero (invalid)"); - return Sig ^ Seed; -} - -/// @brief Checks if the signal matches the seed (user_seed or kernel_seed) -template -inline BOOL sig_matches_seed(rt_signal_kind sig) { - return (sig & 0xFF000000) == (Seed & 0xFF000000); -} - -/// @brief Validate signal from **sig** -inline BOOL sig_validate_unique(rt_signal_kind sig) { - return sig > 0; -} -} // namespace Kernel diff --git a/dev/kernel/SignalKit/Signals.h b/dev/kernel/SignalKit/Signals.h new file mode 100644 index 00000000..fdc27161 --- /dev/null +++ b/dev/kernel/SignalKit/Signals.h @@ -0,0 +1,51 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include + +#define SIGKILL 1 /* kill */ +#define SIGPAUS 2 /* pause */ +#define SIGEXEC 3 /* execute */ +#define SIGTRAP 4 /* trap */ +#define SIGABRT 5 /* abort */ +#define SIGCONT 6 /* continue */ +#define SIGSEG 7 /* process fault */ +#define SIGBREK 8 +#define SIGATCH 9 +#define SIGDTCH 10 + +/// @author Amlal El Mahrouss +/// @brief Signal Generation API. + +namespace Kernel { +typedef SizeT rt_signal_kind; + +/// @brief Standard signal seed for general purpose usage. +inline constexpr auto kUserSignalSeed = 0x0895034fUL; + +/// @brief Special signal seed for kernel usage. +inline constexpr auto kKernelSignalSeed = 0x0895034f9fUL; + +/// @brief Generate signal from **Sig** +template +inline rt_signal_kind sig_generate_unique() { + static_assert(Sig > 0, "Signal is zero (invalid)"); + return Sig ^ Seed; +} + +/// @brief Checks if the signal matches the seed (user_seed or kernel_seed) +template +inline BOOL sig_matches_seed(rt_signal_kind sig) { + return (sig & 0xFF000000) == (Seed & 0xFF000000); +} + +/// @brief Validate signal from **sig** +inline BOOL sig_validate_unique(rt_signal_kind sig) { + return sig > 0; +} +} // namespace Kernel diff --git a/dev/kernel/src/UserProcessScheduler.cc b/dev/kernel/src/UserProcessScheduler.cc index af54799e..2306d3e4 100644 --- a/dev/kernel/src/UserProcessScheduler.cc +++ b/dev/kernel/src/UserProcessScheduler.cc @@ -21,7 +21,7 @@ #include #include #include -#include +#include ///! BUGS: 0 -- cgit v1.2.3 From 974d5eae785025facb2c0037c4ec3aaca1da7b20 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sun, 19 Oct 2025 20:06:33 +0200 Subject: feat: kernel: disk_swap and network improvements. Signed-off-by: Amlal El Mahrouss --- dev/kernel/src/AsciiUtils.cc | 3 +++ dev/kernel/src/Network/NetworkDevice.cc | 2 +- dev/kernel/src/Swap/DiskSwap.cc | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'dev/kernel') diff --git a/dev/kernel/src/AsciiUtils.cc b/dev/kernel/src/AsciiUtils.cc index cca3a368..8d2f9dc5 100644 --- a/dev/kernel/src/AsciiUtils.cc +++ b/dev/kernel/src/AsciiUtils.cc @@ -52,9 +52,12 @@ Int32 rt_copy_memory_safe(const voidPtr src, voidPtr dst, Size len, Size dst_siz } return -1; } + auto s = reinterpret_cast(src); auto d = reinterpret_cast(dst); + for (Size i = 0; i < len; ++i) d[i] = s[i]; + return static_cast(len); } diff --git a/dev/kernel/src/Network/NetworkDevice.cc b/dev/kernel/src/Network/NetworkDevice.cc index 7f93fa1b..ffdfa53b 100644 --- a/dev/kernel/src/Network/NetworkDevice.cc +++ b/dev/kernel/src/Network/NetworkDevice.cc @@ -11,7 +11,7 @@ namespace Kernel { /// \brief Getter for fNetworkName. /// \return Network device name. const Char* NetworkDevice::Name() const { - return "/devices/net{}"; + return "/devices/net/net{}"; } /// \brief Setter for fNetworkName. diff --git a/dev/kernel/src/Swap/DiskSwap.cc b/dev/kernel/src/Swap/DiskSwap.cc index 8578450c..b9cfaf77 100644 --- a/dev/kernel/src/Swap/DiskSwap.cc +++ b/dev/kernel/src/Swap/DiskSwap.cc @@ -8,6 +8,8 @@ #include namespace Kernel { +static constexpr UInt32 kSwapDiskHeaderMagic = 0x44535750; // 'DSWP' + /***********************************************************************************/ /// @brief Write memory chunk onto disk. /// @param fork_name The swap name to recognize this memory region. @@ -20,7 +22,7 @@ BOOL DiskSwapInterface::Write(const Char* fork_name, SizeT fork_name_len, SWAP_D if (*fork_name == 0) return NO; - if (!data) return NO; + if (!data || data->fMagic != kSwapDiskHeaderMagic) return NO; FileStream file(kSwapPageFilePath, kRestrictWRB); @@ -52,6 +54,8 @@ SWAP_DISK_HEADER* DiskSwapInterface::Read(const Char* fork_name, SizeT fork_name VoidPtr blob = file.Read(fork_name, sizeof(SWAP_DISK_HEADER) + data_len); + if (!blob || ((SWAP_DISK_HEADER*)blob)->fMagic != kSwapDiskHeaderMagic) return nullptr; + return reinterpret_cast(blob); } } // namespace Kernel -- cgit v1.2.3 From e2ce7d7a1b37824b6939c68a931e0f6e537d760a Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sun, 19 Oct 2025 20:09:25 +0200 Subject: fix: kernel: Fix memory leak in DiskSwap.cc Signed-off-by: Amlal El Mahrouss --- dev/kernel/src/Swap/DiskSwap.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'dev/kernel') diff --git a/dev/kernel/src/Swap/DiskSwap.cc b/dev/kernel/src/Swap/DiskSwap.cc index b9cfaf77..99efb2c0 100644 --- a/dev/kernel/src/Swap/DiskSwap.cc +++ b/dev/kernel/src/Swap/DiskSwap.cc @@ -54,7 +54,10 @@ SWAP_DISK_HEADER* DiskSwapInterface::Read(const Char* fork_name, SizeT fork_name VoidPtr blob = file.Read(fork_name, sizeof(SWAP_DISK_HEADER) + data_len); - if (!blob || ((SWAP_DISK_HEADER*)blob)->fMagic != kSwapDiskHeaderMagic) return nullptr; + if (!blob || ((SWAP_DISK_HEADER*) blob)->fMagic != kSwapDiskHeaderMagic) { + if (blob) mm_free_ptr(blob); + return nullptr; + } return reinterpret_cast(blob); } -- cgit v1.2.3 From ab89ba1512f6a7411a2bcb27e710f6e5078309a6 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 21 Oct 2025 04:05:25 +0200 Subject: dev/kernel: crc32 module improvements on portability. Signed-off-by: Amlal El Mahrouss --- dev/kernel/NeKit/Crc32.h | 8 +++----- dev/kernel/arm64-desktop.make | 2 +- dev/kernel/src/Atom.cc | 2 +- dev/kernel/src/Crc32.cc | 4 +++- public/manuals/troff/cxxdrv.7 | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'dev/kernel') diff --git a/dev/kernel/NeKit/Crc32.h b/dev/kernel/NeKit/Crc32.h index 0fc35134..f6b04641 100644 --- a/dev/kernel/NeKit/Crc32.h +++ b/dev/kernel/NeKit/Crc32.h @@ -8,15 +8,13 @@ * ======================================================== */ -#ifndef CRC32_H -#define CRC32_H +#ifndef NEKIT_CRC32_H +#define NEKIT_CRC32_H #include -#define kCrcCnt (256) - namespace Kernel { UInt32 ke_calculate_crc32(const VoidPtr crc, Int32 len) noexcept; } // namespace Kernel -#endif // !CRC32_H +#endif // !NEKIT_CRC32_H diff --git a/dev/kernel/arm64-desktop.make b/dev/kernel/arm64-desktop.make index e83e1db8..da629254 100644 --- a/dev/kernel/arm64-desktop.make +++ b/dev/kernel/arm64-desktop.make @@ -37,7 +37,7 @@ nekernel-arm64-epm: clean $(CC) $(CCFLAGS) $(DISKDRIVER) $(DEBUG) $(wildcard src/*.cc) \ $(wildcard src/FS/*.cc) $(wildcard HALKit/ARM64/Storage/*.cc) \ $(wildcard HALKit/ARM64/PCI/*.cc) $(wildcard src/Network/*.cc) $(wildcard src/Storage/*.cc) \ - $(wildcard HALKit/ARM64/*.cc) $(wildcard HALKit/ARM64/*.cpp) \ + $(wildcard HALKit/ARM64/*.cc) $(wildcard HALKit/ARM64/*.cc) \ $(wildcard HALKit/ARM64/*.s) $(wildcard HALKit/ARM64/APM/*.cc) $(MOVEALL) diff --git a/dev/kernel/src/Atom.cc b/dev/kernel/src/Atom.cc index 6e84d7d5..a0e45468 100644 --- a/dev/kernel/src/Atom.cc +++ b/dev/kernel/src/Atom.cc @@ -6,5 +6,5 @@ #include -// @file Atom.cpp +// @file Atom.cc // @brief Atomic primitives diff --git a/dev/kernel/src/Crc32.cc b/dev/kernel/src/Crc32.cc index 46a1d940..df0b34e3 100644 --- a/dev/kernel/src/Crc32.cc +++ b/dev/kernel/src/Crc32.cc @@ -6,7 +6,9 @@ #include -// @file CRC32.cpp +#define kCrcCnt (256) + +// @file CRC32.cc // @brief Check sequence implementation. namespace Kernel { diff --git a/public/manuals/troff/cxxdrv.7 b/public/manuals/troff/cxxdrv.7 index 20e28fd4..65c5fc49 100644 --- a/public/manuals/troff/cxxdrv.7 +++ b/public/manuals/troff/cxxdrv.7 @@ -17,8 +17,8 @@ Specify the output file. .SH USAGE EXAMPLES .TP -.B Generate object file from the main.cpp unit. -.B cxxdrv main.cpp +.B Generate object file from the main.cc unit. +.B cxxdrv main.cc .SH EXIT STATUS .TP -- cgit v1.2.3 From d6abde3a33353818e4ac0b00c5fd5ec1988d2518 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 21 Oct 2025 04:08:01 +0200 Subject: fix: kernel: fix ArrayList constructor. Signed-off-by: Amlal El Mahrouss --- dev/kernel/NeKit/ArrayList.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dev/kernel') diff --git a/dev/kernel/NeKit/ArrayList.h b/dev/kernel/NeKit/ArrayList.h index 1f5226f4..ee1a4b40 100644 --- a/dev/kernel/NeKit/ArrayList.h +++ b/dev/kernel/NeKit/ArrayList.h @@ -12,7 +12,7 @@ namespace Kernel { template class ArrayList final { public: - explicit ArrayList(T* list, SizeT length) : fList(reinterpret_cast(list)) {} + explicit ArrayList(T* list, SizeT length) : fList(reinterpret_cast(list)), fLen(length) {} ~ArrayList() = default; -- cgit v1.2.3 From 75dbfdb442c540ea18d156a67c5f3e6147deb237 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Wed, 22 Oct 2025 10:01:47 +0200 Subject: feat: DriveMgr: zero init DriveTrait. Signed-off-by: Amlal El Mahrouss --- dev/kernel/KernelKit/DriveMgr.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'dev/kernel') diff --git a/dev/kernel/KernelKit/DriveMgr.h b/dev/kernel/KernelKit/DriveMgr.h index 69df1cec..03f9a717 100644 --- a/dev/kernel/KernelKit/DriveMgr.h +++ b/dev/kernel/KernelKit/DriveMgr.h @@ -52,9 +52,9 @@ enum { /// @brief Media drive trait type. struct DriveTrait final { - Char fName[kDriveNameLen]; // /System, /boot, //./Devices/USB... - Int32 fKind; // fMassStorage, fFloppy, fOpticalDrive. - Int32 fFlags; // fReadOnly, fEPMDrive... + Char fName[kDriveNameLen] = {0}; // /System, /boot, //./Devices/USB... + UInt32 fKind{}; // fMassStorage, fFloppy, fOpticalDrive. + UInt32 fFlags{}; // fReadOnly, fEPMDrive... /// @brief Packet drive (StorageKit compilant.) struct DrivePacket final { @@ -70,11 +70,11 @@ struct DriveTrait final { Lba fLbaStart{0}, fLbaEnd{0}; SizeT fSectorSz{kDriveSectorSz}; - Void (*fInput)(DrivePacket& packet); - Void (*fOutput)(DrivePacket& packet); - Void (*fVerify)(DrivePacket& packet); - Void (*fInit)(DrivePacket& packet); - const Char* (*fProtocol)(Void); + Void (*fInput)(DrivePacket& packet){}; + Void (*fOutput)(DrivePacket& packet){}; + Void (*fVerify)(DrivePacket& packet){}; + Void (*fInit)(DrivePacket& packet){}; + const Char* (*fProtocol)(Void){}; }; namespace Detail { -- cgit v1.2.3 From 9c4d2506ccb897045d9fb0c1082ed69ac24ce251 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Wed, 22 Oct 2025 11:52:04 +0200 Subject: feat: kernel! new KString API. And Network stack fixes. Signed-off-by: Amlal El Mahrouss --- dev/kernel/NeKit/KString.h | 45 +++++++------- dev/kernel/NeKit/KString.inl | 116 ++++++++++++++++-------------------- dev/kernel/NeKit/Utils.h | 12 ++++ dev/kernel/src/Network/IPAddress.cc | 4 +- 4 files changed, 91 insertions(+), 86 deletions(-) (limited to 'dev/kernel') diff --git a/dev/kernel/NeKit/KString.h b/dev/kernel/NeKit/KString.h index bbe49f8e..ec883a2f 100644 --- a/dev/kernel/NeKit/KString.h +++ b/dev/kernel/NeKit/KString.h @@ -16,13 +16,13 @@ namespace Kernel { /// @brief Kernel string class, not dynamic. -template +template class BasicKString final { public: explicit BasicKString() { - fDataSz = MinSz; + fDataSz = kMinimumStringSize; - fData = new Char[fDataSz]; + fData = new CharKind[fDataSz]; MUST_PASS(fData); rt_set_memory(fData, 0, fDataSz); @@ -31,7 +31,7 @@ class BasicKString final { explicit BasicKString(SizeT Sz) : fDataSz(Sz) { MUST_PASS(Sz > 1); - fData = new Char[Sz]; + fData = new CharKind[Sz]; MUST_PASS(fData); rt_set_memory(fData, 0, Sz); @@ -46,18 +46,18 @@ class BasicKString final { NE_COPY_DEFAULT(BasicKString) - Char* Data(); - const Char* CData() const; - Size Length() const; + CharKind* Data(); + const CharKind* CData() const; + Size Length() const; - bool operator==(const Char* rhs) const; - bool operator!=(const Char* rhs) const; + bool operator==(const CharKind* rhs) const; + bool operator!=(const CharKind* rhs) const; - bool operator==(const BasicKString<>& rhs) const; - bool operator!=(const BasicKString<>& rhs) const; + bool operator==(const BasicKString& rhs) const; + bool operator!=(const BasicKString& rhs) const; - BasicKString<>& operator+=(const Char* rhs); - BasicKString<>& operator+=(const BasicKString<>& rhs); + BasicKString& operator+=(const CharKind* rhs); + BasicKString& operator+=(const BasicKString& rhs); operator const char*() { return fData; } @@ -66,9 +66,9 @@ class BasicKString final { bool operator!() { return fData; } private: - Char* fData{nullptr}; - Size fDataSz{0}; - Size fCur{0}; + CharKind* fData{nullptr}; + Size fDataSz{0}; + Size fCur{0}; friend class KStringBuilder; }; @@ -78,11 +78,14 @@ using KStringOr = ErrorOr; class KStringBuilder final { public: - static ErrorOr Construct(const Char* data); - static const Char* FromBool(const Char* fmt, bool n); - static const Char* Format(const Char* fmt, const Char* from); - static bool Equals(const Char* lhs, const Char* rhs); - static bool Equals(const Utf8Char* lhs, const Utf8Char* rhs); + template + static ErrorOr> Construct(const CharKind* data); + template + static const CharKind* FromBool(const CharKind* fmt, bool n); + template + static const CharKind* Format(const CharKind* fmt, const CharKind* from); + template + static bool Equals(const CharKind* lhs, const CharKind* rhs); }; } // namespace Kernel diff --git a/dev/kernel/NeKit/KString.inl b/dev/kernel/NeKit/KString.inl index 1faefb08..4bb48415 100644 --- a/dev/kernel/NeKit/KString.inl +++ b/dev/kernel/NeKit/KString.inl @@ -4,14 +4,13 @@ ------------------------------------------- */ -#include - -/// @file BasicKString<>.cc +/// @file BasicKString.inl /// @brief Kernel String manipulation file. namespace Kernel { -inline void rt_string_append(Char* lhs, const Char* rhs, Int32 cur) { - SizeT sz_rhs = rt_string_len(rhs); +template +inline void ort_string_append(CharKind* lhs, const CharKind* rhs, Int32 cur) { + SizeT sz_rhs = ort_string_len(rhs); SizeT rhs_i = 0; for (; rhs_i < sz_rhs; ++rhs_i) { @@ -19,23 +18,23 @@ inline void rt_string_append(Char* lhs, const Char* rhs, Int32 cur) { } } -template <> -inline Char* BasicKString<>::Data() { +template +inline CharKind* BasicKString::Data() { return this->fData; } -template <> -inline const Char* BasicKString<>::CData() const { - return const_cast(this->fData); +template +inline const CharKind* BasicKString::CData() const { + return const_cast(this->fData); } -template <> -inline SizeT BasicKString<>::Length() const { +template +inline SizeT BasicKString::Length() const { return this->fDataSz; } -template <> -inline bool BasicKString<>::operator==(const BasicKString<>& rhs) const { +template +inline bool BasicKString::operator==(const BasicKString& rhs) const { if (rhs.Length() != this->Length()) return false; for (Size index = 0; index < this->Length(); ++index) { @@ -45,19 +44,19 @@ inline bool BasicKString<>::operator==(const BasicKString<>& rhs) const { return true; } -template <> -inline bool BasicKString<>::operator==(const Char* rhs) const { - if (rt_string_len(rhs) != this->Length()) return false; +template +inline bool BasicKString::operator==(const CharKind* rhs) const { + if (ort_string_len(rhs) != this->Length()) return false; - for (Size index = 0; index < rt_string_len(rhs); ++index) { + for (Size index = 0; index < ort_string_len(rhs); ++index) { if (rhs[index] != this->fData[index]) return false; } return true; } -template <> -inline bool BasicKString<>::operator!=(const BasicKString<>& rhs) const { +template +inline bool BasicKString::operator!=(const BasicKString& rhs) const { if (rhs.Length() != this->Length()) return false; for (Size index = 0; index < rhs.Length(); ++index) { @@ -67,54 +66,55 @@ inline bool BasicKString<>::operator!=(const BasicKString<>& rhs) const { return true; } -template <> -inline bool BasicKString<>::operator!=(const Char* rhs) const { - if (rt_string_len(rhs) != this->Length()) return false; +template +inline bool BasicKString::operator!=(const CharKind* rhs) const { + if (ort_string_len(rhs) != this->Length()) return false; - for (Size index = 0; index < rt_string_len(rhs); ++index) { + for (Size index = 0; index < ort_string_len(rhs); ++index) { if (rhs[index] == this->fData[index]) return false; } return true; } -template <> -inline BasicKString<>& BasicKString<>::operator+=(const BasicKString<>& rhs) { - if (rt_string_len(rhs.fData) > this->Length()) return *this; +template +inline BasicKString& BasicKString::operator+=(const BasicKString& rhs) { + if (ort_string_len(rhs.fData) > this->Length()) return *this; - rt_string_append(this->fData, const_cast(rhs.fData), this->fCur); - this->fCur += rt_string_len(const_cast(rhs.fData)); + ort_string_append(this->fData, const_cast(rhs.fData), this->fCur); + this->fCur += ort_string_len(const_cast(rhs.fData)); return *this; } -template <> -inline BasicKString<>& BasicKString<>::operator+=(const Char* rhs) { - rt_string_append(this->fData, const_cast(rhs), this->fCur); - this->fCur += rt_string_len(const_cast(rhs)); +template +inline BasicKString& BasicKString::operator+=(const CharKind* rhs) { + ort_string_append(this->fData, const_cast(rhs), this->fCur); + this->fCur += ort_string_len(const_cast(rhs)); return *this; } -inline ErrorOr> KStringBuilder::Construct(const Char* data) { - if (!data || *data == 0) return ErrorOr>(new BasicKString<>(0)); +template +inline ErrorOr> KStringBuilder::Construct(const CharKind* data) { + if (!data || *data == 0) return ErrorOr>(nullptr); - BasicKString<>* view = new BasicKString<>(rt_string_len(data)); + BasicKString* view = new BasicKString(ort_string_len(data)); (*view) += data; - return ErrorOr>(*view); + return ErrorOr>(*view); } - -inline const Char* KStringBuilder::FromBool(const Char* fmt, bool i) { +template +inline const CharKind* KStringBuilder::FromBool(const CharKind* fmt, bool i) { if (!fmt) return ("?"); - const Char* boolean_expr = i ? "YES" : "NO"; - Char* ret = (Char*) RTL_ALLOCA(rt_string_len(boolean_expr) + rt_string_len(fmt)); + const CharKind* boolean_expr = i ? "YES" : "NO"; + CharKind* ret = (CharKind*) RTL_ALLOCA(ort_string_len(boolean_expr) + ort_string_len(fmt)); if (!ret) return ("?"); - const auto fmt_len = rt_string_len(fmt); - const auto res_len = rt_string_len(boolean_expr); + const auto fmt_len = ort_string_len(fmt); + const auto res_len = ort_string_len(boolean_expr); for (Size idx = 0; idx < fmt_len; ++idx) { if (fmt[idx] == '%') { @@ -133,41 +133,31 @@ inline const Char* KStringBuilder::FromBool(const Char* fmt, bool i) { return ret; } +template +inline bool KStringBuilder::Equals(const CharKind* lhs, const CharKind* rhs) { + if (ort_string_len(rhs) != ort_string_len(lhs)) return false; -inline bool KStringBuilder::Equals(const Char* lhs, const Char* rhs) { - if (rt_string_len(rhs) != rt_string_len(lhs)) return false; - - for (Size index = 0; index < rt_string_len(rhs); ++index) { + for (Size index = 0; index < ort_string_len(rhs); ++index) { if (rhs[index] != lhs[index]) return false; } return true; } - -inline bool KStringBuilder::Equals(const Utf8Char* lhs, const Utf8Char* rhs) { - if (urt_string_len(rhs) != urt_string_len(lhs)) return false; - - for (Size index = 0; rhs[index] != 0; ++index) { - if (rhs[index] != lhs[index]) return false; - } - - return true; -} - -inline const Char* KStringBuilder::Format(const Char* fmt, const Char* fmt2) { +template +inline const CharKind* KStringBuilder::Format(const CharKind* fmt, const CharKind* fmt2) { if (!fmt || !fmt2) return ("?"); - Char* ret = (Char*) RTL_ALLOCA(sizeof(char) * (rt_string_len(fmt2) + rt_string_len(fmt))); + CharKind* ret = (CharKind*) RTL_ALLOCA(sizeof(char) * (ort_string_len(fmt2) + ort_string_len(fmt))); if (!ret) return ("?"); - const auto len = rt_string_len(fmt); + const auto len = ort_string_len(fmt); for (Size idx = 0; idx < len; ++idx) { - if (fmt[idx] == '%' && idx < rt_string_len(fmt) && fmt[idx] == 's') { + if (fmt[idx] == '%' && idx < ort_string_len(fmt) && fmt[idx] == 's') { Size result_cnt = idx; - for (Size y_idx = 0; y_idx < rt_string_len(fmt2); ++y_idx) { + for (Size y_idx = 0; y_idx < ort_string_len(fmt2); ++y_idx) { ret[result_cnt] = fmt2[y_idx]; ++result_cnt; } diff --git a/dev/kernel/NeKit/Utils.h b/dev/kernel/NeKit/Utils.h index a7576e77..ee18d04c 100644 --- a/dev/kernel/NeKit/Utils.h +++ b/dev/kernel/NeKit/Utils.h @@ -38,4 +38,16 @@ Int urt_string_cmp(const Utf8Char* src, const Utf8Char* cmp, Size len); Void urt_set_memory(const voidPtr src, UInt32 dst, Size len); Int urt_copy_memory(const voidPtr src, voidPtr dst, Size len); Size urt_string_len(const Utf8Char* str); + +/// OpenTemplate UTILS API + +template +inline SizeT ort_string_len(const CharType* str) { + if (!str) return 0; + + SizeT len{0}; + + while (str[len] != 0) ++len; + return len; +} } // namespace Kernel diff --git a/dev/kernel/src/Network/IPAddress.cc b/dev/kernel/src/Network/IPAddress.cc index b02eae08..bc46292b 100644 --- a/dev/kernel/src/Network/IPAddress.cc +++ b/dev/kernel/src/Network/IPAddress.cc @@ -73,14 +73,14 @@ bool RawIPAddress6::operator!=(const RawIPAddress6& ipv6) { /// @todo ErrorOr IPFactory::ToKString(Ref& ipv6) { NE_UNUSED(ipv6); - auto str = KStringBuilder::Construct(0); + auto str = KStringBuilder::Construct(""); return str; } /// @todo ErrorOr IPFactory::ToKString(Ref& ipv4) { NE_UNUSED(ipv4); - auto str = KStringBuilder::Construct(0); + auto str = KStringBuilder::Construct(""); return str; } -- cgit v1.2.3 From 64492ed9c42659d0c5f7eb2143a673dd0b5f9dc3 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Thu, 23 Oct 2025 09:27:16 +0200 Subject: feat! breaking API changes in kernel. Signed-off-by: Amlal El Mahrouss --- dev/kernel/CFKit/Property.h | 4 +-- dev/kernel/FSKit/IndexableProperty.h | 2 +- dev/kernel/NeKit/Defines.h | 11 ++++--- dev/kernel/NeKit/Json.h | 46 +++++++++++++++--------------- dev/kernel/NeKit/KString.h | 26 ++++++++--------- dev/kernel/NeKit/KString.inl | 28 +++++++++--------- dev/kernel/NeKit/Ref.h | 3 ++ dev/kernel/NeKit/Variant.h | 7 +++-- dev/kernel/src/FS/HeFS+FileMgr.cc | 33 ++++++++++++++++++--- dev/kernel/src/FS/HeFS+FileSystemParser.cc | 2 ++ dev/kernel/src/Json.cc | 2 +- dev/kernel/src/Property.cc | 4 +-- dev/libMsg/MsgKit/Server.h | 9 +++--- 13 files changed, 106 insertions(+), 71 deletions(-) (limited to 'dev/kernel') diff --git a/dev/kernel/CFKit/Property.h b/dev/kernel/CFKit/Property.h index 17246a63..e8f2f713 100644 --- a/dev/kernel/CFKit/Property.h +++ b/dev/kernel/CFKit/Property.h @@ -30,9 +30,9 @@ class Property { Property& operator=(const Property&) = default; Property(const Property&) = default; - BOOL StringEquals(BasicKString<>& name); + BOOL StringEquals(KBasicString<>& name); PropertyId& GetValue(); - BasicKString<>& GetKey(); + KBasicString<>& GetKey(); private: KString fName{kMaxPropLen}; diff --git a/dev/kernel/FSKit/IndexableProperty.h b/dev/kernel/FSKit/IndexableProperty.h index 8be6d7c3..d6b89d35 100644 --- a/dev/kernel/FSKit/IndexableProperty.h +++ b/dev/kernel/FSKit/IndexableProperty.h @@ -25,7 +25,7 @@ namespace Indexer { class IndexableProperty final : public Property { public: explicit IndexableProperty() : Property() { - Kernel::BasicKString<> strProp(kMaxPropLen); + Kernel::KBasicString<> strProp(kMaxPropLen); strProp += "/prop/indexable"; this->GetKey() = strProp; diff --git a/dev/kernel/NeKit/Defines.h b/dev/kernel/NeKit/Defines.h index c5f02e0a..ed979e03 100644 --- a/dev/kernel/NeKit/Defines.h +++ b/dev/kernel/NeKit/Defines.h @@ -12,7 +12,7 @@ #define NEKIT_VERSION_BCD 0x0001 #ifndef __cplusplus -#error Kernel compiles with a C++ compiler. +#error !!! Kernel compiles only with a C++ compiler. !!! #endif #if __cplusplus <= 201703L @@ -39,7 +39,7 @@ using Int32 = __INT32_TYPE__; using UShort = __UINT16_TYPE__; using UInt16 = __UINT16_TYPE__; using Short = short; -using Int16 = short; +using Int16 = __INT16_TYPE__; using UInt = __UINT32_TYPE__; using UInt32 = __UINT32_TYPE__; using Long = __INT64_TYPE__; @@ -49,11 +49,13 @@ using UInt64 = __UINT64_TYPE__; using Boolean = bool; using Bool = bool; using Char = char; +using Int8 = __INT8_TYPE__; +using Char8 = char8_t; using UChar = __UINT8_TYPE__; using UInt8 = __UINT8_TYPE__; -using SSize = Int64; -using SSizeT = Int64; +using SSize = long; +using SSizeT = long; using Size = __SIZE_TYPE__; using SizeT = __SIZE_TYPE__; using IntPtr = __INTPTR_TYPE__; @@ -83,6 +85,7 @@ typedef UInt32 PhysicalAddressKind; typedef UIntPtr VirtualAddressKind; using Void = void; +using Any = void*; using Lba = UInt64; diff --git a/dev/kernel/NeKit/Json.h b/dev/kernel/NeKit/Json.h index 24357dd7..35f53b57 100644 --- a/dev/kernel/NeKit/Json.h +++ b/dev/kernel/NeKit/Json.h @@ -7,7 +7,7 @@ #pragma once -// last-rev: 02/04/25 +/// @brief Kernel JSON API. #include #include @@ -15,58 +15,58 @@ #include #include -#define kJSONMaxLen (8196) -#define kJSONLen (256) -#define kJSONNullArr "[]" -#define kJSONNullObj "{}" +#define kNeJsonMaxLen (8196) +#define kNeJsonLen (256) +#define kNeJsonNullArr "[]" +#define kNeJsonNullObj "{}" namespace Kernel { /// @brief JavaScript object class -class Json final { +class JsonObject final { public: - explicit Json() { - auto len = kJSONMaxLen; - BasicKString<> key = KString(len); - key += kJSONNullObj; + explicit JsonObject() { + auto len = kNeJsonMaxLen; + KBasicString<> key = KString(len); + key += kNeJsonNullObj; this->AsKey() = key; this->AsValue() = key; } - explicit Json(SizeT lhsLen, SizeT rhsLen) : fKey(lhsLen), fValue(rhsLen) {} + explicit JsonObject(SizeT lhsLen, SizeT rhsLen) : fKey(lhsLen), fValue(rhsLen) {} - ~Json() = default; + ~JsonObject() = default; - NE_COPY_DEFAULT(Json) + NE_COPY_DEFAULT(JsonObject) Bool& IsUndefined() { return fUndefined; } private: Bool fUndefined; // is this instance undefined? - BasicKString<> fKey; - BasicKString<> fValue; + KBasicString<> fKey; + KBasicString<> fValue; public: /// @brief returns the key of the json /// @return the key as string view. - BasicKString<>& AsKey() { return fKey; } + KBasicString<>& AsKey() { return fKey; } /// @brief returns the value of the json. /// @return the key as string view. - BasicKString<>& AsValue() { return fValue; } + KBasicString<>& AsValue() { return fValue; } - static Json kNull; + static JsonObject kNull; }; -/// @brief Json stream reader helper. +/// @brief JsonObject stream reader helper. struct JsonStreamReader final { - STATIC Json In(const Char* full_array) { + STATIC JsonObject In(const Char* full_array) { auto start_val = '{'; auto end_val = '}'; Boolean probe_value = false; if (full_array[0] != start_val) { - if (full_array[0] != '[') return Json::kNull; + if (full_array[0] != '[') return JsonObject::kNull; start_val = '['; end_val = ']'; @@ -79,7 +79,7 @@ struct JsonStreamReader final { SizeT key_len = 0; SizeT value_len = 0; - Json type(kJSONMaxLen, kJSONMaxLen); + JsonObject type(kNeJsonMaxLen, kNeJsonMaxLen); for (SizeT i = 1; i < len; ++i) { if (full_array[i] == '\r' || full_array[i] == '\n') continue; @@ -125,5 +125,5 @@ struct JsonStreamReader final { } }; -using JsonStream = Stream; +using JsonStream = Stream; } // namespace Kernel diff --git a/dev/kernel/NeKit/KString.h b/dev/kernel/NeKit/KString.h index ec883a2f..6a1b04d2 100644 --- a/dev/kernel/NeKit/KString.h +++ b/dev/kernel/NeKit/KString.h @@ -12,14 +12,14 @@ #include #include -#define kMinimumStringSize (8196U) - namespace Kernel { +inline auto kMinimumStringSize = 8196; + /// @brief Kernel string class, not dynamic. template -class BasicKString final { +class KBasicString final { public: - explicit BasicKString() { + explicit KBasicString() { fDataSz = kMinimumStringSize; fData = new CharKind[fDataSz]; @@ -28,7 +28,7 @@ class BasicKString final { rt_set_memory(fData, 0, fDataSz); } - explicit BasicKString(SizeT Sz) : fDataSz(Sz) { + explicit KBasicString(SizeT Sz) : fDataSz(Sz) { MUST_PASS(Sz > 1); fData = new CharKind[Sz]; @@ -37,14 +37,14 @@ class BasicKString final { rt_set_memory(fData, 0, Sz); } - ~BasicKString() { + ~KBasicString() { if (fData) { delete[] fData; fData = nullptr; } } - NE_COPY_DEFAULT(BasicKString) + NE_COPY_DEFAULT(KBasicString) CharKind* Data(); const CharKind* CData() const; @@ -53,11 +53,11 @@ class BasicKString final { bool operator==(const CharKind* rhs) const; bool operator!=(const CharKind* rhs) const; - bool operator==(const BasicKString& rhs) const; - bool operator!=(const BasicKString& rhs) const; + bool operator==(const KBasicString& rhs) const; + bool operator!=(const KBasicString& rhs) const; - BasicKString& operator+=(const CharKind* rhs); - BasicKString& operator+=(const BasicKString& rhs); + KBasicString& operator+=(const CharKind* rhs); + KBasicString& operator+=(const KBasicString& rhs); operator const char*() { return fData; } @@ -73,13 +73,13 @@ class BasicKString final { friend class KStringBuilder; }; -using KString = BasicKString<>; +using KString = KBasicString<>; using KStringOr = ErrorOr; class KStringBuilder final { public: template - static ErrorOr> Construct(const CharKind* data); + static ErrorOr> Construct(const CharKind* data); template static const CharKind* FromBool(const CharKind* fmt, bool n); template diff --git a/dev/kernel/NeKit/KString.inl b/dev/kernel/NeKit/KString.inl index 4bb48415..d238818c 100644 --- a/dev/kernel/NeKit/KString.inl +++ b/dev/kernel/NeKit/KString.inl @@ -4,7 +4,7 @@ ------------------------------------------- */ -/// @file BasicKString.inl +/// @file KBasicString.inl /// @brief Kernel String manipulation file. namespace Kernel { @@ -19,22 +19,22 @@ inline void ort_string_append(CharKind* lhs, const CharKind* rhs, Int32 cur) { } template -inline CharKind* BasicKString::Data() { +inline CharKind* KBasicString::Data() { return this->fData; } template -inline const CharKind* BasicKString::CData() const { +inline const CharKind* KBasicString::CData() const { return const_cast(this->fData); } template -inline SizeT BasicKString::Length() const { +inline SizeT KBasicString::Length() const { return this->fDataSz; } template -inline bool BasicKString::operator==(const BasicKString& rhs) const { +inline bool KBasicString::operator==(const KBasicString& rhs) const { if (rhs.Length() != this->Length()) return false; for (Size index = 0; index < this->Length(); ++index) { @@ -45,7 +45,7 @@ inline bool BasicKString::operator==(const BasicKString& rhs } template -inline bool BasicKString::operator==(const CharKind* rhs) const { +inline bool KBasicString::operator==(const CharKind* rhs) const { if (ort_string_len(rhs) != this->Length()) return false; for (Size index = 0; index < ort_string_len(rhs); ++index) { @@ -56,7 +56,7 @@ inline bool BasicKString::operator==(const CharKind* rhs) const { } template -inline bool BasicKString::operator!=(const BasicKString& rhs) const { +inline bool KBasicString::operator!=(const KBasicString& rhs) const { if (rhs.Length() != this->Length()) return false; for (Size index = 0; index < rhs.Length(); ++index) { @@ -67,7 +67,7 @@ inline bool BasicKString::operator!=(const BasicKString& rhs } template -inline bool BasicKString::operator!=(const CharKind* rhs) const { +inline bool KBasicString::operator!=(const CharKind* rhs) const { if (ort_string_len(rhs) != this->Length()) return false; for (Size index = 0; index < ort_string_len(rhs); ++index) { @@ -78,7 +78,7 @@ inline bool BasicKString::operator!=(const CharKind* rhs) const { } template -inline BasicKString& BasicKString::operator+=(const BasicKString& rhs) { +inline KBasicString& KBasicString::operator+=(const KBasicString& rhs) { if (ort_string_len(rhs.fData) > this->Length()) return *this; ort_string_append(this->fData, const_cast(rhs.fData), this->fCur); @@ -88,7 +88,7 @@ inline BasicKString& BasicKString::operator+=(const BasicKSt } template -inline BasicKString& BasicKString::operator+=(const CharKind* rhs) { +inline KBasicString& KBasicString::operator+=(const CharKind* rhs) { ort_string_append(this->fData, const_cast(rhs), this->fCur); this->fCur += ort_string_len(const_cast(rhs)); @@ -96,13 +96,13 @@ inline BasicKString& BasicKString::operator+=(const CharKind } template -inline ErrorOr> KStringBuilder::Construct(const CharKind* data) { - if (!data || *data == 0) return ErrorOr>(nullptr); +inline ErrorOr> KStringBuilder::Construct(const CharKind* data) { + if (!data || *data == 0) return ErrorOr>(nullptr); - BasicKString* view = new BasicKString(ort_string_len(data)); + KBasicString* view = new KBasicString(ort_string_len(data)); (*view) += data; - return ErrorOr>(*view); + return ErrorOr>(*view); } template inline const CharKind* KStringBuilder::FromBool(const CharKind* fmt, bool i) { diff --git a/dev/kernel/NeKit/Ref.h b/dev/kernel/NeKit/Ref.h index 6f7eca21..566f7486 100644 --- a/dev/kernel/NeKit/Ref.h +++ b/dev/kernel/NeKit/Ref.h @@ -65,6 +65,9 @@ class NonNullRef final { private: Ref fRef{}; }; + +using RefAny = Ref; +using NonNullRefAny = NonNullRef; } // namespace Kernel #endif // ifndef _NEKIT_REF_H_ diff --git a/dev/kernel/NeKit/Variant.h b/dev/kernel/NeKit/Variant.h index 51548272..700c9d9a 100644 --- a/dev/kernel/NeKit/Variant.h +++ b/dev/kernel/NeKit/Variant.h @@ -33,9 +33,10 @@ class Variant final { ~Variant() = default; public: - explicit Variant(KString* stringView) : fPtr((VoidPtr) stringView), fKind(VariantKind::kString) {} + template + explicit Variant(KBasicString* stringView) : fPtr((VoidPtr) stringView), fKind(VariantKind::kString) {} - explicit Variant(Json* json) : fPtr((VoidPtr) json), fKind(VariantKind::kJson) {} + explicit Variant(JsonObject* json) : fPtr((VoidPtr) json), fKind(VariantKind::kJson) {} explicit Variant(nullPtr ptr) : fPtr(ptr), fKind(VariantKind::kNull) {} @@ -55,7 +56,7 @@ class Variant final { VariantKind& Kind(); private: - voidPtr fPtr{nullptr}; + VoidPtr fPtr{nullptr}; VariantKind fKind{VariantKind::kNull}; }; } // namespace Kernel diff --git a/dev/kernel/src/FS/HeFS+FileMgr.cc b/dev/kernel/src/FS/HeFS+FileMgr.cc index 6b559cf4..33813f65 100644 --- a/dev/kernel/src/FS/HeFS+FileMgr.cc +++ b/dev/kernel/src/FS/HeFS+FileMgr.cc @@ -19,12 +19,12 @@ HeFileSystemMgr::HeFileSystemMgr() { mParser = new HeFileSystemParser(); MUST_PASS(mParser); - kout << "We are done allocating NeFileSystemParser...\n"; + kout << "We are done allocating HeFileSystemParser...\n"; } HeFileSystemMgr::~HeFileSystemMgr() { if (mParser) { - kout << "Destroying NeFileSystemParser...\n"; + kout << "Destroying HeFileSystemParser...\n"; delete mParser; mParser = nullptr; } @@ -124,21 +124,44 @@ _Output NodePtr HeFileSystemMgr::Open(_Input const Char* path, _Input const Char } Void HeFileSystemMgr::Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, - _Input SizeT size) {} + _Input SizeT size) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(size); + NE_UNUSED(data); +} _Output VoidPtr HeFileSystemMgr::Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT size) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(size); + return nullptr; } Void HeFileSystemMgr::Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, - _Input Int32 flags, _Input SizeT size) {} + _Input Int32 flags, _Input SizeT size) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(size); + NE_UNUSED(name); + NE_UNUSED(data); +} _Output VoidPtr HeFileSystemMgr::Read(_Input const Char* name, _Input NodePtr node, _Input Int32 flags, _Input SizeT sz) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(sz); + NE_UNUSED(name); + return nullptr; } _Output Bool HeFileSystemMgr::Seek(NodePtr node, SizeT off) { + NE_UNUSED(node); + NE_UNUSED(off); + return false; } @@ -146,6 +169,7 @@ _Output Bool HeFileSystemMgr::Seek(NodePtr node, SizeT off) { /// @param node /// @return kFileMgrNPos if invalid, else current offset. _Output SizeT HeFileSystemMgr::Tell(NodePtr node) { + NE_UNUSED(node); return kFileMgrNPos; } @@ -153,6 +177,7 @@ _Output SizeT HeFileSystemMgr::Tell(NodePtr node) { /// @param node /// @return False if invalid, nah? calls Seek(node, 0). _Output Bool HeFileSystemMgr::Rewind(NodePtr node) { + NE_UNUSED(node); return kFileMgrNPos; } diff --git a/dev/kernel/src/FS/HeFS+FileSystemParser.cc b/dev/kernel/src/FS/HeFS+FileSystemParser.cc index 86f929c0..029fdf26 100644 --- a/dev/kernel/src/FS/HeFS+FileSystemParser.cc +++ b/dev/kernel/src/FS/HeFS+FileSystemParser.cc @@ -79,12 +79,14 @@ namespace Detail { const Utf8Char* dir_name, UInt16 flags, const BOOL delete_or_create); + /// @brief This helper makes it easier for other machines to understand HeFS encoded hashes. STATIC UInt64 hefsi_to_big_endian_64(UInt64 val) { return ((val >> 56) & 0x00000000000000FFULL) | ((val >> 40) & 0x000000000000FF00ULL) | ((val >> 24) & 0x0000000000FF0000ULL) | ((val >> 8) & 0x00000000FF000000ULL) | ((val << 8) & 0x000000FF00000000ULL) | ((val << 24) & 0x0000FF0000000000ULL) | ((val << 40) & 0x00FF000000000000ULL) | ((val << 56) & 0xFF00000000000000ULL); } + /// @brief Simple algorithm to hash directory entries for INDs. /// @param path the directory path. /// @return The hashed path. diff --git a/dev/kernel/src/Json.cc b/dev/kernel/src/Json.cc index 68ab55fc..d156c0ce 100644 --- a/dev/kernel/src/Json.cc +++ b/dev/kernel/src/Json.cc @@ -7,4 +7,4 @@ #include /// @brief Undefined object, is null in length. -RTL_INIT_OBJECT(Kernel::Json::kNull, Kernel::Json); +RTL_INIT_OBJECT(Kernel::JsonObject::kNull, Kernel::JsonObject); diff --git a/dev/kernel/src/Property.cc b/dev/kernel/src/Property.cc index 1d01293f..714fb2a4 100644 --- a/dev/kernel/src/Property.cc +++ b/dev/kernel/src/Property.cc @@ -21,14 +21,14 @@ Property::Property() = default; /// @brief Check if property's name equals to name. /// @param name string to check. /***********************************************************************************/ -Bool Property::StringEquals(BasicKString<>& name) { +Bool Property::StringEquals(KBasicString<>& name) { return this->fName && this->fName == name; } /***********************************************************************************/ /// @brief Gets the key (name) of property. /***********************************************************************************/ -BasicKString<>& Property::GetKey() { +KBasicString<>& Property::GetKey() { return this->fName; } diff --git a/dev/libMsg/MsgKit/Server.h b/dev/libMsg/MsgKit/Server.h index 022aa425..5bc9617d 100644 --- a/dev/libMsg/MsgKit/Server.h +++ b/dev/libMsg/MsgKit/Server.h @@ -13,6 +13,7 @@ #endif /// @author Amlal El Mahrouss +/// @file Server.h /// @brief libMsg LISP system. struct LIBMSG_EXPR; @@ -23,8 +24,8 @@ struct LIBMSG_EXPR final { CF::CFString* l_key{nullptr}; CF::CFString* l_value{nullptr}; #else - VoidPtr l_key{nullptr}; - VoidPtr l_value{nullptr}; + // if we use C< we won't know about CF, so let's make those private. + VoidPtr l_private_data[2]{nullptr}; #endif LIBMSG_EXPR* l_head{nullptr}; @@ -33,8 +34,8 @@ struct LIBMSG_EXPR final { }; /// @brief Function type for LibMSG lisp. -typedef Void (*libmsg_func_t)(struct LIBMSG_EXPR* self, VoidPtr arg, SizeT arg_size); +typedef Void (*libmsg_func_type)(struct LIBMSG_EXPR* self, VoidPtr arg, SizeT arg_size); -IMPORT_C Void libmsg_init_library(libmsg_func_t* funcs, SizeT cnt); +IMPORT_C Void libmsg_init_library(libmsg_func_type* funcs, SizeT cnt); IMPORT_C UInt32 libmsg_close_library(Void); IMPORT_C UInt32 libmsg_eval_expr(struct LIBMSG_EXPR* head); -- cgit v1.2.3 From e1b8ba28465ac52638d849fb4179eceb55e257ab Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Thu, 23 Oct 2025 09:40:53 +0200 Subject: fix: kernel: HTS is now indexing hwthread correctly. Signed-off-by: Amlal El Mahrouss --- dev/kernel/KernelKit/HardwareThreadScheduler.h | 2 +- dev/kernel/src/HardwareThreadScheduler.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'dev/kernel') diff --git a/dev/kernel/KernelKit/HardwareThreadScheduler.h b/dev/kernel/KernelKit/HardwareThreadScheduler.h index 76327a93..e26a353a 100644 --- a/dev/kernel/KernelKit/HardwareThreadScheduler.h +++ b/dev/kernel/KernelKit/HardwareThreadScheduler.h @@ -120,7 +120,7 @@ class HardwareThreadScheduler final : public ISchedulable { private: Array fThreadList; - ThreadID fCurrentThread{0}; + ThreadID fCurrentThreadIdx{0}; }; /// @brief wakes up thread. diff --git a/dev/kernel/src/HardwareThreadScheduler.cc b/dev/kernel/src/HardwareThreadScheduler.cc index 86f46718..a4b6b4b8 100644 --- a/dev/kernel/src/HardwareThreadScheduler.cc +++ b/dev/kernel/src/HardwareThreadScheduler.cc @@ -134,7 +134,7 @@ HardwareThreadScheduler& HardwareThreadScheduler::The() { /// @brief Get Stack Frame of AP. /***********************************************************************************/ HAL::StackFramePtr HardwareThreadScheduler::Leak() noexcept { - return fThreadList[fCurrentThread].fStack; + return fThreadList[fCurrentThreadIdx].fStack; } /***********************************************************************************/ @@ -150,6 +150,7 @@ Ref HardwareThreadScheduler::operator[](SizeT idx) { return {kFakeThread}; } + fCurrentThreadIdx = idx; return &fThreadList[idx]; } -- cgit v1.2.3 From 744e9aba579a51dcab8f78009cbc091ce3cd8503 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Fri, 24 Oct 2025 12:05:40 +0200 Subject: feat: scheduler: process scheduler improvements and wip subsystem. Signed-off-by: Amlal El Mahrouss --- dev/kernel/src/IPEFDylibObject.cc | 4 ++++ dev/kernel/src/KernelTaskScheduler.cc | 15 ++++++++++++++- dev/kernel/src/UserProcessScheduler.cc | 10 +++------- 3 files changed, 21 insertions(+), 8 deletions(-) (limited to 'dev/kernel') diff --git a/dev/kernel/src/IPEFDylibObject.cc b/dev/kernel/src/IPEFDylibObject.cc index a24fba72..91f8c88a 100644 --- a/dev/kernel/src/IPEFDylibObject.cc +++ b/dev/kernel/src/IPEFDylibObject.cc @@ -90,6 +90,10 @@ EXTERN_C IDylibRef rtl_init_dylib_pef(USER_PROCESS& process) { EXTERN_C Void rtl_fini_dylib_pef(USER_PROCESS& process, IDylibRef dll_obj, BOOL* successful) { MUST_PASS(successful); + if (!successful) { + return; + } + // sanity check (will also trigger a bug check if this fails) if (dll_obj == nullptr) { *successful = false; diff --git a/dev/kernel/src/KernelTaskScheduler.cc b/dev/kernel/src/KernelTaskScheduler.cc index 1997c175..8bbe5601 100644 --- a/dev/kernel/src/KernelTaskScheduler.cc +++ b/dev/kernel/src/KernelTaskScheduler.cc @@ -15,4 +15,17 @@ /// @author Amlal El Mahrouss (amlal@nekernel.org) /***********************************************************************************/ -namespace Kernel {} // namespace Kernel \ No newline at end of file +namespace Kernel { +EXTERN_C Void hal_switch_kernel_task(HAL::StackFramePtr frame, ProcessID kid); + +Bool KernelTaskHelper::Switch(HAL::StackFramePtr frame_ptr, ProcessID new_kid) { + NE_UNUSED(frame_ptr); + NE_UNUSED(new_kid); + + return NO; +} + +Bool KernelTaskHelper::CanBeScheduled(const KERNEL_TASK& task) { + return task.Kid > 0 && task.Image.HasCode(); +} +} // namespace Kernel \ No newline at end of file diff --git a/dev/kernel/src/UserProcessScheduler.cc b/dev/kernel/src/UserProcessScheduler.cc index 2306d3e4..ac25c3d8 100644 --- a/dev/kernel/src/UserProcessScheduler.cc +++ b/dev/kernel/src/UserProcessScheduler.cc @@ -581,17 +581,13 @@ ErrorOr UserProcessHelper::TheCurrentPID() { /// @retval true can be schedulded. /// @retval false cannot be schedulded. Bool UserProcessHelper::CanBeScheduled(const USER_PROCESS& process) { + if (process.Affinity == AffinityKind::kRealTime) return Yes; + if (process.Status != ProcessStatusKind::kRunning) return No; if (process.Affinity == AffinityKind::kInvalid) return No; if (process.StackSize > kSchedMaxStackSz) return No; if (!process.Name[0]) return No; - - // real time processes shouldn't wait that much. - if (process.Affinity == AffinityKind::kRealTime) return Yes; - - if (process.Signal.SignalID == sig_generate_unique()) { - return No; - } + if (process.Signal.SignalID == sig_generate_unique()) return No; return process.PTime < 1; } -- cgit v1.2.3 From b6ce6640afaf6c1cc6ad274f3053b2e218a49554 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sun, 26 Oct 2025 12:29:35 +0100 Subject: feat: refactor HeFS to OpenHeFS. Signed-off-by: Amlal El Mahrouss --- README.md | 4 +- dev/boot/src/docs/MKFS_HEFS.md | 8 +- dev/kernel/FSKit/HeFS.h | 434 -------- dev/kernel/FSKit/OpenHeFS.h | 434 ++++++++ dev/kernel/FirmwareKit/EPM.h | 2 +- dev/kernel/HALKit/AMD64/HalKernelMain.cc | 2 +- dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc | 8 +- dev/kernel/HALKit/AMD64/Storage/NVME+Generic.cc | 9 + dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc | 8 +- dev/kernel/KernelKit/DriveMgr.h | 8 +- dev/kernel/KernelKit/FileMgr.h | 6 +- dev/kernel/KernelKit/IFS.h | 4 +- dev/kernel/KernelKit/ILoader.h | 32 + dev/kernel/KernelKit/LoaderInterface.h | 32 - dev/kernel/KernelKit/PEF.h | 2 +- dev/kernel/KernelKit/PEFCodeMgr.h | 2 +- dev/kernel/KernelKit/UserMgr.h | 6 +- dev/kernel/KernelKit/ZXD.h | 4 +- dev/kernel/StorageKit/AHCI.h | 10 +- dev/kernel/StorageKit/ATA.h | 10 +- dev/kernel/StorageKit/NVME.h | 8 +- dev/kernel/src/FS/HeFS+FileMgr.cc | 191 ---- dev/kernel/src/FS/HeFS+FileSystemParser.cc | 1166 -------------------- dev/kernel/src/FS/NeFS+FileSystemParser.cc | 6 +- dev/kernel/src/FS/OpenHeFS+FileMgr.cc | 191 ++++ dev/kernel/src/FS/OpenHeFS+FileSystemParser.cc | 1166 ++++++++++++++++++++ dev/kernel/src/IFS.cc | 20 +- dev/kernel/src/Storage/AHCIDeviceInterface.cc | 14 +- dev/kernel/src/Storage/ATADeviceInterface.cc | 14 +- dev/kernel/src/Storage/NVMEDeviceInterface.cc | 4 +- dev/libSystem/SystemKit/System.h | 4 +- docs/tex/hefs.tex | 14 +- .../frameworks/DiskImage.fwrk/headers/DiskImage.h | 2 +- .../DiskImage.fwrk/src/DiskImage+HeFS.cc | 6 +- public/manuals/nekernel/mgmt.hefs.util.man | 6 +- tools/fsck.hefs.cc | 10 +- tools/libmkfs/hefs.h | 116 -- tools/libmkfs/openhefs.h | 116 ++ tools/mkfs.hefs.cc | 2 +- 39 files changed, 2045 insertions(+), 2036 deletions(-) delete mode 100644 dev/kernel/FSKit/HeFS.h create mode 100644 dev/kernel/FSKit/OpenHeFS.h create mode 100644 dev/kernel/HALKit/AMD64/Storage/NVME+Generic.cc create mode 100644 dev/kernel/KernelKit/ILoader.h delete mode 100644 dev/kernel/KernelKit/LoaderInterface.h delete mode 100644 dev/kernel/src/FS/HeFS+FileMgr.cc delete mode 100644 dev/kernel/src/FS/HeFS+FileSystemParser.cc create mode 100644 dev/kernel/src/FS/OpenHeFS+FileMgr.cc create mode 100644 dev/kernel/src/FS/OpenHeFS+FileSystemParser.cc delete mode 100644 tools/libmkfs/hefs.h create mode 100644 tools/libmkfs/openhefs.h (limited to 'dev/kernel') diff --git a/README.md b/README.md index 299a4656..30495c8b 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ - **Modular Microkernel Architecture**: Clean separation of kernel, drivers, userland, and frameworks. -- **Custom Filesystems**: (HeFS), catalog/fork model (NeFS), and metadata handling. +- **Custom Filesystems**: (OpenHeFS), catalog/fork model (NeFS), and metadata handling. - **Memory Management**: Custom heap manager, page manager, and safe memory utilities. Kernel heap allocations are protected with metadata and CRCs. Userland and kernel memory separation. @@ -38,7 +38,7 @@ - **Security and Robustness**: kernel and tools (bounds checks, safe memory copy/set, error codes). Kernel panics and error reporting for critical failures. No dynamic code loading in kernel space. -- **Documentation and Specs**: Full LaTeX specifications for HeFS and NeFS, with on-disk structure diagrams and API documentation. Markdown docs for tools and usage. +- **Documentation and Specs**: Full LaTeX specifications for OpenHeFS and NeFS, with on-disk structure diagrams and API documentation. Markdown docs for tools and usage. - **Cross-Platform Boot Support**: Bootloader and platform code for AMD64 and ARM64, with handover and hardware abstraction layers. diff --git a/dev/boot/src/docs/MKFS_HEFS.md b/dev/boot/src/docs/MKFS_HEFS.md index c9aa0628..ac84d132 100644 --- a/dev/boot/src/docs/MKFS_HEFS.md +++ b/dev/boot/src/docs/MKFS_HEFS.md @@ -1,6 +1,6 @@ -# `mkfs.hefs` – HeFS Filesystem Formatter +# `mkfs.hefs` – OpenHeFS Filesystem Formatter -`mkfs.hefs` is a command-line utility used to format a block device or disk image with the **High-throughput Extended File System (HeFS)** used by NeKernel. This tool initializes a HeFS volume by writing a boot node and configuring directory and inode index regions, block ranges, and volume metadata. +`mkfs.hefs` is a command-line utility used to format a block device or disk image with the **High-throughput Extended File System (OpenHeFS)** used by NeKernel. This tool initializes a OpenHeFS volume by writing a boot node and configuring directory and inode index regions, block ranges, and volume metadata. --- @@ -61,7 +61,7 @@ -is 0x800000 -ie 0xA00000 \ -S 128 -o hefs.img -This will create a 128 GiB formatted HeFS image named `hefs.img` with specified region boundaries. +This will create a 128 GiB formatted OpenHeFS image named `hefs.img` with specified region boundaries. --- @@ -96,7 +96,7 @@ The `BootNode` stores key filesystem metadata: ## 📚 Source Location -Part of the [HeFS Tooling module](https://github.com/nekernel-org/nekernel) and used during system setup or disk preparation for NeKernel. +Part of the [OpenHeFS Tooling module](https://github.com/nekernel-org/nekernel) and used during system setup or disk preparation for NeKernel. --- diff --git a/dev/kernel/FSKit/HeFS.h b/dev/kernel/FSKit/HeFS.h deleted file mode 100644 index 51ec7648..00000000 --- a/dev/kernel/FSKit/HeFS.h +++ /dev/null @@ -1,434 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -/// @file HeFS.h -/// @brief HeFS filesystem support. - -#define kHeFSVersion (0x0103) -#define kHeFSMagic " HeFS" -#define kHeFSMagicLen (8) - -#define kHeFSBlockLen (512U) -#define kHeFSFileNameLen (256U) -#define kHeFSPartNameLen (128U) - -#define kHeFSMinimumDiskSize (gib_cast(128)) - -#define kHeFSDefaultVolumeName u8"HeFS Volume" - -#define kHeFSINDStartOffset (sizeof(HEFS_BOOT_NODE)) -#define kHeFSINStartOffset (sizeof(HEFS_INDEX_NODE_DIRECTORY)) - -#define kHeFSRootDirectory "/" -#define kHeFSRootDirectoryU8 u8"/" - -#define kHeFSSeparator '/' -#define kHeFSUpDir ".." - -#define kHeFSRootDirectoryLen (2U) - -#define kHeFSSearchAllStr u8"*" - -struct HEFS_BOOT_NODE; -struct HEFS_INDEX_NODE; -struct HEFS_INDEX_NODE_DIRECTORY; -struct HEFS_JOURNAL_NODE; - -enum : UInt8 { - kHeFSHardDrive = 0xC0, // Hard Drive - kHeFSSolidStateDrive = 0xC1, // Solid State Drive - kHeFSOpticalDrive = 0x0C, // Blu-Ray/DVD - kHeFSMassStorageDevice = 0xCC, // USB - kHeFSScsiDrive = 0xC4, // SCSI Hard Drive - kHeFSFlashDrive = 0xC6, - kHeFSUnknown = 0xFF, // Unknown device. - kHeFSDriveCount = 8, -}; - -enum : UInt8 { - kHeFSStatusUnlocked = 0x18, - kHeFSStatusLocked, - kHeFSStatusError, - kHeFSStatusInvalid, - kHeFSStatusCount, -}; - -enum : UInt16 { - kHeFSEncodingFlagsUTF8 = 0x50, - kHeFSEncodingFlagsUTF16, - kHeFSEncodingFlagsUTF32, - kHeFSEncodingFlagsUTF16BE, - kHeFSEncodingFlagsUTF16LE, - kHeFSEncodingFlagsUTF32BE, - kHeFSEncodingFlagsUTF32LE, - kHeFSEncodingFlagsUTF8BE, - kHeFSEncodingFlagsUTF8LE, - kHeFSEncodingFlagsBinary, - kHeFSEncodingFlagsCount = 11, - kHeFSFlagsNone = 0, - kHeFSFlagsReadOnly = 0x100, - kHeFSFlagsHidden, - kHeFSFlagsSystem, - kHeFSFlagsArchive, - kHeFSFlagsDevice, - kHeFSFlagsCount = 7 -}; - -inline constexpr UInt16 kHeFSFileKindRegular = 0x00; -inline constexpr UInt16 kHeFSFileKindDirectory = 0x01; -inline constexpr UInt16 kHeFSFileKindBlock = 0x02; -inline constexpr UInt16 kHeFSFileKindCharacter = 0x03; -inline constexpr UInt16 kHeFSFileKindFIFO = 0x04; -inline constexpr UInt16 kHeFSFileKindSocket = 0x05; -inline constexpr UInt16 kHeFSFileKindSymbolicLink = 0x06; -inline constexpr UInt16 kHeFSFileKindUnknown = 0x07; -inline constexpr UInt16 kHeFSFileKindCount = 0x08; - -/// @brief HeFS blocks are array containing sparse blocks of data. -/// @details The blocks are used to store the data of a file. Each block is a pointer to a block of -/// data on the disk. -inline constexpr UInt16 kHeFSSliceCount = 0x10; - -inline constexpr UInt16 kHeFSInvalidVID = 0xFFFF; - -namespace Kernel { -/// @brief Access time type. -/// @details Used to keep track of the INode, INodeDir allocation status. -typedef UInt64 ATime; - -/// @brief HeFS Boot node. -/// @details Acts like a superblock, it contains the information about the filesystem. -/// @note The boot node is the first block of the filesystem. -struct PACKED HEFS_BOOT_NODE final { - Char fMagic[kHeFSMagicLen]; /// @brief Magic number of the filesystem. - Utf8Char fVolName[kHeFSPartNameLen]; /// @brief Volume name. - UInt32 fVersion; /// @brief Version of the filesystem. - UInt64 fBadSectors; /// @brief Number of bad sectors in the filesystem. - UInt64 fSectorCount; /// @brief Number of sectors in the filesystem. - UInt64 fSectorSize; /// @brief Size of the sector. - UInt32 fChecksum; /// @brief Checksum of the boot node. - UInt8 fDiskKind; /// @brief Kind of the drive. (Hard Drive, Solid State Drive, Optical - /// Drive, etc). - UInt8 fEncoding; /// @brief Encoding of the filesystem. (UTF-8, UTF-16, etc). - UInt64 fStartIND; /// @brief Start of the INode directory tree. - UInt64 fEndIND; /// @brief End of the INode directory tree. - UInt64 fINDCount; /// @brief Number of leafs in the INode tree. - UInt64 fDiskSize; /// @brief Size of the disk. (Could be a virtual size, that is not the - /// real size of the disk.) - UInt16 fDiskStatus; /// @brief Status of the disk. (locked, unlocked, error, invalid). - UInt16 fDiskFlags; /// @brief Flags of the disk. (read-only, read-write, etc). - UInt16 fVID; /// @brief Virtual Identification Number within an EPM disk. (0xFFFF if not used). - UInt64 fStartIN; /// @brief Start INodes range - UInt64 fEndIN; /// @brief End INodes range - UInt64 fStartBlock; /// @brief Start Blocks range - UInt64 fEndBlock; /// @brief End Blocks range - UInt64 fJournalLBA; /// @brief Boot Node's COW journal LBA. - Char fPad[264]; -}; - -inline constexpr ATime kHeFSTimeInvalid = 0x0000000000000000; -inline constexpr ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF - 1; - -/// @brief Journal Node structure -/// @param fHashPath target hash path -/// @param fStatus target status -/// @param fCopyElem copy of element -/// @param fCopyKind kind of element -struct PACKED HEFS_JOURNAL_NODE { - UInt64 fHashPath; - UInt64 fStatus; - UInt64 fCopyElem; - UInt8 fCopyKind; - UInt8 fPad[487]; -}; - -/// @brief This enum defines the opcode of the journal, here mentioned as 'kinds' -enum HeFSJournalKind : UInt8 { - kJournalKindInvalid = 0x00, - kJournalKindWrite = 0x01, - kJournalKindRename = 0x02, - kJournalKindDelete = 0x03, - kJournalKindFlagEdit = 0x04, - kJournalKindCreate = 0x05, - kJournalKindCount, -}; - -/// @brief HeFS index node. -/// @details This structure is used to store the file information of a file. -/// @note The index node is a special type of INode that contains the file information. -/// @note The index node is used to store the file information of a file. -struct PACKED HEFS_INDEX_NODE final { - UInt64 fHashPath; /// @brief File name. - UInt32 fFlags; /// @brief File flags. - UInt16 fKind; /// @brief File kind. (Regular, Directory, Block, Character, FIFO, Socket, - /// Symbolic Link, Unknown). - UInt32 fSize; /// @brief File size. - UInt32 fChecksum; /// @brief Checksum. - - Boolean fSymLink; /// @brief Is this a symbolic link? (if yes, the fName is the path to - /// the file and blocklinkstart and end contains it's inodes.) - - ATime fCreated, fAccessed, fModified, fDeleted; /// @brief File timestamps. - UInt32 fUID, fGID; /// @brief User ID and Group ID of the file. - UInt32 fMode; /// @brief File mode. (read, write, execute, etc). - - /// @brief Extents system by using blocks - /// @details Using an offset to ask fBase, and fLength to compute each slice's length. - UInt32 fOffsetSliceLow; - UInt32 fOffsetSliceHigh; - - Char fPad[437]; -}; - -enum { - kHeFSInvalidColor = 0, - kHeFSRed = 100, - kHeFSBlack, - kHeFSColorCount, -}; - -/// @brief HeFS directory node. -/// @details This structure is used to store the directory information of a file. -/// @note The directory node is a special type of INode that contains the directory entries. -struct PACKED HEFS_INDEX_NODE_DIRECTORY final { - UInt64 fHashPath; /// @brief Directory path as FNV hash. - - UInt32 fFlags; /// @brief File flags. - UInt16 fReserved; /// @note Reserved for future use. - UInt32 fEntryCount; /// @brief Entry Count of this directory inode. - UInt32 fChecksum; /// @brief Checksum of the file, index node checksum. - - ATime fCreated, fAccessed, fModified, - fDeleted; /// @brief File timestamps and allocation status. - UInt32 fUID, fGID; /// @brief User ID and Group ID of the file. - UInt32 fMode; /// @brief File mode. (read, write, execute, etc). - - /// @note These slices are organized as: - /// [0] = OFFSET - /// [1] = SIZE - /// @note Thus the += 2 when iterating over them. - UInt64 fINSlices[kHeFSSliceCount]; /// @brief Start of the index node. - - UInt8 fColor; /// @brief Color of the node. (Red or Black). - Lba fNext, fPrev, fChild, fParent; /// @brief Red-black tree pointers. - - Char fPad[285]; -}; -} // namespace Kernel - -namespace Kernel::Detail { -/// @brief HeFS get year from ATime. -/// @param raw_atime the raw ATime value. -/// @return the year value. -/// @note The year is stored in the upper 32 bits of the ATime value. -inline UInt32 hefs_year_get(ATime raw_atime) noexcept { - return (raw_atime) >> 32; -} - -/// @brief HeFS get month from ATime. -/// @param raw_atime the raw ATime value. -/// @return the month value. -/// @note The month is stored in the upper 24 bits of the ATime value. -inline UInt32 hefs_month_get(ATime raw_atime) noexcept { - return (raw_atime) >> 24; -} - -/// @brief HeFS get day from ATime. -/// @param raw_atime the raw ATime value. -/// @return the day value. -/// @note The day is stored in the upper 16 bits of the ATime value. -inline UInt32 hefs_day_get(ATime raw_atime) noexcept { - return (raw_atime) >> 16; -} - -/// @brief HeFS get hour from ATime. -/// @param raw_atime the raw ATime value. -/// @return the hour value. -/// @note The hour is stored in the upper 8 bits of the ATime value. -inline UInt32 hefs_hour_get(ATime raw_atime) noexcept { - return (raw_atime) >> 8; -} - -/// @brief HeFS get minute from ATime. -/// @param raw_atime the raw ATime value. -/// @return the minute value. -/// @note The minute is stored in the lower 8 bits of the ATime value. -inline UInt32 hefs_minute_get(ATime raw_atime) noexcept { - return (raw_atime) &0xFF; -} - -inline constexpr UInt32 kHeFSBaseYear = 1970; -inline constexpr UInt32 kHeFSBaseMonth = 1; -inline constexpr UInt32 kHeFSBaseDay = 1; -inline constexpr UInt32 kHeFSBaseHour = 0; -inline constexpr UInt32 kHeFSBaseMinute = 0; - -inline const Char* hefs_status_to_string(UInt16 status) noexcept { - switch (status) { - case kHeFSStatusUnlocked: - return "Unlocked"; - case kHeFSStatusLocked: - return "Locked"; - case kHeFSStatusError: - return "Error"; - case kHeFSStatusInvalid: - return "Invalid"; - default: - return "Unknown"; - } -} - -inline const Char* hefs_drive_kind_to_string(UInt8 kind) noexcept { - switch (kind) { - case kHeFSHardDrive: - return "Hard Drive"; - case kHeFSSolidStateDrive: - return "Solid State Drive"; - case kHeFSOpticalDrive: - return "Optical Drive"; - case kHeFSMassStorageDevice: - return "Mass Storage Device"; - case kHeFSScsiDrive: - return "SCSI/SAS Drive"; - case kHeFSFlashDrive: - return "Flash Drive"; - case kHeFSUnknown: - default: - return "Unknown"; - } -} - -inline const Char* hefs_encoding_to_string(UInt8 encoding) noexcept { - switch (encoding) { - case kHeFSEncodingFlagsUTF8: - return "UTF-8"; - case kHeFSEncodingFlagsUTF16: - return "UTF-16"; - case kHeFSEncodingFlagsUTF32: - return "UTF-32"; - case kHeFSEncodingFlagsUTF16BE: - return "UTF-16BE"; - case kHeFSEncodingFlagsUTF16LE: - return "UTF-16LE"; - case kHeFSEncodingFlagsUTF32BE: - return "UTF-32BE"; - case kHeFSEncodingFlagsUTF32LE: - return "UTF-32LE"; - case kHeFSEncodingFlagsUTF8BE: - return "UTF-8BE"; - case kHeFSEncodingFlagsUTF8LE: - return "UTF-8LE"; - default: - return "Unknown"; - } -} - -inline const Char* hefs_file_kind_to_string(UInt16 kind) noexcept { - switch (kind) { - case kHeFSFileKindRegular: - return "Regular File"; - case kHeFSFileKindDirectory: - return "Directory"; - case kHeFSFileKindBlock: - return "Block Device"; - case kHeFSFileKindCharacter: - return "Character Device"; - case kHeFSFileKindFIFO: - return "FIFO"; - case kHeFSFileKindSocket: - return "Socket"; - case kHeFSFileKindSymbolicLink: - return "Symbolic Link"; - case kHeFSFileKindUnknown: - default: - return "Unknown"; - } -} - -inline const Char* hefs_file_flags_to_string(UInt32 flags) noexcept { - switch (flags) { - case kHeFSFlagsNone: - return "No Flags"; - case kHeFSFlagsReadOnly: - return "Read Only"; - case kHeFSFlagsHidden: - return "Hidden"; - case kHeFSFlagsSystem: - return "System"; - case kHeFSFlagsArchive: - return "Archive"; - case kHeFSFlagsDevice: - return "Device"; - default: - return "Unknown"; - } -} -} // namespace Kernel::Detail - -namespace Kernel { -/// @brief HeFS filesystem parser class. -/// @details This class is used to parse the HeFS filesystem. -class HeFileSystemParser final { - public: - HeFileSystemParser() = default; - ~HeFileSystemParser() = default; - - public: - HeFileSystemParser(const HeFileSystemParser&) = delete; - HeFileSystemParser& operator=(const HeFileSystemParser&) = delete; - - HeFileSystemParser(HeFileSystemParser&&) = delete; - HeFileSystemParser& operator=(HeFileSystemParser&&) = delete; - - public: - /// @brief Make a EPM+HeFS drive out of the disk. - /// @param drive The drive to write on. - /// @return If it was sucessful, see err_local_get(). - _Output Bool Format(_Input _Output DriveTrait* drive, _Input const Int32 flags, - const Utf8Char* part_name); - - _Output Bool CreateINodeDirectory(_Input DriveTrait* drive, _Input const Int32 flags, - const Utf8Char* dir); - - _Output Bool RemoveINodeDirectory(_Input DriveTrait* drive, _Input const Int32 flags, - const Utf8Char* dir); - - _Output Bool CreateINode(_Input DriveTrait* drive, _Input const Int32 flags, const Utf8Char* dir, - const Utf8Char* name, const UInt8 kind); - - _Output Bool DeleteINode(_Input DriveTrait* drive, _Input const Int32 flags, const Utf8Char* dir, - const Utf8Char* name, const UInt8 kind); - - _Output Bool INodeManip(_Input DriveTrait* drive, VoidPtr block, SizeT block_sz, - const Utf8Char* dir, const Utf8Char* name, const UInt8 kind, - const BOOL input); - - private: - _Output Bool INodeCtlManip(_Input DriveTrait* drive, _Input const Int32 flags, - const Utf8Char* dir, const Utf8Char* name, const BOOL delete_or_create, - const UInt8 kind); - - _Output Bool INodeDirectoryCtlManip(_Input DriveTrait* drive, _Input const Int32 flags, - const Utf8Char* dir, const BOOL delete_or_create); -}; - -namespace HeFS { - - /// @brief Initialize HeFS inside the main disk. - /// @return Whether it successfuly formated it or not. - Boolean fs_init_hefs(Void) noexcept; -} // namespace HeFS -} // namespace Kernel diff --git a/dev/kernel/FSKit/OpenHeFS.h b/dev/kernel/FSKit/OpenHeFS.h new file mode 100644 index 00000000..1361da9c --- /dev/null +++ b/dev/kernel/FSKit/OpenHeFS.h @@ -0,0 +1,434 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +/// @file OpenHeFS.h +/// @brief OpenHeFS filesystem support. + +#define kHeFSVersion (0x0103) +#define kHeFSMagic " HeFS" +#define kHeFSMagicLen (8) + +#define kHeFSBlockLen (512U) +#define kHeFSFileNameLen (256U) +#define kHeFSPartNameLen (128U) + +#define kHeFSMinimumDiskSize (gib_cast(128)) + +#define kHeFSDefaultVolumeName u8"OpenHeFS Volume" + +#define kHeFSINDStartOffset (sizeof(HEFS_BOOT_NODE)) +#define kHeFSINStartOffset (sizeof(HEFS_INDEX_NODE_DIRECTORY)) + +#define kHeFSRootDirectory "/" +#define kHeFSRootDirectoryU8 u8"/" + +#define kHeFSSeparator '/' +#define kHeFSUpDir ".." + +#define kHeFSRootDirectoryLen (2U) + +#define kHeFSSearchAllStr u8"*" + +struct HEFS_BOOT_NODE; +struct HEFS_INDEX_NODE; +struct HEFS_INDEX_NODE_DIRECTORY; +struct HEFS_JOURNAL_NODE; + +enum : UInt8 { + kHeFSHardDrive = 0xC0, // Hard Drive + kHeFSSolidStateDrive = 0xC1, // Solid State Drive + kHeFSOpticalDrive = 0x0C, // Blu-Ray/DVD + kHeFSMassStorageDevice = 0xCC, // USB + kHeFSScsiDrive = 0xC4, // SCSI Hard Drive + kHeFSFlashDrive = 0xC6, + kHeFSUnknown = 0xFF, // Unknown device. + kHeFSDriveCount = 8, +}; + +enum : UInt8 { + kHeFSStatusUnlocked = 0x18, + kHeFSStatusLocked, + kHeFSStatusError, + kHeFSStatusInvalid, + kHeFSStatusCount, +}; + +enum : UInt16 { + kHeFSEncodingFlagsUTF8 = 0x50, + kHeFSEncodingFlagsUTF16, + kHeFSEncodingFlagsUTF32, + kHeFSEncodingFlagsUTF16BE, + kHeFSEncodingFlagsUTF16LE, + kHeFSEncodingFlagsUTF32BE, + kHeFSEncodingFlagsUTF32LE, + kHeFSEncodingFlagsUTF8BE, + kHeFSEncodingFlagsUTF8LE, + kHeFSEncodingFlagsBinary, + kHeFSEncodingFlagsCount = 11, + kHeFSFlagsNone = 0, + kHeFSFlagsReadOnly = 0x100, + kHeFSFlagsHidden, + kHeFSFlagsSystem, + kHeFSFlagsArchive, + kHeFSFlagsDevice, + kHeFSFlagsCount = 7 +}; + +inline constexpr UInt16 kHeFSFileKindRegular = 0x00; +inline constexpr UInt16 kHeFSFileKindDirectory = 0x01; +inline constexpr UInt16 kHeFSFileKindBlock = 0x02; +inline constexpr UInt16 kHeFSFileKindCharacter = 0x03; +inline constexpr UInt16 kHeFSFileKindFIFO = 0x04; +inline constexpr UInt16 kHeFSFileKindSocket = 0x05; +inline constexpr UInt16 kHeFSFileKindSymbolicLink = 0x06; +inline constexpr UInt16 kHeFSFileKindUnknown = 0x07; +inline constexpr UInt16 kHeFSFileKindCount = 0x08; + +/// @brief OpenHeFS blocks are array containing sparse blocks of data. +/// @details The blocks are used to store the data of a file. Each block is a pointer to a block of +/// data on the disk. +inline constexpr UInt16 kHeFSSliceCount = 0x10; + +inline constexpr UInt16 kHeFSInvalidVID = 0xFFFF; + +namespace Kernel { +/// @brief Access time type. +/// @details Used to keep track of the INode, INodeDir allocation status. +typedef UInt64 ATime; + +/// @brief OpenHeFS Boot node. +/// @details Acts like a superblock, it contains the information about the filesystem. +/// @note The boot node is the first block of the filesystem. +struct PACKED HEFS_BOOT_NODE final { + Char fMagic[kHeFSMagicLen]; /// @brief Magic number of the filesystem. + Utf8Char fVolName[kHeFSPartNameLen]; /// @brief Volume name. + UInt32 fVersion; /// @brief Version of the filesystem. + UInt64 fBadSectors; /// @brief Number of bad sectors in the filesystem. + UInt64 fSectorCount; /// @brief Number of sectors in the filesystem. + UInt64 fSectorSize; /// @brief Size of the sector. + UInt32 fChecksum; /// @brief Checksum of the boot node. + UInt8 fDiskKind; /// @brief Kind of the drive. (Hard Drive, Solid State Drive, Optical + /// Drive, etc). + UInt8 fEncoding; /// @brief Encoding of the filesystem. (UTF-8, UTF-16, etc). + UInt64 fStartIND; /// @brief Start of the INode directory tree. + UInt64 fEndIND; /// @brief End of the INode directory tree. + UInt64 fINDCount; /// @brief Number of leafs in the INode tree. + UInt64 fDiskSize; /// @brief Size of the disk. (Could be a virtual size, that is not the + /// real size of the disk.) + UInt16 fDiskStatus; /// @brief Status of the disk. (locked, unlocked, error, invalid). + UInt16 fDiskFlags; /// @brief Flags of the disk. (read-only, read-write, etc). + UInt16 fVID; /// @brief Virtual Identification Number within an EPM disk. (0xFFFF if not used). + UInt64 fStartIN; /// @brief Start INodes range + UInt64 fEndIN; /// @brief End INodes range + UInt64 fStartBlock; /// @brief Start Blocks range + UInt64 fEndBlock; /// @brief End Blocks range + UInt64 fJournalLBA; /// @brief Boot Node's COW journal LBA. + Char fPad[264]; +}; + +inline constexpr ATime kHeFSTimeInvalid = 0x0000000000000000; +inline constexpr ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF - 1; + +/// @brief Journal Node structure +/// @param fHashPath target hash path +/// @param fStatus target status +/// @param fCopyElem copy of element +/// @param fCopyKind kind of element +struct PACKED HEFS_JOURNAL_NODE { + UInt64 fHashPath; + UInt64 fStatus; + UInt64 fCopyElem; + UInt8 fCopyKind; + UInt8 fPad[487]; +}; + +/// @brief This enum defines the opcode of the journal, here mentioned as 'kinds' +enum HeFSJournalKind : UInt8 { + kJournalKindInvalid = 0x00, + kJournalKindWrite = 0x01, + kJournalKindRename = 0x02, + kJournalKindDelete = 0x03, + kJournalKindFlagEdit = 0x04, + kJournalKindCreate = 0x05, + kJournalKindCount, +}; + +/// @brief OpenHeFS index node. +/// @details This structure is used to store the file information of a file. +/// @note The index node is a special type of INode that contains the file information. +/// @note The index node is used to store the file information of a file. +struct PACKED HEFS_INDEX_NODE final { + UInt64 fHashPath; /// @brief File name. + UInt32 fFlags; /// @brief File flags. + UInt16 fKind; /// @brief File kind. (Regular, Directory, Block, Character, FIFO, Socket, + /// Symbolic Link, Unknown). + UInt32 fSize; /// @brief File size. + UInt32 fChecksum; /// @brief Checksum. + + Boolean fSymLink; /// @brief Is this a symbolic link? (if yes, the fName is the path to + /// the file and blocklinkstart and end contains it's inodes.) + + ATime fCreated, fAccessed, fModified, fDeleted; /// @brief File timestamps. + UInt32 fUID, fGID; /// @brief User ID and Group ID of the file. + UInt32 fMode; /// @brief File mode. (read, write, execute, etc). + + /// @brief Extents system by using blocks + /// @details Using an offset to ask fBase, and fLength to compute each slice's length. + UInt32 fOffsetSliceLow; + UInt32 fOffsetSliceHigh; + + Char fPad[437]; +}; + +enum { + kHeFSInvalidColor = 0, + kHeFSRed = 100, + kHeFSBlack, + kHeFSColorCount, +}; + +/// @brief OpenHeFS directory node. +/// @details This structure is used to store the directory information of a file. +/// @note The directory node is a special type of INode that contains the directory entries. +struct PACKED HEFS_INDEX_NODE_DIRECTORY final { + UInt64 fHashPath; /// @brief Directory path as FNV hash. + + UInt32 fFlags; /// @brief File flags. + UInt16 fReserved; /// @note Reserved for future use. + UInt32 fEntryCount; /// @brief Entry Count of this directory inode. + UInt32 fChecksum; /// @brief Checksum of the file, index node checksum. + + ATime fCreated, fAccessed, fModified, + fDeleted; /// @brief File timestamps and allocation status. + UInt32 fUID, fGID; /// @brief User ID and Group ID of the file. + UInt32 fMode; /// @brief File mode. (read, write, execute, etc). + + /// @note These slices are organized as: + /// [0] = OFFSET + /// [1] = SIZE + /// @note Thus the += 2 when iterating over them. + UInt64 fINSlices[kHeFSSliceCount]; /// @brief Start of the index node. + + UInt8 fColor; /// @brief Color of the node. (Red or Black). + Lba fNext, fPrev, fChild, fParent; /// @brief Red-black tree pointers. + + Char fPad[285]; +}; +} // namespace Kernel + +namespace Kernel::Detail { +/// @brief OpenHeFS get year from ATime. +/// @param raw_atime the raw ATime value. +/// @return the year value. +/// @note The year is stored in the upper 32 bits of the ATime value. +inline UInt32 hefs_year_get(ATime raw_atime) noexcept { + return (raw_atime) >> 32; +} + +/// @brief OpenHeFS get month from ATime. +/// @param raw_atime the raw ATime value. +/// @return the month value. +/// @note The month is stored in the upper 24 bits of the ATime value. +inline UInt32 hefs_month_get(ATime raw_atime) noexcept { + return (raw_atime) >> 24; +} + +/// @brief OpenHeFS get day from ATime. +/// @param raw_atime the raw ATime value. +/// @return the day value. +/// @note The day is stored in the upper 16 bits of the ATime value. +inline UInt32 hefs_day_get(ATime raw_atime) noexcept { + return (raw_atime) >> 16; +} + +/// @brief OpenHeFS get hour from ATime. +/// @param raw_atime the raw ATime value. +/// @return the hour value. +/// @note The hour is stored in the upper 8 bits of the ATime value. +inline UInt32 hefs_hour_get(ATime raw_atime) noexcept { + return (raw_atime) >> 8; +} + +/// @brief OpenHeFS get minute from ATime. +/// @param raw_atime the raw ATime value. +/// @return the minute value. +/// @note The minute is stored in the lower 8 bits of the ATime value. +inline UInt32 hefs_minute_get(ATime raw_atime) noexcept { + return (raw_atime) &0xFF; +} + +inline constexpr UInt32 kHeFSBaseYear = 1970; +inline constexpr UInt32 kHeFSBaseMonth = 1; +inline constexpr UInt32 kHeFSBaseDay = 1; +inline constexpr UInt32 kHeFSBaseHour = 0; +inline constexpr UInt32 kHeFSBaseMinute = 0; + +inline const Char* hefs_status_to_string(UInt16 status) noexcept { + switch (status) { + case kHeFSStatusUnlocked: + return "Unlocked"; + case kHeFSStatusLocked: + return "Locked"; + case kHeFSStatusError: + return "Error"; + case kHeFSStatusInvalid: + return "Invalid"; + default: + return "Unknown"; + } +} + +inline const Char* hefs_drive_kind_to_string(UInt8 kind) noexcept { + switch (kind) { + case kHeFSHardDrive: + return "Hard Drive"; + case kHeFSSolidStateDrive: + return "Solid State Drive"; + case kHeFSOpticalDrive: + return "Optical Drive"; + case kHeFSMassStorageDevice: + return "Mass Storage Device"; + case kHeFSScsiDrive: + return "SCSI/SAS Drive"; + case kHeFSFlashDrive: + return "Flash Drive"; + case kHeFSUnknown: + default: + return "Unknown"; + } +} + +inline const Char* hefs_encoding_to_string(UInt8 encoding) noexcept { + switch (encoding) { + case kHeFSEncodingFlagsUTF8: + return "UTF-8"; + case kHeFSEncodingFlagsUTF16: + return "UTF-16"; + case kHeFSEncodingFlagsUTF32: + return "UTF-32"; + case kHeFSEncodingFlagsUTF16BE: + return "UTF-16BE"; + case kHeFSEncodingFlagsUTF16LE: + return "UTF-16LE"; + case kHeFSEncodingFlagsUTF32BE: + return "UTF-32BE"; + case kHeFSEncodingFlagsUTF32LE: + return "UTF-32LE"; + case kHeFSEncodingFlagsUTF8BE: + return "UTF-8BE"; + case kHeFSEncodingFlagsUTF8LE: + return "UTF-8LE"; + default: + return "Unknown"; + } +} + +inline const Char* hefs_file_kind_to_string(UInt16 kind) noexcept { + switch (kind) { + case kHeFSFileKindRegular: + return "Regular File"; + case kHeFSFileKindDirectory: + return "Directory"; + case kHeFSFileKindBlock: + return "Block Device"; + case kHeFSFileKindCharacter: + return "Character Device"; + case kHeFSFileKindFIFO: + return "FIFO"; + case kHeFSFileKindSocket: + return "Socket"; + case kHeFSFileKindSymbolicLink: + return "Symbolic Link"; + case kHeFSFileKindUnknown: + default: + return "Unknown"; + } +} + +inline const Char* hefs_file_flags_to_string(UInt32 flags) noexcept { + switch (flags) { + case kHeFSFlagsNone: + return "No Flags"; + case kHeFSFlagsReadOnly: + return "Read Only"; + case kHeFSFlagsHidden: + return "Hidden"; + case kHeFSFlagsSystem: + return "System"; + case kHeFSFlagsArchive: + return "Archive"; + case kHeFSFlagsDevice: + return "Device"; + default: + return "Unknown"; + } +} +} // namespace Kernel::Detail + +namespace Kernel { +/// @brief OpenHeFS filesystem parser class. +/// @details This class is used to parse the OpenHeFS filesystem. +class HeFileSystemParser final { + public: + HeFileSystemParser() = default; + ~HeFileSystemParser() = default; + + public: + HeFileSystemParser(const HeFileSystemParser&) = delete; + HeFileSystemParser& operator=(const HeFileSystemParser&) = delete; + + HeFileSystemParser(HeFileSystemParser&&) = delete; + HeFileSystemParser& operator=(HeFileSystemParser&&) = delete; + + public: + /// @brief Make a EPM+OpenHeFS drive out of the disk. + /// @param drive The drive to write on. + /// @return If it was sucessful, see err_local_get(). + _Output Bool Format(_Input _Output DriveTrait* drive, _Input const Int32 flags, + const Utf8Char* part_name); + + _Output Bool CreateINodeDirectory(_Input DriveTrait* drive, _Input const Int32 flags, + const Utf8Char* dir); + + _Output Bool RemoveINodeDirectory(_Input DriveTrait* drive, _Input const Int32 flags, + const Utf8Char* dir); + + _Output Bool CreateINode(_Input DriveTrait* drive, _Input const Int32 flags, const Utf8Char* dir, + const Utf8Char* name, const UInt8 kind); + + _Output Bool DeleteINode(_Input DriveTrait* drive, _Input const Int32 flags, const Utf8Char* dir, + const Utf8Char* name, const UInt8 kind); + + _Output Bool INodeManip(_Input DriveTrait* drive, VoidPtr block, SizeT block_sz, + const Utf8Char* dir, const Utf8Char* name, const UInt8 kind, + const BOOL input); + + private: + _Output Bool INodeCtlManip(_Input DriveTrait* drive, _Input const Int32 flags, + const Utf8Char* dir, const Utf8Char* name, const BOOL delete_or_create, + const UInt8 kind); + + _Output Bool INodeDirectoryCtlManip(_Input DriveTrait* drive, _Input const Int32 flags, + const Utf8Char* dir, const BOOL delete_or_create); +}; + +namespace OpenHeFS { + + /// @brief Initialize OpenHeFS inside the main disk. + /// @return Whether it successfuly formated it or not. + Boolean fs_init_hefs(Void) noexcept; +} // namespace OpenHeFS +} // namespace Kernel diff --git a/dev/kernel/FirmwareKit/EPM.h b/dev/kernel/FirmwareKit/EPM.h index dcab3607..20c966e4 100644 --- a/dev/kernel/FirmwareKit/EPM.h +++ b/dev/kernel/FirmwareKit/EPM.h @@ -89,7 +89,7 @@ struct PACKED EPM_PART_BLOCK { Kernel::Int16 Kind; Kernel::Int16 Flags; Kernel::Int32 FsVersion; - Kernel::Char Fs[kEPMFilesystemLength]; /* NeFS, HeFS... */ + Kernel::Char Fs[kEPMFilesystemLength]; /* NeFS, OpenHeFS... */ Kernel::Char Reserved[kEPMReserveLen]; // to fill a full sector. }; diff --git a/dev/kernel/HALKit/AMD64/HalKernelMain.cc b/dev/kernel/HALKit/AMD64/HalKernelMain.cc index 6f4d7e0a..2b478dd6 100644 --- a/dev/kernel/HALKit/AMD64/HalKernelMain.cc +++ b/dev/kernel/HALKit/AMD64/HalKernelMain.cc @@ -145,7 +145,7 @@ EXTERN_C Kernel::Void hal_real_init(Kernel::Void) { HAL::mp_init_cores(kHandoverHeader->f_HardwareTables.f_VendorPtr); #ifdef __FSKIT_INCLUDES_HEFS__ - HeFS::fs_init_hefs(); + OpenHeFS::fs_init_hefs(); #endif #ifdef __FSKIT_INCLUDES_NEFS__ diff --git a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc index 0a465145..1acfac0e 100644 --- a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc +++ b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc @@ -546,8 +546,8 @@ namespace Detail { /// @brief Read AHCI device. /// @param self device /// @param mnt mounted disk. - STATIC Void sk_io_read_ahci(DeviceInterface* self, - MountpointInterface* mnt) { + STATIC Void sk_io_read_ahci(DeviceInterface* self, + IMountpoint* mnt) { AHCIDeviceInterface* dev = (AHCIDeviceInterface*) self; err_global_get() = kErrorDisk; @@ -568,8 +568,8 @@ namespace Detail { /// @brief Write AHCI device. /// @param self device /// @param mnt mounted disk. - STATIC Void sk_io_write_ahci(DeviceInterface* self, - MountpointInterface* mnt) { + STATIC Void sk_io_write_ahci(DeviceInterface* self, + IMountpoint* mnt) { AHCIDeviceInterface* dev = (AHCIDeviceInterface*) self; err_global_get() = kErrorDisk; diff --git a/dev/kernel/HALKit/AMD64/Storage/NVME+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/NVME+Generic.cc new file mode 100644 index 00000000..67b59813 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Storage/NVME+Generic.cc @@ -0,0 +1,9 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include + +using namespace Kernel; diff --git a/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc index 6fccbdfa..5b768fbb 100644 --- a/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc +++ b/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc @@ -200,8 +200,8 @@ namespace Detail { /// @brief Read PIO device. /// @param self device /// @param mnt mounted disk. - STATIC Void sk_io_read_pio(DeviceInterface* self, - MountpointInterface* mnt) { + STATIC Void sk_io_read_pio(DeviceInterface* self, + IMountpoint* mnt) { ATADeviceInterface* dev = (ATADeviceInterface*) self; err_global_get() = kErrorDisk; @@ -222,8 +222,8 @@ namespace Detail { /// @brief Write PIO device. /// @param self device /// @param mnt mounted disk. - STATIC Void sk_io_write_pio(DeviceInterface* self, - MountpointInterface* mnt) { + STATIC Void sk_io_write_pio(DeviceInterface* self, + IMountpoint* mnt) { ATADeviceInterface* dev = (ATADeviceInterface*) self; err_global_get() = kErrorDisk; diff --git a/dev/kernel/KernelKit/DriveMgr.h b/dev/kernel/KernelKit/DriveMgr.h index 03f9a717..6340d966 100644 --- a/dev/kernel/KernelKit/DriveMgr.h +++ b/dev/kernel/KernelKit/DriveMgr.h @@ -89,12 +89,12 @@ typedef DriveTrait* DriveTraitPtr; * @note This class has all of it's drive set to nullptr, allocate them using * GetAddressOf(index). */ -class MountpointInterface final { +class IMountpoint final { public: - explicit MountpointInterface() = default; - ~MountpointInterface() = default; + explicit IMountpoint() = default; + ~IMountpoint() = default; - NE_COPY_DEFAULT(MountpointInterface) + NE_COPY_DEFAULT(IMountpoint) public: DriveTrait& A() { return mA; } diff --git a/dev/kernel/KernelKit/FileMgr.h b/dev/kernel/KernelKit/FileMgr.h index cc2feeb8..ff290780 100644 --- a/dev/kernel/KernelKit/FileMgr.h +++ b/dev/kernel/KernelKit/FileMgr.h @@ -23,12 +23,12 @@ #define INC_FILEMGR_H /// @file FileMgr.h -/// @brief File Manager. +/// @brief File Manager System. /// @author Amlal El Mahrouss (amlal@nekernel.org) //! Include filesystems that NeKernel supports. #include -#include +#include #include #include @@ -71,7 +71,7 @@ enum { kFileIOCnt = (kFileFlagData - kFileWriteAll) + 1, }; -typedef VoidPtr NodePtr; +using NodePtr = VoidPtr; /** @brief Filesystem Mgr Interface class diff --git a/dev/kernel/KernelKit/IFS.h b/dev/kernel/KernelKit/IFS.h index ed1d87b5..b1dd2001 100644 --- a/dev/kernel/KernelKit/IFS.h +++ b/dev/kernel/KernelKit/IFS.h @@ -14,12 +14,12 @@ namespace Kernel { /// @param DrvTrait drive info /// @param DrvIndex drive index. /// @return -Int32 fs_ifs_read(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); +Int32 fs_ifs_read(IMountpoint* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); /// @brief Write to IFS disk. /// @param Mnt mounted interface. /// @param DrvTrait drive info /// @param DrvIndex drive index. /// @return -Int32 fs_ifs_write(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); +Int32 fs_ifs_write(IMountpoint* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); } // namespace Kernel diff --git a/dev/kernel/KernelKit/ILoader.h b/dev/kernel/KernelKit/ILoader.h new file mode 100644 index 00000000..ec8ee1bc --- /dev/null +++ b/dev/kernel/KernelKit/ILoader.h @@ -0,0 +1,32 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include +#include +#include +#include + +namespace Kernel { +/// @brief This interface is used to make loader contracts (MSCOFF, PEF). +/// @author @Amlal-El-Mahrouss +class ILoader { + public: + explicit ILoader() = default; + virtual ~ILoader() = default; + + NE_COPY_DEFAULT(ILoader) + + public: + virtual _Output ErrorOr GetBlob() = 0; + virtual _Output const Char* AsString() = 0; + virtual _Output const Char* MIME() = 0; + virtual _Output const Char* Path() = 0; + virtual _Output ErrorOr FindStart() = 0; + virtual _Output ErrorOr FindSymbol(_Input const Char* name, _Input Int32 kind) = 0; +}; +} // namespace Kernel diff --git a/dev/kernel/KernelKit/LoaderInterface.h b/dev/kernel/KernelKit/LoaderInterface.h deleted file mode 100644 index 1f9b1e56..00000000 --- a/dev/kernel/KernelKit/LoaderInterface.h +++ /dev/null @@ -1,32 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#pragma once - -#include -#include -#include -#include - -namespace Kernel { -/// @brief This interface is used to make loader contracts (MSCOFF, PEF). -/// @author @Amlal-El-Mahrouss -class LoaderInterface { - public: - explicit LoaderInterface() = default; - virtual ~LoaderInterface() = default; - - NE_COPY_DEFAULT(LoaderInterface) - - public: - virtual _Output ErrorOr GetBlob() = 0; - virtual _Output const Char* AsString() = 0; - virtual _Output const Char* MIME() = 0; - virtual _Output const Char* Path() = 0; - virtual _Output ErrorOr FindStart() = 0; - virtual _Output ErrorOr FindSymbol(_Input const Char* name, _Input Int32 kind) = 0; -}; -} // namespace Kernel diff --git a/dev/kernel/KernelKit/PEF.h b/dev/kernel/KernelKit/PEF.h index f0ba9ef9..0410c63a 100644 --- a/dev/kernel/KernelKit/PEF.h +++ b/dev/kernel/KernelKit/PEF.h @@ -15,7 +15,7 @@ #define __KERNELKIT_PEF_H__ #include -#include +#include #include #define kPefMagic "Open" diff --git a/dev/kernel/KernelKit/PEFCodeMgr.h b/dev/kernel/KernelKit/PEFCodeMgr.h index d61aa863..3ed9c097 100644 --- a/dev/kernel/KernelKit/PEFCodeMgr.h +++ b/dev/kernel/KernelKit/PEFCodeMgr.h @@ -27,7 +27,7 @@ namespace Kernel { /// \name PEFLoader /// \brief PEF loader class. /// -class PEFLoader : public LoaderInterface { +class PEFLoader : public ILoader { private: explicit PEFLoader() = delete; diff --git a/dev/kernel/KernelKit/UserMgr.h b/dev/kernel/KernelKit/UserMgr.h index 6fa8ba14..c660025b 100644 --- a/dev/kernel/KernelKit/UserMgr.h +++ b/dev/kernel/KernelKit/UserMgr.h @@ -22,9 +22,9 @@ ///! We got the MGMT, STD (%s format) and GUEST users, ///! all are used to make authorized operations. -#define kSuperUser "OS AUTHORITY/MGMT/%s" -#define kGuestUser "OS AUTHORITY/GUEST/%s" -#define kStdUser "OS AUTHORITY/STD/%s" +#define kSuperUser "NEKERNEL/MGMT/%s" +#define kGuestUser "NEKERNEL/GUEST/%s" +#define kStdUser "NEKERNEL/STD/%s" #define kUsersDir "/users/" diff --git a/dev/kernel/KernelKit/ZXD.h b/dev/kernel/KernelKit/ZXD.h index 966c54c7..bae47258 100644 --- a/dev/kernel/KernelKit/ZXD.h +++ b/dev/kernel/KernelKit/ZXD.h @@ -23,7 +23,7 @@ enum ZXD_FLAGS { /// @brief ZXD executable header /// @details This header is used to identify ZXD executable files. -struct PACKED ZXD_EXEC_HEADER { +struct PACKED ZXD_EXEC_HEADER final { UInt32 fMagic; UInt32 fVersion; UInt32 fFlags; @@ -42,7 +42,7 @@ struct PACKED ZXD_EXEC_HEADER { /// @brief ZXD stub header /// @details This header is used to identify ZXD stub files. It contains the size of the stub, the /// offset of the stub, and the CRC32 checksum of the stub. -struct PACKED ZXD_STUB_HEADER { +struct PACKED ZXD_STUB_HEADER final { UInt32 fStubSize; UInt32 fStubOffset; UInt32 fStubCRC32; diff --git a/dev/kernel/StorageKit/AHCI.h b/dev/kernel/StorageKit/AHCI.h index 3605abe6..d4f7cc55 100644 --- a/dev/kernel/StorageKit/AHCI.h +++ b/dev/kernel/StorageKit/AHCI.h @@ -14,10 +14,10 @@ namespace Kernel { /// @brief AHCIDeviceInterface class /// @details This class is used to send and receive data from the AHCI device. /// @note The class is derived from the DeviceInterface class. -class AHCIDeviceInterface NE_DEVICE { +class AHCIDeviceInterface NE_DEVICE { public: - explicit AHCIDeviceInterface(void (*out)(DeviceInterface* self, MountpointInterface* out), - void (*in)(DeviceInterface* self, MountpointInterface* in)); + explicit AHCIDeviceInterface(void (*out)(DeviceInterface* self, IMountpoint* out), + void (*in)(DeviceInterface* self, IMountpoint* in)); virtual ~AHCIDeviceInterface() override; @@ -36,8 +36,8 @@ class AHCIDeviceInterface NE_DEVICE { Void SetIndex(const UInt32& drv); public: - AHCIDeviceInterface& operator<<(MountpointInterface* Data) override; - AHCIDeviceInterface& operator>>(MountpointInterface* Data) override; + AHCIDeviceInterface& operator<<(IMountpoint* Data) override; + AHCIDeviceInterface& operator>>(IMountpoint* Data) override; private: UInt16 fPortsImplemented{0U}; diff --git a/dev/kernel/StorageKit/ATA.h b/dev/kernel/StorageKit/ATA.h index d4c894a3..49ab3e4e 100644 --- a/dev/kernel/StorageKit/ATA.h +++ b/dev/kernel/StorageKit/ATA.h @@ -13,16 +13,16 @@ namespace Kernel { /// @brief ATA device interface class. -class ATADeviceInterface : public DeviceInterface { +class ATADeviceInterface : public DeviceInterface { public: - explicit ATADeviceInterface(void (*Out)(DeviceInterface*, MountpointInterface* outpacket), - void (*In)(DeviceInterface*, MountpointInterface* inpacket)); + explicit ATADeviceInterface(void (*Out)(DeviceInterface*, IMountpoint* outpacket), + void (*In)(DeviceInterface*, IMountpoint* inpacket)); virtual ~ATADeviceInterface(); public: - ATADeviceInterface& operator<<(MountpointInterface* Data) override; - ATADeviceInterface& operator>>(MountpointInterface* Data) override; + ATADeviceInterface& operator<<(IMountpoint* Data) override; + ATADeviceInterface& operator>>(IMountpoint* Data) override; public: ATADeviceInterface& operator=(const ATADeviceInterface&) = default; diff --git a/dev/kernel/StorageKit/NVME.h b/dev/kernel/StorageKit/NVME.h index 1b2b6358..9852c5eb 100644 --- a/dev/kernel/StorageKit/NVME.h +++ b/dev/kernel/StorageKit/NVME.h @@ -10,10 +10,10 @@ #include namespace Kernel { -class NVMEDeviceInterface final NE_DEVICE { +class NVMEDeviceInterface final NE_DEVICE { public: - explicit NVMEDeviceInterface(Void (*out)(DeviceInterface*, MountpointInterface* out_packet), - Void (*in)(DeviceInterface*, MountpointInterface* in_packet), + explicit NVMEDeviceInterface(Void (*out)(DeviceInterface*, IMountpoint* out_packet), + Void (*in)(DeviceInterface*, IMountpoint* in_packet), Void (*cleanup)(Void)); ~NVMEDeviceInterface() override; @@ -24,7 +24,7 @@ class NVMEDeviceInterface final NE_DEVICE { const Char* Name() const override; public: - OwnPtr operator()(UInt32 dma_low, UInt32 dma_high, SizeT dma_sz); + OwnPtr operator()(UInt32 dma_low, UInt32 dma_high, SizeT dma_sz); private: Void (*fCleanup)(Void) = {nullptr}; diff --git a/dev/kernel/src/FS/HeFS+FileMgr.cc b/dev/kernel/src/FS/HeFS+FileMgr.cc deleted file mode 100644 index 33813f65..00000000 --- a/dev/kernel/src/FS/HeFS+FileMgr.cc +++ /dev/null @@ -1,191 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#ifndef __NE_MINIMAL_OS__ -#ifdef __FSKIT_INCLUDES_HEFS__ - -#include -#include - -/// @brief HeFS File System Manager. -/// BUGS: 0 - -namespace Kernel { -/// @brief C++ constructor -HeFileSystemMgr::HeFileSystemMgr() { - mParser = new HeFileSystemParser(); - MUST_PASS(mParser); - - kout << "We are done allocating HeFileSystemParser...\n"; -} - -HeFileSystemMgr::~HeFileSystemMgr() { - if (mParser) { - kout << "Destroying HeFileSystemParser...\n"; - delete mParser; - mParser = nullptr; - } -} - -/// @brief Removes a node from the filesystem. -/// @param path The filename -/// @return If it was deleted or not. -bool HeFileSystemMgr::Remove(_Input const Char* path) { - if (path == nullptr || *path == 0) { - kout << "HeFS: Remove called with null or empty path\n"; - return false; - } - - return NO; -} - -/// @brief Creates a node with the specified. -/// @param path The filename path. -/// @return The Node pointer. -NodePtr HeFileSystemMgr::Create(_Input const Char* path) { - if (!path || *path == 0) { - kout << "HeFS: Create called with null or empty path\n"; - return nullptr; - } - return nullptr; -} - -/// @brief Creates a node which is a directory. -/// @param path The filename path. -/// @return The Node pointer. -NodePtr HeFileSystemMgr::CreateDirectory(const Char* path) { - if (!path || *path == 0) { - kout << "HeFS: CreateDirectory called with null or empty path\n"; - return nullptr; - } - return nullptr; -} - -/// @brief Creates a node which is an alias. -/// @param path The filename path. -/// @return The Node pointer. -NodePtr HeFileSystemMgr::CreateAlias(const Char* path) { - if (!path || *path == 0) { - kout << "HeFS: CreateAlias called with null or empty path\n"; - return nullptr; - } - return nullptr; -} - -NodePtr HeFileSystemMgr::CreateSwapFile(const Char* path) { - if (!path || *path == 0) { - kout << "HeFS: CreateSwapFile called with null or empty path\n"; - return nullptr; - } - return nullptr; -} - -/// @brief Gets the root directory. -/// @return -const Char* NeFileSystemHelper::Root() { - return kHeFSRootDirectory; -} - -/// @brief Gets the up-dir directory. -/// @return -const Char* NeFileSystemHelper::UpDir() { - return kHeFSUpDir; -} - -/// @brief Gets the separator character. -/// @return -Char NeFileSystemHelper::Separator() { - return kHeFSSeparator; -} - -/// @brief Gets the metafile character. -/// @return -Char NeFileSystemHelper::MetaFile() { - return 0; -} - -/// @brief Opens a new file. -/// @param path -/// @param r -/// @return -_Output NodePtr HeFileSystemMgr::Open(_Input const Char* path, _Input const Char* r) { - if (!path || *path == 0) { - kout << "HeFS: Open called with null or empty path\n"; - return nullptr; - } - if (!r || *r == 0) { - kout << "HeFS: Open called with null or empty mode string\n"; - return nullptr; - } - return nullptr; -} - -Void HeFileSystemMgr::Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, - _Input SizeT size) { - NE_UNUSED(node); - NE_UNUSED(flags); - NE_UNUSED(size); - NE_UNUSED(data); -} - -_Output VoidPtr HeFileSystemMgr::Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT size) { - NE_UNUSED(node); - NE_UNUSED(flags); - NE_UNUSED(size); - - return nullptr; -} - -Void HeFileSystemMgr::Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, - _Input Int32 flags, _Input SizeT size) { - NE_UNUSED(node); - NE_UNUSED(flags); - NE_UNUSED(size); - NE_UNUSED(name); - NE_UNUSED(data); -} - -_Output VoidPtr HeFileSystemMgr::Read(_Input const Char* name, _Input NodePtr node, - _Input Int32 flags, _Input SizeT sz) { - NE_UNUSED(node); - NE_UNUSED(flags); - NE_UNUSED(sz); - NE_UNUSED(name); - - return nullptr; -} - -_Output Bool HeFileSystemMgr::Seek(NodePtr node, SizeT off) { - NE_UNUSED(node); - NE_UNUSED(off); - - return false; -} - -/// @brief Tell current offset within catalog. -/// @param node -/// @return kFileMgrNPos if invalid, else current offset. -_Output SizeT HeFileSystemMgr::Tell(NodePtr node) { - NE_UNUSED(node); - return kFileMgrNPos; -} - -/// @brief Rewinds the catalog -/// @param node -/// @return False if invalid, nah? calls Seek(node, 0). -_Output Bool HeFileSystemMgr::Rewind(NodePtr node) { - NE_UNUSED(node); - return kFileMgrNPos; -} - -/// @brief Returns the parser of HeFS. -_Output HeFileSystemParser* HeFileSystemMgr::GetParser() noexcept { - return mParser; -} -} // namespace Kernel - -#endif // ifdef __FSKIT_INCLUDES_HEFS__ -#endif // ifndef __NE_MINIMAL_OS__ diff --git a/dev/kernel/src/FS/HeFS+FileSystemParser.cc b/dev/kernel/src/FS/HeFS+FileSystemParser.cc deleted file mode 100644 index 029fdf26..00000000 --- a/dev/kernel/src/FS/HeFS+FileSystemParser.cc +++ /dev/null @@ -1,1166 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#ifdef __FSKIT_INCLUDES_HEFS__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Kernel { -namespace Detail { - /// @brief Forward declarations of internal functions. - - /***********************************************************************************/ - /// @brief Traverse the RB-Tree of the filesystem. - /// @param dir The directory to traverse. - /// @param start The starting point of the traversal. - /// @note This function is used to traverse the RB-Tree of the filesystem. - /// @internal Internal filesystem use only. - /***********************************************************************************/ - STATIC ATTRIBUTE(unused) _Output Void - hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, DriveTrait* mnt, const Lba& start_ind, - Lba& start); - - /***********************************************************************************/ - /// @brief Get the index node of a file or directory. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read from. - /// @param dir_name The name of the directory. - /// @param file_name The name of the file. - /// @param kind The kind of the file (regular, directory, block, character, FIFO, socket, symbolic - /// link, unknown). - /***********************************************************************************/ - STATIC ATTRIBUTE(unused) _Output HEFS_INDEX_NODE* hefsi_fetch_in(HEFS_BOOT_NODE* boot, - DriveTrait* mnt, - const Utf8Char* dir_name, - const Utf8Char* file_name, - UInt8 kind); - - /***********************************************************************************/ - /// @brief Allocate a new index node-> - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read/write from. - /// @param dir_name The name of the parent directory. - /// @return Status, see err_global_get(). - /***********************************************************************************/ - STATIC ATTRIBUTE(unused) _Output BOOL - hefsi_update_in_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, const Utf8Char* dir_name, - HEFS_INDEX_NODE* node, const BOOL create_or_delete); - - /***********************************************************************************/ - /// @brief Balance RB-Tree of the filesystem. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read/write from. - /// @return Status, see err_global_get(). - /***********************************************************************************/ - STATIC ATTRIBUTE(unused) _Output BOOL hefsi_balance_ind(HEFS_BOOT_NODE* boot, DriveTrait* mnt); - - /// @brief Alllocate IND from boot node. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read from. - /// @param dir_name The name of the directory. - /// @param dir_name The parent of the directory. - /// @param flags Directory flags. - /// @param delete_or_create Delete or create directory. - STATIC _Output BOOL hefsi_update_ind_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, - const Utf8Char* dir_name, UInt16 flags, - const BOOL delete_or_create); - - /// @brief This helper makes it easier for other machines to understand HeFS encoded hashes. - STATIC UInt64 hefsi_to_big_endian_64(UInt64 val) { - return ((val >> 56) & 0x00000000000000FFULL) | ((val >> 40) & 0x000000000000FF00ULL) | - ((val >> 24) & 0x0000000000FF0000ULL) | ((val >> 8) & 0x00000000FF000000ULL) | - ((val << 8) & 0x000000FF00000000ULL) | ((val << 24) & 0x0000FF0000000000ULL) | - ((val << 40) & 0x00FF000000000000ULL) | ((val << 56) & 0xFF00000000000000ULL); - } - - /// @brief Simple algorithm to hash directory entries for INDs. - /// @param path the directory path. - /// @return The hashed path. - template - STATIC UInt64 hefsi_hash_64(const CharT* path) { - if (!path || *path == 0) return 0; - - const UInt64 kFnvBaseOffset = 0xcbf29ce484222325ULL; - const UInt64 kFnvPrimeNumber = 0x100000001b3ULL; - - UInt64 hash = kFnvBaseOffset; - - while (*path) { - hash ^= (CharT) (*path++); - hash *= kFnvPrimeNumber; - } - - return hefsi_to_big_endian_64(hash); - } - - /// @brief Traverse the RB-Tree of the filesystem. - /// @param dir The directory to traverse. - /// @param start The starting point of the traversal. - /// @note This function is used to traverse the RB-Tree of the filesystem. - /// @internal Internal filesystem use only. - STATIC ATTRIBUTE(unused) Void hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, DriveTrait* mnt, - const Lba& ind_start, Lba& start) { - if (!mnt || !dir) return; - - BOOL check_is_good = NO; - HEFS_INDEX_NODE_DIRECTORY* dir_tmp = new HEFS_INDEX_NODE_DIRECTORY(); - - while (YES) { - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir_tmp; - mnt->fInput(mnt->fPacket); - - if (!mnt->fPacket.fPacketGood) break; - - if (dir_tmp->fNext != 0) { - if (check_is_good) break; - - start = dir_tmp->fNext; - - check_is_good = YES; - continue; - } else if (dir_tmp->fPrev != 0) { - if (check_is_good) break; - - start = dir_tmp->fPrev; - check_is_good = YES; - continue; - } else { - if (dir_tmp->fParent != 0) { - if (check_is_good) break; - - start = dir_tmp->fParent; - check_is_good = YES; - continue; - } else if (dir_tmp->fPrev != 0) { - if (check_is_good) break; - - start = dir_tmp->fPrev; - check_is_good = YES; - continue; - } else { - if (start == 0) { - start = ind_start; - continue; - } - - start += sizeof(HEFS_INDEX_NODE_DIRECTORY); - break; - } - } - } - - delete dir_tmp; - - start += sizeof(HEFS_INDEX_NODE_DIRECTORY); - if (start == 0) start = ind_start; - } - - /***********************************************************************************/ - /// @brief Rotate the RB-Tree to the left or right. - /// @internal - /***********************************************************************************/ - STATIC ATTRIBUTE(unused) _Output Void hefsi_rotate_tree(Lba& start, DriveTrait* mnt) { - if (!start || !mnt) return; - - HEFS_INDEX_NODE_DIRECTORY* cur = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = cur; - - mnt->fInput(mnt->fPacket); - - if (cur->fHashPath == 0) return; - - HEFS_INDEX_NODE_DIRECTORY* sibling = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = cur->fPrev; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = sibling; - - mnt->fInput(mnt->fPacket); - - if (sibling->fHashPath == 0) return; - - auto child_sibling = sibling->fChild; - auto child_cur = cur->fChild; - - cur->fChild = child_sibling; - sibling->fChild = child_cur; - - sibling->fChecksum = ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - cur->fChecksum = ke_calculate_crc32((Char*) cur, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = cur->fParent; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = sibling; - - mnt->fOutput(mnt->fPacket); - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = cur; - - mnt->fOutput(mnt->fPacket); - - HEFS_INDEX_NODE_DIRECTORY* sibling_child = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = child_sibling; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = sibling_child; - - mnt->fInput(mnt->fPacket); - - sibling_child->fParent = cur->fParent; - - sibling_child->fChecksum = - ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fOutput(mnt->fPacket); - - HEFS_INDEX_NODE_DIRECTORY* cur_child = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = child_cur; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = cur_child; - - mnt->fInput(mnt->fPacket); - - cur_child->fParent = start; - - cur_child->fChecksum = ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fOutput(mnt->fPacket); - - kout << "RB-Tree has been rotated.\r"; - } - - /// @brief Alllocate IND from boot node. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read from. - /// @param dir_name The name of the directory. - /// @param dir_name The parent of the directory. - /// @param flags Directory flags. - /// @param delete_or_create Delete or create directory. - STATIC _Output BOOL hefsi_update_ind_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, - const Utf8Char* dir_name, UInt16 flags, - const BOOL delete_or_create) { - if (mnt) { - HEFS_INDEX_NODE_DIRECTORY* tmpdir = - (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); - - auto start = boot->fStartIND; - auto prev_location = start; - auto parent_location = 0UL; - - MUST_PASS(boot->fStartIND > mnt->fLbaStart); - - while (YES) { - auto prev_start = start; - - if (start) - mnt->fPacket.fPacketLba = start; - else - mnt->fPacket.fPacketLba = prev_location + sizeof(HEFS_INDEX_NODE_DIRECTORY); - - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = tmpdir; - - mnt->fInput(mnt->fPacket); - - BOOL expr = NO; - - if (!delete_or_create) { - expr = (!tmpdir->fCreated && tmpdir->fDeleted) || tmpdir->fHashPath == 0; - } else { - expr = - tmpdir->fCreated && !tmpdir->fDeleted && hefsi_hash_64(dir_name) == tmpdir->fHashPath; - } - - if (expr) { - HEFS_INDEX_NODE_DIRECTORY* dirent = - (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); - - rt_set_memory(dirent, 0, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - dirent->fHashPath = delete_or_create ? 0UL : hefsi_hash_64(dir_name); - dirent->fAccessed = 0UL; - dirent->fCreated = delete_or_create ? 0UL : 1UL; - dirent->fDeleted = delete_or_create ? 1UL : 0UL; - dirent->fModified = 0UL; - dirent->fEntryCount = 0UL; - - dirent->fReserved = 0; - dirent->fFlags = flags; - dirent->fChecksum = 0; - - dirent->fEntryCount = 0; - - if (parent_location) { - HEFS_INDEX_NODE_DIRECTORY* tmpend = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = parent_location; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = tmpend; - - mnt->fInput(mnt->fPacket); - - if (tmpend->fChecksum != - ke_calculate_crc32((Char*) tmpend, sizeof(HEFS_INDEX_NODE_DIRECTORY))) - ke_panic(RUNTIME_CHECK_FILESYSTEM, "Bad CRC32 value, aborting."); - - if (delete_or_create) - --tmpend->fEntryCount; - else - ++tmpend->fEntryCount; - - tmpend->fChecksum = - ke_calculate_crc32((Char*) tmpend, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fOutput(mnt->fPacket); - - auto child_first = tmpend->fChild; - - while (YES) { - mnt->fPacket.fPacketLba = child_first; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = tmpend; - - mnt->fInput(mnt->fPacket); - - if ((!tmpend->fCreated && tmpend->fDeleted) || tmpend->fHashPath == 0) { - start = child_first; - break; - } - - hefsi_traverse_tree(tmpend, mnt, boot->fStartIND, child_first); - } - } - - dirent->fNext = tmpdir->fNext; - dirent->fPrev = tmpdir->fPrev; - dirent->fParent = tmpdir->fParent; - dirent->fChild = tmpdir->fChild; - dirent->fColor = tmpdir->fColor; - - if (dirent->fColor == 0) { - dirent->fColor = dirent->fNext ? kHeFSRed : kHeFSBlack; - } - - if (dirent->fPrev == 0) { - dirent->fPrev = boot->fStartIND; - } - - if (dirent->fParent == 0) { - dirent->fParent = boot->fStartIND; - } - - if (tmpdir->fChild == 0) { - auto child = dirent->fNext + sizeof(HEFS_INDEX_NODE_DIRECTORY); - - HEFS_INDEX_NODE_DIRECTORY* tmpend = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - while (YES) { - mnt->fPacket.fPacketLba = child; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = tmpend; - - mnt->fInput(mnt->fPacket); - - if ((!tmpend->fCreated && tmpend->fDeleted) || tmpdir->fHashPath == 0) { - break; - } - - child += sizeof(HEFS_INDEX_NODE_DIRECTORY); - if (child > boot->fEndIND) break; - } - - dirent->fColor = kHeFSRed; - dirent->fChild = child; - - if (child > boot->fEndIND) dirent->fChild = boot->fStartIND; - } - - for (SizeT index = 0UL; index < kHeFSSliceCount; ++index) { - dirent->fINSlices[index] = 0UL; - } - - dirent->fChecksum = ke_calculate_crc32((Char*) dirent, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = prev_start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dirent; - - mnt->fOutput(mnt->fPacket); - - err_global_get() = kErrorSuccess; - - mm_free_ptr(dirent); - mm_free_ptr(tmpdir); - - if (!delete_or_create) - ++boot->fINDCount; - else - --boot->fINDCount; - - boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fOutput(mnt->fPacket); - - return YES; - } - - prev_location = start; - - hefsi_traverse_tree(tmpdir, mnt, boot->fStartIND, start); - if (start > boot->fEndIND || start == 0) break; - } - - err_global_get() = kErrorDisk; - mm_free_ptr(tmpdir); - - return NO; - } - - err_global_get() = kErrorDiskIsFull; - return NO; - } - - /// @brief Get the index node of a file or directory. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read from. - /// @param dir_name The name of the directory. - /// @param file_name The name of the file. - /// @param kind The kind of the file (regular, directory, block, character, FIFO, socket, symbolic - /// link, unknown). - STATIC ATTRIBUTE(unused) _Output HEFS_INDEX_NODE* hefsi_fetch_in(HEFS_BOOT_NODE* boot, - DriveTrait* mnt, - const Utf8Char* dir_name, - const Utf8Char* file_name, - UInt8 kind) { - if (mnt) { - if (boot->fStartIND > boot->fEndIND) return nullptr; - if (boot->fStartIN > boot->fEndIN) return nullptr; - - auto start = boot->fStartIND; - HEFS_INDEX_NODE* node = new HEFS_INDEX_NODE(); - - HEFS_INDEX_NODE_DIRECTORY* dir = - (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); - - while (YES) { - if (err_global_get() == kErrorDiskIsCorrupted) { - delete dir; - dir = nullptr; - - delete node; - node = nullptr; - - return nullptr; - } - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fInput(mnt->fPacket); - - (Void)(kout << hex_number(hefsi_hash_64(dir_name)) << kendl); - (Void)(kout << hex_number(dir->fHashPath) << kendl); - - if (dir->fHashPath == 0) break; - - if (hefsi_hash_64(dir_name) == dir->fHashPath) { - for (SizeT inode_index = 0UL; inode_index < kHeFSSliceCount; ++inode_index) { - mnt->fPacket.fPacketLba = dir->fINSlices[inode_index]; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); - mnt->fPacket.fPacketContent = node; - - mnt->fInput(mnt->fPacket); - - (Void)(kout << hex_number(hefsi_hash_64(file_name)) << kendl); - (Void)(kout << hex_number(node->fHashPath) << kendl); - - if (hefsi_hash_64(file_name) == node->fHashPath && node->fKind == kind) { - delete dir; - dir = nullptr; - - return node; - } - } - } - - hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); - if (start == boot->fStartIND || start == boot->fStartIND) break; - } - - delete node; - node = nullptr; - - delete dir; - dir = nullptr; - } - - kout << "Error: Failed to find IN.\r"; - - err_global_get() = kErrorFileNotFound; - - return nullptr; - } - - STATIC ATTRIBUTE(unused) _Output BOOL - hefsi_update_in_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, const Utf8Char* dir_name, - HEFS_INDEX_NODE* node, BOOL delete_or_create) { - if (!boot || !mnt) return NO; - - auto start = boot->fStartIND; - - if (start > boot->fEndIND) return NO; - if (boot->fStartIN > boot->fEndIN) return NO; - ; - if (boot->fStartBlock > boot->fEndBlock) return NO; - - if (mnt) { - HEFS_INDEX_NODE_DIRECTORY* dir = - (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); - - auto hash_file = node->fHashPath; - - while (YES) { - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fInput(mnt->fPacket); - - (Void)(kout << hex_number(hefsi_hash_64(dir_name)) << kendl); - (Void)(kout << hex_number(dir->fHashPath) << kendl); - - if (hefsi_hash_64(dir_name) == dir->fHashPath) { - for (SizeT inode_index = 0UL; inode_index < kHeFSSliceCount; ++inode_index) { - if (dir->fINSlices[inode_index] == 0 && !delete_or_create) { - dir->fINSlices[inode_index] = boot->fStartIN; - - ++dir->fEntryCount; - - dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fOutput(mnt->fPacket); - - auto lba = dir->fINSlices[inode_index]; - - node->fOffsetSliceLow = (UInt32) (boot->fStartBlock); - node->fOffsetSliceHigh = (UInt32) (boot->fStartBlock >> 32); - - node->fChecksum = ke_calculate_crc32((Char*) node, sizeof(HEFS_INDEX_NODE)); - - mnt->fPacket.fPacketLba = lba; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); - mnt->fPacket.fPacketContent = node; - - mnt->fOutput(mnt->fPacket); - - boot->fStartIN += sizeof(HEFS_INDEX_NODE); - boot->fStartBlock += kHeFSBlockLen; - - boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fOutput(mnt->fPacket); - - mm_free_ptr(dir); - - return YES; - } else if (dir->fINSlices[inode_index] != 0 && delete_or_create) { - auto lba = dir->fINSlices[inode_index]; - - HEFS_INDEX_NODE tmp_node{}; - - mnt->fPacket.fPacketLba = lba; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); - mnt->fPacket.fPacketContent = &tmp_node; - - mnt->fInput(mnt->fPacket); - - if (tmp_node.fHashPath != hash_file) { - continue; - } - - node->fOffsetSliceLow = 0; - node->fOffsetSliceHigh = 0; - - boot->fStartIN -= sizeof(HEFS_INDEX_NODE); - boot->fStartBlock -= kHeFSBlockLen; - - boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fOutput(mnt->fPacket); - - mnt->fPacket.fPacketLba = lba; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); - mnt->fPacket.fPacketContent = node; - - mnt->fOutput(mnt->fPacket); - - dir->fINSlices[inode_index] = 0; - - if (dir->fEntryCount) --dir->fEntryCount; - - dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fOutput(mnt->fPacket); - - mm_free_ptr(dir); - - return YES; - } - } - } - - hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); - if (start > boot->fEndIND || start == 0) break; - } - - mm_free_ptr(dir); - err_global_get() = kErrorFileNotFound; - return NO; - } - - err_global_get() = kErrorDiskIsFull; - return NO; - } - - /// @brief Balance RB-Tree of the filesystem. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read/write from. - /// @return Status, see err_global_get(). - STATIC ATTRIBUTE(unused) _Output BOOL hefsi_balance_ind(HEFS_BOOT_NODE* boot, DriveTrait* mnt) { - if (mnt) { - HEFS_INDEX_NODE_DIRECTORY* dir = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - auto start = boot->fStartIND; - - while (YES) { - if (start == 0UL || start > boot->fEndIND) break; - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fInput(mnt->fPacket); - - if (!mnt->fPacket.fPacketGood) { - err_global_get() = kErrorDiskIsCorrupted; - - return NO; - } - - if (start == boot->fStartIND) { - dir->fColor = kHeFSBlack; - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fOutput(mnt->fPacket); - } - - if (dir->fColor == kHeFSBlack && dir->fChild != 0UL) { - dir->fColor = kHeFSRed; - hefsi_rotate_tree(start, mnt); - } else if (dir->fColor == kHeFSBlack && dir->fChild == 0UL) { - dir->fColor = kHeFSBlack; - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fOutput(mnt->fPacket); - } - - if (ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)) != dir->fChecksum) { - dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fOutput(mnt->fPacket); - } - - hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); - } - - err_global_get() = kErrorSuccess; - return YES; - } - - err_global_get() = kErrorDisk; - return NO; - } -} // namespace Detail -} // namespace Kernel - -/// @note HeFS will allocate inodes and ind in advance, to avoid having to allocate them in -/// real-time. -/// @note This is certainly take longer to format a disk with it, but worth-it in the long run. - -namespace Kernel { -/// @brief Make a EPM+HeFS mnt out of the disk. -/// @param mnt The mnt to write on. -/// @return If it was sucessful, see err_local_get(). -_Output Bool HeFileSystemParser::Format(_Input _Output DriveTrait* mnt, _Input const Int32 flags, - _Input const Utf8Char* vol_name) { - // Verify Disk. - mnt->fVerify(mnt->fPacket); - - // if disk isn't good, then error out. - if (false == mnt->fPacket.fPacketGood) { - err_global_get() = kErrorDiskIsCorrupted; - return false; - } - - if (drv_std_get_size() < kHeFSMinimumDiskSize) { - (Void)(kout << "OpenHeFS recommends at least 128 GiB of free space." << kendl); - (Void)( - kout - << "The OS will still try to format a HeFS disk here anyway, don't expect perfect geometry." - << kendl); - } - - HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) RTL_ALLOCA(sizeof(HEFS_BOOT_NODE)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fInput(mnt->fPacket); - - if (!mnt->fPacket.fPacketGood) { - err_global_get() = kErrorDiskIsCorrupted; - - return NO; - } - - // Check if the disk is already formatted. - - if (KStringBuilder::Equals(boot->fMagic, kHeFSMagic) && boot->fVersion == kHeFSVersion) { - if (ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)) != boot->fChecksum && - boot->fChecksum > 0) { - err_global_get() = kErrorDiskIsCorrupted; - return NO; - } - - err_global_get() = kErrorSuccess; - return YES; - } - - if (ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)) != boot->fChecksum && - boot->fChecksum > 0) { - err_global_get() = kErrorDiskIsCorrupted; - return NO; - } - - rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, - rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); - - urt_copy_memory((VoidPtr) vol_name, boot->fVolName, urt_string_len(vol_name) + 1); - rt_copy_memory_safe((VoidPtr) kHeFSMagic, boot->fMagic, kHeFSMagicLen - 1, sizeof(boot->fMagic)); - - if (mnt->fLbaStart > mnt->fLbaEnd) { - err_global_get() = kErrorDiskIsCorrupted; - - return NO; - } - - boot->fBadSectors = 0; - - boot->fSectorCount = drv_std_get_sector_count(); - boot->fSectorSize = mnt->fSectorSz; - - MUST_PASS(boot->fSectorSize); - - /// @note all HeFS strucutres are equal to 512, so here it's fine, unless fSectoSize is 2048. - const SizeT max_lba = (drv_std_get_size()) / boot->fSectorSize; - - const SizeT dir_max = max_lba / 300; // 5% for directory inodes - const SizeT inode_max = max_lba / 400; // 5% for inodes - - boot->fStartIND = mnt->fLbaStart + kHeFSINDStartOffset; - boot->fEndIND = boot->fStartIND + dir_max; - - boot->fStartIN = boot->fEndIND; - boot->fEndIN = boot->fStartIN + inode_max; - - boot->fStartBlock = boot->fEndIN; - boot->fEndBlock = drv_std_get_size(); - - boot->fINDCount = 0; - - boot->fDiskSize = drv_std_get_size(); - boot->fDiskStatus = kHeFSStatusUnlocked; - - boot->fDiskFlags = flags; - - if (mnt->fKind & kMassStorageDrive) { - boot->fDiskKind = kHeFSMassStorageDevice; - } else if (mnt->fKind & kHeFSOpticalDrive) { - boot->fDiskKind = kHeFSOpticalDrive; - } else { - boot->fDiskKind = kHeFSUnknown; - } - - boot->fVersion = kHeFSVersion; - - boot->fVID = kHeFSInvalidVID; - - boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fOutput(mnt->fPacket); - - (Void)(kout << "Protocol: " << mnt->fProtocol() << kendl); - (Void)(kout8 << u8"Volume Name: " << boot->fVolName << kendl8); - (Void)(kout << "Start IND: " << hex_number(boot->fStartIND) << kendl); - (Void)(kout << "End IND: " << hex_number(boot->fEndIND) << kendl); - (Void)(kout << "Start IN: " << hex_number(boot->fStartIN) << kendl); - (Void)(kout << "End IN: " << hex_number(boot->fEndIN) << kendl); - (Void)(kout << "Start Block: " << hex_number(boot->fStartBlock) << kendl); - (Void)(kout << "End Block: " << hex_number(boot->fEndBlock) << kendl); - (Void)(kout << "Number of IND: " << hex_number(boot->fINDCount) << kendl); - (Void)(kout << "Sector Size: " << hex_number(boot->fSectorSize) << kendl); - (Void)(kout << "Drive Kind: " << Detail::hefs_drive_kind_to_string(boot->fDiskKind) << kendl); - - if (!mnt->fPacket.fPacketGood) { - err_global_get() = kErrorDiskIsCorrupted; - return NO; - } - - constexpr const SizeT kHeFSPreallocateCount = 0x6UL; - - const Utf8Char* kFileMap[kHeFSPreallocateCount] = {u8"/", u8"/boot", u8"/system", - u8"/network", u8"/devices", u8"/media"}; - - for (SizeT i = 0; i < kHeFSPreallocateCount; ++i) { - this->CreateINodeDirectory(mnt, kHeFSEncodingFlagsUTF8, kFileMap[i]); - } - - err_global_get() = kErrorSuccess; - - return YES; -} - -/// @brief Create a new directory on the disk. -/// @param mnt The mnt to write on. -/// @param flags The flags to use. -/// @param dir The directory to create the file in. -/// @return If it was sucessful, see err_local_get(). -_Output Bool HeFileSystemParser::INodeDirectoryCtlManip(_Input DriveTrait* mnt, - _Input const Int32 flags, - const Utf8Char* dir, - const BOOL delete_or_create) { - if (urt_string_len(dir) > kHeFSFileNameLen) { - err_global_get() = kErrorDisk; - return NO; - } - - HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) mm_alloc_ptr(sizeof(HEFS_BOOT_NODE), Yes, No); - - rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, - rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fInput(mnt->fPacket); - - if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { - err_global_get() = kErrorDisk; - return YES; - } - - if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { - err_global_get() = kErrorDiskIsCorrupted; - - kout << "Invalid Boot Node, this can't continue!\r"; - - return NO; - } - - if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { - kout << "Error: Invalid directory name.\r"; - - err_global_get() = kErrorInvalidData; - - return NO; - } - - if (Detail::hefsi_update_ind_status(boot, mnt, dir, flags, delete_or_create)) { - // todo: make it smarter for high-throughput. - Detail::hefsi_balance_ind(boot, mnt); - - mm_free_ptr((VoidPtr) boot); - return YES; - } - - mm_free_ptr((VoidPtr) boot); - return NO; -} - -_Output Bool HeFileSystemParser::RemoveINodeDirectory(_Input DriveTrait* mnt, - _Input const Int32 flags, - const Utf8Char* dir) { - return this->INodeDirectoryCtlManip(mnt, flags, dir, YES); -} - -_Output Bool HeFileSystemParser::CreateINodeDirectory(_Input DriveTrait* mnt, - _Input const Int32 flags, - const Utf8Char* dir) { - return this->INodeDirectoryCtlManip(mnt, flags, dir, NO); -} - -_Output Bool HeFileSystemParser::DeleteINode(_Input DriveTrait* mnt, _Input const Int32 flags, - const Utf8Char* dir, const Utf8Char* name, - const UInt8 kind) { - return this->INodeCtlManip(mnt, flags, dir, name, YES, kind); -} - -_Output Bool HeFileSystemParser::CreateINode(_Input DriveTrait* mnt, _Input const Int32 flags, - const Utf8Char* dir, const Utf8Char* name, - const UInt8 kind) { - return this->INodeCtlManip(mnt, flags, dir, name, NO, kind); -} - -_Output Bool HeFileSystemParser::INodeManip(_Input DriveTrait* mnt, VoidPtr block, SizeT block_sz, - const Utf8Char* dir, const Utf8Char* name, - const UInt8 kind, const BOOL is_input) { - if (urt_string_len(dir) > kHeFSFileNameLen) { - err_global_get() = kErrorDisk; - return NO; - } - - if (urt_string_len(name) > kHeFSFileNameLen) { - err_global_get() = kErrorDisk; - return NO; - } - - HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) mm_alloc_ptr(sizeof(HEFS_BOOT_NODE), Yes, No); - - if (!boot) { - err_global_get() = kErrorInvalidData; - return NO; - } - - rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, - rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fInput(mnt->fPacket); - - if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { - (Void)(kout << "Invalid Boot Node, HeFS partition is invalid." << kendl); - mm_free_ptr((VoidPtr) boot); - err_global_get() = kErrorDisk; - return NO; - } - - auto start = Detail::hefsi_fetch_in(boot, mnt, dir, name, kind); - - if (start) { - (Void)(kout << hex_number(start->fHashPath) << kendl); - (Void)(kout << hex_number(start->fOffsetSliceLow) << kendl); - - if (start->fOffsetSliceLow && start->fHashPath) { - mnt->fPacket.fPacketLba = ((UInt64) start->fOffsetSliceHigh << 32) | start->fOffsetSliceLow; - mnt->fPacket.fPacketSize = block_sz; - mnt->fPacket.fPacketContent = block; - - if (is_input) { - mnt->fInput(mnt->fPacket); - } else { - if (start->fFlags & kHeFSFlagsReadOnly) { - mm_free_ptr((VoidPtr) boot); - delete start; - - kout << "Error: File is read-only\r"; - - return NO; - } - - mnt->fOutput(mnt->fPacket); - } - } - } - - mm_free_ptr((VoidPtr) boot); - delete start; - return YES; -} - -/// @brief Create a new file on the disk. -/// @param mnt The mnt to write on. -/// @param flags The flags to use. -/// @param dir The directory to create the file in. -/// @param name The name of the file. -/// @return If it was sucessful, see err_local_get(). -_Output Bool HeFileSystemParser::INodeCtlManip(_Input DriveTrait* mnt, _Input const Int32 flags, - const Utf8Char* dir, const Utf8Char* name, - const BOOL delete_or_create, const UInt8 kind) { - if (urt_string_len(name) > kHeFSFileNameLen) { - err_global_get() = kErrorDisk; - return NO; - } - - if (urt_string_len(dir) > kHeFSFileNameLen) { - err_global_get() = kErrorDisk; - return NO; - } - - HEFS_INDEX_NODE* node = (HEFS_INDEX_NODE*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE), Yes, No); - - if (!node) { - err_global_get() = kErrorInvalidData; - return NO; - } - - rt_set_memory(node, 0, sizeof(HEFS_INDEX_NODE)); - - HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) RTL_ALLOCA(sizeof(HEFS_BOOT_NODE)); - - if (!boot) { - mm_free_ptr((VoidPtr) node); - err_global_get() = kErrorInvalidData; - - return NO; - } - - rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, - rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fInput(mnt->fPacket); - - if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { - err_global_get() = kErrorDisk; - return YES; - } - - if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { - kout << "Error: Invalid file name.\r"; - - err_global_get() = kErrorInvalidData; - return NO; - } - - for (SizeT i_name = 0UL; i_name < urt_string_len(name); ++i_name) { - if (name[i_name] == u'/') { - err_global_get() = kErrorInvalidData; - return NO; - } - } - - if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { - kout << "Error: Invalid directory name.\r"; - - err_global_get() = kErrorInvalidData; - return NO; - } - - node->fAccessed = 0; - node->fCreated = delete_or_create ? NO : YES; - node->fDeleted = delete_or_create ? 1UL : NO; - node->fModified = 0; - node->fSize = 0; - node->fKind = kind; - node->fFlags = flags; - node->fChecksum = 0; - node->fGID = 0; - node->fUID = 0; - node->fHashPath = Detail::hefsi_hash_64(name); - - if (Detail::hefsi_update_in_status(boot, mnt, dir, node, delete_or_create)) { - mm_free_ptr((VoidPtr) node); - - Detail::hefsi_balance_ind(boot, mnt); - - err_global_get() = kErrorSuccess; - return YES; - } - - mm_free_ptr((VoidPtr) node); - err_global_get() = kErrorDirectoryNotFound; - - return NO; -} - -STATIC DriveTrait kMountPoint; - -/// @brief Initialize the HeFS filesystem. -/// @return To check its status, see err_local_get(). -Boolean HeFS::fs_init_hefs(Void) noexcept { - kout << "Verifying disk...\r"; - - kMountPoint = io_construct_main_drive(); - - if (kMountPoint.fPacket.fPacketReadOnly == YES) - ke_panic(RUNTIME_CHECK_FILESYSTEM, "Main disk cannot be mounted (read-only media)."); - - HeFileSystemParser parser; - - return parser.Format(&kMountPoint, kHeFSEncodingFlagsUTF8, kHeFSDefaultVolumeName); -} -} // namespace Kernel - -#endif // ifdef __FSKIT_INCLUDES_HEFS__ diff --git a/dev/kernel/src/FS/NeFS+FileSystemParser.cc b/dev/kernel/src/FS/NeFS+FileSystemParser.cc index 14e0b974..b50841a4 100644 --- a/dev/kernel/src/FS/NeFS+FileSystemParser.cc +++ b/dev/kernel/src/FS/NeFS+FileSystemParser.cc @@ -74,7 +74,7 @@ static inline bool is_valid_lba(Lba lba, DriveTrait& drive) { return (lba >= part_block.StartCatalog) && (lba < maxLba); } -STATIC MountpointInterface kMountpoint; +STATIC IMountpoint kMountpoint; /***********************************************************************************/ /// @brief Creates a new fork inside the New filesystem partition. /// @param catalog it's catalog @@ -141,7 +141,7 @@ _Output BOOL NeFileSystemParser::CreateFork(_Input NEFS_FORK_STRUCT& the_fork) { drv.fPacket.fPacketContent = reinterpret_cast(&the_fork); drv.fOutput(drv.fPacket); - fs_ifs_write(&kMountpoint, drv, MountpointInterface::kDriveIndexA); + fs_ifs_write(&kMountpoint, drv, IMountpoint::kDriveIndexA); delete catalog; return YES; @@ -858,7 +858,7 @@ namespace Kernel::NeFS { /// @brief Construct NeFS drives. /***********************************************************************************/ Boolean fs_init_nefs(Void) noexcept { - kout << "Creating HeFS disk...\r"; + kout << "Creating OpenHeFS disk...\r"; kMountpoint.A() = io_construct_main_drive(); if (kMountpoint.A().fPacket.fPacketReadOnly == YES) ke_panic(RUNTIME_CHECK_FILESYSTEM, "Main disk cannot be mounted."); diff --git a/dev/kernel/src/FS/OpenHeFS+FileMgr.cc b/dev/kernel/src/FS/OpenHeFS+FileMgr.cc new file mode 100644 index 00000000..bb87fd67 --- /dev/null +++ b/dev/kernel/src/FS/OpenHeFS+FileMgr.cc @@ -0,0 +1,191 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef __NE_MINIMAL_OS__ +#ifdef __FSKIT_INCLUDES_HEFS__ + +#include +#include + +/// @brief OpenHeFS File System Manager. +/// BUGS: 0 + +namespace Kernel { +/// @brief C++ constructor +HeFileSystemMgr::HeFileSystemMgr() { + mParser = new HeFileSystemParser(); + MUST_PASS(mParser); + + kout << "We are done allocating HeFileSystemParser...\n"; +} + +HeFileSystemMgr::~HeFileSystemMgr() { + if (mParser) { + kout << "Destroying HeFileSystemParser...\n"; + delete mParser; + mParser = nullptr; + } +} + +/// @brief Removes a node from the filesystem. +/// @param path The filename +/// @return If it was deleted or not. +bool HeFileSystemMgr::Remove(_Input const Char* path) { + if (path == nullptr || *path == 0) { + kout << "OpenHeFS: Remove called with null or empty path\n"; + return false; + } + + return NO; +} + +/// @brief Creates a node with the specified. +/// @param path The filename path. +/// @return The Node pointer. +NodePtr HeFileSystemMgr::Create(_Input const Char* path) { + if (!path || *path == 0) { + kout << "OpenHeFS: Create called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +/// @brief Creates a node which is a directory. +/// @param path The filename path. +/// @return The Node pointer. +NodePtr HeFileSystemMgr::CreateDirectory(const Char* path) { + if (!path || *path == 0) { + kout << "OpenHeFS: CreateDirectory called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +/// @brief Creates a node which is an alias. +/// @param path The filename path. +/// @return The Node pointer. +NodePtr HeFileSystemMgr::CreateAlias(const Char* path) { + if (!path || *path == 0) { + kout << "OpenHeFS: CreateAlias called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +NodePtr HeFileSystemMgr::CreateSwapFile(const Char* path) { + if (!path || *path == 0) { + kout << "OpenHeFS: CreateSwapFile called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +/// @brief Gets the root directory. +/// @return +const Char* NeFileSystemHelper::Root() { + return kHeFSRootDirectory; +} + +/// @brief Gets the up-dir directory. +/// @return +const Char* NeFileSystemHelper::UpDir() { + return kHeFSUpDir; +} + +/// @brief Gets the separator character. +/// @return +Char NeFileSystemHelper::Separator() { + return kHeFSSeparator; +} + +/// @brief Gets the metafile character. +/// @return +Char NeFileSystemHelper::MetaFile() { + return '\0'; +} + +/// @brief Opens a new file. +/// @param path +/// @param r +/// @return +_Output NodePtr HeFileSystemMgr::Open(_Input const Char* path, _Input const Char* r) { + if (!path || *path == 0) { + kout << "OpenHeFS: Open called with null or empty path\n"; + return nullptr; + } + if (!r || *r == 0) { + kout << "OpenHeFS: Open called with null or empty mode string\n"; + return nullptr; + } + return nullptr; +} + +Void HeFileSystemMgr::Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, + _Input SizeT size) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(size); + NE_UNUSED(data); +} + +_Output VoidPtr HeFileSystemMgr::Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT size) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(size); + + return nullptr; +} + +Void HeFileSystemMgr::Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, + _Input Int32 flags, _Input SizeT size) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(size); + NE_UNUSED(name); + NE_UNUSED(data); +} + +_Output VoidPtr HeFileSystemMgr::Read(_Input const Char* name, _Input NodePtr node, + _Input Int32 flags, _Input SizeT sz) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(sz); + NE_UNUSED(name); + + return nullptr; +} + +_Output Bool HeFileSystemMgr::Seek(NodePtr node, SizeT off) { + NE_UNUSED(node); + NE_UNUSED(off); + + return false; +} + +/// @brief Tell current offset within catalog. +/// @param node +/// @return kFileMgrNPos if invalid, else current offset. +_Output SizeT HeFileSystemMgr::Tell(NodePtr node) { + NE_UNUSED(node); + return kFileMgrNPos; +} + +/// @brief Rewinds the catalog +/// @param node +/// @return False if invalid, nah? calls Seek(node, 0). +_Output Bool HeFileSystemMgr::Rewind(NodePtr node) { + NE_UNUSED(node); + return kFileMgrNPos; +} + +/// @brief Returns the parser of OpenHeFS. +_Output HeFileSystemParser* HeFileSystemMgr::GetParser() noexcept { + return mParser; +} +} // namespace Kernel + +#endif // ifdef __FSKIT_INCLUDES_HEFS__ +#endif // ifndef __NE_MINIMAL_OS__ diff --git a/dev/kernel/src/FS/OpenHeFS+FileSystemParser.cc b/dev/kernel/src/FS/OpenHeFS+FileSystemParser.cc new file mode 100644 index 00000000..3746ebc1 --- /dev/null +++ b/dev/kernel/src/FS/OpenHeFS+FileSystemParser.cc @@ -0,0 +1,1166 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __FSKIT_INCLUDES_HEFS__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { +namespace Detail { + /// @brief Forward declarations of internal functions. + + /***********************************************************************************/ + /// @brief Traverse the RB-Tree of the filesystem. + /// @param dir The directory to traverse. + /// @param start The starting point of the traversal. + /// @note This function is used to traverse the RB-Tree of the filesystem. + /// @internal Internal filesystem use only. + /***********************************************************************************/ + STATIC ATTRIBUTE(unused) _Output Void + hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, DriveTrait* mnt, const Lba& start_ind, + Lba& start); + + /***********************************************************************************/ + /// @brief Get the index node of a file or directory. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read from. + /// @param dir_name The name of the directory. + /// @param file_name The name of the file. + /// @param kind The kind of the file (regular, directory, block, character, FIFO, socket, symbolic + /// link, unknown). + /***********************************************************************************/ + STATIC ATTRIBUTE(unused) _Output HEFS_INDEX_NODE* hefsi_fetch_in(HEFS_BOOT_NODE* boot, + DriveTrait* mnt, + const Utf8Char* dir_name, + const Utf8Char* file_name, + UInt8 kind); + + /***********************************************************************************/ + /// @brief Allocate a new index node-> + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read/write from. + /// @param dir_name The name of the parent directory. + /// @return Status, see err_global_get(). + /***********************************************************************************/ + STATIC ATTRIBUTE(unused) _Output BOOL + hefsi_update_in_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, const Utf8Char* dir_name, + HEFS_INDEX_NODE* node, const BOOL create_or_delete); + + /***********************************************************************************/ + /// @brief Balance RB-Tree of the filesystem. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read/write from. + /// @return Status, see err_global_get(). + /***********************************************************************************/ + STATIC ATTRIBUTE(unused) _Output BOOL hefsi_balance_ind(HEFS_BOOT_NODE* boot, DriveTrait* mnt); + + /// @brief Alllocate IND from boot node. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read from. + /// @param dir_name The name of the directory. + /// @param dir_name The parent of the directory. + /// @param flags Directory flags. + /// @param delete_or_create Delete or create directory. + STATIC _Output BOOL hefsi_update_ind_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, + const Utf8Char* dir_name, UInt16 flags, + const BOOL delete_or_create); + + /// @brief This helper makes it easier for other machines to understand OpenHeFS encoded hashes. + STATIC UInt64 hefsi_to_big_endian_64(UInt64 val) { + return ((val >> 56) & 0x00000000000000FFULL) | ((val >> 40) & 0x000000000000FF00ULL) | + ((val >> 24) & 0x0000000000FF0000ULL) | ((val >> 8) & 0x00000000FF000000ULL) | + ((val << 8) & 0x000000FF00000000ULL) | ((val << 24) & 0x0000FF0000000000ULL) | + ((val << 40) & 0x00FF000000000000ULL) | ((val << 56) & 0xFF00000000000000ULL); + } + + /// @brief Simple algorithm to hash directory entries for INDs. + /// @param path the directory path. + /// @return The hashed path. + template + STATIC UInt64 hefsi_hash_64(const CharT* path) { + if (!path || *path == 0) return 0; + + const UInt64 kFnvBaseOffset = 0xcbf29ce484222325ULL; + const UInt64 kFnvPrimeNumber = 0x100000001b3ULL; + + UInt64 hash = kFnvBaseOffset; + + while (*path) { + hash ^= (CharT) (*path++); + hash *= kFnvPrimeNumber; + } + + return hefsi_to_big_endian_64(hash); + } + + /// @brief Traverse the RB-Tree of the filesystem. + /// @param dir The directory to traverse. + /// @param start The starting point of the traversal. + /// @note This function is used to traverse the RB-Tree of the filesystem. + /// @internal Internal filesystem use only. + STATIC ATTRIBUTE(unused) Void hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, DriveTrait* mnt, + const Lba& ind_start, Lba& start) { + if (!mnt || !dir) return; + + BOOL check_is_good = NO; + HEFS_INDEX_NODE_DIRECTORY* dir_tmp = new HEFS_INDEX_NODE_DIRECTORY(); + + while (YES) { + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir_tmp; + mnt->fInput(mnt->fPacket); + + if (!mnt->fPacket.fPacketGood) break; + + if (dir_tmp->fNext != 0) { + if (check_is_good) break; + + start = dir_tmp->fNext; + + check_is_good = YES; + continue; + } else if (dir_tmp->fPrev != 0) { + if (check_is_good) break; + + start = dir_tmp->fPrev; + check_is_good = YES; + continue; + } else { + if (dir_tmp->fParent != 0) { + if (check_is_good) break; + + start = dir_tmp->fParent; + check_is_good = YES; + continue; + } else if (dir_tmp->fPrev != 0) { + if (check_is_good) break; + + start = dir_tmp->fPrev; + check_is_good = YES; + continue; + } else { + if (start == 0) { + start = ind_start; + continue; + } + + start += sizeof(HEFS_INDEX_NODE_DIRECTORY); + break; + } + } + } + + delete dir_tmp; + + start += sizeof(HEFS_INDEX_NODE_DIRECTORY); + if (start == 0) start = ind_start; + } + + /***********************************************************************************/ + /// @brief Rotate the RB-Tree to the left or right. + /// @internal + /***********************************************************************************/ + STATIC ATTRIBUTE(unused) _Output Void hefsi_rotate_tree(Lba& start, DriveTrait* mnt) { + if (!start || !mnt) return; + + HEFS_INDEX_NODE_DIRECTORY* cur = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = cur; + + mnt->fInput(mnt->fPacket); + + if (cur->fHashPath == 0) return; + + HEFS_INDEX_NODE_DIRECTORY* sibling = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = cur->fPrev; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = sibling; + + mnt->fInput(mnt->fPacket); + + if (sibling->fHashPath == 0) return; + + auto child_sibling = sibling->fChild; + auto child_cur = cur->fChild; + + cur->fChild = child_sibling; + sibling->fChild = child_cur; + + sibling->fChecksum = ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + cur->fChecksum = ke_calculate_crc32((Char*) cur, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = cur->fParent; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = sibling; + + mnt->fOutput(mnt->fPacket); + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = cur; + + mnt->fOutput(mnt->fPacket); + + HEFS_INDEX_NODE_DIRECTORY* sibling_child = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = child_sibling; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = sibling_child; + + mnt->fInput(mnt->fPacket); + + sibling_child->fParent = cur->fParent; + + sibling_child->fChecksum = + ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fOutput(mnt->fPacket); + + HEFS_INDEX_NODE_DIRECTORY* cur_child = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = child_cur; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = cur_child; + + mnt->fInput(mnt->fPacket); + + cur_child->fParent = start; + + cur_child->fChecksum = ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fOutput(mnt->fPacket); + + kout << "RB-Tree has been rotated.\r"; + } + + /// @brief Alllocate IND from boot node. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read from. + /// @param dir_name The name of the directory. + /// @param dir_name The parent of the directory. + /// @param flags Directory flags. + /// @param delete_or_create Delete or create directory. + STATIC _Output BOOL hefsi_update_ind_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, + const Utf8Char* dir_name, UInt16 flags, + const BOOL delete_or_create) { + if (mnt) { + HEFS_INDEX_NODE_DIRECTORY* tmpdir = + (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); + + auto start = boot->fStartIND; + auto prev_location = start; + auto parent_location = 0UL; + + MUST_PASS(boot->fStartIND > mnt->fLbaStart); + + while (YES) { + auto prev_start = start; + + if (start) + mnt->fPacket.fPacketLba = start; + else + mnt->fPacket.fPacketLba = prev_location + sizeof(HEFS_INDEX_NODE_DIRECTORY); + + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = tmpdir; + + mnt->fInput(mnt->fPacket); + + BOOL expr = NO; + + if (!delete_or_create) { + expr = (!tmpdir->fCreated && tmpdir->fDeleted) || tmpdir->fHashPath == 0; + } else { + expr = + tmpdir->fCreated && !tmpdir->fDeleted && hefsi_hash_64(dir_name) == tmpdir->fHashPath; + } + + if (expr) { + HEFS_INDEX_NODE_DIRECTORY* dirent = + (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); + + rt_set_memory(dirent, 0, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + dirent->fHashPath = delete_or_create ? 0UL : hefsi_hash_64(dir_name); + dirent->fAccessed = 0UL; + dirent->fCreated = delete_or_create ? 0UL : 1UL; + dirent->fDeleted = delete_or_create ? 1UL : 0UL; + dirent->fModified = 0UL; + dirent->fEntryCount = 0UL; + + dirent->fReserved = 0; + dirent->fFlags = flags; + dirent->fChecksum = 0; + + dirent->fEntryCount = 0; + + if (parent_location) { + HEFS_INDEX_NODE_DIRECTORY* tmpend = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = parent_location; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = tmpend; + + mnt->fInput(mnt->fPacket); + + if (tmpend->fChecksum != + ke_calculate_crc32((Char*) tmpend, sizeof(HEFS_INDEX_NODE_DIRECTORY))) + ke_panic(RUNTIME_CHECK_FILESYSTEM, "Bad CRC32 value, aborting."); + + if (delete_or_create) + --tmpend->fEntryCount; + else + ++tmpend->fEntryCount; + + tmpend->fChecksum = + ke_calculate_crc32((Char*) tmpend, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fOutput(mnt->fPacket); + + auto child_first = tmpend->fChild; + + while (YES) { + mnt->fPacket.fPacketLba = child_first; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = tmpend; + + mnt->fInput(mnt->fPacket); + + if ((!tmpend->fCreated && tmpend->fDeleted) || tmpend->fHashPath == 0) { + start = child_first; + break; + } + + hefsi_traverse_tree(tmpend, mnt, boot->fStartIND, child_first); + } + } + + dirent->fNext = tmpdir->fNext; + dirent->fPrev = tmpdir->fPrev; + dirent->fParent = tmpdir->fParent; + dirent->fChild = tmpdir->fChild; + dirent->fColor = tmpdir->fColor; + + if (dirent->fColor == 0) { + dirent->fColor = dirent->fNext ? kHeFSRed : kHeFSBlack; + } + + if (dirent->fPrev == 0) { + dirent->fPrev = boot->fStartIND; + } + + if (dirent->fParent == 0) { + dirent->fParent = boot->fStartIND; + } + + if (tmpdir->fChild == 0) { + auto child = dirent->fNext + sizeof(HEFS_INDEX_NODE_DIRECTORY); + + HEFS_INDEX_NODE_DIRECTORY* tmpend = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + while (YES) { + mnt->fPacket.fPacketLba = child; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = tmpend; + + mnt->fInput(mnt->fPacket); + + if ((!tmpend->fCreated && tmpend->fDeleted) || tmpdir->fHashPath == 0) { + break; + } + + child += sizeof(HEFS_INDEX_NODE_DIRECTORY); + if (child > boot->fEndIND) break; + } + + dirent->fColor = kHeFSRed; + dirent->fChild = child; + + if (child > boot->fEndIND) dirent->fChild = boot->fStartIND; + } + + for (SizeT index = 0UL; index < kHeFSSliceCount; ++index) { + dirent->fINSlices[index] = 0UL; + } + + dirent->fChecksum = ke_calculate_crc32((Char*) dirent, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = prev_start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dirent; + + mnt->fOutput(mnt->fPacket); + + err_global_get() = kErrorSuccess; + + mm_free_ptr(dirent); + mm_free_ptr(tmpdir); + + if (!delete_or_create) + ++boot->fINDCount; + else + --boot->fINDCount; + + boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fOutput(mnt->fPacket); + + return YES; + } + + prev_location = start; + + hefsi_traverse_tree(tmpdir, mnt, boot->fStartIND, start); + if (start > boot->fEndIND || start == 0) break; + } + + err_global_get() = kErrorDisk; + mm_free_ptr(tmpdir); + + return NO; + } + + err_global_get() = kErrorDiskIsFull; + return NO; + } + + /// @brief Get the index node of a file or directory. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read from. + /// @param dir_name The name of the directory. + /// @param file_name The name of the file. + /// @param kind The kind of the file (regular, directory, block, character, FIFO, socket, symbolic + /// link, unknown). + STATIC ATTRIBUTE(unused) _Output HEFS_INDEX_NODE* hefsi_fetch_in(HEFS_BOOT_NODE* boot, + DriveTrait* mnt, + const Utf8Char* dir_name, + const Utf8Char* file_name, + UInt8 kind) { + if (mnt) { + if (boot->fStartIND > boot->fEndIND) return nullptr; + if (boot->fStartIN > boot->fEndIN) return nullptr; + + auto start = boot->fStartIND; + HEFS_INDEX_NODE* node = new HEFS_INDEX_NODE(); + + HEFS_INDEX_NODE_DIRECTORY* dir = + (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); + + while (YES) { + if (err_global_get() == kErrorDiskIsCorrupted) { + delete dir; + dir = nullptr; + + delete node; + node = nullptr; + + return nullptr; + } + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fInput(mnt->fPacket); + + (Void)(kout << hex_number(hefsi_hash_64(dir_name)) << kendl); + (Void)(kout << hex_number(dir->fHashPath) << kendl); + + if (dir->fHashPath == 0) break; + + if (hefsi_hash_64(dir_name) == dir->fHashPath) { + for (SizeT inode_index = 0UL; inode_index < kHeFSSliceCount; ++inode_index) { + mnt->fPacket.fPacketLba = dir->fINSlices[inode_index]; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); + mnt->fPacket.fPacketContent = node; + + mnt->fInput(mnt->fPacket); + + (Void)(kout << hex_number(hefsi_hash_64(file_name)) << kendl); + (Void)(kout << hex_number(node->fHashPath) << kendl); + + if (hefsi_hash_64(file_name) == node->fHashPath && node->fKind == kind) { + delete dir; + dir = nullptr; + + return node; + } + } + } + + hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); + if (start == boot->fStartIND || start == boot->fStartIND) break; + } + + delete node; + node = nullptr; + + delete dir; + dir = nullptr; + } + + kout << "Error: Failed to find IN.\r"; + + err_global_get() = kErrorFileNotFound; + + return nullptr; + } + + STATIC ATTRIBUTE(unused) _Output BOOL + hefsi_update_in_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, const Utf8Char* dir_name, + HEFS_INDEX_NODE* node, BOOL delete_or_create) { + if (!boot || !mnt) return NO; + + auto start = boot->fStartIND; + + if (start > boot->fEndIND) return NO; + if (boot->fStartIN > boot->fEndIN) return NO; + ; + if (boot->fStartBlock > boot->fEndBlock) return NO; + + if (mnt) { + HEFS_INDEX_NODE_DIRECTORY* dir = + (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); + + auto hash_file = node->fHashPath; + + while (YES) { + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fInput(mnt->fPacket); + + (Void)(kout << hex_number(hefsi_hash_64(dir_name)) << kendl); + (Void)(kout << hex_number(dir->fHashPath) << kendl); + + if (hefsi_hash_64(dir_name) == dir->fHashPath) { + for (SizeT inode_index = 0UL; inode_index < kHeFSSliceCount; ++inode_index) { + if (dir->fINSlices[inode_index] == 0 && !delete_or_create) { + dir->fINSlices[inode_index] = boot->fStartIN; + + ++dir->fEntryCount; + + dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fOutput(mnt->fPacket); + + auto lba = dir->fINSlices[inode_index]; + + node->fOffsetSliceLow = (UInt32) (boot->fStartBlock); + node->fOffsetSliceHigh = (UInt32) (boot->fStartBlock >> 32); + + node->fChecksum = ke_calculate_crc32((Char*) node, sizeof(HEFS_INDEX_NODE)); + + mnt->fPacket.fPacketLba = lba; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); + mnt->fPacket.fPacketContent = node; + + mnt->fOutput(mnt->fPacket); + + boot->fStartIN += sizeof(HEFS_INDEX_NODE); + boot->fStartBlock += kHeFSBlockLen; + + boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fOutput(mnt->fPacket); + + mm_free_ptr(dir); + + return YES; + } else if (dir->fINSlices[inode_index] != 0 && delete_or_create) { + auto lba = dir->fINSlices[inode_index]; + + HEFS_INDEX_NODE tmp_node{}; + + mnt->fPacket.fPacketLba = lba; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); + mnt->fPacket.fPacketContent = &tmp_node; + + mnt->fInput(mnt->fPacket); + + if (tmp_node.fHashPath != hash_file) { + continue; + } + + node->fOffsetSliceLow = 0; + node->fOffsetSliceHigh = 0; + + boot->fStartIN -= sizeof(HEFS_INDEX_NODE); + boot->fStartBlock -= kHeFSBlockLen; + + boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fOutput(mnt->fPacket); + + mnt->fPacket.fPacketLba = lba; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); + mnt->fPacket.fPacketContent = node; + + mnt->fOutput(mnt->fPacket); + + dir->fINSlices[inode_index] = 0; + + if (dir->fEntryCount) --dir->fEntryCount; + + dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fOutput(mnt->fPacket); + + mm_free_ptr(dir); + + return YES; + } + } + } + + hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); + if (start > boot->fEndIND || start == 0) break; + } + + mm_free_ptr(dir); + err_global_get() = kErrorFileNotFound; + return NO; + } + + err_global_get() = kErrorDiskIsFull; + return NO; + } + + /// @brief Balance RB-Tree of the filesystem. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read/write from. + /// @return Status, see err_global_get(). + STATIC ATTRIBUTE(unused) _Output BOOL hefsi_balance_ind(HEFS_BOOT_NODE* boot, DriveTrait* mnt) { + if (mnt) { + HEFS_INDEX_NODE_DIRECTORY* dir = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + auto start = boot->fStartIND; + + while (YES) { + if (start == 0UL || start > boot->fEndIND) break; + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fInput(mnt->fPacket); + + if (!mnt->fPacket.fPacketGood) { + err_global_get() = kErrorDiskIsCorrupted; + + return NO; + } + + if (start == boot->fStartIND) { + dir->fColor = kHeFSBlack; + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fOutput(mnt->fPacket); + } + + if (dir->fColor == kHeFSBlack && dir->fChild != 0UL) { + dir->fColor = kHeFSRed; + hefsi_rotate_tree(start, mnt); + } else if (dir->fColor == kHeFSBlack && dir->fChild == 0UL) { + dir->fColor = kHeFSBlack; + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fOutput(mnt->fPacket); + } + + if (ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)) != dir->fChecksum) { + dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fOutput(mnt->fPacket); + } + + hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); + } + + err_global_get() = kErrorSuccess; + return YES; + } + + err_global_get() = kErrorDisk; + return NO; + } +} // namespace Detail +} // namespace Kernel + +/// @note OpenHeFS will allocate inodes and ind in advance, to avoid having to allocate them in +/// real-time. +/// @note This is certainly take longer to format a disk with it, but worth-it in the long run. + +namespace Kernel { +/// @brief Make a EPM+OpenHeFS mnt out of the disk. +/// @param mnt The mnt to write on. +/// @return If it was sucessful, see err_local_get(). +_Output Bool HeFileSystemParser::Format(_Input _Output DriveTrait* mnt, _Input const Int32 flags, + _Input const Utf8Char* vol_name) { + // Verify Disk. + mnt->fVerify(mnt->fPacket); + + // if disk isn't good, then error out. + if (false == mnt->fPacket.fPacketGood) { + err_global_get() = kErrorDiskIsCorrupted; + return false; + } + + if (drv_std_get_size() < kHeFSMinimumDiskSize) { + (Void)(kout << "OpenHeFS recommends at least 128 GiB of free space." << kendl); + (Void)( + kout + << "The OS will still try to format a OpenHeFS disk here anyway, don't expect perfect geometry." + << kendl); + } + + HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) RTL_ALLOCA(sizeof(HEFS_BOOT_NODE)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fInput(mnt->fPacket); + + if (!mnt->fPacket.fPacketGood) { + err_global_get() = kErrorDiskIsCorrupted; + + return NO; + } + + // Check if the disk is already formatted. + + if (KStringBuilder::Equals(boot->fMagic, kHeFSMagic) && boot->fVersion == kHeFSVersion) { + if (ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)) != boot->fChecksum && + boot->fChecksum > 0) { + err_global_get() = kErrorDiskIsCorrupted; + return NO; + } + + err_global_get() = kErrorSuccess; + return YES; + } + + if (ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)) != boot->fChecksum && + boot->fChecksum > 0) { + err_global_get() = kErrorDiskIsCorrupted; + return NO; + } + + rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, + rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); + + urt_copy_memory((VoidPtr) vol_name, boot->fVolName, urt_string_len(vol_name) + 1); + rt_copy_memory_safe((VoidPtr) kHeFSMagic, boot->fMagic, kHeFSMagicLen - 1, sizeof(boot->fMagic)); + + if (mnt->fLbaStart > mnt->fLbaEnd) { + err_global_get() = kErrorDiskIsCorrupted; + + return NO; + } + + boot->fBadSectors = 0; + + boot->fSectorCount = drv_std_get_sector_count(); + boot->fSectorSize = mnt->fSectorSz; + + MUST_PASS(boot->fSectorSize); + + /// @note all OpenHeFS strucutres are equal to 512, so here it's fine, unless fSectoSize is 2048. + const SizeT max_lba = (drv_std_get_size()) / boot->fSectorSize; + + const SizeT dir_max = max_lba / 300; // 5% for directory inodes + const SizeT inode_max = max_lba / 400; // 5% for inodes + + boot->fStartIND = mnt->fLbaStart + kHeFSINDStartOffset; + boot->fEndIND = boot->fStartIND + dir_max; + + boot->fStartIN = boot->fEndIND; + boot->fEndIN = boot->fStartIN + inode_max; + + boot->fStartBlock = boot->fEndIN; + boot->fEndBlock = drv_std_get_size(); + + boot->fINDCount = 0; + + boot->fDiskSize = drv_std_get_size(); + boot->fDiskStatus = kHeFSStatusUnlocked; + + boot->fDiskFlags = flags; + + if (mnt->fKind & kMassStorageDrive) { + boot->fDiskKind = kHeFSMassStorageDevice; + } else if (mnt->fKind & kHeFSOpticalDrive) { + boot->fDiskKind = kHeFSOpticalDrive; + } else { + boot->fDiskKind = kHeFSUnknown; + } + + boot->fVersion = kHeFSVersion; + + boot->fVID = kHeFSInvalidVID; + + boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fOutput(mnt->fPacket); + + (Void)(kout << "Protocol: " << mnt->fProtocol() << kendl); + (Void)(kout8 << u8"Volume Name: " << boot->fVolName << kendl8); + (Void)(kout << "Start IND: " << hex_number(boot->fStartIND) << kendl); + (Void)(kout << "End IND: " << hex_number(boot->fEndIND) << kendl); + (Void)(kout << "Start IN: " << hex_number(boot->fStartIN) << kendl); + (Void)(kout << "End IN: " << hex_number(boot->fEndIN) << kendl); + (Void)(kout << "Start Block: " << hex_number(boot->fStartBlock) << kendl); + (Void)(kout << "End Block: " << hex_number(boot->fEndBlock) << kendl); + (Void)(kout << "Number of IND: " << hex_number(boot->fINDCount) << kendl); + (Void)(kout << "Sector Size: " << hex_number(boot->fSectorSize) << kendl); + (Void)(kout << "Drive Kind: " << Detail::hefs_drive_kind_to_string(boot->fDiskKind) << kendl); + + if (!mnt->fPacket.fPacketGood) { + err_global_get() = kErrorDiskIsCorrupted; + return NO; + } + + constexpr const SizeT kHeFSPreallocateCount = 0x6UL; + + const Utf8Char* kFileMap[kHeFSPreallocateCount] = {u8"/", u8"/boot", u8"/system", + u8"/network", u8"/devices", u8"/media"}; + + for (SizeT i = 0; i < kHeFSPreallocateCount; ++i) { + this->CreateINodeDirectory(mnt, kHeFSEncodingFlagsUTF8, kFileMap[i]); + } + + err_global_get() = kErrorSuccess; + + return YES; +} + +/// @brief Create a new directory on the disk. +/// @param mnt The mnt to write on. +/// @param flags The flags to use. +/// @param dir The directory to create the file in. +/// @return If it was sucessful, see err_local_get(). +_Output Bool HeFileSystemParser::INodeDirectoryCtlManip(_Input DriveTrait* mnt, + _Input const Int32 flags, + const Utf8Char* dir, + const BOOL delete_or_create) { + if (urt_string_len(dir) > kHeFSFileNameLen) { + err_global_get() = kErrorDisk; + return NO; + } + + HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) mm_alloc_ptr(sizeof(HEFS_BOOT_NODE), Yes, No); + + rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, + rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fInput(mnt->fPacket); + + if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { + err_global_get() = kErrorDisk; + return YES; + } + + if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { + err_global_get() = kErrorDiskIsCorrupted; + + kout << "Invalid Boot Node, this can't continue!\r"; + + return NO; + } + + if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { + kout << "Error: Invalid directory name.\r"; + + err_global_get() = kErrorInvalidData; + + return NO; + } + + if (Detail::hefsi_update_ind_status(boot, mnt, dir, flags, delete_or_create)) { + // todo: make it smarter for high-throughput. + Detail::hefsi_balance_ind(boot, mnt); + + mm_free_ptr((VoidPtr) boot); + return YES; + } + + mm_free_ptr((VoidPtr) boot); + return NO; +} + +_Output Bool HeFileSystemParser::RemoveINodeDirectory(_Input DriveTrait* mnt, + _Input const Int32 flags, + const Utf8Char* dir) { + return this->INodeDirectoryCtlManip(mnt, flags, dir, YES); +} + +_Output Bool HeFileSystemParser::CreateINodeDirectory(_Input DriveTrait* mnt, + _Input const Int32 flags, + const Utf8Char* dir) { + return this->INodeDirectoryCtlManip(mnt, flags, dir, NO); +} + +_Output Bool HeFileSystemParser::DeleteINode(_Input DriveTrait* mnt, _Input const Int32 flags, + const Utf8Char* dir, const Utf8Char* name, + const UInt8 kind) { + return this->INodeCtlManip(mnt, flags, dir, name, YES, kind); +} + +_Output Bool HeFileSystemParser::CreateINode(_Input DriveTrait* mnt, _Input const Int32 flags, + const Utf8Char* dir, const Utf8Char* name, + const UInt8 kind) { + return this->INodeCtlManip(mnt, flags, dir, name, NO, kind); +} + +_Output Bool HeFileSystemParser::INodeManip(_Input DriveTrait* mnt, VoidPtr block, SizeT block_sz, + const Utf8Char* dir, const Utf8Char* name, + const UInt8 kind, const BOOL is_input) { + if (urt_string_len(dir) > kHeFSFileNameLen) { + err_global_get() = kErrorDisk; + return NO; + } + + if (urt_string_len(name) > kHeFSFileNameLen) { + err_global_get() = kErrorDisk; + return NO; + } + + HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) mm_alloc_ptr(sizeof(HEFS_BOOT_NODE), Yes, No); + + if (!boot) { + err_global_get() = kErrorInvalidData; + return NO; + } + + rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, + rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fInput(mnt->fPacket); + + if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { + (Void)(kout << "Invalid Boot Node, OpenHeFS partition is invalid." << kendl); + mm_free_ptr((VoidPtr) boot); + err_global_get() = kErrorDisk; + return NO; + } + + auto start = Detail::hefsi_fetch_in(boot, mnt, dir, name, kind); + + if (start) { + (Void)(kout << hex_number(start->fHashPath) << kendl); + (Void)(kout << hex_number(start->fOffsetSliceLow) << kendl); + + if (start->fOffsetSliceLow && start->fHashPath) { + mnt->fPacket.fPacketLba = ((UInt64) start->fOffsetSliceHigh << 32) | start->fOffsetSliceLow; + mnt->fPacket.fPacketSize = block_sz; + mnt->fPacket.fPacketContent = block; + + if (is_input) { + mnt->fInput(mnt->fPacket); + } else { + if (start->fFlags & kHeFSFlagsReadOnly) { + mm_free_ptr((VoidPtr) boot); + delete start; + + kout << "Error: File is read-only\r"; + + return NO; + } + + mnt->fOutput(mnt->fPacket); + } + } + } + + mm_free_ptr((VoidPtr) boot); + delete start; + return YES; +} + +/// @brief Create a new file on the disk. +/// @param mnt The mnt to write on. +/// @param flags The flags to use. +/// @param dir The directory to create the file in. +/// @param name The name of the file. +/// @return If it was sucessful, see err_local_get(). +_Output Bool HeFileSystemParser::INodeCtlManip(_Input DriveTrait* mnt, _Input const Int32 flags, + const Utf8Char* dir, const Utf8Char* name, + const BOOL delete_or_create, const UInt8 kind) { + if (urt_string_len(name) > kHeFSFileNameLen) { + err_global_get() = kErrorDisk; + return NO; + } + + if (urt_string_len(dir) > kHeFSFileNameLen) { + err_global_get() = kErrorDisk; + return NO; + } + + HEFS_INDEX_NODE* node = (HEFS_INDEX_NODE*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE), Yes, No); + + if (!node) { + err_global_get() = kErrorInvalidData; + return NO; + } + + rt_set_memory(node, 0, sizeof(HEFS_INDEX_NODE)); + + HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) RTL_ALLOCA(sizeof(HEFS_BOOT_NODE)); + + if (!boot) { + mm_free_ptr((VoidPtr) node); + err_global_get() = kErrorInvalidData; + + return NO; + } + + rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, + rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fInput(mnt->fPacket); + + if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { + err_global_get() = kErrorDisk; + return YES; + } + + if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { + kout << "Error: Invalid file name.\r"; + + err_global_get() = kErrorInvalidData; + return NO; + } + + for (SizeT i_name = 0UL; i_name < urt_string_len(name); ++i_name) { + if (name[i_name] == u'/') { + err_global_get() = kErrorInvalidData; + return NO; + } + } + + if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { + kout << "Error: Invalid directory name.\r"; + + err_global_get() = kErrorInvalidData; + return NO; + } + + node->fAccessed = 0; + node->fCreated = delete_or_create ? NO : YES; + node->fDeleted = delete_or_create ? 1UL : NO; + node->fModified = 0; + node->fSize = 0; + node->fKind = kind; + node->fFlags = flags; + node->fChecksum = 0; + node->fGID = 0; + node->fUID = 0; + node->fHashPath = Detail::hefsi_hash_64(name); + + if (Detail::hefsi_update_in_status(boot, mnt, dir, node, delete_or_create)) { + mm_free_ptr((VoidPtr) node); + + Detail::hefsi_balance_ind(boot, mnt); + + err_global_get() = kErrorSuccess; + return YES; + } + + mm_free_ptr((VoidPtr) node); + err_global_get() = kErrorDirectoryNotFound; + + return NO; +} + +STATIC DriveTrait kMountPoint; + +/// @brief Initialize the OpenHeFS filesystem. +/// @return To check its status, see err_local_get(). +Boolean OpenHeFS::fs_init_hefs(Void) noexcept { + kout << "Verifying disk...\r"; + + kMountPoint = io_construct_main_drive(); + + if (kMountPoint.fPacket.fPacketReadOnly == YES) + ke_panic(RUNTIME_CHECK_FILESYSTEM, "Main disk cannot be mounted (read-only media)."); + + HeFileSystemParser parser; + + return parser.Format(&kMountPoint, kHeFSEncodingFlagsUTF8, kHeFSDefaultVolumeName); +} +} // namespace Kernel + +#endif // ifdef __FSKIT_INCLUDES_HEFS__ diff --git a/dev/kernel/src/IFS.cc b/dev/kernel/src/IFS.cc index ba2ec8c0..ffb8ef8e 100644 --- a/dev/kernel/src/IFS.cc +++ b/dev/kernel/src/IFS.cc @@ -28,25 +28,25 @@ namespace Kernel { /// @param DrvTrait drive info /// @param DrvIndex drive index. /// @return -Int32 fs_ifs_read(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) { +Int32 fs_ifs_read(IMountpoint* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) { if (!Mnt) return kErrorDisk; DrvTrait.fPacket.fPacketGood = false; switch (DrvIndex) { - case MountpointInterface::kDriveIndexA: { + case IMountpoint::kDriveIndexA: { fsi_ifs_read(A, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexB: { + case IMountpoint::kDriveIndexB: { fsi_ifs_read(B, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexC: { + case IMountpoint::kDriveIndexC: { fsi_ifs_read(C, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexD: { + case IMountpoint::kDriveIndexD: { fsi_ifs_read(D, DrvTrait.fPacket, Mnt); break; } @@ -60,25 +60,25 @@ Int32 fs_ifs_read(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex /// @param DrvTrait drive info /// @param DrvIndex drive index. /// @return -Int32 fs_ifs_write(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) { +Int32 fs_ifs_write(IMountpoint* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) { if (!Mnt) return kErrorDisk; DrvTrait.fPacket.fPacketGood = false; switch (DrvIndex) { - case MountpointInterface::kDriveIndexA: { + case IMountpoint::kDriveIndexA: { fsi_ifs_write(A, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexB: { + case IMountpoint::kDriveIndexB: { fsi_ifs_write(B, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexC: { + case IMountpoint::kDriveIndexC: { fsi_ifs_write(C, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexD: { + case IMountpoint::kDriveIndexD: { fsi_ifs_write(D, DrvTrait.fPacket, Mnt); break; } diff --git a/dev/kernel/src/Storage/AHCIDeviceInterface.cc b/dev/kernel/src/Storage/AHCIDeviceInterface.cc index 182ed2b3..6dcfed69 100644 --- a/dev/kernel/src/Storage/AHCIDeviceInterface.cc +++ b/dev/kernel/src/Storage/AHCIDeviceInterface.cc @@ -13,9 +13,9 @@ using namespace Kernel; /// @param In Drive input /// @param Cleanup Drive cleanup. AHCIDeviceInterface::AHCIDeviceInterface(void (*out)(DeviceInterface* self, - MountpointInterface* outpacket), + IMountpoint* outpacket), void (*in)(DeviceInterface* self, - MountpointInterface* inpacket)) + IMountpoint* inpacket)) : DeviceInterface(out, in) {} /// @brief Class desctructor @@ -30,7 +30,7 @@ const Char* AHCIDeviceInterface::Name() const { /// @brief Output operator. /// @param mnt the disk mountpoint. /// @return the class itself after operation. -AHCIDeviceInterface& AHCIDeviceInterface::operator<<(MountpointInterface* mnt) { +AHCIDeviceInterface& AHCIDeviceInterface::operator<<(IMountpoint* mnt) { if (!mnt) return *this; for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) { @@ -45,13 +45,13 @@ AHCIDeviceInterface& AHCIDeviceInterface::operator<<(MountpointInterface* mnt) { } } - return (AHCIDeviceInterface&) DeviceInterface::operator<<(mnt); + return (AHCIDeviceInterface&) DeviceInterface::operator<<(mnt); } /// @brief Input operator. /// @param mnt the disk mountpoint. /// @return the class itself after operation. -AHCIDeviceInterface& AHCIDeviceInterface::operator>>(MountpointInterface* mnt) { +AHCIDeviceInterface& AHCIDeviceInterface::operator>>(IMountpoint* mnt) { if (!mnt) return *this; for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) { @@ -67,7 +67,7 @@ AHCIDeviceInterface& AHCIDeviceInterface::operator>>(MountpointInterface* mnt) { } } - return (AHCIDeviceInterface&) DeviceInterface::operator>>(mnt); + return (AHCIDeviceInterface&) DeviceInterface::operator>>(mnt); } const UInt16& AHCIDeviceInterface::GetPortsImplemented() { @@ -84,6 +84,6 @@ const UInt32& AHCIDeviceInterface::GetIndex() { } Void AHCIDeviceInterface::SetIndex(const UInt32& drv) { - MUST_PASS(MountpointInterface::kDriveIndexInvalid < drv); + MUST_PASS(IMountpoint::kDriveIndexInvalid < drv); this->fDriveIndex = drv; } \ No newline at end of file diff --git a/dev/kernel/src/Storage/ATADeviceInterface.cc b/dev/kernel/src/Storage/ATADeviceInterface.cc index e302d2cc..70d6e9ae 100644 --- a/dev/kernel/src/Storage/ATADeviceInterface.cc +++ b/dev/kernel/src/Storage/ATADeviceInterface.cc @@ -13,8 +13,8 @@ using namespace Kernel; /// @param In Drive input /// @param Cleanup Drive cleanup. ATADeviceInterface::ATADeviceInterface(void (*Out)(DeviceInterface*, - MountpointInterface* outpacket), - void (*In)(DeviceInterface*, MountpointInterface* inpacket)) + IMountpoint* outpacket), + void (*In)(DeviceInterface*, IMountpoint* inpacket)) : DeviceInterface(Out, In) {} /// @brief Class desctructor @@ -29,7 +29,7 @@ const Char* ATADeviceInterface::Name() const { /// @brief Output operator. /// @param Data the disk mountpoint. /// @return the class itself after operation. -ATADeviceInterface& ATADeviceInterface::operator<<(MountpointInterface* Data) { +ATADeviceInterface& ATADeviceInterface::operator<<(IMountpoint* Data) { if (!Data) return *this; for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) { @@ -44,13 +44,13 @@ ATADeviceInterface& ATADeviceInterface::operator<<(MountpointInterface* Data) { } } - return (ATADeviceInterface&) DeviceInterface::operator<<(Data); + return (ATADeviceInterface&) DeviceInterface::operator<<(Data); } /// @brief Input operator. /// @param Data the disk mountpoint. /// @return the class itself after operation. -ATADeviceInterface& ATADeviceInterface::operator>>(MountpointInterface* Data) { +ATADeviceInterface& ATADeviceInterface::operator>>(IMountpoint* Data) { if (!Data) return *this; for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) { @@ -66,7 +66,7 @@ ATADeviceInterface& ATADeviceInterface::operator>>(MountpointInterface* Data) { } } - return (ATADeviceInterface&) DeviceInterface::operator>>(Data); + return (ATADeviceInterface&) DeviceInterface::operator>>(Data); } const UInt32& ATADeviceInterface::GetIndex() { @@ -74,7 +74,7 @@ const UInt32& ATADeviceInterface::GetIndex() { } Void ATADeviceInterface::SetIndex(const UInt32& drv) { - MUST_PASS(MountpointInterface::kDriveIndexInvalid < drv); + MUST_PASS(IMountpoint::kDriveIndexInvalid < drv); this->fDriveIndex = drv; } diff --git a/dev/kernel/src/Storage/NVMEDeviceInterface.cc b/dev/kernel/src/Storage/NVMEDeviceInterface.cc index 077595cf..0b8043b7 100644 --- a/dev/kernel/src/Storage/NVMEDeviceInterface.cc +++ b/dev/kernel/src/Storage/NVMEDeviceInterface.cc @@ -8,8 +8,8 @@ namespace Kernel { NVMEDeviceInterface::NVMEDeviceInterface( - void (*out)(DeviceInterface*, MountpointInterface* outpacket), - void (*in)(DeviceInterface*, MountpointInterface* inpacket), void (*cleanup)(void)) + void (*out)(DeviceInterface*, IMountpoint* outpacket), + void (*in)(DeviceInterface*, IMountpoint* inpacket), void (*cleanup)(void)) : DeviceInterface(out, in), fCleanup(cleanup) {} NVMEDeviceInterface::~NVMEDeviceInterface() { diff --git a/dev/libSystem/SystemKit/System.h b/dev/libSystem/SystemKit/System.h index f46fe523..88472513 100644 --- a/dev/libSystem/SystemKit/System.h +++ b/dev/libSystem/SystemKit/System.h @@ -79,7 +79,7 @@ IMPORT_C Void IoCloseFile(_Input Ref file_desc); /// @param in_data the input data. /// @param out_data the output data. /// @return the number of bytes written. -/// @note This function is used to control the file descriptor, introduced for HeFS. +/// @note This function is used to control the file descriptor, introduced for OpenHeFS. IMPORT_C SInt32 IoCtrlFile(_Input Ref file_desc, _Input UInt32 ioctl_code, _Input VoidPtr in_data, _Output VoidPtr out_data); @@ -89,7 +89,7 @@ IMPORT_C const Char* IoMimeFile(_Input Ref file_desc); /// @brief Gets the dir DIM. /// @param dir_desc directory descriptor. -/// @note only works in HeFS, will return nil-x/nil if used on any other filesystem. +/// @note only works in OpenHeFS, will return nil-x/nil if used on any other filesystem. IMPORT_C const Char* IoDimFile(_Input Ref dir_desc); /// @brief Write data to a file ref diff --git a/docs/tex/hefs.tex b/docs/tex/hefs.tex index c35bca53..9ec68020 100644 --- a/docs/tex/hefs.tex +++ b/docs/tex/hefs.tex @@ -4,7 +4,7 @@ \usepackage{longtable} \usepackage{listings} \geometry{margin=1in} -\title{HeFS: Hight-throughput extended File System} +\title{OpenHeFS: Hight-throughput extended File System} \author{Amlal El Mahrouss} \date{\today} @@ -13,7 +13,7 @@ \maketitle \section{Overview} -The High-throughput Extended File System (HeFS) is a custom filesystem tailored for performance, structure, and compact representation. It uses red-black trees for directory indexing, sparse block slicing for file layout, and fixed-size metadata structures optimized for 512-byte sector alignment. +The High-throughput Extended File System (OpenHeFS) is a custom filesystem tailored for performance, structure, and compact representation. It uses red-black trees for directory indexing, sparse block slicing for file layout, and fixed-size metadata structures optimized for 512-byte sector alignment. \section{Constants and Macros} \begin{longtable}{|l|l|} @@ -21,13 +21,13 @@ The High-throughput Extended File System (HeFS) is a custom filesystem tailored \textbf{Name} & \textbf{Value / Description} \\ \hline \texttt{kHeFSVersion} & 0x0103 \\ -\texttt{kHeFSMagic} & " HeFS" (8-byte magic identifier) \\ +\texttt{kHeFSMagic} & " OpenHeFS" (8-byte magic identifier) \\ \texttt{kHeFSMagicLen} & 8 \\ \texttt{kHeFSBlockLen} & 512 bytes \\ \texttt{kHeFSFileNameLen} & 256 characters \\ \texttt{kHeFSPartNameLen} & 128 characters \\ \texttt{kHeFSMinimumDiskSize} & 128 GiB \\ -\texttt{kHeFSDefaultVolumeName} & "HeFS Volume" \\ +\texttt{kHeFSDefaultVolumeName} & "OpenHeFS Volume" \\ \texttt{kHeFSINDStartOffset} & Offset after boot node \\ \texttt{kHeFSSearchAllStr} & "*" (wildcard string) \\ \hline @@ -151,10 +151,10 @@ Constants: \section{Filesystem API}\label{sec:filesystem-api} -Provided by \texttt{Kernel::HeFS::HeFileSystemParser}. +Provided by \texttt{Kernel::OpenHeFS::HeFileSystemParser}. \begin{itemize} - \item \texttt{Format(drive, flags, name)} - Format drive with HeFS + \item \texttt{Format(drive, flags, name)} - Format drive with OpenHeFS \item \texttt{CreateINodeDirectory(drive, flags, dir)} \item \texttt{RemoveINodeDirectory(drive, flags, dir)} \item \texttt{CreateINode(drive, flags, dir, name, kind)} @@ -168,7 +168,7 @@ Internal helpers: \end{itemize} \section{Conclusion} -HeFS provides a modern and compact approach to high-performance file storage. +OpenHeFS provides a modern and compact approach to high-performance file storage. Its use of red-black trees, fixed-size metadata, slice-based sparse files, and minimal overhead makes it a strong candidate for performance-sensitive use cases. \end{document} diff --git a/public/frameworks/DiskImage.fwrk/headers/DiskImage.h b/public/frameworks/DiskImage.fwrk/headers/DiskImage.h index 4a18b079..198d64a1 100644 --- a/public/frameworks/DiskImage.fwrk/headers/DiskImage.h +++ b/public/frameworks/DiskImage.fwrk/headers/DiskImage.h @@ -52,7 +52,7 @@ SInt32 DIFormatPartitionEPM(struct DI_DISK_IMAGE& img) noexcept; /// @return Status code upon completion. SInt32 DIFormatFilesystemNeFS(struct DI_DISK_IMAGE& img) noexcept; -/// @brief HeFS format over EPM. +/// @brief OpenHeFS format over EPM. /// @param img disk image structure. /// @return Status code upon completion. SInt32 DIFormatFilesystemHeFS(struct DI_DISK_IMAGE& img) noexcept; diff --git a/public/frameworks/DiskImage.fwrk/src/DiskImage+HeFS.cc b/public/frameworks/DiskImage.fwrk/src/DiskImage+HeFS.cc index 7f917052..aa7abdf4 100644 --- a/public/frameworks/DiskImage.fwrk/src/DiskImage+HeFS.cc +++ b/public/frameworks/DiskImage.fwrk/src/DiskImage+HeFS.cc @@ -2,17 +2,17 @@ Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. - FILE: DiskImage+HeFS.cc + FILE: DiskImage+OpenHeFS.cc PURPOSE: Disk Imaging framework. ------------------------------------------- */ #include -#include +#include #include -/// @brief format HeFS over an EPM disk. +/// @brief format OpenHeFS over an EPM disk. /// @param img disk image structure. /// @return Status code upon completion. SInt32 DI::DIFormatFilesystemHeFS(struct DI_DISK_IMAGE& img) noexcept { diff --git a/public/manuals/nekernel/mgmt.hefs.util.man b/public/manuals/nekernel/mgmt.hefs.util.man index 3274f93a..1cb7022d 100644 --- a/public/manuals/nekernel/mgmt.hefs.util.man +++ b/public/manuals/nekernel/mgmt.hefs.util.man @@ -1,12 +1,12 @@ NAME - mgmt.hefs — HeFS Management utility command + mgmt.hefs — OpenHeFS Management utility command SYNOPSIS mgmt.hefs [OPTIONS] DESCRIPTION The `mgmt.hefs` command provides scheduling, execution, and remote orchestration - of a HeFS volume inside a System One environement. One might use this tool to + of a OpenHeFS volume inside a System One environement. One might use this tool to create, edit, and remove volumes from a disk. Usages include, but are not limited to: @@ -16,7 +16,7 @@ DESCRIPTION OPTIONS -v, --volume Device input - -c, --create Create HeFS volume + -c, --create Create OpenHeFS volume -x, --xml Pass PropertyList to volume creation tool. -t, --time Time to run the script -d, --day Day of the week (e.g., Mon, Tue, Wed) diff --git a/tools/fsck.hefs.cc b/tools/fsck.hefs.cc index df89bf07..a2162a4f 100644 --- a/tools/fsck.hefs.cc +++ b/tools/fsck.hefs.cc @@ -4,7 +4,7 @@ ------------------------------------------- */ -#include +#include #include #include #include @@ -26,7 +26,7 @@ int main(int argc, char** argv) { auto origin = mkfs::get_option(args, "-org"); if (opt_disk.empty()) { - mkfs::console_out() << "fsck: hefs: error: HeFS partition is empty! Exiting..." + mkfs::console_out() << "fsck: hefs: error: OpenHeFS partition is empty! Exiting..." << "\n"; return EXIT_FAILURE; } @@ -59,16 +59,16 @@ int main(int argc, char** argv) { if (strncmp(boot_node.magic, kHeFSMagic, kHeFSMagicLen) != 0 || boot_node.sectorCount < 1 || boot_node.sectorSize < kMkFsSectorSz) { - mkfs::console_out() << "hefs: error: Device is not an HeFS disk: " << opt_disk << "\n"; + mkfs::console_out() << "hefs: error: Device is not an OpenHeFS disk: " << opt_disk << "\n"; return EXIT_FAILURE; } if (boot_node.badSectors > kMkFsMaxBadSectors) { - mkfs::console_out() << "hefs: error: HeFS disk has too much bad sectors: " << opt_disk << "\n"; + mkfs::console_out() << "hefs: error: OpenHeFS disk has too much bad sectors: " << opt_disk << "\n"; return EXIT_FAILURE; } - mkfs::console_out() << "hefs: HeFS partition is healthy, exiting...\n"; + mkfs::console_out() << "hefs: OpenHeFS partition is healthy, exiting...\n"; output_device.close(); diff --git a/tools/libmkfs/hefs.h b/tools/libmkfs/hefs.h deleted file mode 100644 index 52bb3086..00000000 --- a/tools/libmkfs/hefs.h +++ /dev/null @@ -1,116 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#pragma once - -#include -#include - -#define kHeFSVersion (0x0101) -#define kHeFSMagic " HeFS" -#define kHeFSMagicLen (8) - -#define kHeFSFileNameLen (256U) -#define kHeFSPartNameLen (128U) - -#define kHeFSDefaultVolumeName u8"HeFS Volume" - -namespace mkfs::hefs { - -// Drive kinds -enum { - kHeFSHardDrive = 0xC0, // Hard Drive - kHeFSSolidStateDrive = 0xC1, // Solid State Drive - kHeFSOpticalDrive = 0x0C, // Blu-Ray/DVD - kHeFSMassStorageDevice = 0xCC, // USB - kHeFSScsiDrive = 0xC4, // SCSI Hard Drive - kHeFSFlashDrive = 0xC6, - kHeFSUnknown = 0xFF, // Unknown device. - kHeFSDriveCount = 8, -}; - -// Disk status -enum { - kHeFSStatusUnlocked = 0x18, - kHeFSStatusLocked, - kHeFSStatusError, - kHeFSStatusInvalid, - kHeFSStatusCount, -}; - -// Encodings -enum { - kHeFSEncodingFlagsUTF8 = 0x50, - kHeFSEncodingFlagsUTF16, - kHeFSEncodingFlagsUTF32, - kHeFSEncodingFlagsUTF16BE, - kHeFSEncodingFlagsUTF16LE, - kHeFSEncodingFlagsUTF32BE, - kHeFSEncodingFlagsUTF32LE, - kHeFSEncodingFlagsUTF8BE, - kHeFSEncodingFlagsUTF8LE, - kHeFSEncodingFlagsBinary, - kHeFSEncodingFlagsCount = 11, - kHeFSFlagsNone = 0, - kHeFSFlagsReadOnly = 0x100, - kHeFSFlagsHidden, - kHeFSFlagsSystem, - kHeFSFlagsArchive, - kHeFSFlagsDevice, - kHeFSFlagsCount = 7 -}; - -// Time type -using ATime = std::uint64_t; - -// File kinds -inline constexpr uint16_t kHeFSFileKindRegular = 0x00; -inline constexpr uint16_t kHeFSFileKindDirectory = 0x01; -inline constexpr uint16_t kHeFSFileKindBlock = 0x02; -inline constexpr uint16_t kHeFSFileKindCharacter = 0x03; -inline constexpr uint16_t kHeFSFileKindFIFO = 0x04; -inline constexpr uint16_t kHeFSFileKindSocket = 0x05; -inline constexpr uint16_t kHeFSFileKindSymbolicLink = 0x06; -inline constexpr uint16_t kHeFSFileKindUnknown = 0x07; -inline constexpr uint16_t kHeFSFileKindCount = 0x08; - -// Red-black tree colors -enum { - kHeFSInvalidColor = 0, - kHeFSRed = 100, - kHeFSBlack, - kHeFSColorCount, -}; - -// Time constants -inline constexpr ATime kHeFSTimeInvalid = 0x0000000000000000; -inline constexpr ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF - 1; - -// Boot Node -struct __attribute__((packed)) BootNode { - char magic[kHeFSMagicLen]{}; - char8_t volumeName[kHeFSPartNameLen]{}; - std::uint32_t version{}; - std::uint64_t badSectors{}; - std::uint64_t sectorCount{}; - std::uint64_t sectorSize{}; - std::uint32_t checksum{}; - std::uint8_t diskKind{}; - std::uint8_t encoding{}; - std::uint64_t startIND{}; - std::uint64_t endIND{}; - std::uint64_t indCount{}; - std::uint64_t diskSize{}; - std::uint16_t diskStatus{}; - std::uint16_t diskFlags{}; - std::uint16_t vid{}; - std::uint64_t startIN{}; - std::uint64_t endIN{}; - std::uint64_t startBlock{}; - std::uint64_t endBlock{}; - char pad[272]{}; -}; -} // namespace mkfs::hefs diff --git a/tools/libmkfs/openhefs.h b/tools/libmkfs/openhefs.h new file mode 100644 index 00000000..3bba79e8 --- /dev/null +++ b/tools/libmkfs/openhefs.h @@ -0,0 +1,116 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include +#include + +#define kHeFSVersion (0x0101) +#define kHeFSMagic " HeFS" +#define kHeFSMagicLen (8) + +#define kHeFSFileNameLen (256U) +#define kHeFSPartNameLen (128U) + +#define kHeFSDefaultVolumeName u8"OpenHeFS Volume" + +namespace mkfs::hefs { + +// Drive kinds +enum { + kHeFSHardDrive = 0xC0, // Hard Drive + kHeFSSolidStateDrive = 0xC1, // Solid State Drive + kHeFSOpticalDrive = 0x0C, // Blu-Ray/DVD + kHeFSMassStorageDevice = 0xCC, // USB + kHeFSScsiDrive = 0xC4, // SCSI Hard Drive + kHeFSFlashDrive = 0xC6, + kHeFSUnknown = 0xFF, // Unknown device. + kHeFSDriveCount = 8, +}; + +// Disk status +enum { + kHeFSStatusUnlocked = 0x18, + kHeFSStatusLocked, + kHeFSStatusError, + kHeFSStatusInvalid, + kHeFSStatusCount, +}; + +// Encodings +enum { + kHeFSEncodingFlagsUTF8 = 0x50, + kHeFSEncodingFlagsUTF16, + kHeFSEncodingFlagsUTF32, + kHeFSEncodingFlagsUTF16BE, + kHeFSEncodingFlagsUTF16LE, + kHeFSEncodingFlagsUTF32BE, + kHeFSEncodingFlagsUTF32LE, + kHeFSEncodingFlagsUTF8BE, + kHeFSEncodingFlagsUTF8LE, + kHeFSEncodingFlagsBinary, + kHeFSEncodingFlagsCount = 11, + kHeFSFlagsNone = 0, + kHeFSFlagsReadOnly = 0x100, + kHeFSFlagsHidden, + kHeFSFlagsSystem, + kHeFSFlagsArchive, + kHeFSFlagsDevice, + kHeFSFlagsCount = 7 +}; + +// Time type +using ATime = std::uint64_t; + +// File kinds +inline constexpr uint16_t kHeFSFileKindRegular = 0x00; +inline constexpr uint16_t kHeFSFileKindDirectory = 0x01; +inline constexpr uint16_t kHeFSFileKindBlock = 0x02; +inline constexpr uint16_t kHeFSFileKindCharacter = 0x03; +inline constexpr uint16_t kHeFSFileKindFIFO = 0x04; +inline constexpr uint16_t kHeFSFileKindSocket = 0x05; +inline constexpr uint16_t kHeFSFileKindSymbolicLink = 0x06; +inline constexpr uint16_t kHeFSFileKindUnknown = 0x07; +inline constexpr uint16_t kHeFSFileKindCount = 0x08; + +// Red-black tree colors +enum { + kHeFSInvalidColor = 0, + kHeFSRed = 100, + kHeFSBlack, + kHeFSColorCount, +}; + +// Time constants +inline constexpr ATime kHeFSTimeInvalid = 0x0000000000000000; +inline constexpr ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF - 1; + +// Boot Node +struct __attribute__((packed)) BootNode { + char magic[kHeFSMagicLen]{}; + char8_t volumeName[kHeFSPartNameLen]{}; + std::uint32_t version{}; + std::uint64_t badSectors{}; + std::uint64_t sectorCount{}; + std::uint64_t sectorSize{}; + std::uint32_t checksum{}; + std::uint8_t diskKind{}; + std::uint8_t encoding{}; + std::uint64_t startIND{}; + std::uint64_t endIND{}; + std::uint64_t indCount{}; + std::uint64_t diskSize{}; + std::uint16_t diskStatus{}; + std::uint16_t diskFlags{}; + std::uint16_t vid{}; + std::uint64_t startIN{}; + std::uint64_t endIN{}; + std::uint64_t startBlock{}; + std::uint64_t endBlock{}; + char pad[272]{}; +}; +} // namespace mkfs::hefs diff --git a/tools/mkfs.hefs.cc b/tools/mkfs.hefs.cc index 9f70b78f..d1139e10 100644 --- a/tools/mkfs.hefs.cc +++ b/tools/mkfs.hefs.cc @@ -4,7 +4,7 @@ ------------------------------------------- */ -#include +#include #include #include #include -- cgit v1.2.3