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 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'dev/kernel/NeKit') 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_ -- 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/NeKit') 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/NeKit') 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 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/NeKit') 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/NeKit') 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 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/NeKit') 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/NeKit') 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