From ee64ca1014ee2bdf07bd5011f6aa9f77da104a4d Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sat, 4 Oct 2025 02:47:12 +0200 Subject: feat: kernel: new `kernel` process type, and usage of `explicit operator bool` feat: libSystem: minor tweaks. feat: indexer: important fixes in `RemoveFlag` Signed-off-by: Amlal El Mahrouss --- dev/libSystem/SystemKit/Verify.h | 4 +- dev/libSystem/src/System.cc | 193 --------------------------------------- dev/libSystem/src/SystemCalls.cc | 193 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 195 deletions(-) delete mode 100644 dev/libSystem/src/System.cc create mode 100644 dev/libSystem/src/SystemCalls.cc (limited to 'dev/libSystem') diff --git a/dev/libSystem/SystemKit/Verify.h b/dev/libSystem/SystemKit/Verify.h index cbf85830..5ad0dbff 100644 --- a/dev/libSystem/SystemKit/Verify.h +++ b/dev/libSystem/SystemKit/Verify.h @@ -11,7 +11,7 @@ #include -namespace LibSystem::Detail { +namespace LibSystem::Verify { /// @author 0xf00sec, and Amlal El Mahrouss /// @brief safe cast operator. template @@ -34,7 +34,7 @@ struct must_cast_traits { /// @brief Safe constexpr cast. template inline constexpr R* sys_constexpr_cast(T* ptr) { - static_assert(must_cast_traits::value, "constexpr cast failed! types are a mismatch!"); + static_assert(must_cast_traits::value, "constexpr cast failed! types are mismatching!"); return static_cast(ptr); } } // namespace LibSystem::Detail diff --git a/dev/libSystem/src/System.cc b/dev/libSystem/src/System.cc deleted file mode 100644 index da9931fe..00000000 --- a/dev/libSystem/src/System.cc +++ /dev/null @@ -1,193 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#include -#include -#include -#include - -using namespace LibSystem; - -IMPORT_C Void _rtl_assert(Bool expr, const Char* origin) { - if (!expr) { - PrintOut(nullptr, "Assertion failed: %s\r", origin); - libsys_syscall_arg_1(SYSCALL_HASH("_rtl_debug_break")); - } -} - -/// @note this uses the FNV 64-bit variant. -IMPORT_C UInt64 libsys_hash_64(const Char* path) { - if (!path || *path == 0) return 0; - - const UInt64 kFNVSeed = 0xcbf29ce484222325ULL; - const UInt64 kFNVPrime = 0x100000001b3ULL; - - UInt64 hash = kFNVSeed; - - while (*path) { - hash ^= (Char) (*path++); - hash *= kFNVPrime; - } - - return hash; -} - -IMPORT_C Char* StrFmt(const Char* fmt, ...) { - if (!fmt || *fmt == 0) return const_cast("(null)"); - - return const_cast(""); -} - -// memmove-style copy -IMPORT_C VoidPtr MmCopyMemory(_Input VoidPtr dest, _Input VoidPtr src, _Input SizeT len) { - // handles overlap, prefers 64-bit word copies when aligned - if (!len || !dest || !src) return nullptr; - - auto s = static_cast(src); - auto d = static_cast(dest); - - if (d == s) return dest; - - // decide direction - if (d > s && d < s + len) { - const UInt8* rs = s + len; - UInt8* rd = d + len; - - // try 64-bit aligned backward copy - if (len >= sizeof(UInt64) && (reinterpret_cast(rs) % sizeof(UInt64) == 0) && - (reinterpret_cast(rd) % sizeof(UInt64) == 0)) { - auto rsw = reinterpret_cast(rs); - auto rdw = reinterpret_cast(rd); - - SizeT words = len / sizeof(UInt64); - - for (SizeT i = 0; i < words; ++i) { - rdw[-1 - static_cast(i)] = rsw[-1 - static_cast(i)]; - } - - SizeT rem = len % sizeof(UInt64); - for (SizeT i = 0; i < rem; ++i) { - rd[-1 - i] = rs[-1 - i]; - } - } else { - // byte-wise backward - for (SizeT i = 0; i < len; ++i) { - rd[-1 - i] = rs[-1 - i]; - } - } - } else { - // try 64-bit aligned forward copy - if (len >= sizeof(UInt64) && (reinterpret_cast(s) % sizeof(UInt64) == 0) && - (reinterpret_cast(d) % sizeof(UInt64) == 0)) { - auto sw = reinterpret_cast(s); - auto dw = reinterpret_cast(d); - SizeT words = len / sizeof(UInt64); - - for (SizeT i = 0; i < words; ++i) { - dw[i] = sw[i]; - } - - SizeT rem = len % sizeof(UInt64); - const SizeT offset = words * sizeof(UInt64); - for (SizeT i = 0; i < rem; ++i) { - d[offset + i] = s[offset + i]; - } - } else { - for (SizeT i = 0; i < len; ++i) { - d[i] = s[i]; - } - } - } - - return dest; -} - -IMPORT_C SInt64 MmStrLen(const Char* in) { - // strlen via pointer walk - if (!in) return -kErrorInvalidData; - - const Char* p = in; - while (*p) ++p; - - return static_cast(p - in); -} - -IMPORT_C VoidPtr MmFillMemory(_Input VoidPtr dest, _Input SizeT len, _Input UInt8 value) { - if (!len || !dest) return nullptr; - - auto d = static_cast(dest); - - if (len >= sizeof(UInt64) && (reinterpret_cast(d) % sizeof(UInt64)) == 0) { - UInt64 pattern = static_cast(value); - pattern |= (pattern << 8); - pattern |= (pattern << 16); - pattern |= (pattern << 32); - - auto dw = reinterpret_cast(d); - SizeT words = len / sizeof(UInt64); - - for (SizeT i = 0; i < words; ++i) { - dw[i] = pattern; - } - - SizeT rem = len % sizeof(UInt64); - const SizeT offset = words * sizeof(UInt64); - for (SizeT i = 0; i < rem; ++i) { - d[offset + i] = value; - } - } else { - for (SizeT i = 0; i < len; ++i) d[i] = value; - } - - return dest; -} - -IMPORT_C Ref IoOpenFile(_Input const Char* path, _Input const Char* drv_letter) { - return static_cast(libsys_syscall_arg_3( - SYSCALL_HASH("IoOpenFile"), Detail::sys_safe_cast(path), Detail::sys_safe_cast(drv_letter))); -} - -IMPORT_C Void IoCloseFile(_Input Ref desc) { - libsys_syscall_arg_2(SYSCALL_HASH("IoCloseFile"), static_cast(desc)); -} - -IMPORT_C UInt64 IoSeekFile(_Input Ref desc, _Input UInt64 off) { - auto ret_ptr = libsys_syscall_arg_3(SYSCALL_HASH("IoSeekFile"), static_cast(desc), - reinterpret_cast(&off)); - - if (!ret_ptr) return ~0UL; - - auto ret = static_cast(ret_ptr); - UInt64 result = *ret; - MUST_PASS(result != ~0UL); - return result; -} - -IMPORT_C UInt64 IoTellFile(_Input Ref desc) { - auto ret_ptr = libsys_syscall_arg_2(SYSCALL_HASH("IoTellFile"), static_cast(desc)); - if (!ret_ptr) return ~0UL; - auto ret = static_cast(ret_ptr); - return *ret; -} - -IMPORT_C SInt32 PrintOut(_Input IORef desc, const Char* fmt, ...) { - va_list args; - va_start(args, fmt); - - auto buf = StrFmt(fmt, args); - - va_end(args); - - // if truncated, `needed` >= kBufferSz; we still send truncated buffer - auto ret_ptr = libsys_syscall_arg_3(SYSCALL_HASH("PrintOut"), static_cast(desc), - Detail::sys_safe_cast(buf)); - - if (!ret_ptr) return -kErrorInvalidData; - - auto ret = static_cast(ret_ptr); - - return *ret; -} diff --git a/dev/libSystem/src/SystemCalls.cc b/dev/libSystem/src/SystemCalls.cc new file mode 100644 index 00000000..571a99a6 --- /dev/null +++ b/dev/libSystem/src/SystemCalls.cc @@ -0,0 +1,193 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include +#include +#include +#include + +using namespace LibSystem; + +IMPORT_C Void _rtl_assert(Bool expr, const Char* origin) { + if (!expr) { + PrintOut(nullptr, "Assertion failed: %s\r", origin); + libsys_syscall_arg_1(SYSCALL_HASH("_rtl_debug_break")); + } +} + +/// @note this uses the FNV 64-bit variant. +IMPORT_C UInt64 libsys_hash_64(const Char* path) { + if (!path || *path == 0) return 0; + + const UInt64 kFNVSeed = 0xcbf29ce484222325ULL; + const UInt64 kFNVPrime = 0x100000001b3ULL; + + UInt64 hash = kFNVSeed; + + while (*path) { + hash ^= (Char) (*path++); + hash *= kFNVPrime; + } + + return hash; +} + +IMPORT_C Char* StrFmt(const Char* fmt, ...) { + if (!fmt || *fmt == 0) return const_cast("(null)"); + + return const_cast(""); +} + +// memmove-style copy +IMPORT_C VoidPtr MmCopyMemory(_Input VoidPtr dest, _Input VoidPtr src, _Input SizeT len) { + // handles overlap, prefers 64-bit word copies when aligned + if (!len || !dest || !src) return nullptr; + + auto s = static_cast(src); + auto d = static_cast(dest); + + if (d == s) return dest; + + // decide direction + if (d > s && d < s + len) { + const UInt8* rs = s + len; + UInt8* rd = d + len; + + // try 64-bit aligned backward copy + if (len >= sizeof(UInt64) && (reinterpret_cast(rs) % sizeof(UInt64) == 0) && + (reinterpret_cast(rd) % sizeof(UInt64) == 0)) { + auto rsw = reinterpret_cast(rs); + auto rdw = reinterpret_cast(rd); + + SizeT words = len / sizeof(UInt64); + + for (SizeT i = 0; i < words; ++i) { + rdw[-1 - static_cast(i)] = rsw[-1 - static_cast(i)]; + } + + SizeT rem = len % sizeof(UInt64); + for (SizeT i = 0; i < rem; ++i) { + rd[-1 - i] = rs[-1 - i]; + } + } else { + // byte-wise backward + for (SizeT i = 0; i < len; ++i) { + rd[-1 - i] = rs[-1 - i]; + } + } + } else { + // try 64-bit aligned forward copy + if (len >= sizeof(UInt64) && (reinterpret_cast(s) % sizeof(UInt64) == 0) && + (reinterpret_cast(d) % sizeof(UInt64) == 0)) { + auto sw = reinterpret_cast(s); + auto dw = reinterpret_cast(d); + SizeT words = len / sizeof(UInt64); + + for (SizeT i = 0; i < words; ++i) { + dw[i] = sw[i]; + } + + SizeT rem = len % sizeof(UInt64); + const SizeT offset = words * sizeof(UInt64); + for (SizeT i = 0; i < rem; ++i) { + d[offset + i] = s[offset + i]; + } + } else { + for (SizeT i = 0; i < len; ++i) { + d[i] = s[i]; + } + } + } + + return dest; +} + +IMPORT_C SInt64 MmStrLen(const Char* in) { + // strlen via pointer walk + if (!in) return -kErrorInvalidData; + + const Char* p = in; + while (*p) ++p; + + return static_cast(p - in); +} + +IMPORT_C VoidPtr MmFillMemory(_Input VoidPtr dest, _Input SizeT len, _Input UInt8 value) { + if (!len || !dest) return nullptr; + + auto d = static_cast(dest); + + if (len >= sizeof(UInt64) && (reinterpret_cast(d) % sizeof(UInt64)) == 0) { + UInt64 pattern = static_cast(value); + pattern |= (pattern << 8); + pattern |= (pattern << 16); + pattern |= (pattern << 32); + + auto dw = reinterpret_cast(d); + SizeT words = len / sizeof(UInt64); + + for (SizeT i = 0; i < words; ++i) { + dw[i] = pattern; + } + + SizeT rem = len % sizeof(UInt64); + const SizeT offset = words * sizeof(UInt64); + for (SizeT i = 0; i < rem; ++i) { + d[offset + i] = value; + } + } else { + for (SizeT i = 0; i < len; ++i) d[i] = value; + } + + return dest; +} + +IMPORT_C Ref IoOpenFile(_Input const Char* path, _Input const Char* drv_letter) { + return static_cast(libsys_syscall_arg_3( + SYSCALL_HASH("IoOpenFile"), Verify::sys_safe_cast(path), Verify::sys_safe_cast(drv_letter))); +} + +IMPORT_C Void IoCloseFile(_Input Ref desc) { + libsys_syscall_arg_2(SYSCALL_HASH("IoCloseFile"), static_cast(desc)); +} + +IMPORT_C UInt64 IoSeekFile(_Input Ref desc, _Input UInt64 off) { + auto ret_ptr = libsys_syscall_arg_3(SYSCALL_HASH("IoSeekFile"), static_cast(desc), + reinterpret_cast(&off)); + + if (!ret_ptr) return ~0UL; + + auto ret = static_cast(ret_ptr); + UInt64 result = *ret; + MUST_PASS(result != ~0UL); + return result; +} + +IMPORT_C UInt64 IoTellFile(_Input Ref desc) { + auto ret_ptr = libsys_syscall_arg_2(SYSCALL_HASH("IoTellFile"), static_cast(desc)); + if (!ret_ptr) return ~0UL; + auto ret = static_cast(ret_ptr); + return *ret; +} + +IMPORT_C SInt32 PrintOut(_Input IORef desc, const Char* fmt, ...) { + va_list args; + va_start(args, fmt); + + auto buf = StrFmt(fmt, args); + + va_end(args); + + // if truncated, `needed` >= kBufferSz; we still send truncated buffer + auto ret_ptr = libsys_syscall_arg_3(SYSCALL_HASH("PrintOut"), static_cast(desc), + Verify::sys_safe_cast(buf)); + + if (!ret_ptr) return -kErrorInvalidData; + + auto ret = static_cast(ret_ptr); + + return *ret; +} -- 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/libSystem') 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 4afdeade47b4295e49b9d65ae26fa218e2fd81dd Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Wed, 8 Oct 2025 21:50:05 +0200 Subject: feat: libSystem: new version of libSystem. --- dev/libSystem/src/JailCalls.cc | 17 +++++++ dev/libSystem/src/Makefile | 6 +-- dev/libSystem/src/SystemCalls.cc | 7 --- dev/libSystem/src/SystemCallsABI+AMD64.asm | 81 ++++++++++++++++++++++++++++++ dev/libSystem/src/SystemProc.asm | 81 ------------------------------ dev/libSystem/src/VerifyCalls.cc | 17 +++++++ 6 files changed, 118 insertions(+), 91 deletions(-) create mode 100644 dev/libSystem/src/JailCalls.cc create mode 100644 dev/libSystem/src/SystemCallsABI+AMD64.asm delete mode 100644 dev/libSystem/src/SystemProc.asm create mode 100644 dev/libSystem/src/VerifyCalls.cc (limited to 'dev/libSystem') diff --git a/dev/libSystem/src/JailCalls.cc b/dev/libSystem/src/JailCalls.cc new file mode 100644 index 00000000..32192a13 --- /dev/null +++ b/dev/libSystem/src/JailCalls.cc @@ -0,0 +1,17 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include +#include +#include +#include +#include + +using namespace LibSystem; + +IMPORT_C struct JAIL* JailGetCurrent(Void) { + (struct JAIL*)libsys_syscall_arg_1(SYSCALL_HASH("JailGetCurrent")); +} \ No newline at end of file diff --git a/dev/libSystem/src/Makefile b/dev/libSystem/src/Makefile index 64ef02cc..ea8e9905 100644 --- a/dev/libSystem/src/Makefile +++ b/dev/libSystem/src/Makefile @@ -1,5 +1,5 @@ ################################################## -# (c) Amlal El Mahrouss, all rights reserved. +# (c) Amlal El Mahrouss and NeKernel contributors, all rights reserved. # This file is for libSystem.dll's syscall stubs. ################################################## @@ -8,9 +8,9 @@ FLAGS=-f win64 .PHONY: error error: - @echo "==> Invalid rule." + @echo "==> Invalid recipe." @echo "==> Use libsys_asm_io_ instead." .PHONY: libsys_asm_io_x64 libsys_asm_io_x64: - $(ASM) $(FLAGS) SystemProc.asm -o SystemProc.stub.obj + $(ASM) $(FLAGS) SystemCallsABI+AMD64.asm -o SystemCallsABI+AMD64.stub.obj diff --git a/dev/libSystem/src/SystemCalls.cc b/dev/libSystem/src/SystemCalls.cc index 571a99a6..3db9368d 100644 --- a/dev/libSystem/src/SystemCalls.cc +++ b/dev/libSystem/src/SystemCalls.cc @@ -11,13 +11,6 @@ using namespace LibSystem; -IMPORT_C Void _rtl_assert(Bool expr, const Char* origin) { - if (!expr) { - PrintOut(nullptr, "Assertion failed: %s\r", origin); - libsys_syscall_arg_1(SYSCALL_HASH("_rtl_debug_break")); - } -} - /// @note this uses the FNV 64-bit variant. IMPORT_C UInt64 libsys_hash_64(const Char* path) { if (!path || *path == 0) return 0; diff --git a/dev/libSystem/src/SystemCallsABI+AMD64.asm b/dev/libSystem/src/SystemCallsABI+AMD64.asm new file mode 100644 index 00000000..da19f41f --- /dev/null +++ b/dev/libSystem/src/SystemCallsABI+AMD64.asm @@ -0,0 +1,81 @@ +;; /* +;; * ======================================================== +;; * +;; * libSystem/src/SystemCallsABI+AMD64.asm +;; * Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. +;; * +;; * ======================================================== +;; */ + +[bits 64] + +section .text + +global libsys_syscall_arg_1 +global libsys_syscall_arg_2 +global libsys_syscall_arg_3 +global libsys_syscall_arg_4 + +libsys_syscall_arg_1: + push rbp + mov rbp, rsp + + mov r8, rcx + + xor rax, rax + + syscall + + pop rbp + + ret + +libsys_syscall_arg_2: + push rbp + mov rbp, rsp + + mov r8, rcx + mov r9, rdx + + xor rax, rax + + syscall + + pop rbp + + ret + +libsys_syscall_arg_3: + push rbp + mov rbp, rsp + + mov r8, rcx + mov r9, rdx + mov r10, rbx + + xor rax, rax + + syscall + + pop rbp + + ret + +libsys_syscall_arg_4: + push rbp + mov rbp, rsp + + mov rax, r8 + + mov r8, rcx + mov r9, rdx + mov r10, rbx + mov r11, rax + + xor rax, rax + + syscall + + pop rbp + + ret diff --git a/dev/libSystem/src/SystemProc.asm b/dev/libSystem/src/SystemProc.asm deleted file mode 100644 index 991a371f..00000000 --- a/dev/libSystem/src/SystemProc.asm +++ /dev/null @@ -1,81 +0,0 @@ -;; /* -;; * ======================================================== -;; * -;; * libSystem/src/SystemProc.asm -;; * Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. -;; * -;; * ======================================================== -;; */ - -[bits 64] - -section .text - -global libsys_syscall_arg_1 -global libsys_syscall_arg_2 -global libsys_syscall_arg_3 -global libsys_syscall_arg_4 - -libsys_syscall_arg_1: - push rbp - mov rbp, rsp - - mov r8, rcx - - xor rax, rax - - syscall - - pop rbp - - ret - -libsys_syscall_arg_2: - push rbp - mov rbp, rsp - - mov r8, rcx - mov r9, rdx - - xor rax, rax - - syscall - - pop rbp - - ret - -libsys_syscall_arg_3: - push rbp - mov rbp, rsp - - mov r8, rcx - mov r9, rdx - mov r10, rbx - - xor rax, rax - - syscall - - pop rbp - - ret - -libsys_syscall_arg_4: - push rbp - mov rbp, rsp - - mov rax, r8 - - mov r8, rcx - mov r9, rdx - mov r10, rbx - mov r11, rax - - xor rax, rax - - syscall - - pop rbp - - ret diff --git a/dev/libSystem/src/VerifyCalls.cc b/dev/libSystem/src/VerifyCalls.cc new file mode 100644 index 00000000..fb38c682 --- /dev/null +++ b/dev/libSystem/src/VerifyCalls.cc @@ -0,0 +1,17 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include +#include + +using namespace LibSystem; + +IMPORT_C Void _rtl_assert(Bool expr, const Char* origin) { + if (!expr) { + PrintOut(nullptr, "Assertion failed: %s\r", origin); + libsys_syscall_arg_1(SYSCALL_HASH("_rtl_debug_break")); + } +} \ No newline at end of file -- cgit v1.2.3 From bcc74b466240a3df8a4750e2a5a60a3748d6b3d7 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Wed, 8 Oct 2025 21:51:20 +0200 Subject: fix: libSystem: return JAIL correctly and fix missing macro in JailCalls.cc Signed-off-by: Amlal El Mahrouss --- dev/libSystem/src/JailCalls.cc | 2 +- dev/libSystem/src/VerifyCalls.cc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'dev/libSystem') diff --git a/dev/libSystem/src/JailCalls.cc b/dev/libSystem/src/JailCalls.cc index 32192a13..85796e9f 100644 --- a/dev/libSystem/src/JailCalls.cc +++ b/dev/libSystem/src/JailCalls.cc @@ -13,5 +13,5 @@ using namespace LibSystem; IMPORT_C struct JAIL* JailGetCurrent(Void) { - (struct JAIL*)libsys_syscall_arg_1(SYSCALL_HASH("JailGetCurrent")); + return (struct JAIL*)libsys_syscall_arg_1(SYSCALL_HASH("JailGetCurrent")); } \ No newline at end of file diff --git a/dev/libSystem/src/VerifyCalls.cc b/dev/libSystem/src/VerifyCalls.cc index fb38c682..83617ae0 100644 --- a/dev/libSystem/src/VerifyCalls.cc +++ b/dev/libSystem/src/VerifyCalls.cc @@ -6,6 +6,7 @@ #include #include +#include using namespace LibSystem; -- cgit v1.2.3 From 212c57ea05bf918dc26fe8864ad617f2f6259cea Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Fri, 10 Oct 2025 10:30:38 +0200 Subject: feat: kernel: dispatch structures have two new methods. Signed-off-by: Amlal El Mahrouss --- dev/kernel/ArchKit/ArchKit.h | 6 ++++++ dev/kernel/CFKit/GUIDWrapper.h | 5 ++--- dev/kernel/src/UserMgr.cc | 2 +- dev/kernel/src/UserProcessScheduler.cc | 1 - dev/libSystem/src/JailCalls.cc | 4 ++-- dev/libSystem/src/VerifyCalls.cc | 2 +- 6 files changed, 12 insertions(+), 8 deletions(-) (limited to 'dev/libSystem') diff --git a/dev/kernel/ArchKit/ArchKit.h b/dev/kernel/ArchKit/ArchKit.h index 2042bded..9c45b6bb 100644 --- a/dev/kernel/ArchKit/ArchKit.h +++ b/dev/kernel/ArchKit/ArchKit.h @@ -75,6 +75,9 @@ struct HAL_DISPATCH_ENTRY final { Kernel::Bool fHooked; rt_syscall_proc fProc; + BOOL IsKernCall() { return NO; } + BOOL IsSysCall() { return YES; } + operator bool() { return fHooked; } }; @@ -86,6 +89,9 @@ struct HAL_KERNEL_DISPATCH_ENTRY final { Kernel::Bool fHooked; rt_kerncall_proc fProc; + BOOL IsKernCall() { return YES; } + BOOL IsSysCall() { return NO; } + operator bool() { return fHooked; } }; diff --git a/dev/kernel/CFKit/GUIDWrapper.h b/dev/kernel/CFKit/GUIDWrapper.h index 05cb4754..14a96fde 100644 --- a/dev/kernel/CFKit/GUIDWrapper.h +++ b/dev/kernel/CFKit/GUIDWrapper.h @@ -16,7 +16,7 @@ /// @brief eXtended Resource Namespace namespace Kernel::CF::XRN { -union GUIDSequence { +union GUIDSequence final { alignas(8) UShort fU8[16]; alignas(8) UShort fU16[8]; alignas(8) UInt fU32[4]; @@ -36,8 +36,7 @@ class GUID final { ~GUID() = default; public: - GUID& operator=(const GUID&) = default; - GUID(const GUID&) = default; + NE_COPY_DEFAULT(GUID) public: GUIDSequence& operator->() noexcept { return fUUID; } diff --git a/dev/kernel/src/UserMgr.cc b/dev/kernel/src/UserMgr.cc index 9db1ca4d..5ee2aa33 100644 --- a/dev/kernel/src/UserMgr.cc +++ b/dev/kernel/src/UserMgr.cc @@ -39,7 +39,7 @@ namespace Detail { kout << "user_fnv_generator: Hashing user password...\r"; const UInt64 kFnvOffsetBasis = 0xcbf29ce484222325ULL; - const UInt64 fFnvPrime = 0x100000001b3ULL; + const UInt64 fFnvPrime = 0x100000001b3ULL; UInt64 hash = kFnvOffsetBasis; diff --git a/dev/kernel/src/UserProcessScheduler.cc b/dev/kernel/src/UserProcessScheduler.cc index ad6263c8..af54799e 100644 --- a/dev/kernel/src/UserProcessScheduler.cc +++ b/dev/kernel/src/UserProcessScheduler.cc @@ -21,7 +21,6 @@ #include #include #include -#include #include ///! BUGS: 0 diff --git a/dev/libSystem/src/JailCalls.cc b/dev/libSystem/src/JailCalls.cc index 85796e9f..5cb47bb5 100644 --- a/dev/libSystem/src/JailCalls.cc +++ b/dev/libSystem/src/JailCalls.cc @@ -5,13 +5,13 @@ ------------------------------------------- */ #include +#include #include #include -#include #include using namespace LibSystem; IMPORT_C struct JAIL* JailGetCurrent(Void) { - return (struct JAIL*)libsys_syscall_arg_1(SYSCALL_HASH("JailGetCurrent")); + return (struct JAIL*) libsys_syscall_arg_1(SYSCALL_HASH("JailGetCurrent")); } \ No newline at end of file diff --git a/dev/libSystem/src/VerifyCalls.cc b/dev/libSystem/src/VerifyCalls.cc index 83617ae0..078f921b 100644 --- a/dev/libSystem/src/VerifyCalls.cc +++ b/dev/libSystem/src/VerifyCalls.cc @@ -5,8 +5,8 @@ ------------------------------------------- */ #include -#include #include +#include using namespace LibSystem; -- cgit v1.2.3 From b6ce6640afaf6c1cc6ad274f3053b2e218a49554 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sun, 26 Oct 2025 12:29:35 +0100 Subject: feat: refactor HeFS to OpenHeFS. Signed-off-by: Amlal El Mahrouss --- README.md | 4 +- dev/boot/src/docs/MKFS_HEFS.md | 8 +- dev/kernel/FSKit/HeFS.h | 434 -------- dev/kernel/FSKit/OpenHeFS.h | 434 ++++++++ dev/kernel/FirmwareKit/EPM.h | 2 +- dev/kernel/HALKit/AMD64/HalKernelMain.cc | 2 +- dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc | 8 +- dev/kernel/HALKit/AMD64/Storage/NVME+Generic.cc | 9 + dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc | 8 +- dev/kernel/KernelKit/DriveMgr.h | 8 +- dev/kernel/KernelKit/FileMgr.h | 6 +- dev/kernel/KernelKit/IFS.h | 4 +- dev/kernel/KernelKit/ILoader.h | 32 + dev/kernel/KernelKit/LoaderInterface.h | 32 - dev/kernel/KernelKit/PEF.h | 2 +- dev/kernel/KernelKit/PEFCodeMgr.h | 2 +- dev/kernel/KernelKit/UserMgr.h | 6 +- dev/kernel/KernelKit/ZXD.h | 4 +- dev/kernel/StorageKit/AHCI.h | 10 +- dev/kernel/StorageKit/ATA.h | 10 +- dev/kernel/StorageKit/NVME.h | 8 +- dev/kernel/src/FS/HeFS+FileMgr.cc | 191 ---- dev/kernel/src/FS/HeFS+FileSystemParser.cc | 1166 -------------------- dev/kernel/src/FS/NeFS+FileSystemParser.cc | 6 +- dev/kernel/src/FS/OpenHeFS+FileMgr.cc | 191 ++++ dev/kernel/src/FS/OpenHeFS+FileSystemParser.cc | 1166 ++++++++++++++++++++ dev/kernel/src/IFS.cc | 20 +- dev/kernel/src/Storage/AHCIDeviceInterface.cc | 14 +- dev/kernel/src/Storage/ATADeviceInterface.cc | 14 +- dev/kernel/src/Storage/NVMEDeviceInterface.cc | 4 +- dev/libSystem/SystemKit/System.h | 4 +- docs/tex/hefs.tex | 14 +- .../frameworks/DiskImage.fwrk/headers/DiskImage.h | 2 +- .../DiskImage.fwrk/src/DiskImage+HeFS.cc | 6 +- public/manuals/nekernel/mgmt.hefs.util.man | 6 +- tools/fsck.hefs.cc | 10 +- tools/libmkfs/hefs.h | 116 -- tools/libmkfs/openhefs.h | 116 ++ tools/mkfs.hefs.cc | 2 +- 39 files changed, 2045 insertions(+), 2036 deletions(-) delete mode 100644 dev/kernel/FSKit/HeFS.h create mode 100644 dev/kernel/FSKit/OpenHeFS.h create mode 100644 dev/kernel/HALKit/AMD64/Storage/NVME+Generic.cc create mode 100644 dev/kernel/KernelKit/ILoader.h delete mode 100644 dev/kernel/KernelKit/LoaderInterface.h delete mode 100644 dev/kernel/src/FS/HeFS+FileMgr.cc delete mode 100644 dev/kernel/src/FS/HeFS+FileSystemParser.cc create mode 100644 dev/kernel/src/FS/OpenHeFS+FileMgr.cc create mode 100644 dev/kernel/src/FS/OpenHeFS+FileSystemParser.cc delete mode 100644 tools/libmkfs/hefs.h create mode 100644 tools/libmkfs/openhefs.h (limited to 'dev/libSystem') diff --git a/README.md b/README.md index 299a4656..30495c8b 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ - **Modular Microkernel Architecture**: Clean separation of kernel, drivers, userland, and frameworks. -- **Custom Filesystems**: (HeFS), catalog/fork model (NeFS), and metadata handling. +- **Custom Filesystems**: (OpenHeFS), catalog/fork model (NeFS), and metadata handling. - **Memory Management**: Custom heap manager, page manager, and safe memory utilities. Kernel heap allocations are protected with metadata and CRCs. Userland and kernel memory separation. @@ -38,7 +38,7 @@ - **Security and Robustness**: kernel and tools (bounds checks, safe memory copy/set, error codes). Kernel panics and error reporting for critical failures. No dynamic code loading in kernel space. -- **Documentation and Specs**: Full LaTeX specifications for HeFS and NeFS, with on-disk structure diagrams and API documentation. Markdown docs for tools and usage. +- **Documentation and Specs**: Full LaTeX specifications for OpenHeFS and NeFS, with on-disk structure diagrams and API documentation. Markdown docs for tools and usage. - **Cross-Platform Boot Support**: Bootloader and platform code for AMD64 and ARM64, with handover and hardware abstraction layers. diff --git a/dev/boot/src/docs/MKFS_HEFS.md b/dev/boot/src/docs/MKFS_HEFS.md index c9aa0628..ac84d132 100644 --- a/dev/boot/src/docs/MKFS_HEFS.md +++ b/dev/boot/src/docs/MKFS_HEFS.md @@ -1,6 +1,6 @@ -# `mkfs.hefs` – HeFS Filesystem Formatter +# `mkfs.hefs` – OpenHeFS Filesystem Formatter -`mkfs.hefs` is a command-line utility used to format a block device or disk image with the **High-throughput Extended File System (HeFS)** used by NeKernel. This tool initializes a HeFS volume by writing a boot node and configuring directory and inode index regions, block ranges, and volume metadata. +`mkfs.hefs` is a command-line utility used to format a block device or disk image with the **High-throughput Extended File System (OpenHeFS)** used by NeKernel. This tool initializes a OpenHeFS volume by writing a boot node and configuring directory and inode index regions, block ranges, and volume metadata. --- @@ -61,7 +61,7 @@ -is 0x800000 -ie 0xA00000 \ -S 128 -o hefs.img -This will create a 128 GiB formatted HeFS image named `hefs.img` with specified region boundaries. +This will create a 128 GiB formatted OpenHeFS image named `hefs.img` with specified region boundaries. --- @@ -96,7 +96,7 @@ The `BootNode` stores key filesystem metadata: ## 📚 Source Location -Part of the [HeFS Tooling module](https://github.com/nekernel-org/nekernel) and used during system setup or disk preparation for NeKernel. +Part of the [OpenHeFS Tooling module](https://github.com/nekernel-org/nekernel) and used during system setup or disk preparation for NeKernel. --- diff --git a/dev/kernel/FSKit/HeFS.h b/dev/kernel/FSKit/HeFS.h deleted file mode 100644 index 51ec7648..00000000 --- a/dev/kernel/FSKit/HeFS.h +++ /dev/null @@ -1,434 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -/// @file HeFS.h -/// @brief HeFS filesystem support. - -#define kHeFSVersion (0x0103) -#define kHeFSMagic " HeFS" -#define kHeFSMagicLen (8) - -#define kHeFSBlockLen (512U) -#define kHeFSFileNameLen (256U) -#define kHeFSPartNameLen (128U) - -#define kHeFSMinimumDiskSize (gib_cast(128)) - -#define kHeFSDefaultVolumeName u8"HeFS Volume" - -#define kHeFSINDStartOffset (sizeof(HEFS_BOOT_NODE)) -#define kHeFSINStartOffset (sizeof(HEFS_INDEX_NODE_DIRECTORY)) - -#define kHeFSRootDirectory "/" -#define kHeFSRootDirectoryU8 u8"/" - -#define kHeFSSeparator '/' -#define kHeFSUpDir ".." - -#define kHeFSRootDirectoryLen (2U) - -#define kHeFSSearchAllStr u8"*" - -struct HEFS_BOOT_NODE; -struct HEFS_INDEX_NODE; -struct HEFS_INDEX_NODE_DIRECTORY; -struct HEFS_JOURNAL_NODE; - -enum : UInt8 { - kHeFSHardDrive = 0xC0, // Hard Drive - kHeFSSolidStateDrive = 0xC1, // Solid State Drive - kHeFSOpticalDrive = 0x0C, // Blu-Ray/DVD - kHeFSMassStorageDevice = 0xCC, // USB - kHeFSScsiDrive = 0xC4, // SCSI Hard Drive - kHeFSFlashDrive = 0xC6, - kHeFSUnknown = 0xFF, // Unknown device. - kHeFSDriveCount = 8, -}; - -enum : UInt8 { - kHeFSStatusUnlocked = 0x18, - kHeFSStatusLocked, - kHeFSStatusError, - kHeFSStatusInvalid, - kHeFSStatusCount, -}; - -enum : UInt16 { - kHeFSEncodingFlagsUTF8 = 0x50, - kHeFSEncodingFlagsUTF16, - kHeFSEncodingFlagsUTF32, - kHeFSEncodingFlagsUTF16BE, - kHeFSEncodingFlagsUTF16LE, - kHeFSEncodingFlagsUTF32BE, - kHeFSEncodingFlagsUTF32LE, - kHeFSEncodingFlagsUTF8BE, - kHeFSEncodingFlagsUTF8LE, - kHeFSEncodingFlagsBinary, - kHeFSEncodingFlagsCount = 11, - kHeFSFlagsNone = 0, - kHeFSFlagsReadOnly = 0x100, - kHeFSFlagsHidden, - kHeFSFlagsSystem, - kHeFSFlagsArchive, - kHeFSFlagsDevice, - kHeFSFlagsCount = 7 -}; - -inline constexpr UInt16 kHeFSFileKindRegular = 0x00; -inline constexpr UInt16 kHeFSFileKindDirectory = 0x01; -inline constexpr UInt16 kHeFSFileKindBlock = 0x02; -inline constexpr UInt16 kHeFSFileKindCharacter = 0x03; -inline constexpr UInt16 kHeFSFileKindFIFO = 0x04; -inline constexpr UInt16 kHeFSFileKindSocket = 0x05; -inline constexpr UInt16 kHeFSFileKindSymbolicLink = 0x06; -inline constexpr UInt16 kHeFSFileKindUnknown = 0x07; -inline constexpr UInt16 kHeFSFileKindCount = 0x08; - -/// @brief HeFS blocks are array containing sparse blocks of data. -/// @details The blocks are used to store the data of a file. Each block is a pointer to a block of -/// data on the disk. -inline constexpr UInt16 kHeFSSliceCount = 0x10; - -inline constexpr UInt16 kHeFSInvalidVID = 0xFFFF; - -namespace Kernel { -/// @brief Access time type. -/// @details Used to keep track of the INode, INodeDir allocation status. -typedef UInt64 ATime; - -/// @brief HeFS Boot node. -/// @details Acts like a superblock, it contains the information about the filesystem. -/// @note The boot node is the first block of the filesystem. -struct PACKED HEFS_BOOT_NODE final { - Char fMagic[kHeFSMagicLen]; /// @brief Magic number of the filesystem. - Utf8Char fVolName[kHeFSPartNameLen]; /// @brief Volume name. - UInt32 fVersion; /// @brief Version of the filesystem. - UInt64 fBadSectors; /// @brief Number of bad sectors in the filesystem. - UInt64 fSectorCount; /// @brief Number of sectors in the filesystem. - UInt64 fSectorSize; /// @brief Size of the sector. - UInt32 fChecksum; /// @brief Checksum of the boot node. - UInt8 fDiskKind; /// @brief Kind of the drive. (Hard Drive, Solid State Drive, Optical - /// Drive, etc). - UInt8 fEncoding; /// @brief Encoding of the filesystem. (UTF-8, UTF-16, etc). - UInt64 fStartIND; /// @brief Start of the INode directory tree. - UInt64 fEndIND; /// @brief End of the INode directory tree. - UInt64 fINDCount; /// @brief Number of leafs in the INode tree. - UInt64 fDiskSize; /// @brief Size of the disk. (Could be a virtual size, that is not the - /// real size of the disk.) - UInt16 fDiskStatus; /// @brief Status of the disk. (locked, unlocked, error, invalid). - UInt16 fDiskFlags; /// @brief Flags of the disk. (read-only, read-write, etc). - UInt16 fVID; /// @brief Virtual Identification Number within an EPM disk. (0xFFFF if not used). - UInt64 fStartIN; /// @brief Start INodes range - UInt64 fEndIN; /// @brief End INodes range - UInt64 fStartBlock; /// @brief Start Blocks range - UInt64 fEndBlock; /// @brief End Blocks range - UInt64 fJournalLBA; /// @brief Boot Node's COW journal LBA. - Char fPad[264]; -}; - -inline constexpr ATime kHeFSTimeInvalid = 0x0000000000000000; -inline constexpr ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF - 1; - -/// @brief Journal Node structure -/// @param fHashPath target hash path -/// @param fStatus target status -/// @param fCopyElem copy of element -/// @param fCopyKind kind of element -struct PACKED HEFS_JOURNAL_NODE { - UInt64 fHashPath; - UInt64 fStatus; - UInt64 fCopyElem; - UInt8 fCopyKind; - UInt8 fPad[487]; -}; - -/// @brief This enum defines the opcode of the journal, here mentioned as 'kinds' -enum HeFSJournalKind : UInt8 { - kJournalKindInvalid = 0x00, - kJournalKindWrite = 0x01, - kJournalKindRename = 0x02, - kJournalKindDelete = 0x03, - kJournalKindFlagEdit = 0x04, - kJournalKindCreate = 0x05, - kJournalKindCount, -}; - -/// @brief HeFS index node. -/// @details This structure is used to store the file information of a file. -/// @note The index node is a special type of INode that contains the file information. -/// @note The index node is used to store the file information of a file. -struct PACKED HEFS_INDEX_NODE final { - UInt64 fHashPath; /// @brief File name. - UInt32 fFlags; /// @brief File flags. - UInt16 fKind; /// @brief File kind. (Regular, Directory, Block, Character, FIFO, Socket, - /// Symbolic Link, Unknown). - UInt32 fSize; /// @brief File size. - UInt32 fChecksum; /// @brief Checksum. - - Boolean fSymLink; /// @brief Is this a symbolic link? (if yes, the fName is the path to - /// the file and blocklinkstart and end contains it's inodes.) - - ATime fCreated, fAccessed, fModified, fDeleted; /// @brief File timestamps. - UInt32 fUID, fGID; /// @brief User ID and Group ID of the file. - UInt32 fMode; /// @brief File mode. (read, write, execute, etc). - - /// @brief Extents system by using blocks - /// @details Using an offset to ask fBase, and fLength to compute each slice's length. - UInt32 fOffsetSliceLow; - UInt32 fOffsetSliceHigh; - - Char fPad[437]; -}; - -enum { - kHeFSInvalidColor = 0, - kHeFSRed = 100, - kHeFSBlack, - kHeFSColorCount, -}; - -/// @brief HeFS directory node. -/// @details This structure is used to store the directory information of a file. -/// @note The directory node is a special type of INode that contains the directory entries. -struct PACKED HEFS_INDEX_NODE_DIRECTORY final { - UInt64 fHashPath; /// @brief Directory path as FNV hash. - - UInt32 fFlags; /// @brief File flags. - UInt16 fReserved; /// @note Reserved for future use. - UInt32 fEntryCount; /// @brief Entry Count of this directory inode. - UInt32 fChecksum; /// @brief Checksum of the file, index node checksum. - - ATime fCreated, fAccessed, fModified, - fDeleted; /// @brief File timestamps and allocation status. - UInt32 fUID, fGID; /// @brief User ID and Group ID of the file. - UInt32 fMode; /// @brief File mode. (read, write, execute, etc). - - /// @note These slices are organized as: - /// [0] = OFFSET - /// [1] = SIZE - /// @note Thus the += 2 when iterating over them. - UInt64 fINSlices[kHeFSSliceCount]; /// @brief Start of the index node. - - UInt8 fColor; /// @brief Color of the node. (Red or Black). - Lba fNext, fPrev, fChild, fParent; /// @brief Red-black tree pointers. - - Char fPad[285]; -}; -} // namespace Kernel - -namespace Kernel::Detail { -/// @brief HeFS get year from ATime. -/// @param raw_atime the raw ATime value. -/// @return the year value. -/// @note The year is stored in the upper 32 bits of the ATime value. -inline UInt32 hefs_year_get(ATime raw_atime) noexcept { - return (raw_atime) >> 32; -} - -/// @brief HeFS get month from ATime. -/// @param raw_atime the raw ATime value. -/// @return the month value. -/// @note The month is stored in the upper 24 bits of the ATime value. -inline UInt32 hefs_month_get(ATime raw_atime) noexcept { - return (raw_atime) >> 24; -} - -/// @brief HeFS get day from ATime. -/// @param raw_atime the raw ATime value. -/// @return the day value. -/// @note The day is stored in the upper 16 bits of the ATime value. -inline UInt32 hefs_day_get(ATime raw_atime) noexcept { - return (raw_atime) >> 16; -} - -/// @brief HeFS get hour from ATime. -/// @param raw_atime the raw ATime value. -/// @return the hour value. -/// @note The hour is stored in the upper 8 bits of the ATime value. -inline UInt32 hefs_hour_get(ATime raw_atime) noexcept { - return (raw_atime) >> 8; -} - -/// @brief HeFS get minute from ATime. -/// @param raw_atime the raw ATime value. -/// @return the minute value. -/// @note The minute is stored in the lower 8 bits of the ATime value. -inline UInt32 hefs_minute_get(ATime raw_atime) noexcept { - return (raw_atime) &0xFF; -} - -inline constexpr UInt32 kHeFSBaseYear = 1970; -inline constexpr UInt32 kHeFSBaseMonth = 1; -inline constexpr UInt32 kHeFSBaseDay = 1; -inline constexpr UInt32 kHeFSBaseHour = 0; -inline constexpr UInt32 kHeFSBaseMinute = 0; - -inline const Char* hefs_status_to_string(UInt16 status) noexcept { - switch (status) { - case kHeFSStatusUnlocked: - return "Unlocked"; - case kHeFSStatusLocked: - return "Locked"; - case kHeFSStatusError: - return "Error"; - case kHeFSStatusInvalid: - return "Invalid"; - default: - return "Unknown"; - } -} - -inline const Char* hefs_drive_kind_to_string(UInt8 kind) noexcept { - switch (kind) { - case kHeFSHardDrive: - return "Hard Drive"; - case kHeFSSolidStateDrive: - return "Solid State Drive"; - case kHeFSOpticalDrive: - return "Optical Drive"; - case kHeFSMassStorageDevice: - return "Mass Storage Device"; - case kHeFSScsiDrive: - return "SCSI/SAS Drive"; - case kHeFSFlashDrive: - return "Flash Drive"; - case kHeFSUnknown: - default: - return "Unknown"; - } -} - -inline const Char* hefs_encoding_to_string(UInt8 encoding) noexcept { - switch (encoding) { - case kHeFSEncodingFlagsUTF8: - return "UTF-8"; - case kHeFSEncodingFlagsUTF16: - return "UTF-16"; - case kHeFSEncodingFlagsUTF32: - return "UTF-32"; - case kHeFSEncodingFlagsUTF16BE: - return "UTF-16BE"; - case kHeFSEncodingFlagsUTF16LE: - return "UTF-16LE"; - case kHeFSEncodingFlagsUTF32BE: - return "UTF-32BE"; - case kHeFSEncodingFlagsUTF32LE: - return "UTF-32LE"; - case kHeFSEncodingFlagsUTF8BE: - return "UTF-8BE"; - case kHeFSEncodingFlagsUTF8LE: - return "UTF-8LE"; - default: - return "Unknown"; - } -} - -inline const Char* hefs_file_kind_to_string(UInt16 kind) noexcept { - switch (kind) { - case kHeFSFileKindRegular: - return "Regular File"; - case kHeFSFileKindDirectory: - return "Directory"; - case kHeFSFileKindBlock: - return "Block Device"; - case kHeFSFileKindCharacter: - return "Character Device"; - case kHeFSFileKindFIFO: - return "FIFO"; - case kHeFSFileKindSocket: - return "Socket"; - case kHeFSFileKindSymbolicLink: - return "Symbolic Link"; - case kHeFSFileKindUnknown: - default: - return "Unknown"; - } -} - -inline const Char* hefs_file_flags_to_string(UInt32 flags) noexcept { - switch (flags) { - case kHeFSFlagsNone: - return "No Flags"; - case kHeFSFlagsReadOnly: - return "Read Only"; - case kHeFSFlagsHidden: - return "Hidden"; - case kHeFSFlagsSystem: - return "System"; - case kHeFSFlagsArchive: - return "Archive"; - case kHeFSFlagsDevice: - return "Device"; - default: - return "Unknown"; - } -} -} // namespace Kernel::Detail - -namespace Kernel { -/// @brief HeFS filesystem parser class. -/// @details This class is used to parse the HeFS filesystem. -class HeFileSystemParser final { - public: - HeFileSystemParser() = default; - ~HeFileSystemParser() = default; - - public: - HeFileSystemParser(const HeFileSystemParser&) = delete; - HeFileSystemParser& operator=(const HeFileSystemParser&) = delete; - - HeFileSystemParser(HeFileSystemParser&&) = delete; - HeFileSystemParser& operator=(HeFileSystemParser&&) = delete; - - public: - /// @brief Make a EPM+HeFS drive out of the disk. - /// @param drive The drive to write on. - /// @return If it was sucessful, see err_local_get(). - _Output Bool Format(_Input _Output DriveTrait* drive, _Input const Int32 flags, - const Utf8Char* part_name); - - _Output Bool CreateINodeDirectory(_Input DriveTrait* drive, _Input const Int32 flags, - const Utf8Char* dir); - - _Output Bool RemoveINodeDirectory(_Input DriveTrait* drive, _Input const Int32 flags, - const Utf8Char* dir); - - _Output Bool CreateINode(_Input DriveTrait* drive, _Input const Int32 flags, const Utf8Char* dir, - const Utf8Char* name, const UInt8 kind); - - _Output Bool DeleteINode(_Input DriveTrait* drive, _Input const Int32 flags, const Utf8Char* dir, - const Utf8Char* name, const UInt8 kind); - - _Output Bool INodeManip(_Input DriveTrait* drive, VoidPtr block, SizeT block_sz, - const Utf8Char* dir, const Utf8Char* name, const UInt8 kind, - const BOOL input); - - private: - _Output Bool INodeCtlManip(_Input DriveTrait* drive, _Input const Int32 flags, - const Utf8Char* dir, const Utf8Char* name, const BOOL delete_or_create, - const UInt8 kind); - - _Output Bool INodeDirectoryCtlManip(_Input DriveTrait* drive, _Input const Int32 flags, - const Utf8Char* dir, const BOOL delete_or_create); -}; - -namespace HeFS { - - /// @brief Initialize HeFS inside the main disk. - /// @return Whether it successfuly formated it or not. - Boolean fs_init_hefs(Void) noexcept; -} // namespace HeFS -} // namespace Kernel diff --git a/dev/kernel/FSKit/OpenHeFS.h b/dev/kernel/FSKit/OpenHeFS.h new file mode 100644 index 00000000..1361da9c --- /dev/null +++ b/dev/kernel/FSKit/OpenHeFS.h @@ -0,0 +1,434 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +/// @file OpenHeFS.h +/// @brief OpenHeFS filesystem support. + +#define kHeFSVersion (0x0103) +#define kHeFSMagic " HeFS" +#define kHeFSMagicLen (8) + +#define kHeFSBlockLen (512U) +#define kHeFSFileNameLen (256U) +#define kHeFSPartNameLen (128U) + +#define kHeFSMinimumDiskSize (gib_cast(128)) + +#define kHeFSDefaultVolumeName u8"OpenHeFS Volume" + +#define kHeFSINDStartOffset (sizeof(HEFS_BOOT_NODE)) +#define kHeFSINStartOffset (sizeof(HEFS_INDEX_NODE_DIRECTORY)) + +#define kHeFSRootDirectory "/" +#define kHeFSRootDirectoryU8 u8"/" + +#define kHeFSSeparator '/' +#define kHeFSUpDir ".." + +#define kHeFSRootDirectoryLen (2U) + +#define kHeFSSearchAllStr u8"*" + +struct HEFS_BOOT_NODE; +struct HEFS_INDEX_NODE; +struct HEFS_INDEX_NODE_DIRECTORY; +struct HEFS_JOURNAL_NODE; + +enum : UInt8 { + kHeFSHardDrive = 0xC0, // Hard Drive + kHeFSSolidStateDrive = 0xC1, // Solid State Drive + kHeFSOpticalDrive = 0x0C, // Blu-Ray/DVD + kHeFSMassStorageDevice = 0xCC, // USB + kHeFSScsiDrive = 0xC4, // SCSI Hard Drive + kHeFSFlashDrive = 0xC6, + kHeFSUnknown = 0xFF, // Unknown device. + kHeFSDriveCount = 8, +}; + +enum : UInt8 { + kHeFSStatusUnlocked = 0x18, + kHeFSStatusLocked, + kHeFSStatusError, + kHeFSStatusInvalid, + kHeFSStatusCount, +}; + +enum : UInt16 { + kHeFSEncodingFlagsUTF8 = 0x50, + kHeFSEncodingFlagsUTF16, + kHeFSEncodingFlagsUTF32, + kHeFSEncodingFlagsUTF16BE, + kHeFSEncodingFlagsUTF16LE, + kHeFSEncodingFlagsUTF32BE, + kHeFSEncodingFlagsUTF32LE, + kHeFSEncodingFlagsUTF8BE, + kHeFSEncodingFlagsUTF8LE, + kHeFSEncodingFlagsBinary, + kHeFSEncodingFlagsCount = 11, + kHeFSFlagsNone = 0, + kHeFSFlagsReadOnly = 0x100, + kHeFSFlagsHidden, + kHeFSFlagsSystem, + kHeFSFlagsArchive, + kHeFSFlagsDevice, + kHeFSFlagsCount = 7 +}; + +inline constexpr UInt16 kHeFSFileKindRegular = 0x00; +inline constexpr UInt16 kHeFSFileKindDirectory = 0x01; +inline constexpr UInt16 kHeFSFileKindBlock = 0x02; +inline constexpr UInt16 kHeFSFileKindCharacter = 0x03; +inline constexpr UInt16 kHeFSFileKindFIFO = 0x04; +inline constexpr UInt16 kHeFSFileKindSocket = 0x05; +inline constexpr UInt16 kHeFSFileKindSymbolicLink = 0x06; +inline constexpr UInt16 kHeFSFileKindUnknown = 0x07; +inline constexpr UInt16 kHeFSFileKindCount = 0x08; + +/// @brief OpenHeFS blocks are array containing sparse blocks of data. +/// @details The blocks are used to store the data of a file. Each block is a pointer to a block of +/// data on the disk. +inline constexpr UInt16 kHeFSSliceCount = 0x10; + +inline constexpr UInt16 kHeFSInvalidVID = 0xFFFF; + +namespace Kernel { +/// @brief Access time type. +/// @details Used to keep track of the INode, INodeDir allocation status. +typedef UInt64 ATime; + +/// @brief OpenHeFS Boot node. +/// @details Acts like a superblock, it contains the information about the filesystem. +/// @note The boot node is the first block of the filesystem. +struct PACKED HEFS_BOOT_NODE final { + Char fMagic[kHeFSMagicLen]; /// @brief Magic number of the filesystem. + Utf8Char fVolName[kHeFSPartNameLen]; /// @brief Volume name. + UInt32 fVersion; /// @brief Version of the filesystem. + UInt64 fBadSectors; /// @brief Number of bad sectors in the filesystem. + UInt64 fSectorCount; /// @brief Number of sectors in the filesystem. + UInt64 fSectorSize; /// @brief Size of the sector. + UInt32 fChecksum; /// @brief Checksum of the boot node. + UInt8 fDiskKind; /// @brief Kind of the drive. (Hard Drive, Solid State Drive, Optical + /// Drive, etc). + UInt8 fEncoding; /// @brief Encoding of the filesystem. (UTF-8, UTF-16, etc). + UInt64 fStartIND; /// @brief Start of the INode directory tree. + UInt64 fEndIND; /// @brief End of the INode directory tree. + UInt64 fINDCount; /// @brief Number of leafs in the INode tree. + UInt64 fDiskSize; /// @brief Size of the disk. (Could be a virtual size, that is not the + /// real size of the disk.) + UInt16 fDiskStatus; /// @brief Status of the disk. (locked, unlocked, error, invalid). + UInt16 fDiskFlags; /// @brief Flags of the disk. (read-only, read-write, etc). + UInt16 fVID; /// @brief Virtual Identification Number within an EPM disk. (0xFFFF if not used). + UInt64 fStartIN; /// @brief Start INodes range + UInt64 fEndIN; /// @brief End INodes range + UInt64 fStartBlock; /// @brief Start Blocks range + UInt64 fEndBlock; /// @brief End Blocks range + UInt64 fJournalLBA; /// @brief Boot Node's COW journal LBA. + Char fPad[264]; +}; + +inline constexpr ATime kHeFSTimeInvalid = 0x0000000000000000; +inline constexpr ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF - 1; + +/// @brief Journal Node structure +/// @param fHashPath target hash path +/// @param fStatus target status +/// @param fCopyElem copy of element +/// @param fCopyKind kind of element +struct PACKED HEFS_JOURNAL_NODE { + UInt64 fHashPath; + UInt64 fStatus; + UInt64 fCopyElem; + UInt8 fCopyKind; + UInt8 fPad[487]; +}; + +/// @brief This enum defines the opcode of the journal, here mentioned as 'kinds' +enum HeFSJournalKind : UInt8 { + kJournalKindInvalid = 0x00, + kJournalKindWrite = 0x01, + kJournalKindRename = 0x02, + kJournalKindDelete = 0x03, + kJournalKindFlagEdit = 0x04, + kJournalKindCreate = 0x05, + kJournalKindCount, +}; + +/// @brief OpenHeFS index node. +/// @details This structure is used to store the file information of a file. +/// @note The index node is a special type of INode that contains the file information. +/// @note The index node is used to store the file information of a file. +struct PACKED HEFS_INDEX_NODE final { + UInt64 fHashPath; /// @brief File name. + UInt32 fFlags; /// @brief File flags. + UInt16 fKind; /// @brief File kind. (Regular, Directory, Block, Character, FIFO, Socket, + /// Symbolic Link, Unknown). + UInt32 fSize; /// @brief File size. + UInt32 fChecksum; /// @brief Checksum. + + Boolean fSymLink; /// @brief Is this a symbolic link? (if yes, the fName is the path to + /// the file and blocklinkstart and end contains it's inodes.) + + ATime fCreated, fAccessed, fModified, fDeleted; /// @brief File timestamps. + UInt32 fUID, fGID; /// @brief User ID and Group ID of the file. + UInt32 fMode; /// @brief File mode. (read, write, execute, etc). + + /// @brief Extents system by using blocks + /// @details Using an offset to ask fBase, and fLength to compute each slice's length. + UInt32 fOffsetSliceLow; + UInt32 fOffsetSliceHigh; + + Char fPad[437]; +}; + +enum { + kHeFSInvalidColor = 0, + kHeFSRed = 100, + kHeFSBlack, + kHeFSColorCount, +}; + +/// @brief OpenHeFS directory node. +/// @details This structure is used to store the directory information of a file. +/// @note The directory node is a special type of INode that contains the directory entries. +struct PACKED HEFS_INDEX_NODE_DIRECTORY final { + UInt64 fHashPath; /// @brief Directory path as FNV hash. + + UInt32 fFlags; /// @brief File flags. + UInt16 fReserved; /// @note Reserved for future use. + UInt32 fEntryCount; /// @brief Entry Count of this directory inode. + UInt32 fChecksum; /// @brief Checksum of the file, index node checksum. + + ATime fCreated, fAccessed, fModified, + fDeleted; /// @brief File timestamps and allocation status. + UInt32 fUID, fGID; /// @brief User ID and Group ID of the file. + UInt32 fMode; /// @brief File mode. (read, write, execute, etc). + + /// @note These slices are organized as: + /// [0] = OFFSET + /// [1] = SIZE + /// @note Thus the += 2 when iterating over them. + UInt64 fINSlices[kHeFSSliceCount]; /// @brief Start of the index node. + + UInt8 fColor; /// @brief Color of the node. (Red or Black). + Lba fNext, fPrev, fChild, fParent; /// @brief Red-black tree pointers. + + Char fPad[285]; +}; +} // namespace Kernel + +namespace Kernel::Detail { +/// @brief OpenHeFS get year from ATime. +/// @param raw_atime the raw ATime value. +/// @return the year value. +/// @note The year is stored in the upper 32 bits of the ATime value. +inline UInt32 hefs_year_get(ATime raw_atime) noexcept { + return (raw_atime) >> 32; +} + +/// @brief OpenHeFS get month from ATime. +/// @param raw_atime the raw ATime value. +/// @return the month value. +/// @note The month is stored in the upper 24 bits of the ATime value. +inline UInt32 hefs_month_get(ATime raw_atime) noexcept { + return (raw_atime) >> 24; +} + +/// @brief OpenHeFS get day from ATime. +/// @param raw_atime the raw ATime value. +/// @return the day value. +/// @note The day is stored in the upper 16 bits of the ATime value. +inline UInt32 hefs_day_get(ATime raw_atime) noexcept { + return (raw_atime) >> 16; +} + +/// @brief OpenHeFS get hour from ATime. +/// @param raw_atime the raw ATime value. +/// @return the hour value. +/// @note The hour is stored in the upper 8 bits of the ATime value. +inline UInt32 hefs_hour_get(ATime raw_atime) noexcept { + return (raw_atime) >> 8; +} + +/// @brief OpenHeFS get minute from ATime. +/// @param raw_atime the raw ATime value. +/// @return the minute value. +/// @note The minute is stored in the lower 8 bits of the ATime value. +inline UInt32 hefs_minute_get(ATime raw_atime) noexcept { + return (raw_atime) &0xFF; +} + +inline constexpr UInt32 kHeFSBaseYear = 1970; +inline constexpr UInt32 kHeFSBaseMonth = 1; +inline constexpr UInt32 kHeFSBaseDay = 1; +inline constexpr UInt32 kHeFSBaseHour = 0; +inline constexpr UInt32 kHeFSBaseMinute = 0; + +inline const Char* hefs_status_to_string(UInt16 status) noexcept { + switch (status) { + case kHeFSStatusUnlocked: + return "Unlocked"; + case kHeFSStatusLocked: + return "Locked"; + case kHeFSStatusError: + return "Error"; + case kHeFSStatusInvalid: + return "Invalid"; + default: + return "Unknown"; + } +} + +inline const Char* hefs_drive_kind_to_string(UInt8 kind) noexcept { + switch (kind) { + case kHeFSHardDrive: + return "Hard Drive"; + case kHeFSSolidStateDrive: + return "Solid State Drive"; + case kHeFSOpticalDrive: + return "Optical Drive"; + case kHeFSMassStorageDevice: + return "Mass Storage Device"; + case kHeFSScsiDrive: + return "SCSI/SAS Drive"; + case kHeFSFlashDrive: + return "Flash Drive"; + case kHeFSUnknown: + default: + return "Unknown"; + } +} + +inline const Char* hefs_encoding_to_string(UInt8 encoding) noexcept { + switch (encoding) { + case kHeFSEncodingFlagsUTF8: + return "UTF-8"; + case kHeFSEncodingFlagsUTF16: + return "UTF-16"; + case kHeFSEncodingFlagsUTF32: + return "UTF-32"; + case kHeFSEncodingFlagsUTF16BE: + return "UTF-16BE"; + case kHeFSEncodingFlagsUTF16LE: + return "UTF-16LE"; + case kHeFSEncodingFlagsUTF32BE: + return "UTF-32BE"; + case kHeFSEncodingFlagsUTF32LE: + return "UTF-32LE"; + case kHeFSEncodingFlagsUTF8BE: + return "UTF-8BE"; + case kHeFSEncodingFlagsUTF8LE: + return "UTF-8LE"; + default: + return "Unknown"; + } +} + +inline const Char* hefs_file_kind_to_string(UInt16 kind) noexcept { + switch (kind) { + case kHeFSFileKindRegular: + return "Regular File"; + case kHeFSFileKindDirectory: + return "Directory"; + case kHeFSFileKindBlock: + return "Block Device"; + case kHeFSFileKindCharacter: + return "Character Device"; + case kHeFSFileKindFIFO: + return "FIFO"; + case kHeFSFileKindSocket: + return "Socket"; + case kHeFSFileKindSymbolicLink: + return "Symbolic Link"; + case kHeFSFileKindUnknown: + default: + return "Unknown"; + } +} + +inline const Char* hefs_file_flags_to_string(UInt32 flags) noexcept { + switch (flags) { + case kHeFSFlagsNone: + return "No Flags"; + case kHeFSFlagsReadOnly: + return "Read Only"; + case kHeFSFlagsHidden: + return "Hidden"; + case kHeFSFlagsSystem: + return "System"; + case kHeFSFlagsArchive: + return "Archive"; + case kHeFSFlagsDevice: + return "Device"; + default: + return "Unknown"; + } +} +} // namespace Kernel::Detail + +namespace Kernel { +/// @brief OpenHeFS filesystem parser class. +/// @details This class is used to parse the OpenHeFS filesystem. +class HeFileSystemParser final { + public: + HeFileSystemParser() = default; + ~HeFileSystemParser() = default; + + public: + HeFileSystemParser(const HeFileSystemParser&) = delete; + HeFileSystemParser& operator=(const HeFileSystemParser&) = delete; + + HeFileSystemParser(HeFileSystemParser&&) = delete; + HeFileSystemParser& operator=(HeFileSystemParser&&) = delete; + + public: + /// @brief Make a EPM+OpenHeFS drive out of the disk. + /// @param drive The drive to write on. + /// @return If it was sucessful, see err_local_get(). + _Output Bool Format(_Input _Output DriveTrait* drive, _Input const Int32 flags, + const Utf8Char* part_name); + + _Output Bool CreateINodeDirectory(_Input DriveTrait* drive, _Input const Int32 flags, + const Utf8Char* dir); + + _Output Bool RemoveINodeDirectory(_Input DriveTrait* drive, _Input const Int32 flags, + const Utf8Char* dir); + + _Output Bool CreateINode(_Input DriveTrait* drive, _Input const Int32 flags, const Utf8Char* dir, + const Utf8Char* name, const UInt8 kind); + + _Output Bool DeleteINode(_Input DriveTrait* drive, _Input const Int32 flags, const Utf8Char* dir, + const Utf8Char* name, const UInt8 kind); + + _Output Bool INodeManip(_Input DriveTrait* drive, VoidPtr block, SizeT block_sz, + const Utf8Char* dir, const Utf8Char* name, const UInt8 kind, + const BOOL input); + + private: + _Output Bool INodeCtlManip(_Input DriveTrait* drive, _Input const Int32 flags, + const Utf8Char* dir, const Utf8Char* name, const BOOL delete_or_create, + const UInt8 kind); + + _Output Bool INodeDirectoryCtlManip(_Input DriveTrait* drive, _Input const Int32 flags, + const Utf8Char* dir, const BOOL delete_or_create); +}; + +namespace OpenHeFS { + + /// @brief Initialize OpenHeFS inside the main disk. + /// @return Whether it successfuly formated it or not. + Boolean fs_init_hefs(Void) noexcept; +} // namespace OpenHeFS +} // namespace Kernel diff --git a/dev/kernel/FirmwareKit/EPM.h b/dev/kernel/FirmwareKit/EPM.h index dcab3607..20c966e4 100644 --- a/dev/kernel/FirmwareKit/EPM.h +++ b/dev/kernel/FirmwareKit/EPM.h @@ -89,7 +89,7 @@ struct PACKED EPM_PART_BLOCK { Kernel::Int16 Kind; Kernel::Int16 Flags; Kernel::Int32 FsVersion; - Kernel::Char Fs[kEPMFilesystemLength]; /* NeFS, HeFS... */ + Kernel::Char Fs[kEPMFilesystemLength]; /* NeFS, OpenHeFS... */ Kernel::Char Reserved[kEPMReserveLen]; // to fill a full sector. }; diff --git a/dev/kernel/HALKit/AMD64/HalKernelMain.cc b/dev/kernel/HALKit/AMD64/HalKernelMain.cc index 6f4d7e0a..2b478dd6 100644 --- a/dev/kernel/HALKit/AMD64/HalKernelMain.cc +++ b/dev/kernel/HALKit/AMD64/HalKernelMain.cc @@ -145,7 +145,7 @@ EXTERN_C Kernel::Void hal_real_init(Kernel::Void) { HAL::mp_init_cores(kHandoverHeader->f_HardwareTables.f_VendorPtr); #ifdef __FSKIT_INCLUDES_HEFS__ - HeFS::fs_init_hefs(); + OpenHeFS::fs_init_hefs(); #endif #ifdef __FSKIT_INCLUDES_NEFS__ diff --git a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc index 0a465145..1acfac0e 100644 --- a/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc +++ b/dev/kernel/HALKit/AMD64/Storage/AHCI+Generic.cc @@ -546,8 +546,8 @@ namespace Detail { /// @brief Read AHCI device. /// @param self device /// @param mnt mounted disk. - STATIC Void sk_io_read_ahci(DeviceInterface* self, - MountpointInterface* mnt) { + STATIC Void sk_io_read_ahci(DeviceInterface* self, + IMountpoint* mnt) { AHCIDeviceInterface* dev = (AHCIDeviceInterface*) self; err_global_get() = kErrorDisk; @@ -568,8 +568,8 @@ namespace Detail { /// @brief Write AHCI device. /// @param self device /// @param mnt mounted disk. - STATIC Void sk_io_write_ahci(DeviceInterface* self, - MountpointInterface* mnt) { + STATIC Void sk_io_write_ahci(DeviceInterface* self, + IMountpoint* mnt) { AHCIDeviceInterface* dev = (AHCIDeviceInterface*) self; err_global_get() = kErrorDisk; diff --git a/dev/kernel/HALKit/AMD64/Storage/NVME+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/NVME+Generic.cc new file mode 100644 index 00000000..67b59813 --- /dev/null +++ b/dev/kernel/HALKit/AMD64/Storage/NVME+Generic.cc @@ -0,0 +1,9 @@ +/* ------------------------------------------- + + Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#include + +using namespace Kernel; diff --git a/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc b/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc index 6fccbdfa..5b768fbb 100644 --- a/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc +++ b/dev/kernel/HALKit/AMD64/Storage/PIO+Generic.cc @@ -200,8 +200,8 @@ namespace Detail { /// @brief Read PIO device. /// @param self device /// @param mnt mounted disk. - STATIC Void sk_io_read_pio(DeviceInterface* self, - MountpointInterface* mnt) { + STATIC Void sk_io_read_pio(DeviceInterface* self, + IMountpoint* mnt) { ATADeviceInterface* dev = (ATADeviceInterface*) self; err_global_get() = kErrorDisk; @@ -222,8 +222,8 @@ namespace Detail { /// @brief Write PIO device. /// @param self device /// @param mnt mounted disk. - STATIC Void sk_io_write_pio(DeviceInterface* self, - MountpointInterface* mnt) { + STATIC Void sk_io_write_pio(DeviceInterface* self, + IMountpoint* mnt) { ATADeviceInterface* dev = (ATADeviceInterface*) self; err_global_get() = kErrorDisk; diff --git a/dev/kernel/KernelKit/DriveMgr.h b/dev/kernel/KernelKit/DriveMgr.h index 03f9a717..6340d966 100644 --- a/dev/kernel/KernelKit/DriveMgr.h +++ b/dev/kernel/KernelKit/DriveMgr.h @@ -89,12 +89,12 @@ typedef DriveTrait* DriveTraitPtr; * @note This class has all of it's drive set to nullptr, allocate them using * GetAddressOf(index). */ -class MountpointInterface final { +class IMountpoint final { public: - explicit MountpointInterface() = default; - ~MountpointInterface() = default; + explicit IMountpoint() = default; + ~IMountpoint() = default; - NE_COPY_DEFAULT(MountpointInterface) + NE_COPY_DEFAULT(IMountpoint) public: DriveTrait& A() { return mA; } diff --git a/dev/kernel/KernelKit/FileMgr.h b/dev/kernel/KernelKit/FileMgr.h index cc2feeb8..ff290780 100644 --- a/dev/kernel/KernelKit/FileMgr.h +++ b/dev/kernel/KernelKit/FileMgr.h @@ -23,12 +23,12 @@ #define INC_FILEMGR_H /// @file FileMgr.h -/// @brief File Manager. +/// @brief File Manager System. /// @author Amlal El Mahrouss (amlal@nekernel.org) //! Include filesystems that NeKernel supports. #include -#include +#include #include #include @@ -71,7 +71,7 @@ enum { kFileIOCnt = (kFileFlagData - kFileWriteAll) + 1, }; -typedef VoidPtr NodePtr; +using NodePtr = VoidPtr; /** @brief Filesystem Mgr Interface class diff --git a/dev/kernel/KernelKit/IFS.h b/dev/kernel/KernelKit/IFS.h index ed1d87b5..b1dd2001 100644 --- a/dev/kernel/KernelKit/IFS.h +++ b/dev/kernel/KernelKit/IFS.h @@ -14,12 +14,12 @@ namespace Kernel { /// @param DrvTrait drive info /// @param DrvIndex drive index. /// @return -Int32 fs_ifs_read(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); +Int32 fs_ifs_read(IMountpoint* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); /// @brief Write to IFS disk. /// @param Mnt mounted interface. /// @param DrvTrait drive info /// @param DrvIndex drive index. /// @return -Int32 fs_ifs_write(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); +Int32 fs_ifs_write(IMountpoint* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex); } // namespace Kernel diff --git a/dev/kernel/KernelKit/ILoader.h b/dev/kernel/KernelKit/ILoader.h new file mode 100644 index 00000000..ec8ee1bc --- /dev/null +++ b/dev/kernel/KernelKit/ILoader.h @@ -0,0 +1,32 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include +#include +#include +#include + +namespace Kernel { +/// @brief This interface is used to make loader contracts (MSCOFF, PEF). +/// @author @Amlal-El-Mahrouss +class ILoader { + public: + explicit ILoader() = default; + virtual ~ILoader() = default; + + NE_COPY_DEFAULT(ILoader) + + public: + virtual _Output ErrorOr GetBlob() = 0; + virtual _Output const Char* AsString() = 0; + virtual _Output const Char* MIME() = 0; + virtual _Output const Char* Path() = 0; + virtual _Output ErrorOr FindStart() = 0; + virtual _Output ErrorOr FindSymbol(_Input const Char* name, _Input Int32 kind) = 0; +}; +} // namespace Kernel diff --git a/dev/kernel/KernelKit/LoaderInterface.h b/dev/kernel/KernelKit/LoaderInterface.h deleted file mode 100644 index 1f9b1e56..00000000 --- a/dev/kernel/KernelKit/LoaderInterface.h +++ /dev/null @@ -1,32 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#pragma once - -#include -#include -#include -#include - -namespace Kernel { -/// @brief This interface is used to make loader contracts (MSCOFF, PEF). -/// @author @Amlal-El-Mahrouss -class LoaderInterface { - public: - explicit LoaderInterface() = default; - virtual ~LoaderInterface() = default; - - NE_COPY_DEFAULT(LoaderInterface) - - public: - virtual _Output ErrorOr GetBlob() = 0; - virtual _Output const Char* AsString() = 0; - virtual _Output const Char* MIME() = 0; - virtual _Output const Char* Path() = 0; - virtual _Output ErrorOr FindStart() = 0; - virtual _Output ErrorOr FindSymbol(_Input const Char* name, _Input Int32 kind) = 0; -}; -} // namespace Kernel diff --git a/dev/kernel/KernelKit/PEF.h b/dev/kernel/KernelKit/PEF.h index f0ba9ef9..0410c63a 100644 --- a/dev/kernel/KernelKit/PEF.h +++ b/dev/kernel/KernelKit/PEF.h @@ -15,7 +15,7 @@ #define __KERNELKIT_PEF_H__ #include -#include +#include #include #define kPefMagic "Open" diff --git a/dev/kernel/KernelKit/PEFCodeMgr.h b/dev/kernel/KernelKit/PEFCodeMgr.h index d61aa863..3ed9c097 100644 --- a/dev/kernel/KernelKit/PEFCodeMgr.h +++ b/dev/kernel/KernelKit/PEFCodeMgr.h @@ -27,7 +27,7 @@ namespace Kernel { /// \name PEFLoader /// \brief PEF loader class. /// -class PEFLoader : public LoaderInterface { +class PEFLoader : public ILoader { private: explicit PEFLoader() = delete; diff --git a/dev/kernel/KernelKit/UserMgr.h b/dev/kernel/KernelKit/UserMgr.h index 6fa8ba14..c660025b 100644 --- a/dev/kernel/KernelKit/UserMgr.h +++ b/dev/kernel/KernelKit/UserMgr.h @@ -22,9 +22,9 @@ ///! We got the MGMT, STD (%s format) and GUEST users, ///! all are used to make authorized operations. -#define kSuperUser "OS AUTHORITY/MGMT/%s" -#define kGuestUser "OS AUTHORITY/GUEST/%s" -#define kStdUser "OS AUTHORITY/STD/%s" +#define kSuperUser "NEKERNEL/MGMT/%s" +#define kGuestUser "NEKERNEL/GUEST/%s" +#define kStdUser "NEKERNEL/STD/%s" #define kUsersDir "/users/" diff --git a/dev/kernel/KernelKit/ZXD.h b/dev/kernel/KernelKit/ZXD.h index 966c54c7..bae47258 100644 --- a/dev/kernel/KernelKit/ZXD.h +++ b/dev/kernel/KernelKit/ZXD.h @@ -23,7 +23,7 @@ enum ZXD_FLAGS { /// @brief ZXD executable header /// @details This header is used to identify ZXD executable files. -struct PACKED ZXD_EXEC_HEADER { +struct PACKED ZXD_EXEC_HEADER final { UInt32 fMagic; UInt32 fVersion; UInt32 fFlags; @@ -42,7 +42,7 @@ struct PACKED ZXD_EXEC_HEADER { /// @brief ZXD stub header /// @details This header is used to identify ZXD stub files. It contains the size of the stub, the /// offset of the stub, and the CRC32 checksum of the stub. -struct PACKED ZXD_STUB_HEADER { +struct PACKED ZXD_STUB_HEADER final { UInt32 fStubSize; UInt32 fStubOffset; UInt32 fStubCRC32; diff --git a/dev/kernel/StorageKit/AHCI.h b/dev/kernel/StorageKit/AHCI.h index 3605abe6..d4f7cc55 100644 --- a/dev/kernel/StorageKit/AHCI.h +++ b/dev/kernel/StorageKit/AHCI.h @@ -14,10 +14,10 @@ namespace Kernel { /// @brief AHCIDeviceInterface class /// @details This class is used to send and receive data from the AHCI device. /// @note The class is derived from the DeviceInterface class. -class AHCIDeviceInterface NE_DEVICE { +class AHCIDeviceInterface NE_DEVICE { public: - explicit AHCIDeviceInterface(void (*out)(DeviceInterface* self, MountpointInterface* out), - void (*in)(DeviceInterface* self, MountpointInterface* in)); + explicit AHCIDeviceInterface(void (*out)(DeviceInterface* self, IMountpoint* out), + void (*in)(DeviceInterface* self, IMountpoint* in)); virtual ~AHCIDeviceInterface() override; @@ -36,8 +36,8 @@ class AHCIDeviceInterface NE_DEVICE { Void SetIndex(const UInt32& drv); public: - AHCIDeviceInterface& operator<<(MountpointInterface* Data) override; - AHCIDeviceInterface& operator>>(MountpointInterface* Data) override; + AHCIDeviceInterface& operator<<(IMountpoint* Data) override; + AHCIDeviceInterface& operator>>(IMountpoint* Data) override; private: UInt16 fPortsImplemented{0U}; diff --git a/dev/kernel/StorageKit/ATA.h b/dev/kernel/StorageKit/ATA.h index d4c894a3..49ab3e4e 100644 --- a/dev/kernel/StorageKit/ATA.h +++ b/dev/kernel/StorageKit/ATA.h @@ -13,16 +13,16 @@ namespace Kernel { /// @brief ATA device interface class. -class ATADeviceInterface : public DeviceInterface { +class ATADeviceInterface : public DeviceInterface { public: - explicit ATADeviceInterface(void (*Out)(DeviceInterface*, MountpointInterface* outpacket), - void (*In)(DeviceInterface*, MountpointInterface* inpacket)); + explicit ATADeviceInterface(void (*Out)(DeviceInterface*, IMountpoint* outpacket), + void (*In)(DeviceInterface*, IMountpoint* inpacket)); virtual ~ATADeviceInterface(); public: - ATADeviceInterface& operator<<(MountpointInterface* Data) override; - ATADeviceInterface& operator>>(MountpointInterface* Data) override; + ATADeviceInterface& operator<<(IMountpoint* Data) override; + ATADeviceInterface& operator>>(IMountpoint* Data) override; public: ATADeviceInterface& operator=(const ATADeviceInterface&) = default; diff --git a/dev/kernel/StorageKit/NVME.h b/dev/kernel/StorageKit/NVME.h index 1b2b6358..9852c5eb 100644 --- a/dev/kernel/StorageKit/NVME.h +++ b/dev/kernel/StorageKit/NVME.h @@ -10,10 +10,10 @@ #include namespace Kernel { -class NVMEDeviceInterface final NE_DEVICE { +class NVMEDeviceInterface final NE_DEVICE { public: - explicit NVMEDeviceInterface(Void (*out)(DeviceInterface*, MountpointInterface* out_packet), - Void (*in)(DeviceInterface*, MountpointInterface* in_packet), + explicit NVMEDeviceInterface(Void (*out)(DeviceInterface*, IMountpoint* out_packet), + Void (*in)(DeviceInterface*, IMountpoint* in_packet), Void (*cleanup)(Void)); ~NVMEDeviceInterface() override; @@ -24,7 +24,7 @@ class NVMEDeviceInterface final NE_DEVICE { const Char* Name() const override; public: - OwnPtr operator()(UInt32 dma_low, UInt32 dma_high, SizeT dma_sz); + OwnPtr operator()(UInt32 dma_low, UInt32 dma_high, SizeT dma_sz); private: Void (*fCleanup)(Void) = {nullptr}; diff --git a/dev/kernel/src/FS/HeFS+FileMgr.cc b/dev/kernel/src/FS/HeFS+FileMgr.cc deleted file mode 100644 index 33813f65..00000000 --- a/dev/kernel/src/FS/HeFS+FileMgr.cc +++ /dev/null @@ -1,191 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#ifndef __NE_MINIMAL_OS__ -#ifdef __FSKIT_INCLUDES_HEFS__ - -#include -#include - -/// @brief HeFS File System Manager. -/// BUGS: 0 - -namespace Kernel { -/// @brief C++ constructor -HeFileSystemMgr::HeFileSystemMgr() { - mParser = new HeFileSystemParser(); - MUST_PASS(mParser); - - kout << "We are done allocating HeFileSystemParser...\n"; -} - -HeFileSystemMgr::~HeFileSystemMgr() { - if (mParser) { - kout << "Destroying HeFileSystemParser...\n"; - delete mParser; - mParser = nullptr; - } -} - -/// @brief Removes a node from the filesystem. -/// @param path The filename -/// @return If it was deleted or not. -bool HeFileSystemMgr::Remove(_Input const Char* path) { - if (path == nullptr || *path == 0) { - kout << "HeFS: Remove called with null or empty path\n"; - return false; - } - - return NO; -} - -/// @brief Creates a node with the specified. -/// @param path The filename path. -/// @return The Node pointer. -NodePtr HeFileSystemMgr::Create(_Input const Char* path) { - if (!path || *path == 0) { - kout << "HeFS: Create called with null or empty path\n"; - return nullptr; - } - return nullptr; -} - -/// @brief Creates a node which is a directory. -/// @param path The filename path. -/// @return The Node pointer. -NodePtr HeFileSystemMgr::CreateDirectory(const Char* path) { - if (!path || *path == 0) { - kout << "HeFS: CreateDirectory called with null or empty path\n"; - return nullptr; - } - return nullptr; -} - -/// @brief Creates a node which is an alias. -/// @param path The filename path. -/// @return The Node pointer. -NodePtr HeFileSystemMgr::CreateAlias(const Char* path) { - if (!path || *path == 0) { - kout << "HeFS: CreateAlias called with null or empty path\n"; - return nullptr; - } - return nullptr; -} - -NodePtr HeFileSystemMgr::CreateSwapFile(const Char* path) { - if (!path || *path == 0) { - kout << "HeFS: CreateSwapFile called with null or empty path\n"; - return nullptr; - } - return nullptr; -} - -/// @brief Gets the root directory. -/// @return -const Char* NeFileSystemHelper::Root() { - return kHeFSRootDirectory; -} - -/// @brief Gets the up-dir directory. -/// @return -const Char* NeFileSystemHelper::UpDir() { - return kHeFSUpDir; -} - -/// @brief Gets the separator character. -/// @return -Char NeFileSystemHelper::Separator() { - return kHeFSSeparator; -} - -/// @brief Gets the metafile character. -/// @return -Char NeFileSystemHelper::MetaFile() { - return 0; -} - -/// @brief Opens a new file. -/// @param path -/// @param r -/// @return -_Output NodePtr HeFileSystemMgr::Open(_Input const Char* path, _Input const Char* r) { - if (!path || *path == 0) { - kout << "HeFS: Open called with null or empty path\n"; - return nullptr; - } - if (!r || *r == 0) { - kout << "HeFS: Open called with null or empty mode string\n"; - return nullptr; - } - return nullptr; -} - -Void HeFileSystemMgr::Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, - _Input SizeT size) { - NE_UNUSED(node); - NE_UNUSED(flags); - NE_UNUSED(size); - NE_UNUSED(data); -} - -_Output VoidPtr HeFileSystemMgr::Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT size) { - NE_UNUSED(node); - NE_UNUSED(flags); - NE_UNUSED(size); - - return nullptr; -} - -Void HeFileSystemMgr::Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, - _Input Int32 flags, _Input SizeT size) { - NE_UNUSED(node); - NE_UNUSED(flags); - NE_UNUSED(size); - NE_UNUSED(name); - NE_UNUSED(data); -} - -_Output VoidPtr HeFileSystemMgr::Read(_Input const Char* name, _Input NodePtr node, - _Input Int32 flags, _Input SizeT sz) { - NE_UNUSED(node); - NE_UNUSED(flags); - NE_UNUSED(sz); - NE_UNUSED(name); - - return nullptr; -} - -_Output Bool HeFileSystemMgr::Seek(NodePtr node, SizeT off) { - NE_UNUSED(node); - NE_UNUSED(off); - - return false; -} - -/// @brief Tell current offset within catalog. -/// @param node -/// @return kFileMgrNPos if invalid, else current offset. -_Output SizeT HeFileSystemMgr::Tell(NodePtr node) { - NE_UNUSED(node); - return kFileMgrNPos; -} - -/// @brief Rewinds the catalog -/// @param node -/// @return False if invalid, nah? calls Seek(node, 0). -_Output Bool HeFileSystemMgr::Rewind(NodePtr node) { - NE_UNUSED(node); - return kFileMgrNPos; -} - -/// @brief Returns the parser of HeFS. -_Output HeFileSystemParser* HeFileSystemMgr::GetParser() noexcept { - return mParser; -} -} // namespace Kernel - -#endif // ifdef __FSKIT_INCLUDES_HEFS__ -#endif // ifndef __NE_MINIMAL_OS__ diff --git a/dev/kernel/src/FS/HeFS+FileSystemParser.cc b/dev/kernel/src/FS/HeFS+FileSystemParser.cc deleted file mode 100644 index 029fdf26..00000000 --- a/dev/kernel/src/FS/HeFS+FileSystemParser.cc +++ /dev/null @@ -1,1166 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#ifdef __FSKIT_INCLUDES_HEFS__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Kernel { -namespace Detail { - /// @brief Forward declarations of internal functions. - - /***********************************************************************************/ - /// @brief Traverse the RB-Tree of the filesystem. - /// @param dir The directory to traverse. - /// @param start The starting point of the traversal. - /// @note This function is used to traverse the RB-Tree of the filesystem. - /// @internal Internal filesystem use only. - /***********************************************************************************/ - STATIC ATTRIBUTE(unused) _Output Void - hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, DriveTrait* mnt, const Lba& start_ind, - Lba& start); - - /***********************************************************************************/ - /// @brief Get the index node of a file or directory. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read from. - /// @param dir_name The name of the directory. - /// @param file_name The name of the file. - /// @param kind The kind of the file (regular, directory, block, character, FIFO, socket, symbolic - /// link, unknown). - /***********************************************************************************/ - STATIC ATTRIBUTE(unused) _Output HEFS_INDEX_NODE* hefsi_fetch_in(HEFS_BOOT_NODE* boot, - DriveTrait* mnt, - const Utf8Char* dir_name, - const Utf8Char* file_name, - UInt8 kind); - - /***********************************************************************************/ - /// @brief Allocate a new index node-> - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read/write from. - /// @param dir_name The name of the parent directory. - /// @return Status, see err_global_get(). - /***********************************************************************************/ - STATIC ATTRIBUTE(unused) _Output BOOL - hefsi_update_in_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, const Utf8Char* dir_name, - HEFS_INDEX_NODE* node, const BOOL create_or_delete); - - /***********************************************************************************/ - /// @brief Balance RB-Tree of the filesystem. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read/write from. - /// @return Status, see err_global_get(). - /***********************************************************************************/ - STATIC ATTRIBUTE(unused) _Output BOOL hefsi_balance_ind(HEFS_BOOT_NODE* boot, DriveTrait* mnt); - - /// @brief Alllocate IND from boot node. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read from. - /// @param dir_name The name of the directory. - /// @param dir_name The parent of the directory. - /// @param flags Directory flags. - /// @param delete_or_create Delete or create directory. - STATIC _Output BOOL hefsi_update_ind_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, - const Utf8Char* dir_name, UInt16 flags, - const BOOL delete_or_create); - - /// @brief This helper makes it easier for other machines to understand HeFS encoded hashes. - STATIC UInt64 hefsi_to_big_endian_64(UInt64 val) { - return ((val >> 56) & 0x00000000000000FFULL) | ((val >> 40) & 0x000000000000FF00ULL) | - ((val >> 24) & 0x0000000000FF0000ULL) | ((val >> 8) & 0x00000000FF000000ULL) | - ((val << 8) & 0x000000FF00000000ULL) | ((val << 24) & 0x0000FF0000000000ULL) | - ((val << 40) & 0x00FF000000000000ULL) | ((val << 56) & 0xFF00000000000000ULL); - } - - /// @brief Simple algorithm to hash directory entries for INDs. - /// @param path the directory path. - /// @return The hashed path. - template - STATIC UInt64 hefsi_hash_64(const CharT* path) { - if (!path || *path == 0) return 0; - - const UInt64 kFnvBaseOffset = 0xcbf29ce484222325ULL; - const UInt64 kFnvPrimeNumber = 0x100000001b3ULL; - - UInt64 hash = kFnvBaseOffset; - - while (*path) { - hash ^= (CharT) (*path++); - hash *= kFnvPrimeNumber; - } - - return hefsi_to_big_endian_64(hash); - } - - /// @brief Traverse the RB-Tree of the filesystem. - /// @param dir The directory to traverse. - /// @param start The starting point of the traversal. - /// @note This function is used to traverse the RB-Tree of the filesystem. - /// @internal Internal filesystem use only. - STATIC ATTRIBUTE(unused) Void hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, DriveTrait* mnt, - const Lba& ind_start, Lba& start) { - if (!mnt || !dir) return; - - BOOL check_is_good = NO; - HEFS_INDEX_NODE_DIRECTORY* dir_tmp = new HEFS_INDEX_NODE_DIRECTORY(); - - while (YES) { - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir_tmp; - mnt->fInput(mnt->fPacket); - - if (!mnt->fPacket.fPacketGood) break; - - if (dir_tmp->fNext != 0) { - if (check_is_good) break; - - start = dir_tmp->fNext; - - check_is_good = YES; - continue; - } else if (dir_tmp->fPrev != 0) { - if (check_is_good) break; - - start = dir_tmp->fPrev; - check_is_good = YES; - continue; - } else { - if (dir_tmp->fParent != 0) { - if (check_is_good) break; - - start = dir_tmp->fParent; - check_is_good = YES; - continue; - } else if (dir_tmp->fPrev != 0) { - if (check_is_good) break; - - start = dir_tmp->fPrev; - check_is_good = YES; - continue; - } else { - if (start == 0) { - start = ind_start; - continue; - } - - start += sizeof(HEFS_INDEX_NODE_DIRECTORY); - break; - } - } - } - - delete dir_tmp; - - start += sizeof(HEFS_INDEX_NODE_DIRECTORY); - if (start == 0) start = ind_start; - } - - /***********************************************************************************/ - /// @brief Rotate the RB-Tree to the left or right. - /// @internal - /***********************************************************************************/ - STATIC ATTRIBUTE(unused) _Output Void hefsi_rotate_tree(Lba& start, DriveTrait* mnt) { - if (!start || !mnt) return; - - HEFS_INDEX_NODE_DIRECTORY* cur = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = cur; - - mnt->fInput(mnt->fPacket); - - if (cur->fHashPath == 0) return; - - HEFS_INDEX_NODE_DIRECTORY* sibling = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = cur->fPrev; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = sibling; - - mnt->fInput(mnt->fPacket); - - if (sibling->fHashPath == 0) return; - - auto child_sibling = sibling->fChild; - auto child_cur = cur->fChild; - - cur->fChild = child_sibling; - sibling->fChild = child_cur; - - sibling->fChecksum = ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - cur->fChecksum = ke_calculate_crc32((Char*) cur, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = cur->fParent; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = sibling; - - mnt->fOutput(mnt->fPacket); - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = cur; - - mnt->fOutput(mnt->fPacket); - - HEFS_INDEX_NODE_DIRECTORY* sibling_child = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = child_sibling; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = sibling_child; - - mnt->fInput(mnt->fPacket); - - sibling_child->fParent = cur->fParent; - - sibling_child->fChecksum = - ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fOutput(mnt->fPacket); - - HEFS_INDEX_NODE_DIRECTORY* cur_child = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = child_cur; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = cur_child; - - mnt->fInput(mnt->fPacket); - - cur_child->fParent = start; - - cur_child->fChecksum = ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fOutput(mnt->fPacket); - - kout << "RB-Tree has been rotated.\r"; - } - - /// @brief Alllocate IND from boot node. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read from. - /// @param dir_name The name of the directory. - /// @param dir_name The parent of the directory. - /// @param flags Directory flags. - /// @param delete_or_create Delete or create directory. - STATIC _Output BOOL hefsi_update_ind_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, - const Utf8Char* dir_name, UInt16 flags, - const BOOL delete_or_create) { - if (mnt) { - HEFS_INDEX_NODE_DIRECTORY* tmpdir = - (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); - - auto start = boot->fStartIND; - auto prev_location = start; - auto parent_location = 0UL; - - MUST_PASS(boot->fStartIND > mnt->fLbaStart); - - while (YES) { - auto prev_start = start; - - if (start) - mnt->fPacket.fPacketLba = start; - else - mnt->fPacket.fPacketLba = prev_location + sizeof(HEFS_INDEX_NODE_DIRECTORY); - - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = tmpdir; - - mnt->fInput(mnt->fPacket); - - BOOL expr = NO; - - if (!delete_or_create) { - expr = (!tmpdir->fCreated && tmpdir->fDeleted) || tmpdir->fHashPath == 0; - } else { - expr = - tmpdir->fCreated && !tmpdir->fDeleted && hefsi_hash_64(dir_name) == tmpdir->fHashPath; - } - - if (expr) { - HEFS_INDEX_NODE_DIRECTORY* dirent = - (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); - - rt_set_memory(dirent, 0, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - dirent->fHashPath = delete_or_create ? 0UL : hefsi_hash_64(dir_name); - dirent->fAccessed = 0UL; - dirent->fCreated = delete_or_create ? 0UL : 1UL; - dirent->fDeleted = delete_or_create ? 1UL : 0UL; - dirent->fModified = 0UL; - dirent->fEntryCount = 0UL; - - dirent->fReserved = 0; - dirent->fFlags = flags; - dirent->fChecksum = 0; - - dirent->fEntryCount = 0; - - if (parent_location) { - HEFS_INDEX_NODE_DIRECTORY* tmpend = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = parent_location; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = tmpend; - - mnt->fInput(mnt->fPacket); - - if (tmpend->fChecksum != - ke_calculate_crc32((Char*) tmpend, sizeof(HEFS_INDEX_NODE_DIRECTORY))) - ke_panic(RUNTIME_CHECK_FILESYSTEM, "Bad CRC32 value, aborting."); - - if (delete_or_create) - --tmpend->fEntryCount; - else - ++tmpend->fEntryCount; - - tmpend->fChecksum = - ke_calculate_crc32((Char*) tmpend, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fOutput(mnt->fPacket); - - auto child_first = tmpend->fChild; - - while (YES) { - mnt->fPacket.fPacketLba = child_first; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = tmpend; - - mnt->fInput(mnt->fPacket); - - if ((!tmpend->fCreated && tmpend->fDeleted) || tmpend->fHashPath == 0) { - start = child_first; - break; - } - - hefsi_traverse_tree(tmpend, mnt, boot->fStartIND, child_first); - } - } - - dirent->fNext = tmpdir->fNext; - dirent->fPrev = tmpdir->fPrev; - dirent->fParent = tmpdir->fParent; - dirent->fChild = tmpdir->fChild; - dirent->fColor = tmpdir->fColor; - - if (dirent->fColor == 0) { - dirent->fColor = dirent->fNext ? kHeFSRed : kHeFSBlack; - } - - if (dirent->fPrev == 0) { - dirent->fPrev = boot->fStartIND; - } - - if (dirent->fParent == 0) { - dirent->fParent = boot->fStartIND; - } - - if (tmpdir->fChild == 0) { - auto child = dirent->fNext + sizeof(HEFS_INDEX_NODE_DIRECTORY); - - HEFS_INDEX_NODE_DIRECTORY* tmpend = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - while (YES) { - mnt->fPacket.fPacketLba = child; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = tmpend; - - mnt->fInput(mnt->fPacket); - - if ((!tmpend->fCreated && tmpend->fDeleted) || tmpdir->fHashPath == 0) { - break; - } - - child += sizeof(HEFS_INDEX_NODE_DIRECTORY); - if (child > boot->fEndIND) break; - } - - dirent->fColor = kHeFSRed; - dirent->fChild = child; - - if (child > boot->fEndIND) dirent->fChild = boot->fStartIND; - } - - for (SizeT index = 0UL; index < kHeFSSliceCount; ++index) { - dirent->fINSlices[index] = 0UL; - } - - dirent->fChecksum = ke_calculate_crc32((Char*) dirent, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = prev_start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dirent; - - mnt->fOutput(mnt->fPacket); - - err_global_get() = kErrorSuccess; - - mm_free_ptr(dirent); - mm_free_ptr(tmpdir); - - if (!delete_or_create) - ++boot->fINDCount; - else - --boot->fINDCount; - - boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fOutput(mnt->fPacket); - - return YES; - } - - prev_location = start; - - hefsi_traverse_tree(tmpdir, mnt, boot->fStartIND, start); - if (start > boot->fEndIND || start == 0) break; - } - - err_global_get() = kErrorDisk; - mm_free_ptr(tmpdir); - - return NO; - } - - err_global_get() = kErrorDiskIsFull; - return NO; - } - - /// @brief Get the index node of a file or directory. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read from. - /// @param dir_name The name of the directory. - /// @param file_name The name of the file. - /// @param kind The kind of the file (regular, directory, block, character, FIFO, socket, symbolic - /// link, unknown). - STATIC ATTRIBUTE(unused) _Output HEFS_INDEX_NODE* hefsi_fetch_in(HEFS_BOOT_NODE* boot, - DriveTrait* mnt, - const Utf8Char* dir_name, - const Utf8Char* file_name, - UInt8 kind) { - if (mnt) { - if (boot->fStartIND > boot->fEndIND) return nullptr; - if (boot->fStartIN > boot->fEndIN) return nullptr; - - auto start = boot->fStartIND; - HEFS_INDEX_NODE* node = new HEFS_INDEX_NODE(); - - HEFS_INDEX_NODE_DIRECTORY* dir = - (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); - - while (YES) { - if (err_global_get() == kErrorDiskIsCorrupted) { - delete dir; - dir = nullptr; - - delete node; - node = nullptr; - - return nullptr; - } - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fInput(mnt->fPacket); - - (Void)(kout << hex_number(hefsi_hash_64(dir_name)) << kendl); - (Void)(kout << hex_number(dir->fHashPath) << kendl); - - if (dir->fHashPath == 0) break; - - if (hefsi_hash_64(dir_name) == dir->fHashPath) { - for (SizeT inode_index = 0UL; inode_index < kHeFSSliceCount; ++inode_index) { - mnt->fPacket.fPacketLba = dir->fINSlices[inode_index]; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); - mnt->fPacket.fPacketContent = node; - - mnt->fInput(mnt->fPacket); - - (Void)(kout << hex_number(hefsi_hash_64(file_name)) << kendl); - (Void)(kout << hex_number(node->fHashPath) << kendl); - - if (hefsi_hash_64(file_name) == node->fHashPath && node->fKind == kind) { - delete dir; - dir = nullptr; - - return node; - } - } - } - - hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); - if (start == boot->fStartIND || start == boot->fStartIND) break; - } - - delete node; - node = nullptr; - - delete dir; - dir = nullptr; - } - - kout << "Error: Failed to find IN.\r"; - - err_global_get() = kErrorFileNotFound; - - return nullptr; - } - - STATIC ATTRIBUTE(unused) _Output BOOL - hefsi_update_in_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, const Utf8Char* dir_name, - HEFS_INDEX_NODE* node, BOOL delete_or_create) { - if (!boot || !mnt) return NO; - - auto start = boot->fStartIND; - - if (start > boot->fEndIND) return NO; - if (boot->fStartIN > boot->fEndIN) return NO; - ; - if (boot->fStartBlock > boot->fEndBlock) return NO; - - if (mnt) { - HEFS_INDEX_NODE_DIRECTORY* dir = - (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); - - auto hash_file = node->fHashPath; - - while (YES) { - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fInput(mnt->fPacket); - - (Void)(kout << hex_number(hefsi_hash_64(dir_name)) << kendl); - (Void)(kout << hex_number(dir->fHashPath) << kendl); - - if (hefsi_hash_64(dir_name) == dir->fHashPath) { - for (SizeT inode_index = 0UL; inode_index < kHeFSSliceCount; ++inode_index) { - if (dir->fINSlices[inode_index] == 0 && !delete_or_create) { - dir->fINSlices[inode_index] = boot->fStartIN; - - ++dir->fEntryCount; - - dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fOutput(mnt->fPacket); - - auto lba = dir->fINSlices[inode_index]; - - node->fOffsetSliceLow = (UInt32) (boot->fStartBlock); - node->fOffsetSliceHigh = (UInt32) (boot->fStartBlock >> 32); - - node->fChecksum = ke_calculate_crc32((Char*) node, sizeof(HEFS_INDEX_NODE)); - - mnt->fPacket.fPacketLba = lba; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); - mnt->fPacket.fPacketContent = node; - - mnt->fOutput(mnt->fPacket); - - boot->fStartIN += sizeof(HEFS_INDEX_NODE); - boot->fStartBlock += kHeFSBlockLen; - - boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fOutput(mnt->fPacket); - - mm_free_ptr(dir); - - return YES; - } else if (dir->fINSlices[inode_index] != 0 && delete_or_create) { - auto lba = dir->fINSlices[inode_index]; - - HEFS_INDEX_NODE tmp_node{}; - - mnt->fPacket.fPacketLba = lba; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); - mnt->fPacket.fPacketContent = &tmp_node; - - mnt->fInput(mnt->fPacket); - - if (tmp_node.fHashPath != hash_file) { - continue; - } - - node->fOffsetSliceLow = 0; - node->fOffsetSliceHigh = 0; - - boot->fStartIN -= sizeof(HEFS_INDEX_NODE); - boot->fStartBlock -= kHeFSBlockLen; - - boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fOutput(mnt->fPacket); - - mnt->fPacket.fPacketLba = lba; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); - mnt->fPacket.fPacketContent = node; - - mnt->fOutput(mnt->fPacket); - - dir->fINSlices[inode_index] = 0; - - if (dir->fEntryCount) --dir->fEntryCount; - - dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fOutput(mnt->fPacket); - - mm_free_ptr(dir); - - return YES; - } - } - } - - hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); - if (start > boot->fEndIND || start == 0) break; - } - - mm_free_ptr(dir); - err_global_get() = kErrorFileNotFound; - return NO; - } - - err_global_get() = kErrorDiskIsFull; - return NO; - } - - /// @brief Balance RB-Tree of the filesystem. - /// @param boot The boot node of the filesystem. - /// @param mnt The mnt to read/write from. - /// @return Status, see err_global_get(). - STATIC ATTRIBUTE(unused) _Output BOOL hefsi_balance_ind(HEFS_BOOT_NODE* boot, DriveTrait* mnt) { - if (mnt) { - HEFS_INDEX_NODE_DIRECTORY* dir = - (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - auto start = boot->fStartIND; - - while (YES) { - if (start == 0UL || start > boot->fEndIND) break; - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fInput(mnt->fPacket); - - if (!mnt->fPacket.fPacketGood) { - err_global_get() = kErrorDiskIsCorrupted; - - return NO; - } - - if (start == boot->fStartIND) { - dir->fColor = kHeFSBlack; - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fOutput(mnt->fPacket); - } - - if (dir->fColor == kHeFSBlack && dir->fChild != 0UL) { - dir->fColor = kHeFSRed; - hefsi_rotate_tree(start, mnt); - } else if (dir->fColor == kHeFSBlack && dir->fChild == 0UL) { - dir->fColor = kHeFSBlack; - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fOutput(mnt->fPacket); - } - - if (ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)) != dir->fChecksum) { - dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); - - mnt->fPacket.fPacketLba = start; - mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); - mnt->fPacket.fPacketContent = dir; - - mnt->fOutput(mnt->fPacket); - } - - hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); - } - - err_global_get() = kErrorSuccess; - return YES; - } - - err_global_get() = kErrorDisk; - return NO; - } -} // namespace Detail -} // namespace Kernel - -/// @note HeFS will allocate inodes and ind in advance, to avoid having to allocate them in -/// real-time. -/// @note This is certainly take longer to format a disk with it, but worth-it in the long run. - -namespace Kernel { -/// @brief Make a EPM+HeFS mnt out of the disk. -/// @param mnt The mnt to write on. -/// @return If it was sucessful, see err_local_get(). -_Output Bool HeFileSystemParser::Format(_Input _Output DriveTrait* mnt, _Input const Int32 flags, - _Input const Utf8Char* vol_name) { - // Verify Disk. - mnt->fVerify(mnt->fPacket); - - // if disk isn't good, then error out. - if (false == mnt->fPacket.fPacketGood) { - err_global_get() = kErrorDiskIsCorrupted; - return false; - } - - if (drv_std_get_size() < kHeFSMinimumDiskSize) { - (Void)(kout << "OpenHeFS recommends at least 128 GiB of free space." << kendl); - (Void)( - kout - << "The OS will still try to format a HeFS disk here anyway, don't expect perfect geometry." - << kendl); - } - - HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) RTL_ALLOCA(sizeof(HEFS_BOOT_NODE)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fInput(mnt->fPacket); - - if (!mnt->fPacket.fPacketGood) { - err_global_get() = kErrorDiskIsCorrupted; - - return NO; - } - - // Check if the disk is already formatted. - - if (KStringBuilder::Equals(boot->fMagic, kHeFSMagic) && boot->fVersion == kHeFSVersion) { - if (ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)) != boot->fChecksum && - boot->fChecksum > 0) { - err_global_get() = kErrorDiskIsCorrupted; - return NO; - } - - err_global_get() = kErrorSuccess; - return YES; - } - - if (ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)) != boot->fChecksum && - boot->fChecksum > 0) { - err_global_get() = kErrorDiskIsCorrupted; - return NO; - } - - rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, - rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); - - urt_copy_memory((VoidPtr) vol_name, boot->fVolName, urt_string_len(vol_name) + 1); - rt_copy_memory_safe((VoidPtr) kHeFSMagic, boot->fMagic, kHeFSMagicLen - 1, sizeof(boot->fMagic)); - - if (mnt->fLbaStart > mnt->fLbaEnd) { - err_global_get() = kErrorDiskIsCorrupted; - - return NO; - } - - boot->fBadSectors = 0; - - boot->fSectorCount = drv_std_get_sector_count(); - boot->fSectorSize = mnt->fSectorSz; - - MUST_PASS(boot->fSectorSize); - - /// @note all HeFS strucutres are equal to 512, so here it's fine, unless fSectoSize is 2048. - const SizeT max_lba = (drv_std_get_size()) / boot->fSectorSize; - - const SizeT dir_max = max_lba / 300; // 5% for directory inodes - const SizeT inode_max = max_lba / 400; // 5% for inodes - - boot->fStartIND = mnt->fLbaStart + kHeFSINDStartOffset; - boot->fEndIND = boot->fStartIND + dir_max; - - boot->fStartIN = boot->fEndIND; - boot->fEndIN = boot->fStartIN + inode_max; - - boot->fStartBlock = boot->fEndIN; - boot->fEndBlock = drv_std_get_size(); - - boot->fINDCount = 0; - - boot->fDiskSize = drv_std_get_size(); - boot->fDiskStatus = kHeFSStatusUnlocked; - - boot->fDiskFlags = flags; - - if (mnt->fKind & kMassStorageDrive) { - boot->fDiskKind = kHeFSMassStorageDevice; - } else if (mnt->fKind & kHeFSOpticalDrive) { - boot->fDiskKind = kHeFSOpticalDrive; - } else { - boot->fDiskKind = kHeFSUnknown; - } - - boot->fVersion = kHeFSVersion; - - boot->fVID = kHeFSInvalidVID; - - boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fOutput(mnt->fPacket); - - (Void)(kout << "Protocol: " << mnt->fProtocol() << kendl); - (Void)(kout8 << u8"Volume Name: " << boot->fVolName << kendl8); - (Void)(kout << "Start IND: " << hex_number(boot->fStartIND) << kendl); - (Void)(kout << "End IND: " << hex_number(boot->fEndIND) << kendl); - (Void)(kout << "Start IN: " << hex_number(boot->fStartIN) << kendl); - (Void)(kout << "End IN: " << hex_number(boot->fEndIN) << kendl); - (Void)(kout << "Start Block: " << hex_number(boot->fStartBlock) << kendl); - (Void)(kout << "End Block: " << hex_number(boot->fEndBlock) << kendl); - (Void)(kout << "Number of IND: " << hex_number(boot->fINDCount) << kendl); - (Void)(kout << "Sector Size: " << hex_number(boot->fSectorSize) << kendl); - (Void)(kout << "Drive Kind: " << Detail::hefs_drive_kind_to_string(boot->fDiskKind) << kendl); - - if (!mnt->fPacket.fPacketGood) { - err_global_get() = kErrorDiskIsCorrupted; - return NO; - } - - constexpr const SizeT kHeFSPreallocateCount = 0x6UL; - - const Utf8Char* kFileMap[kHeFSPreallocateCount] = {u8"/", u8"/boot", u8"/system", - u8"/network", u8"/devices", u8"/media"}; - - for (SizeT i = 0; i < kHeFSPreallocateCount; ++i) { - this->CreateINodeDirectory(mnt, kHeFSEncodingFlagsUTF8, kFileMap[i]); - } - - err_global_get() = kErrorSuccess; - - return YES; -} - -/// @brief Create a new directory on the disk. -/// @param mnt The mnt to write on. -/// @param flags The flags to use. -/// @param dir The directory to create the file in. -/// @return If it was sucessful, see err_local_get(). -_Output Bool HeFileSystemParser::INodeDirectoryCtlManip(_Input DriveTrait* mnt, - _Input const Int32 flags, - const Utf8Char* dir, - const BOOL delete_or_create) { - if (urt_string_len(dir) > kHeFSFileNameLen) { - err_global_get() = kErrorDisk; - return NO; - } - - HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) mm_alloc_ptr(sizeof(HEFS_BOOT_NODE), Yes, No); - - rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, - rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fInput(mnt->fPacket); - - if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { - err_global_get() = kErrorDisk; - return YES; - } - - if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { - err_global_get() = kErrorDiskIsCorrupted; - - kout << "Invalid Boot Node, this can't continue!\r"; - - return NO; - } - - if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { - kout << "Error: Invalid directory name.\r"; - - err_global_get() = kErrorInvalidData; - - return NO; - } - - if (Detail::hefsi_update_ind_status(boot, mnt, dir, flags, delete_or_create)) { - // todo: make it smarter for high-throughput. - Detail::hefsi_balance_ind(boot, mnt); - - mm_free_ptr((VoidPtr) boot); - return YES; - } - - mm_free_ptr((VoidPtr) boot); - return NO; -} - -_Output Bool HeFileSystemParser::RemoveINodeDirectory(_Input DriveTrait* mnt, - _Input const Int32 flags, - const Utf8Char* dir) { - return this->INodeDirectoryCtlManip(mnt, flags, dir, YES); -} - -_Output Bool HeFileSystemParser::CreateINodeDirectory(_Input DriveTrait* mnt, - _Input const Int32 flags, - const Utf8Char* dir) { - return this->INodeDirectoryCtlManip(mnt, flags, dir, NO); -} - -_Output Bool HeFileSystemParser::DeleteINode(_Input DriveTrait* mnt, _Input const Int32 flags, - const Utf8Char* dir, const Utf8Char* name, - const UInt8 kind) { - return this->INodeCtlManip(mnt, flags, dir, name, YES, kind); -} - -_Output Bool HeFileSystemParser::CreateINode(_Input DriveTrait* mnt, _Input const Int32 flags, - const Utf8Char* dir, const Utf8Char* name, - const UInt8 kind) { - return this->INodeCtlManip(mnt, flags, dir, name, NO, kind); -} - -_Output Bool HeFileSystemParser::INodeManip(_Input DriveTrait* mnt, VoidPtr block, SizeT block_sz, - const Utf8Char* dir, const Utf8Char* name, - const UInt8 kind, const BOOL is_input) { - if (urt_string_len(dir) > kHeFSFileNameLen) { - err_global_get() = kErrorDisk; - return NO; - } - - if (urt_string_len(name) > kHeFSFileNameLen) { - err_global_get() = kErrorDisk; - return NO; - } - - HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) mm_alloc_ptr(sizeof(HEFS_BOOT_NODE), Yes, No); - - if (!boot) { - err_global_get() = kErrorInvalidData; - return NO; - } - - rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, - rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fInput(mnt->fPacket); - - if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { - (Void)(kout << "Invalid Boot Node, HeFS partition is invalid." << kendl); - mm_free_ptr((VoidPtr) boot); - err_global_get() = kErrorDisk; - return NO; - } - - auto start = Detail::hefsi_fetch_in(boot, mnt, dir, name, kind); - - if (start) { - (Void)(kout << hex_number(start->fHashPath) << kendl); - (Void)(kout << hex_number(start->fOffsetSliceLow) << kendl); - - if (start->fOffsetSliceLow && start->fHashPath) { - mnt->fPacket.fPacketLba = ((UInt64) start->fOffsetSliceHigh << 32) | start->fOffsetSliceLow; - mnt->fPacket.fPacketSize = block_sz; - mnt->fPacket.fPacketContent = block; - - if (is_input) { - mnt->fInput(mnt->fPacket); - } else { - if (start->fFlags & kHeFSFlagsReadOnly) { - mm_free_ptr((VoidPtr) boot); - delete start; - - kout << "Error: File is read-only\r"; - - return NO; - } - - mnt->fOutput(mnt->fPacket); - } - } - } - - mm_free_ptr((VoidPtr) boot); - delete start; - return YES; -} - -/// @brief Create a new file on the disk. -/// @param mnt The mnt to write on. -/// @param flags The flags to use. -/// @param dir The directory to create the file in. -/// @param name The name of the file. -/// @return If it was sucessful, see err_local_get(). -_Output Bool HeFileSystemParser::INodeCtlManip(_Input DriveTrait* mnt, _Input const Int32 flags, - const Utf8Char* dir, const Utf8Char* name, - const BOOL delete_or_create, const UInt8 kind) { - if (urt_string_len(name) > kHeFSFileNameLen) { - err_global_get() = kErrorDisk; - return NO; - } - - if (urt_string_len(dir) > kHeFSFileNameLen) { - err_global_get() = kErrorDisk; - return NO; - } - - HEFS_INDEX_NODE* node = (HEFS_INDEX_NODE*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE), Yes, No); - - if (!node) { - err_global_get() = kErrorInvalidData; - return NO; - } - - rt_set_memory(node, 0, sizeof(HEFS_INDEX_NODE)); - - HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) RTL_ALLOCA(sizeof(HEFS_BOOT_NODE)); - - if (!boot) { - mm_free_ptr((VoidPtr) node); - err_global_get() = kErrorInvalidData; - - return NO; - } - - rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, - rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); - - mnt->fPacket.fPacketLba = mnt->fLbaStart; - mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); - mnt->fPacket.fPacketContent = boot; - - mnt->fInput(mnt->fPacket); - - if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { - err_global_get() = kErrorDisk; - return YES; - } - - if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { - kout << "Error: Invalid file name.\r"; - - err_global_get() = kErrorInvalidData; - return NO; - } - - for (SizeT i_name = 0UL; i_name < urt_string_len(name); ++i_name) { - if (name[i_name] == u'/') { - err_global_get() = kErrorInvalidData; - return NO; - } - } - - if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { - kout << "Error: Invalid directory name.\r"; - - err_global_get() = kErrorInvalidData; - return NO; - } - - node->fAccessed = 0; - node->fCreated = delete_or_create ? NO : YES; - node->fDeleted = delete_or_create ? 1UL : NO; - node->fModified = 0; - node->fSize = 0; - node->fKind = kind; - node->fFlags = flags; - node->fChecksum = 0; - node->fGID = 0; - node->fUID = 0; - node->fHashPath = Detail::hefsi_hash_64(name); - - if (Detail::hefsi_update_in_status(boot, mnt, dir, node, delete_or_create)) { - mm_free_ptr((VoidPtr) node); - - Detail::hefsi_balance_ind(boot, mnt); - - err_global_get() = kErrorSuccess; - return YES; - } - - mm_free_ptr((VoidPtr) node); - err_global_get() = kErrorDirectoryNotFound; - - return NO; -} - -STATIC DriveTrait kMountPoint; - -/// @brief Initialize the HeFS filesystem. -/// @return To check its status, see err_local_get(). -Boolean HeFS::fs_init_hefs(Void) noexcept { - kout << "Verifying disk...\r"; - - kMountPoint = io_construct_main_drive(); - - if (kMountPoint.fPacket.fPacketReadOnly == YES) - ke_panic(RUNTIME_CHECK_FILESYSTEM, "Main disk cannot be mounted (read-only media)."); - - HeFileSystemParser parser; - - return parser.Format(&kMountPoint, kHeFSEncodingFlagsUTF8, kHeFSDefaultVolumeName); -} -} // namespace Kernel - -#endif // ifdef __FSKIT_INCLUDES_HEFS__ diff --git a/dev/kernel/src/FS/NeFS+FileSystemParser.cc b/dev/kernel/src/FS/NeFS+FileSystemParser.cc index 14e0b974..b50841a4 100644 --- a/dev/kernel/src/FS/NeFS+FileSystemParser.cc +++ b/dev/kernel/src/FS/NeFS+FileSystemParser.cc @@ -74,7 +74,7 @@ static inline bool is_valid_lba(Lba lba, DriveTrait& drive) { return (lba >= part_block.StartCatalog) && (lba < maxLba); } -STATIC MountpointInterface kMountpoint; +STATIC IMountpoint kMountpoint; /***********************************************************************************/ /// @brief Creates a new fork inside the New filesystem partition. /// @param catalog it's catalog @@ -141,7 +141,7 @@ _Output BOOL NeFileSystemParser::CreateFork(_Input NEFS_FORK_STRUCT& the_fork) { drv.fPacket.fPacketContent = reinterpret_cast(&the_fork); drv.fOutput(drv.fPacket); - fs_ifs_write(&kMountpoint, drv, MountpointInterface::kDriveIndexA); + fs_ifs_write(&kMountpoint, drv, IMountpoint::kDriveIndexA); delete catalog; return YES; @@ -858,7 +858,7 @@ namespace Kernel::NeFS { /// @brief Construct NeFS drives. /***********************************************************************************/ Boolean fs_init_nefs(Void) noexcept { - kout << "Creating HeFS disk...\r"; + kout << "Creating OpenHeFS disk...\r"; kMountpoint.A() = io_construct_main_drive(); if (kMountpoint.A().fPacket.fPacketReadOnly == YES) ke_panic(RUNTIME_CHECK_FILESYSTEM, "Main disk cannot be mounted."); diff --git a/dev/kernel/src/FS/OpenHeFS+FileMgr.cc b/dev/kernel/src/FS/OpenHeFS+FileMgr.cc new file mode 100644 index 00000000..bb87fd67 --- /dev/null +++ b/dev/kernel/src/FS/OpenHeFS+FileMgr.cc @@ -0,0 +1,191 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifndef __NE_MINIMAL_OS__ +#ifdef __FSKIT_INCLUDES_HEFS__ + +#include +#include + +/// @brief OpenHeFS File System Manager. +/// BUGS: 0 + +namespace Kernel { +/// @brief C++ constructor +HeFileSystemMgr::HeFileSystemMgr() { + mParser = new HeFileSystemParser(); + MUST_PASS(mParser); + + kout << "We are done allocating HeFileSystemParser...\n"; +} + +HeFileSystemMgr::~HeFileSystemMgr() { + if (mParser) { + kout << "Destroying HeFileSystemParser...\n"; + delete mParser; + mParser = nullptr; + } +} + +/// @brief Removes a node from the filesystem. +/// @param path The filename +/// @return If it was deleted or not. +bool HeFileSystemMgr::Remove(_Input const Char* path) { + if (path == nullptr || *path == 0) { + kout << "OpenHeFS: Remove called with null or empty path\n"; + return false; + } + + return NO; +} + +/// @brief Creates a node with the specified. +/// @param path The filename path. +/// @return The Node pointer. +NodePtr HeFileSystemMgr::Create(_Input const Char* path) { + if (!path || *path == 0) { + kout << "OpenHeFS: Create called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +/// @brief Creates a node which is a directory. +/// @param path The filename path. +/// @return The Node pointer. +NodePtr HeFileSystemMgr::CreateDirectory(const Char* path) { + if (!path || *path == 0) { + kout << "OpenHeFS: CreateDirectory called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +/// @brief Creates a node which is an alias. +/// @param path The filename path. +/// @return The Node pointer. +NodePtr HeFileSystemMgr::CreateAlias(const Char* path) { + if (!path || *path == 0) { + kout << "OpenHeFS: CreateAlias called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +NodePtr HeFileSystemMgr::CreateSwapFile(const Char* path) { + if (!path || *path == 0) { + kout << "OpenHeFS: CreateSwapFile called with null or empty path\n"; + return nullptr; + } + return nullptr; +} + +/// @brief Gets the root directory. +/// @return +const Char* NeFileSystemHelper::Root() { + return kHeFSRootDirectory; +} + +/// @brief Gets the up-dir directory. +/// @return +const Char* NeFileSystemHelper::UpDir() { + return kHeFSUpDir; +} + +/// @brief Gets the separator character. +/// @return +Char NeFileSystemHelper::Separator() { + return kHeFSSeparator; +} + +/// @brief Gets the metafile character. +/// @return +Char NeFileSystemHelper::MetaFile() { + return '\0'; +} + +/// @brief Opens a new file. +/// @param path +/// @param r +/// @return +_Output NodePtr HeFileSystemMgr::Open(_Input const Char* path, _Input const Char* r) { + if (!path || *path == 0) { + kout << "OpenHeFS: Open called with null or empty path\n"; + return nullptr; + } + if (!r || *r == 0) { + kout << "OpenHeFS: Open called with null or empty mode string\n"; + return nullptr; + } + return nullptr; +} + +Void HeFileSystemMgr::Write(_Input NodePtr node, _Input VoidPtr data, _Input Int32 flags, + _Input SizeT size) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(size); + NE_UNUSED(data); +} + +_Output VoidPtr HeFileSystemMgr::Read(_Input NodePtr node, _Input Int32 flags, _Input SizeT size) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(size); + + return nullptr; +} + +Void HeFileSystemMgr::Write(_Input const Char* name, _Input NodePtr node, _Input VoidPtr data, + _Input Int32 flags, _Input SizeT size) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(size); + NE_UNUSED(name); + NE_UNUSED(data); +} + +_Output VoidPtr HeFileSystemMgr::Read(_Input const Char* name, _Input NodePtr node, + _Input Int32 flags, _Input SizeT sz) { + NE_UNUSED(node); + NE_UNUSED(flags); + NE_UNUSED(sz); + NE_UNUSED(name); + + return nullptr; +} + +_Output Bool HeFileSystemMgr::Seek(NodePtr node, SizeT off) { + NE_UNUSED(node); + NE_UNUSED(off); + + return false; +} + +/// @brief Tell current offset within catalog. +/// @param node +/// @return kFileMgrNPos if invalid, else current offset. +_Output SizeT HeFileSystemMgr::Tell(NodePtr node) { + NE_UNUSED(node); + return kFileMgrNPos; +} + +/// @brief Rewinds the catalog +/// @param node +/// @return False if invalid, nah? calls Seek(node, 0). +_Output Bool HeFileSystemMgr::Rewind(NodePtr node) { + NE_UNUSED(node); + return kFileMgrNPos; +} + +/// @brief Returns the parser of OpenHeFS. +_Output HeFileSystemParser* HeFileSystemMgr::GetParser() noexcept { + return mParser; +} +} // namespace Kernel + +#endif // ifdef __FSKIT_INCLUDES_HEFS__ +#endif // ifndef __NE_MINIMAL_OS__ diff --git a/dev/kernel/src/FS/OpenHeFS+FileSystemParser.cc b/dev/kernel/src/FS/OpenHeFS+FileSystemParser.cc new file mode 100644 index 00000000..3746ebc1 --- /dev/null +++ b/dev/kernel/src/FS/OpenHeFS+FileSystemParser.cc @@ -0,0 +1,1166 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#ifdef __FSKIT_INCLUDES_HEFS__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { +namespace Detail { + /// @brief Forward declarations of internal functions. + + /***********************************************************************************/ + /// @brief Traverse the RB-Tree of the filesystem. + /// @param dir The directory to traverse. + /// @param start The starting point of the traversal. + /// @note This function is used to traverse the RB-Tree of the filesystem. + /// @internal Internal filesystem use only. + /***********************************************************************************/ + STATIC ATTRIBUTE(unused) _Output Void + hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, DriveTrait* mnt, const Lba& start_ind, + Lba& start); + + /***********************************************************************************/ + /// @brief Get the index node of a file or directory. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read from. + /// @param dir_name The name of the directory. + /// @param file_name The name of the file. + /// @param kind The kind of the file (regular, directory, block, character, FIFO, socket, symbolic + /// link, unknown). + /***********************************************************************************/ + STATIC ATTRIBUTE(unused) _Output HEFS_INDEX_NODE* hefsi_fetch_in(HEFS_BOOT_NODE* boot, + DriveTrait* mnt, + const Utf8Char* dir_name, + const Utf8Char* file_name, + UInt8 kind); + + /***********************************************************************************/ + /// @brief Allocate a new index node-> + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read/write from. + /// @param dir_name The name of the parent directory. + /// @return Status, see err_global_get(). + /***********************************************************************************/ + STATIC ATTRIBUTE(unused) _Output BOOL + hefsi_update_in_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, const Utf8Char* dir_name, + HEFS_INDEX_NODE* node, const BOOL create_or_delete); + + /***********************************************************************************/ + /// @brief Balance RB-Tree of the filesystem. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read/write from. + /// @return Status, see err_global_get(). + /***********************************************************************************/ + STATIC ATTRIBUTE(unused) _Output BOOL hefsi_balance_ind(HEFS_BOOT_NODE* boot, DriveTrait* mnt); + + /// @brief Alllocate IND from boot node. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read from. + /// @param dir_name The name of the directory. + /// @param dir_name The parent of the directory. + /// @param flags Directory flags. + /// @param delete_or_create Delete or create directory. + STATIC _Output BOOL hefsi_update_ind_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, + const Utf8Char* dir_name, UInt16 flags, + const BOOL delete_or_create); + + /// @brief This helper makes it easier for other machines to understand OpenHeFS encoded hashes. + STATIC UInt64 hefsi_to_big_endian_64(UInt64 val) { + return ((val >> 56) & 0x00000000000000FFULL) | ((val >> 40) & 0x000000000000FF00ULL) | + ((val >> 24) & 0x0000000000FF0000ULL) | ((val >> 8) & 0x00000000FF000000ULL) | + ((val << 8) & 0x000000FF00000000ULL) | ((val << 24) & 0x0000FF0000000000ULL) | + ((val << 40) & 0x00FF000000000000ULL) | ((val << 56) & 0xFF00000000000000ULL); + } + + /// @brief Simple algorithm to hash directory entries for INDs. + /// @param path the directory path. + /// @return The hashed path. + template + STATIC UInt64 hefsi_hash_64(const CharT* path) { + if (!path || *path == 0) return 0; + + const UInt64 kFnvBaseOffset = 0xcbf29ce484222325ULL; + const UInt64 kFnvPrimeNumber = 0x100000001b3ULL; + + UInt64 hash = kFnvBaseOffset; + + while (*path) { + hash ^= (CharT) (*path++); + hash *= kFnvPrimeNumber; + } + + return hefsi_to_big_endian_64(hash); + } + + /// @brief Traverse the RB-Tree of the filesystem. + /// @param dir The directory to traverse. + /// @param start The starting point of the traversal. + /// @note This function is used to traverse the RB-Tree of the filesystem. + /// @internal Internal filesystem use only. + STATIC ATTRIBUTE(unused) Void hefsi_traverse_tree(HEFS_INDEX_NODE_DIRECTORY* dir, DriveTrait* mnt, + const Lba& ind_start, Lba& start) { + if (!mnt || !dir) return; + + BOOL check_is_good = NO; + HEFS_INDEX_NODE_DIRECTORY* dir_tmp = new HEFS_INDEX_NODE_DIRECTORY(); + + while (YES) { + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir_tmp; + mnt->fInput(mnt->fPacket); + + if (!mnt->fPacket.fPacketGood) break; + + if (dir_tmp->fNext != 0) { + if (check_is_good) break; + + start = dir_tmp->fNext; + + check_is_good = YES; + continue; + } else if (dir_tmp->fPrev != 0) { + if (check_is_good) break; + + start = dir_tmp->fPrev; + check_is_good = YES; + continue; + } else { + if (dir_tmp->fParent != 0) { + if (check_is_good) break; + + start = dir_tmp->fParent; + check_is_good = YES; + continue; + } else if (dir_tmp->fPrev != 0) { + if (check_is_good) break; + + start = dir_tmp->fPrev; + check_is_good = YES; + continue; + } else { + if (start == 0) { + start = ind_start; + continue; + } + + start += sizeof(HEFS_INDEX_NODE_DIRECTORY); + break; + } + } + } + + delete dir_tmp; + + start += sizeof(HEFS_INDEX_NODE_DIRECTORY); + if (start == 0) start = ind_start; + } + + /***********************************************************************************/ + /// @brief Rotate the RB-Tree to the left or right. + /// @internal + /***********************************************************************************/ + STATIC ATTRIBUTE(unused) _Output Void hefsi_rotate_tree(Lba& start, DriveTrait* mnt) { + if (!start || !mnt) return; + + HEFS_INDEX_NODE_DIRECTORY* cur = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = cur; + + mnt->fInput(mnt->fPacket); + + if (cur->fHashPath == 0) return; + + HEFS_INDEX_NODE_DIRECTORY* sibling = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = cur->fPrev; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = sibling; + + mnt->fInput(mnt->fPacket); + + if (sibling->fHashPath == 0) return; + + auto child_sibling = sibling->fChild; + auto child_cur = cur->fChild; + + cur->fChild = child_sibling; + sibling->fChild = child_cur; + + sibling->fChecksum = ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + cur->fChecksum = ke_calculate_crc32((Char*) cur, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = cur->fParent; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = sibling; + + mnt->fOutput(mnt->fPacket); + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = cur; + + mnt->fOutput(mnt->fPacket); + + HEFS_INDEX_NODE_DIRECTORY* sibling_child = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = child_sibling; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = sibling_child; + + mnt->fInput(mnt->fPacket); + + sibling_child->fParent = cur->fParent; + + sibling_child->fChecksum = + ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fOutput(mnt->fPacket); + + HEFS_INDEX_NODE_DIRECTORY* cur_child = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = child_cur; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = cur_child; + + mnt->fInput(mnt->fPacket); + + cur_child->fParent = start; + + cur_child->fChecksum = ke_calculate_crc32((Char*) sibling, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fOutput(mnt->fPacket); + + kout << "RB-Tree has been rotated.\r"; + } + + /// @brief Alllocate IND from boot node. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read from. + /// @param dir_name The name of the directory. + /// @param dir_name The parent of the directory. + /// @param flags Directory flags. + /// @param delete_or_create Delete or create directory. + STATIC _Output BOOL hefsi_update_ind_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, + const Utf8Char* dir_name, UInt16 flags, + const BOOL delete_or_create) { + if (mnt) { + HEFS_INDEX_NODE_DIRECTORY* tmpdir = + (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); + + auto start = boot->fStartIND; + auto prev_location = start; + auto parent_location = 0UL; + + MUST_PASS(boot->fStartIND > mnt->fLbaStart); + + while (YES) { + auto prev_start = start; + + if (start) + mnt->fPacket.fPacketLba = start; + else + mnt->fPacket.fPacketLba = prev_location + sizeof(HEFS_INDEX_NODE_DIRECTORY); + + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = tmpdir; + + mnt->fInput(mnt->fPacket); + + BOOL expr = NO; + + if (!delete_or_create) { + expr = (!tmpdir->fCreated && tmpdir->fDeleted) || tmpdir->fHashPath == 0; + } else { + expr = + tmpdir->fCreated && !tmpdir->fDeleted && hefsi_hash_64(dir_name) == tmpdir->fHashPath; + } + + if (expr) { + HEFS_INDEX_NODE_DIRECTORY* dirent = + (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); + + rt_set_memory(dirent, 0, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + dirent->fHashPath = delete_or_create ? 0UL : hefsi_hash_64(dir_name); + dirent->fAccessed = 0UL; + dirent->fCreated = delete_or_create ? 0UL : 1UL; + dirent->fDeleted = delete_or_create ? 1UL : 0UL; + dirent->fModified = 0UL; + dirent->fEntryCount = 0UL; + + dirent->fReserved = 0; + dirent->fFlags = flags; + dirent->fChecksum = 0; + + dirent->fEntryCount = 0; + + if (parent_location) { + HEFS_INDEX_NODE_DIRECTORY* tmpend = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = parent_location; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = tmpend; + + mnt->fInput(mnt->fPacket); + + if (tmpend->fChecksum != + ke_calculate_crc32((Char*) tmpend, sizeof(HEFS_INDEX_NODE_DIRECTORY))) + ke_panic(RUNTIME_CHECK_FILESYSTEM, "Bad CRC32 value, aborting."); + + if (delete_or_create) + --tmpend->fEntryCount; + else + ++tmpend->fEntryCount; + + tmpend->fChecksum = + ke_calculate_crc32((Char*) tmpend, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fOutput(mnt->fPacket); + + auto child_first = tmpend->fChild; + + while (YES) { + mnt->fPacket.fPacketLba = child_first; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = tmpend; + + mnt->fInput(mnt->fPacket); + + if ((!tmpend->fCreated && tmpend->fDeleted) || tmpend->fHashPath == 0) { + start = child_first; + break; + } + + hefsi_traverse_tree(tmpend, mnt, boot->fStartIND, child_first); + } + } + + dirent->fNext = tmpdir->fNext; + dirent->fPrev = tmpdir->fPrev; + dirent->fParent = tmpdir->fParent; + dirent->fChild = tmpdir->fChild; + dirent->fColor = tmpdir->fColor; + + if (dirent->fColor == 0) { + dirent->fColor = dirent->fNext ? kHeFSRed : kHeFSBlack; + } + + if (dirent->fPrev == 0) { + dirent->fPrev = boot->fStartIND; + } + + if (dirent->fParent == 0) { + dirent->fParent = boot->fStartIND; + } + + if (tmpdir->fChild == 0) { + auto child = dirent->fNext + sizeof(HEFS_INDEX_NODE_DIRECTORY); + + HEFS_INDEX_NODE_DIRECTORY* tmpend = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + while (YES) { + mnt->fPacket.fPacketLba = child; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = tmpend; + + mnt->fInput(mnt->fPacket); + + if ((!tmpend->fCreated && tmpend->fDeleted) || tmpdir->fHashPath == 0) { + break; + } + + child += sizeof(HEFS_INDEX_NODE_DIRECTORY); + if (child > boot->fEndIND) break; + } + + dirent->fColor = kHeFSRed; + dirent->fChild = child; + + if (child > boot->fEndIND) dirent->fChild = boot->fStartIND; + } + + for (SizeT index = 0UL; index < kHeFSSliceCount; ++index) { + dirent->fINSlices[index] = 0UL; + } + + dirent->fChecksum = ke_calculate_crc32((Char*) dirent, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = prev_start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dirent; + + mnt->fOutput(mnt->fPacket); + + err_global_get() = kErrorSuccess; + + mm_free_ptr(dirent); + mm_free_ptr(tmpdir); + + if (!delete_or_create) + ++boot->fINDCount; + else + --boot->fINDCount; + + boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fOutput(mnt->fPacket); + + return YES; + } + + prev_location = start; + + hefsi_traverse_tree(tmpdir, mnt, boot->fStartIND, start); + if (start > boot->fEndIND || start == 0) break; + } + + err_global_get() = kErrorDisk; + mm_free_ptr(tmpdir); + + return NO; + } + + err_global_get() = kErrorDiskIsFull; + return NO; + } + + /// @brief Get the index node of a file or directory. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read from. + /// @param dir_name The name of the directory. + /// @param file_name The name of the file. + /// @param kind The kind of the file (regular, directory, block, character, FIFO, socket, symbolic + /// link, unknown). + STATIC ATTRIBUTE(unused) _Output HEFS_INDEX_NODE* hefsi_fetch_in(HEFS_BOOT_NODE* boot, + DriveTrait* mnt, + const Utf8Char* dir_name, + const Utf8Char* file_name, + UInt8 kind) { + if (mnt) { + if (boot->fStartIND > boot->fEndIND) return nullptr; + if (boot->fStartIN > boot->fEndIN) return nullptr; + + auto start = boot->fStartIND; + HEFS_INDEX_NODE* node = new HEFS_INDEX_NODE(); + + HEFS_INDEX_NODE_DIRECTORY* dir = + (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); + + while (YES) { + if (err_global_get() == kErrorDiskIsCorrupted) { + delete dir; + dir = nullptr; + + delete node; + node = nullptr; + + return nullptr; + } + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fInput(mnt->fPacket); + + (Void)(kout << hex_number(hefsi_hash_64(dir_name)) << kendl); + (Void)(kout << hex_number(dir->fHashPath) << kendl); + + if (dir->fHashPath == 0) break; + + if (hefsi_hash_64(dir_name) == dir->fHashPath) { + for (SizeT inode_index = 0UL; inode_index < kHeFSSliceCount; ++inode_index) { + mnt->fPacket.fPacketLba = dir->fINSlices[inode_index]; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); + mnt->fPacket.fPacketContent = node; + + mnt->fInput(mnt->fPacket); + + (Void)(kout << hex_number(hefsi_hash_64(file_name)) << kendl); + (Void)(kout << hex_number(node->fHashPath) << kendl); + + if (hefsi_hash_64(file_name) == node->fHashPath && node->fKind == kind) { + delete dir; + dir = nullptr; + + return node; + } + } + } + + hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); + if (start == boot->fStartIND || start == boot->fStartIND) break; + } + + delete node; + node = nullptr; + + delete dir; + dir = nullptr; + } + + kout << "Error: Failed to find IN.\r"; + + err_global_get() = kErrorFileNotFound; + + return nullptr; + } + + STATIC ATTRIBUTE(unused) _Output BOOL + hefsi_update_in_status(HEFS_BOOT_NODE* boot, DriveTrait* mnt, const Utf8Char* dir_name, + HEFS_INDEX_NODE* node, BOOL delete_or_create) { + if (!boot || !mnt) return NO; + + auto start = boot->fStartIND; + + if (start > boot->fEndIND) return NO; + if (boot->fStartIN > boot->fEndIN) return NO; + ; + if (boot->fStartBlock > boot->fEndBlock) return NO; + + if (mnt) { + HEFS_INDEX_NODE_DIRECTORY* dir = + (HEFS_INDEX_NODE_DIRECTORY*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE_DIRECTORY), Yes, No); + + auto hash_file = node->fHashPath; + + while (YES) { + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fInput(mnt->fPacket); + + (Void)(kout << hex_number(hefsi_hash_64(dir_name)) << kendl); + (Void)(kout << hex_number(dir->fHashPath) << kendl); + + if (hefsi_hash_64(dir_name) == dir->fHashPath) { + for (SizeT inode_index = 0UL; inode_index < kHeFSSliceCount; ++inode_index) { + if (dir->fINSlices[inode_index] == 0 && !delete_or_create) { + dir->fINSlices[inode_index] = boot->fStartIN; + + ++dir->fEntryCount; + + dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fOutput(mnt->fPacket); + + auto lba = dir->fINSlices[inode_index]; + + node->fOffsetSliceLow = (UInt32) (boot->fStartBlock); + node->fOffsetSliceHigh = (UInt32) (boot->fStartBlock >> 32); + + node->fChecksum = ke_calculate_crc32((Char*) node, sizeof(HEFS_INDEX_NODE)); + + mnt->fPacket.fPacketLba = lba; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); + mnt->fPacket.fPacketContent = node; + + mnt->fOutput(mnt->fPacket); + + boot->fStartIN += sizeof(HEFS_INDEX_NODE); + boot->fStartBlock += kHeFSBlockLen; + + boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fOutput(mnt->fPacket); + + mm_free_ptr(dir); + + return YES; + } else if (dir->fINSlices[inode_index] != 0 && delete_or_create) { + auto lba = dir->fINSlices[inode_index]; + + HEFS_INDEX_NODE tmp_node{}; + + mnt->fPacket.fPacketLba = lba; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); + mnt->fPacket.fPacketContent = &tmp_node; + + mnt->fInput(mnt->fPacket); + + if (tmp_node.fHashPath != hash_file) { + continue; + } + + node->fOffsetSliceLow = 0; + node->fOffsetSliceHigh = 0; + + boot->fStartIN -= sizeof(HEFS_INDEX_NODE); + boot->fStartBlock -= kHeFSBlockLen; + + boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fOutput(mnt->fPacket); + + mnt->fPacket.fPacketLba = lba; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE); + mnt->fPacket.fPacketContent = node; + + mnt->fOutput(mnt->fPacket); + + dir->fINSlices[inode_index] = 0; + + if (dir->fEntryCount) --dir->fEntryCount; + + dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fOutput(mnt->fPacket); + + mm_free_ptr(dir); + + return YES; + } + } + } + + hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); + if (start > boot->fEndIND || start == 0) break; + } + + mm_free_ptr(dir); + err_global_get() = kErrorFileNotFound; + return NO; + } + + err_global_get() = kErrorDiskIsFull; + return NO; + } + + /// @brief Balance RB-Tree of the filesystem. + /// @param boot The boot node of the filesystem. + /// @param mnt The mnt to read/write from. + /// @return Status, see err_global_get(). + STATIC ATTRIBUTE(unused) _Output BOOL hefsi_balance_ind(HEFS_BOOT_NODE* boot, DriveTrait* mnt) { + if (mnt) { + HEFS_INDEX_NODE_DIRECTORY* dir = + (HEFS_INDEX_NODE_DIRECTORY*) RTL_ALLOCA(sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + auto start = boot->fStartIND; + + while (YES) { + if (start == 0UL || start > boot->fEndIND) break; + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fInput(mnt->fPacket); + + if (!mnt->fPacket.fPacketGood) { + err_global_get() = kErrorDiskIsCorrupted; + + return NO; + } + + if (start == boot->fStartIND) { + dir->fColor = kHeFSBlack; + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fOutput(mnt->fPacket); + } + + if (dir->fColor == kHeFSBlack && dir->fChild != 0UL) { + dir->fColor = kHeFSRed; + hefsi_rotate_tree(start, mnt); + } else if (dir->fColor == kHeFSBlack && dir->fChild == 0UL) { + dir->fColor = kHeFSBlack; + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fOutput(mnt->fPacket); + } + + if (ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)) != dir->fChecksum) { + dir->fChecksum = ke_calculate_crc32((Char*) dir, sizeof(HEFS_INDEX_NODE_DIRECTORY)); + + mnt->fPacket.fPacketLba = start; + mnt->fPacket.fPacketSize = sizeof(HEFS_INDEX_NODE_DIRECTORY); + mnt->fPacket.fPacketContent = dir; + + mnt->fOutput(mnt->fPacket); + } + + hefsi_traverse_tree(dir, mnt, boot->fStartIND, start); + } + + err_global_get() = kErrorSuccess; + return YES; + } + + err_global_get() = kErrorDisk; + return NO; + } +} // namespace Detail +} // namespace Kernel + +/// @note OpenHeFS will allocate inodes and ind in advance, to avoid having to allocate them in +/// real-time. +/// @note This is certainly take longer to format a disk with it, but worth-it in the long run. + +namespace Kernel { +/// @brief Make a EPM+OpenHeFS mnt out of the disk. +/// @param mnt The mnt to write on. +/// @return If it was sucessful, see err_local_get(). +_Output Bool HeFileSystemParser::Format(_Input _Output DriveTrait* mnt, _Input const Int32 flags, + _Input const Utf8Char* vol_name) { + // Verify Disk. + mnt->fVerify(mnt->fPacket); + + // if disk isn't good, then error out. + if (false == mnt->fPacket.fPacketGood) { + err_global_get() = kErrorDiskIsCorrupted; + return false; + } + + if (drv_std_get_size() < kHeFSMinimumDiskSize) { + (Void)(kout << "OpenHeFS recommends at least 128 GiB of free space." << kendl); + (Void)( + kout + << "The OS will still try to format a OpenHeFS disk here anyway, don't expect perfect geometry." + << kendl); + } + + HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) RTL_ALLOCA(sizeof(HEFS_BOOT_NODE)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fInput(mnt->fPacket); + + if (!mnt->fPacket.fPacketGood) { + err_global_get() = kErrorDiskIsCorrupted; + + return NO; + } + + // Check if the disk is already formatted. + + if (KStringBuilder::Equals(boot->fMagic, kHeFSMagic) && boot->fVersion == kHeFSVersion) { + if (ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)) != boot->fChecksum && + boot->fChecksum > 0) { + err_global_get() = kErrorDiskIsCorrupted; + return NO; + } + + err_global_get() = kErrorSuccess; + return YES; + } + + if (ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)) != boot->fChecksum && + boot->fChecksum > 0) { + err_global_get() = kErrorDiskIsCorrupted; + return NO; + } + + rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, + rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); + + urt_copy_memory((VoidPtr) vol_name, boot->fVolName, urt_string_len(vol_name) + 1); + rt_copy_memory_safe((VoidPtr) kHeFSMagic, boot->fMagic, kHeFSMagicLen - 1, sizeof(boot->fMagic)); + + if (mnt->fLbaStart > mnt->fLbaEnd) { + err_global_get() = kErrorDiskIsCorrupted; + + return NO; + } + + boot->fBadSectors = 0; + + boot->fSectorCount = drv_std_get_sector_count(); + boot->fSectorSize = mnt->fSectorSz; + + MUST_PASS(boot->fSectorSize); + + /// @note all OpenHeFS strucutres are equal to 512, so here it's fine, unless fSectoSize is 2048. + const SizeT max_lba = (drv_std_get_size()) / boot->fSectorSize; + + const SizeT dir_max = max_lba / 300; // 5% for directory inodes + const SizeT inode_max = max_lba / 400; // 5% for inodes + + boot->fStartIND = mnt->fLbaStart + kHeFSINDStartOffset; + boot->fEndIND = boot->fStartIND + dir_max; + + boot->fStartIN = boot->fEndIND; + boot->fEndIN = boot->fStartIN + inode_max; + + boot->fStartBlock = boot->fEndIN; + boot->fEndBlock = drv_std_get_size(); + + boot->fINDCount = 0; + + boot->fDiskSize = drv_std_get_size(); + boot->fDiskStatus = kHeFSStatusUnlocked; + + boot->fDiskFlags = flags; + + if (mnt->fKind & kMassStorageDrive) { + boot->fDiskKind = kHeFSMassStorageDevice; + } else if (mnt->fKind & kHeFSOpticalDrive) { + boot->fDiskKind = kHeFSOpticalDrive; + } else { + boot->fDiskKind = kHeFSUnknown; + } + + boot->fVersion = kHeFSVersion; + + boot->fVID = kHeFSInvalidVID; + + boot->fChecksum = ke_calculate_crc32((Char*) boot, sizeof(HEFS_BOOT_NODE)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fOutput(mnt->fPacket); + + (Void)(kout << "Protocol: " << mnt->fProtocol() << kendl); + (Void)(kout8 << u8"Volume Name: " << boot->fVolName << kendl8); + (Void)(kout << "Start IND: " << hex_number(boot->fStartIND) << kendl); + (Void)(kout << "End IND: " << hex_number(boot->fEndIND) << kendl); + (Void)(kout << "Start IN: " << hex_number(boot->fStartIN) << kendl); + (Void)(kout << "End IN: " << hex_number(boot->fEndIN) << kendl); + (Void)(kout << "Start Block: " << hex_number(boot->fStartBlock) << kendl); + (Void)(kout << "End Block: " << hex_number(boot->fEndBlock) << kendl); + (Void)(kout << "Number of IND: " << hex_number(boot->fINDCount) << kendl); + (Void)(kout << "Sector Size: " << hex_number(boot->fSectorSize) << kendl); + (Void)(kout << "Drive Kind: " << Detail::hefs_drive_kind_to_string(boot->fDiskKind) << kendl); + + if (!mnt->fPacket.fPacketGood) { + err_global_get() = kErrorDiskIsCorrupted; + return NO; + } + + constexpr const SizeT kHeFSPreallocateCount = 0x6UL; + + const Utf8Char* kFileMap[kHeFSPreallocateCount] = {u8"/", u8"/boot", u8"/system", + u8"/network", u8"/devices", u8"/media"}; + + for (SizeT i = 0; i < kHeFSPreallocateCount; ++i) { + this->CreateINodeDirectory(mnt, kHeFSEncodingFlagsUTF8, kFileMap[i]); + } + + err_global_get() = kErrorSuccess; + + return YES; +} + +/// @brief Create a new directory on the disk. +/// @param mnt The mnt to write on. +/// @param flags The flags to use. +/// @param dir The directory to create the file in. +/// @return If it was sucessful, see err_local_get(). +_Output Bool HeFileSystemParser::INodeDirectoryCtlManip(_Input DriveTrait* mnt, + _Input const Int32 flags, + const Utf8Char* dir, + const BOOL delete_or_create) { + if (urt_string_len(dir) > kHeFSFileNameLen) { + err_global_get() = kErrorDisk; + return NO; + } + + HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) mm_alloc_ptr(sizeof(HEFS_BOOT_NODE), Yes, No); + + rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, + rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fInput(mnt->fPacket); + + if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { + err_global_get() = kErrorDisk; + return YES; + } + + if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { + err_global_get() = kErrorDiskIsCorrupted; + + kout << "Invalid Boot Node, this can't continue!\r"; + + return NO; + } + + if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { + kout << "Error: Invalid directory name.\r"; + + err_global_get() = kErrorInvalidData; + + return NO; + } + + if (Detail::hefsi_update_ind_status(boot, mnt, dir, flags, delete_or_create)) { + // todo: make it smarter for high-throughput. + Detail::hefsi_balance_ind(boot, mnt); + + mm_free_ptr((VoidPtr) boot); + return YES; + } + + mm_free_ptr((VoidPtr) boot); + return NO; +} + +_Output Bool HeFileSystemParser::RemoveINodeDirectory(_Input DriveTrait* mnt, + _Input const Int32 flags, + const Utf8Char* dir) { + return this->INodeDirectoryCtlManip(mnt, flags, dir, YES); +} + +_Output Bool HeFileSystemParser::CreateINodeDirectory(_Input DriveTrait* mnt, + _Input const Int32 flags, + const Utf8Char* dir) { + return this->INodeDirectoryCtlManip(mnt, flags, dir, NO); +} + +_Output Bool HeFileSystemParser::DeleteINode(_Input DriveTrait* mnt, _Input const Int32 flags, + const Utf8Char* dir, const Utf8Char* name, + const UInt8 kind) { + return this->INodeCtlManip(mnt, flags, dir, name, YES, kind); +} + +_Output Bool HeFileSystemParser::CreateINode(_Input DriveTrait* mnt, _Input const Int32 flags, + const Utf8Char* dir, const Utf8Char* name, + const UInt8 kind) { + return this->INodeCtlManip(mnt, flags, dir, name, NO, kind); +} + +_Output Bool HeFileSystemParser::INodeManip(_Input DriveTrait* mnt, VoidPtr block, SizeT block_sz, + const Utf8Char* dir, const Utf8Char* name, + const UInt8 kind, const BOOL is_input) { + if (urt_string_len(dir) > kHeFSFileNameLen) { + err_global_get() = kErrorDisk; + return NO; + } + + if (urt_string_len(name) > kHeFSFileNameLen) { + err_global_get() = kErrorDisk; + return NO; + } + + HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) mm_alloc_ptr(sizeof(HEFS_BOOT_NODE), Yes, No); + + if (!boot) { + err_global_get() = kErrorInvalidData; + return NO; + } + + rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, + rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fInput(mnt->fPacket); + + if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { + (Void)(kout << "Invalid Boot Node, OpenHeFS partition is invalid." << kendl); + mm_free_ptr((VoidPtr) boot); + err_global_get() = kErrorDisk; + return NO; + } + + auto start = Detail::hefsi_fetch_in(boot, mnt, dir, name, kind); + + if (start) { + (Void)(kout << hex_number(start->fHashPath) << kendl); + (Void)(kout << hex_number(start->fOffsetSliceLow) << kendl); + + if (start->fOffsetSliceLow && start->fHashPath) { + mnt->fPacket.fPacketLba = ((UInt64) start->fOffsetSliceHigh << 32) | start->fOffsetSliceLow; + mnt->fPacket.fPacketSize = block_sz; + mnt->fPacket.fPacketContent = block; + + if (is_input) { + mnt->fInput(mnt->fPacket); + } else { + if (start->fFlags & kHeFSFlagsReadOnly) { + mm_free_ptr((VoidPtr) boot); + delete start; + + kout << "Error: File is read-only\r"; + + return NO; + } + + mnt->fOutput(mnt->fPacket); + } + } + } + + mm_free_ptr((VoidPtr) boot); + delete start; + return YES; +} + +/// @brief Create a new file on the disk. +/// @param mnt The mnt to write on. +/// @param flags The flags to use. +/// @param dir The directory to create the file in. +/// @param name The name of the file. +/// @return If it was sucessful, see err_local_get(). +_Output Bool HeFileSystemParser::INodeCtlManip(_Input DriveTrait* mnt, _Input const Int32 flags, + const Utf8Char* dir, const Utf8Char* name, + const BOOL delete_or_create, const UInt8 kind) { + if (urt_string_len(name) > kHeFSFileNameLen) { + err_global_get() = kErrorDisk; + return NO; + } + + if (urt_string_len(dir) > kHeFSFileNameLen) { + err_global_get() = kErrorDisk; + return NO; + } + + HEFS_INDEX_NODE* node = (HEFS_INDEX_NODE*) mm_alloc_ptr(sizeof(HEFS_INDEX_NODE), Yes, No); + + if (!node) { + err_global_get() = kErrorInvalidData; + return NO; + } + + rt_set_memory(node, 0, sizeof(HEFS_INDEX_NODE)); + + HEFS_BOOT_NODE* boot = (HEFS_BOOT_NODE*) RTL_ALLOCA(sizeof(HEFS_BOOT_NODE)); + + if (!boot) { + mm_free_ptr((VoidPtr) node); + err_global_get() = kErrorInvalidData; + + return NO; + } + + rt_copy_memory_safe((VoidPtr) "fs/hefs-packet", mnt->fPacket.fPacketMime, + rt_string_len("fs/hefs-packet"), sizeof(mnt->fPacket.fPacketMime)); + + mnt->fPacket.fPacketLba = mnt->fLbaStart; + mnt->fPacket.fPacketSize = sizeof(HEFS_BOOT_NODE); + mnt->fPacket.fPacketContent = boot; + + mnt->fInput(mnt->fPacket); + + if (!KStringBuilder::Equals(boot->fMagic, kHeFSMagic) || boot->fVersion != kHeFSVersion) { + err_global_get() = kErrorDisk; + return YES; + } + + if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { + kout << "Error: Invalid file name.\r"; + + err_global_get() = kErrorInvalidData; + return NO; + } + + for (SizeT i_name = 0UL; i_name < urt_string_len(name); ++i_name) { + if (name[i_name] == u'/') { + err_global_get() = kErrorInvalidData; + return NO; + } + } + + if (KStringBuilder::Equals(dir, kHeFSSearchAllStr)) { + kout << "Error: Invalid directory name.\r"; + + err_global_get() = kErrorInvalidData; + return NO; + } + + node->fAccessed = 0; + node->fCreated = delete_or_create ? NO : YES; + node->fDeleted = delete_or_create ? 1UL : NO; + node->fModified = 0; + node->fSize = 0; + node->fKind = kind; + node->fFlags = flags; + node->fChecksum = 0; + node->fGID = 0; + node->fUID = 0; + node->fHashPath = Detail::hefsi_hash_64(name); + + if (Detail::hefsi_update_in_status(boot, mnt, dir, node, delete_or_create)) { + mm_free_ptr((VoidPtr) node); + + Detail::hefsi_balance_ind(boot, mnt); + + err_global_get() = kErrorSuccess; + return YES; + } + + mm_free_ptr((VoidPtr) node); + err_global_get() = kErrorDirectoryNotFound; + + return NO; +} + +STATIC DriveTrait kMountPoint; + +/// @brief Initialize the OpenHeFS filesystem. +/// @return To check its status, see err_local_get(). +Boolean OpenHeFS::fs_init_hefs(Void) noexcept { + kout << "Verifying disk...\r"; + + kMountPoint = io_construct_main_drive(); + + if (kMountPoint.fPacket.fPacketReadOnly == YES) + ke_panic(RUNTIME_CHECK_FILESYSTEM, "Main disk cannot be mounted (read-only media)."); + + HeFileSystemParser parser; + + return parser.Format(&kMountPoint, kHeFSEncodingFlagsUTF8, kHeFSDefaultVolumeName); +} +} // namespace Kernel + +#endif // ifdef __FSKIT_INCLUDES_HEFS__ diff --git a/dev/kernel/src/IFS.cc b/dev/kernel/src/IFS.cc index ba2ec8c0..ffb8ef8e 100644 --- a/dev/kernel/src/IFS.cc +++ b/dev/kernel/src/IFS.cc @@ -28,25 +28,25 @@ namespace Kernel { /// @param DrvTrait drive info /// @param DrvIndex drive index. /// @return -Int32 fs_ifs_read(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) { +Int32 fs_ifs_read(IMountpoint* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) { if (!Mnt) return kErrorDisk; DrvTrait.fPacket.fPacketGood = false; switch (DrvIndex) { - case MountpointInterface::kDriveIndexA: { + case IMountpoint::kDriveIndexA: { fsi_ifs_read(A, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexB: { + case IMountpoint::kDriveIndexB: { fsi_ifs_read(B, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexC: { + case IMountpoint::kDriveIndexC: { fsi_ifs_read(C, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexD: { + case IMountpoint::kDriveIndexD: { fsi_ifs_read(D, DrvTrait.fPacket, Mnt); break; } @@ -60,25 +60,25 @@ Int32 fs_ifs_read(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex /// @param DrvTrait drive info /// @param DrvIndex drive index. /// @return -Int32 fs_ifs_write(MountpointInterface* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) { +Int32 fs_ifs_write(IMountpoint* Mnt, DriveTrait& DrvTrait, Int32 DrvIndex) { if (!Mnt) return kErrorDisk; DrvTrait.fPacket.fPacketGood = false; switch (DrvIndex) { - case MountpointInterface::kDriveIndexA: { + case IMountpoint::kDriveIndexA: { fsi_ifs_write(A, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexB: { + case IMountpoint::kDriveIndexB: { fsi_ifs_write(B, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexC: { + case IMountpoint::kDriveIndexC: { fsi_ifs_write(C, DrvTrait.fPacket, Mnt); break; } - case MountpointInterface::kDriveIndexD: { + case IMountpoint::kDriveIndexD: { fsi_ifs_write(D, DrvTrait.fPacket, Mnt); break; } diff --git a/dev/kernel/src/Storage/AHCIDeviceInterface.cc b/dev/kernel/src/Storage/AHCIDeviceInterface.cc index 182ed2b3..6dcfed69 100644 --- a/dev/kernel/src/Storage/AHCIDeviceInterface.cc +++ b/dev/kernel/src/Storage/AHCIDeviceInterface.cc @@ -13,9 +13,9 @@ using namespace Kernel; /// @param In Drive input /// @param Cleanup Drive cleanup. AHCIDeviceInterface::AHCIDeviceInterface(void (*out)(DeviceInterface* self, - MountpointInterface* outpacket), + IMountpoint* outpacket), void (*in)(DeviceInterface* self, - MountpointInterface* inpacket)) + IMountpoint* inpacket)) : DeviceInterface(out, in) {} /// @brief Class desctructor @@ -30,7 +30,7 @@ const Char* AHCIDeviceInterface::Name() const { /// @brief Output operator. /// @param mnt the disk mountpoint. /// @return the class itself after operation. -AHCIDeviceInterface& AHCIDeviceInterface::operator<<(MountpointInterface* mnt) { +AHCIDeviceInterface& AHCIDeviceInterface::operator<<(IMountpoint* mnt) { if (!mnt) return *this; for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) { @@ -45,13 +45,13 @@ AHCIDeviceInterface& AHCIDeviceInterface::operator<<(MountpointInterface* mnt) { } } - return (AHCIDeviceInterface&) DeviceInterface::operator<<(mnt); + return (AHCIDeviceInterface&) DeviceInterface::operator<<(mnt); } /// @brief Input operator. /// @param mnt the disk mountpoint. /// @return the class itself after operation. -AHCIDeviceInterface& AHCIDeviceInterface::operator>>(MountpointInterface* mnt) { +AHCIDeviceInterface& AHCIDeviceInterface::operator>>(IMountpoint* mnt) { if (!mnt) return *this; for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) { @@ -67,7 +67,7 @@ AHCIDeviceInterface& AHCIDeviceInterface::operator>>(MountpointInterface* mnt) { } } - return (AHCIDeviceInterface&) DeviceInterface::operator>>(mnt); + return (AHCIDeviceInterface&) DeviceInterface::operator>>(mnt); } const UInt16& AHCIDeviceInterface::GetPortsImplemented() { @@ -84,6 +84,6 @@ const UInt32& AHCIDeviceInterface::GetIndex() { } Void AHCIDeviceInterface::SetIndex(const UInt32& drv) { - MUST_PASS(MountpointInterface::kDriveIndexInvalid < drv); + MUST_PASS(IMountpoint::kDriveIndexInvalid < drv); this->fDriveIndex = drv; } \ No newline at end of file diff --git a/dev/kernel/src/Storage/ATADeviceInterface.cc b/dev/kernel/src/Storage/ATADeviceInterface.cc index e302d2cc..70d6e9ae 100644 --- a/dev/kernel/src/Storage/ATADeviceInterface.cc +++ b/dev/kernel/src/Storage/ATADeviceInterface.cc @@ -13,8 +13,8 @@ using namespace Kernel; /// @param In Drive input /// @param Cleanup Drive cleanup. ATADeviceInterface::ATADeviceInterface(void (*Out)(DeviceInterface*, - MountpointInterface* outpacket), - void (*In)(DeviceInterface*, MountpointInterface* inpacket)) + IMountpoint* outpacket), + void (*In)(DeviceInterface*, IMountpoint* inpacket)) : DeviceInterface(Out, In) {} /// @brief Class desctructor @@ -29,7 +29,7 @@ const Char* ATADeviceInterface::Name() const { /// @brief Output operator. /// @param Data the disk mountpoint. /// @return the class itself after operation. -ATADeviceInterface& ATADeviceInterface::operator<<(MountpointInterface* Data) { +ATADeviceInterface& ATADeviceInterface::operator<<(IMountpoint* Data) { if (!Data) return *this; for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) { @@ -44,13 +44,13 @@ ATADeviceInterface& ATADeviceInterface::operator<<(MountpointInterface* Data) { } } - return (ATADeviceInterface&) DeviceInterface::operator<<(Data); + return (ATADeviceInterface&) DeviceInterface::operator<<(Data); } /// @brief Input operator. /// @param Data the disk mountpoint. /// @return the class itself after operation. -ATADeviceInterface& ATADeviceInterface::operator>>(MountpointInterface* Data) { +ATADeviceInterface& ATADeviceInterface::operator>>(IMountpoint* Data) { if (!Data) return *this; for (SizeT driveCount = 0; driveCount < kDriveMaxCount; ++driveCount) { @@ -66,7 +66,7 @@ ATADeviceInterface& ATADeviceInterface::operator>>(MountpointInterface* Data) { } } - return (ATADeviceInterface&) DeviceInterface::operator>>(Data); + return (ATADeviceInterface&) DeviceInterface::operator>>(Data); } const UInt32& ATADeviceInterface::GetIndex() { @@ -74,7 +74,7 @@ const UInt32& ATADeviceInterface::GetIndex() { } Void ATADeviceInterface::SetIndex(const UInt32& drv) { - MUST_PASS(MountpointInterface::kDriveIndexInvalid < drv); + MUST_PASS(IMountpoint::kDriveIndexInvalid < drv); this->fDriveIndex = drv; } diff --git a/dev/kernel/src/Storage/NVMEDeviceInterface.cc b/dev/kernel/src/Storage/NVMEDeviceInterface.cc index 077595cf..0b8043b7 100644 --- a/dev/kernel/src/Storage/NVMEDeviceInterface.cc +++ b/dev/kernel/src/Storage/NVMEDeviceInterface.cc @@ -8,8 +8,8 @@ namespace Kernel { NVMEDeviceInterface::NVMEDeviceInterface( - void (*out)(DeviceInterface*, MountpointInterface* outpacket), - void (*in)(DeviceInterface*, MountpointInterface* inpacket), void (*cleanup)(void)) + void (*out)(DeviceInterface*, IMountpoint* outpacket), + void (*in)(DeviceInterface*, IMountpoint* inpacket), void (*cleanup)(void)) : DeviceInterface(out, in), fCleanup(cleanup) {} NVMEDeviceInterface::~NVMEDeviceInterface() { diff --git a/dev/libSystem/SystemKit/System.h b/dev/libSystem/SystemKit/System.h index f46fe523..88472513 100644 --- a/dev/libSystem/SystemKit/System.h +++ b/dev/libSystem/SystemKit/System.h @@ -79,7 +79,7 @@ IMPORT_C Void IoCloseFile(_Input Ref file_desc); /// @param in_data the input data. /// @param out_data the output data. /// @return the number of bytes written. -/// @note This function is used to control the file descriptor, introduced for HeFS. +/// @note This function is used to control the file descriptor, introduced for OpenHeFS. IMPORT_C SInt32 IoCtrlFile(_Input Ref file_desc, _Input UInt32 ioctl_code, _Input VoidPtr in_data, _Output VoidPtr out_data); @@ -89,7 +89,7 @@ IMPORT_C const Char* IoMimeFile(_Input Ref file_desc); /// @brief Gets the dir DIM. /// @param dir_desc directory descriptor. -/// @note only works in HeFS, will return nil-x/nil if used on any other filesystem. +/// @note only works in OpenHeFS, will return nil-x/nil if used on any other filesystem. IMPORT_C const Char* IoDimFile(_Input Ref dir_desc); /// @brief Write data to a file ref diff --git a/docs/tex/hefs.tex b/docs/tex/hefs.tex index c35bca53..9ec68020 100644 --- a/docs/tex/hefs.tex +++ b/docs/tex/hefs.tex @@ -4,7 +4,7 @@ \usepackage{longtable} \usepackage{listings} \geometry{margin=1in} -\title{HeFS: Hight-throughput extended File System} +\title{OpenHeFS: Hight-throughput extended File System} \author{Amlal El Mahrouss} \date{\today} @@ -13,7 +13,7 @@ \maketitle \section{Overview} -The High-throughput Extended File System (HeFS) is a custom filesystem tailored for performance, structure, and compact representation. It uses red-black trees for directory indexing, sparse block slicing for file layout, and fixed-size metadata structures optimized for 512-byte sector alignment. +The High-throughput Extended File System (OpenHeFS) is a custom filesystem tailored for performance, structure, and compact representation. It uses red-black trees for directory indexing, sparse block slicing for file layout, and fixed-size metadata structures optimized for 512-byte sector alignment. \section{Constants and Macros} \begin{longtable}{|l|l|} @@ -21,13 +21,13 @@ The High-throughput Extended File System (HeFS) is a custom filesystem tailored \textbf{Name} & \textbf{Value / Description} \\ \hline \texttt{kHeFSVersion} & 0x0103 \\ -\texttt{kHeFSMagic} & " HeFS" (8-byte magic identifier) \\ +\texttt{kHeFSMagic} & " OpenHeFS" (8-byte magic identifier) \\ \texttt{kHeFSMagicLen} & 8 \\ \texttt{kHeFSBlockLen} & 512 bytes \\ \texttt{kHeFSFileNameLen} & 256 characters \\ \texttt{kHeFSPartNameLen} & 128 characters \\ \texttt{kHeFSMinimumDiskSize} & 128 GiB \\ -\texttt{kHeFSDefaultVolumeName} & "HeFS Volume" \\ +\texttt{kHeFSDefaultVolumeName} & "OpenHeFS Volume" \\ \texttt{kHeFSINDStartOffset} & Offset after boot node \\ \texttt{kHeFSSearchAllStr} & "*" (wildcard string) \\ \hline @@ -151,10 +151,10 @@ Constants: \section{Filesystem API}\label{sec:filesystem-api} -Provided by \texttt{Kernel::HeFS::HeFileSystemParser}. +Provided by \texttt{Kernel::OpenHeFS::HeFileSystemParser}. \begin{itemize} - \item \texttt{Format(drive, flags, name)} - Format drive with HeFS + \item \texttt{Format(drive, flags, name)} - Format drive with OpenHeFS \item \texttt{CreateINodeDirectory(drive, flags, dir)} \item \texttt{RemoveINodeDirectory(drive, flags, dir)} \item \texttt{CreateINode(drive, flags, dir, name, kind)} @@ -168,7 +168,7 @@ Internal helpers: \end{itemize} \section{Conclusion} -HeFS provides a modern and compact approach to high-performance file storage. +OpenHeFS provides a modern and compact approach to high-performance file storage. Its use of red-black trees, fixed-size metadata, slice-based sparse files, and minimal overhead makes it a strong candidate for performance-sensitive use cases. \end{document} diff --git a/public/frameworks/DiskImage.fwrk/headers/DiskImage.h b/public/frameworks/DiskImage.fwrk/headers/DiskImage.h index 4a18b079..198d64a1 100644 --- a/public/frameworks/DiskImage.fwrk/headers/DiskImage.h +++ b/public/frameworks/DiskImage.fwrk/headers/DiskImage.h @@ -52,7 +52,7 @@ SInt32 DIFormatPartitionEPM(struct DI_DISK_IMAGE& img) noexcept; /// @return Status code upon completion. SInt32 DIFormatFilesystemNeFS(struct DI_DISK_IMAGE& img) noexcept; -/// @brief HeFS format over EPM. +/// @brief OpenHeFS format over EPM. /// @param img disk image structure. /// @return Status code upon completion. SInt32 DIFormatFilesystemHeFS(struct DI_DISK_IMAGE& img) noexcept; diff --git a/public/frameworks/DiskImage.fwrk/src/DiskImage+HeFS.cc b/public/frameworks/DiskImage.fwrk/src/DiskImage+HeFS.cc index 7f917052..aa7abdf4 100644 --- a/public/frameworks/DiskImage.fwrk/src/DiskImage+HeFS.cc +++ b/public/frameworks/DiskImage.fwrk/src/DiskImage+HeFS.cc @@ -2,17 +2,17 @@ Copyright (C) 2025, Amlal El Mahrouss, all rights reserved. - FILE: DiskImage+HeFS.cc + FILE: DiskImage+OpenHeFS.cc PURPOSE: Disk Imaging framework. ------------------------------------------- */ #include -#include +#include #include -/// @brief format HeFS over an EPM disk. +/// @brief format OpenHeFS over an EPM disk. /// @param img disk image structure. /// @return Status code upon completion. SInt32 DI::DIFormatFilesystemHeFS(struct DI_DISK_IMAGE& img) noexcept { diff --git a/public/manuals/nekernel/mgmt.hefs.util.man b/public/manuals/nekernel/mgmt.hefs.util.man index 3274f93a..1cb7022d 100644 --- a/public/manuals/nekernel/mgmt.hefs.util.man +++ b/public/manuals/nekernel/mgmt.hefs.util.man @@ -1,12 +1,12 @@ NAME - mgmt.hefs — HeFS Management utility command + mgmt.hefs — OpenHeFS Management utility command SYNOPSIS mgmt.hefs [OPTIONS] DESCRIPTION The `mgmt.hefs` command provides scheduling, execution, and remote orchestration - of a HeFS volume inside a System One environement. One might use this tool to + of a OpenHeFS volume inside a System One environement. One might use this tool to create, edit, and remove volumes from a disk. Usages include, but are not limited to: @@ -16,7 +16,7 @@ DESCRIPTION OPTIONS -v, --volume Device input - -c, --create Create HeFS volume + -c, --create Create OpenHeFS volume -x, --xml Pass PropertyList to volume creation tool. -t, --time Time to run the script -d, --day Day of the week (e.g., Mon, Tue, Wed) diff --git a/tools/fsck.hefs.cc b/tools/fsck.hefs.cc index df89bf07..a2162a4f 100644 --- a/tools/fsck.hefs.cc +++ b/tools/fsck.hefs.cc @@ -4,7 +4,7 @@ ------------------------------------------- */ -#include +#include #include #include #include @@ -26,7 +26,7 @@ int main(int argc, char** argv) { auto origin = mkfs::get_option(args, "-org"); if (opt_disk.empty()) { - mkfs::console_out() << "fsck: hefs: error: HeFS partition is empty! Exiting..." + mkfs::console_out() << "fsck: hefs: error: OpenHeFS partition is empty! Exiting..." << "\n"; return EXIT_FAILURE; } @@ -59,16 +59,16 @@ int main(int argc, char** argv) { if (strncmp(boot_node.magic, kHeFSMagic, kHeFSMagicLen) != 0 || boot_node.sectorCount < 1 || boot_node.sectorSize < kMkFsSectorSz) { - mkfs::console_out() << "hefs: error: Device is not an HeFS disk: " << opt_disk << "\n"; + mkfs::console_out() << "hefs: error: Device is not an OpenHeFS disk: " << opt_disk << "\n"; return EXIT_FAILURE; } if (boot_node.badSectors > kMkFsMaxBadSectors) { - mkfs::console_out() << "hefs: error: HeFS disk has too much bad sectors: " << opt_disk << "\n"; + mkfs::console_out() << "hefs: error: OpenHeFS disk has too much bad sectors: " << opt_disk << "\n"; return EXIT_FAILURE; } - mkfs::console_out() << "hefs: HeFS partition is healthy, exiting...\n"; + mkfs::console_out() << "hefs: OpenHeFS partition is healthy, exiting...\n"; output_device.close(); diff --git a/tools/libmkfs/hefs.h b/tools/libmkfs/hefs.h deleted file mode 100644 index 52bb3086..00000000 --- a/tools/libmkfs/hefs.h +++ /dev/null @@ -1,116 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. - -------------------------------------------- */ - -#pragma once - -#include -#include - -#define kHeFSVersion (0x0101) -#define kHeFSMagic " HeFS" -#define kHeFSMagicLen (8) - -#define kHeFSFileNameLen (256U) -#define kHeFSPartNameLen (128U) - -#define kHeFSDefaultVolumeName u8"HeFS Volume" - -namespace mkfs::hefs { - -// Drive kinds -enum { - kHeFSHardDrive = 0xC0, // Hard Drive - kHeFSSolidStateDrive = 0xC1, // Solid State Drive - kHeFSOpticalDrive = 0x0C, // Blu-Ray/DVD - kHeFSMassStorageDevice = 0xCC, // USB - kHeFSScsiDrive = 0xC4, // SCSI Hard Drive - kHeFSFlashDrive = 0xC6, - kHeFSUnknown = 0xFF, // Unknown device. - kHeFSDriveCount = 8, -}; - -// Disk status -enum { - kHeFSStatusUnlocked = 0x18, - kHeFSStatusLocked, - kHeFSStatusError, - kHeFSStatusInvalid, - kHeFSStatusCount, -}; - -// Encodings -enum { - kHeFSEncodingFlagsUTF8 = 0x50, - kHeFSEncodingFlagsUTF16, - kHeFSEncodingFlagsUTF32, - kHeFSEncodingFlagsUTF16BE, - kHeFSEncodingFlagsUTF16LE, - kHeFSEncodingFlagsUTF32BE, - kHeFSEncodingFlagsUTF32LE, - kHeFSEncodingFlagsUTF8BE, - kHeFSEncodingFlagsUTF8LE, - kHeFSEncodingFlagsBinary, - kHeFSEncodingFlagsCount = 11, - kHeFSFlagsNone = 0, - kHeFSFlagsReadOnly = 0x100, - kHeFSFlagsHidden, - kHeFSFlagsSystem, - kHeFSFlagsArchive, - kHeFSFlagsDevice, - kHeFSFlagsCount = 7 -}; - -// Time type -using ATime = std::uint64_t; - -// File kinds -inline constexpr uint16_t kHeFSFileKindRegular = 0x00; -inline constexpr uint16_t kHeFSFileKindDirectory = 0x01; -inline constexpr uint16_t kHeFSFileKindBlock = 0x02; -inline constexpr uint16_t kHeFSFileKindCharacter = 0x03; -inline constexpr uint16_t kHeFSFileKindFIFO = 0x04; -inline constexpr uint16_t kHeFSFileKindSocket = 0x05; -inline constexpr uint16_t kHeFSFileKindSymbolicLink = 0x06; -inline constexpr uint16_t kHeFSFileKindUnknown = 0x07; -inline constexpr uint16_t kHeFSFileKindCount = 0x08; - -// Red-black tree colors -enum { - kHeFSInvalidColor = 0, - kHeFSRed = 100, - kHeFSBlack, - kHeFSColorCount, -}; - -// Time constants -inline constexpr ATime kHeFSTimeInvalid = 0x0000000000000000; -inline constexpr ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF - 1; - -// Boot Node -struct __attribute__((packed)) BootNode { - char magic[kHeFSMagicLen]{}; - char8_t volumeName[kHeFSPartNameLen]{}; - std::uint32_t version{}; - std::uint64_t badSectors{}; - std::uint64_t sectorCount{}; - std::uint64_t sectorSize{}; - std::uint32_t checksum{}; - std::uint8_t diskKind{}; - std::uint8_t encoding{}; - std::uint64_t startIND{}; - std::uint64_t endIND{}; - std::uint64_t indCount{}; - std::uint64_t diskSize{}; - std::uint16_t diskStatus{}; - std::uint16_t diskFlags{}; - std::uint16_t vid{}; - std::uint64_t startIN{}; - std::uint64_t endIN{}; - std::uint64_t startBlock{}; - std::uint64_t endBlock{}; - char pad[272]{}; -}; -} // namespace mkfs::hefs diff --git a/tools/libmkfs/openhefs.h b/tools/libmkfs/openhefs.h new file mode 100644 index 00000000..3bba79e8 --- /dev/null +++ b/tools/libmkfs/openhefs.h @@ -0,0 +1,116 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#pragma once + +#include +#include + +#define kHeFSVersion (0x0101) +#define kHeFSMagic " HeFS" +#define kHeFSMagicLen (8) + +#define kHeFSFileNameLen (256U) +#define kHeFSPartNameLen (128U) + +#define kHeFSDefaultVolumeName u8"OpenHeFS Volume" + +namespace mkfs::hefs { + +// Drive kinds +enum { + kHeFSHardDrive = 0xC0, // Hard Drive + kHeFSSolidStateDrive = 0xC1, // Solid State Drive + kHeFSOpticalDrive = 0x0C, // Blu-Ray/DVD + kHeFSMassStorageDevice = 0xCC, // USB + kHeFSScsiDrive = 0xC4, // SCSI Hard Drive + kHeFSFlashDrive = 0xC6, + kHeFSUnknown = 0xFF, // Unknown device. + kHeFSDriveCount = 8, +}; + +// Disk status +enum { + kHeFSStatusUnlocked = 0x18, + kHeFSStatusLocked, + kHeFSStatusError, + kHeFSStatusInvalid, + kHeFSStatusCount, +}; + +// Encodings +enum { + kHeFSEncodingFlagsUTF8 = 0x50, + kHeFSEncodingFlagsUTF16, + kHeFSEncodingFlagsUTF32, + kHeFSEncodingFlagsUTF16BE, + kHeFSEncodingFlagsUTF16LE, + kHeFSEncodingFlagsUTF32BE, + kHeFSEncodingFlagsUTF32LE, + kHeFSEncodingFlagsUTF8BE, + kHeFSEncodingFlagsUTF8LE, + kHeFSEncodingFlagsBinary, + kHeFSEncodingFlagsCount = 11, + kHeFSFlagsNone = 0, + kHeFSFlagsReadOnly = 0x100, + kHeFSFlagsHidden, + kHeFSFlagsSystem, + kHeFSFlagsArchive, + kHeFSFlagsDevice, + kHeFSFlagsCount = 7 +}; + +// Time type +using ATime = std::uint64_t; + +// File kinds +inline constexpr uint16_t kHeFSFileKindRegular = 0x00; +inline constexpr uint16_t kHeFSFileKindDirectory = 0x01; +inline constexpr uint16_t kHeFSFileKindBlock = 0x02; +inline constexpr uint16_t kHeFSFileKindCharacter = 0x03; +inline constexpr uint16_t kHeFSFileKindFIFO = 0x04; +inline constexpr uint16_t kHeFSFileKindSocket = 0x05; +inline constexpr uint16_t kHeFSFileKindSymbolicLink = 0x06; +inline constexpr uint16_t kHeFSFileKindUnknown = 0x07; +inline constexpr uint16_t kHeFSFileKindCount = 0x08; + +// Red-black tree colors +enum { + kHeFSInvalidColor = 0, + kHeFSRed = 100, + kHeFSBlack, + kHeFSColorCount, +}; + +// Time constants +inline constexpr ATime kHeFSTimeInvalid = 0x0000000000000000; +inline constexpr ATime kHeFSTimeMax = 0xFFFFFFFFFFFFFFFF - 1; + +// Boot Node +struct __attribute__((packed)) BootNode { + char magic[kHeFSMagicLen]{}; + char8_t volumeName[kHeFSPartNameLen]{}; + std::uint32_t version{}; + std::uint64_t badSectors{}; + std::uint64_t sectorCount{}; + std::uint64_t sectorSize{}; + std::uint32_t checksum{}; + std::uint8_t diskKind{}; + std::uint8_t encoding{}; + std::uint64_t startIND{}; + std::uint64_t endIND{}; + std::uint64_t indCount{}; + std::uint64_t diskSize{}; + std::uint16_t diskStatus{}; + std::uint16_t diskFlags{}; + std::uint16_t vid{}; + std::uint64_t startIN{}; + std::uint64_t endIN{}; + std::uint64_t startBlock{}; + std::uint64_t endBlock{}; + char pad[272]{}; +}; +} // namespace mkfs::hefs diff --git a/tools/mkfs.hefs.cc b/tools/mkfs.hefs.cc index 9f70b78f..d1139e10 100644 --- a/tools/mkfs.hefs.cc +++ b/tools/mkfs.hefs.cc @@ -4,7 +4,7 @@ ------------------------------------------- */ -#include +#include #include #include #include -- cgit v1.2.3