summaryrefslogtreecommitdiffhomepage
path: root/src/kernel/FSKit
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal@nekernel.org>2025-11-23 21:06:27 -0500
committerGitHub <noreply@github.com>2025-11-23 21:06:27 -0500
commit23040fad647634c08697451fc22ee2ca999629c8 (patch)
tree72888f88c7728c82f3f6df1f4f70591de15eab36 /src/kernel/FSKit
parente5cc7351f0577b54c528fb827a7c7e6306c3e843 (diff)
parent83d870e58457a1d335a1d9b9966a6a1887cc297b (diff)
Merge pull request #81 from nekernel-org/dev
feat! breaking changes on kernel sources.
Diffstat (limited to 'src/kernel/FSKit')
-rw-r--r--src/kernel/FSKit/Defines.h12
-rw-r--r--src/kernel/FSKit/Ext2+IFS.h273
-rw-r--r--src/kernel/FSKit/Ext2.h148
-rw-r--r--src/kernel/FSKit/IndexableProperty.h58
-rw-r--r--src/kernel/FSKit/NeFS.h413
-rw-r--r--src/kernel/FSKit/OpenHeFS.h434
6 files changed, 1338 insertions, 0 deletions
diff --git a/src/kernel/FSKit/Defines.h b/src/kernel/FSKit/Defines.h
new file mode 100644
index 00000000..c5bf8f88
--- /dev/null
+++ b/src/kernel/FSKit/Defines.h
@@ -0,0 +1,12 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#pragma once
+
+#include <NeKit/Defines.h>
+
+#define FSKIT_VERSION "1.0.0"
+#define FSKIT_VERSION_BCD 0x0100
diff --git a/src/kernel/FSKit/Ext2+IFS.h b/src/kernel/FSKit/Ext2+IFS.h
new file mode 100644
index 00000000..01ca4c90
--- /dev/null
+++ b/src/kernel/FSKit/Ext2+IFS.h
@@ -0,0 +1,273 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#pragma once
+
+#include <FSKit/Ext2.h>
+#include <KernelKit/DriveMgr.h>
+#include <KernelKit/HeapMgr.h>
+#include <KernelKit/KPC.h>
+#include <NeKit/ErrorOr.h>
+#include <NeKit/KernelPanic.h>
+#include <NeKit/Utils.h>
+
+namespace Kernel {
+/// @brief Context for an EXT2 filesystem on a given drive
+class Ext2Context final {
+ public:
+ DriveTrait* drive{nullptr};
+ EXT2_SUPER_BLOCK* superblock{nullptr};
+
+ /// @brief context with a drive
+ Ext2Context(Kernel::DriveTrait* drv) : drive(drv) {}
+
+ /// @brief Clean up
+ ~Ext2Context() {
+ if (superblock) {
+ Kernel::mm_free_ptr(superblock);
+ superblock = nullptr;
+ }
+ }
+
+ Ext2Context(const Ext2Context&) = delete;
+ Ext2Context& operator=(const Ext2Context&) = delete;
+
+ Ext2Context(Ext2Context&& other) noexcept : drive(other.drive), superblock(other.superblock) {
+ other.drive = nullptr;
+ other.superblock = nullptr;
+ }
+
+ Ext2Context& operator=(Ext2Context&& other) noexcept {
+ if (this != &other) {
+ if (superblock) {
+ Kernel::mm_free_ptr(superblock);
+ }
+ drive = other.drive;
+ superblock = other.superblock;
+ other.drive = nullptr;
+ other.superblock = nullptr;
+ }
+ return *this;
+ }
+
+ SizeT BlockSize() const {
+ if (!superblock) return kExt2FSBlockSizeBase;
+ return kExt2FSBlockSizeBase << superblock->fLogBlockSize;
+ }
+
+ operator BOOL() { return superblock != nullptr; }
+};
+
+/// ======================================================================= ///
+/// IFS FUNCTIONS
+/// ======================================================================= ///
+
+inline BOOL ext2_read_block(Kernel::DriveTrait* drv, Kernel::UInt32 lba, VoidPtr buffer,
+ Kernel::UInt32 size) {
+ if (!drv || !buffer) return false;
+
+ Kernel::DriveTrait::DrivePacket pkt{};
+ pkt.fPacketContent = buffer;
+ pkt.fPacketSize = size;
+ pkt.fPacketLba = lba;
+ drv->fInput(pkt);
+
+ return pkt.fPacketGood;
+}
+
+inline BOOL ext2_write_block(Kernel::DriveTrait* drv, Kernel::UInt32 lba, const VoidPtr buffer,
+ Kernel::UInt32 size) {
+ if (!drv || !buffer) return false;
+
+ Kernel::DriveTrait::DrivePacket pkt{};
+ pkt.fPacketContent = const_cast<VoidPtr>(buffer);
+ pkt.fPacketSize = size;
+ pkt.fPacketLba = lba;
+ drv->fOutput(pkt);
+ return pkt.fPacketGood;
+}
+
+inline Kernel::ErrorOr<EXT2_SUPER_BLOCK*> ext2_load_superblock(Ext2Context* ctx) {
+ if (!ctx || !ctx->drive) return Kernel::ErrorOr<EXT2_SUPER_BLOCK*>(Kernel::kErrorInvalidData);
+
+ auto buf = Kernel::mm_alloc_ptr(sizeof(EXT2_SUPER_BLOCK), true, false);
+ if (!buf) return Kernel::ErrorOr<EXT2_SUPER_BLOCK*>(Kernel::kErrorHeapOutOfMemory);
+
+ Kernel::UInt32 blockLba = kExt2FSSuperblockOffset / ctx->drive->fSectorSz;
+
+ if (!ext2_read_block(ctx->drive, blockLba, buf, sizeof(EXT2_SUPER_BLOCK))) {
+ Kernel::mm_free_ptr(buf);
+ return Kernel::ErrorOr<EXT2_SUPER_BLOCK*>(Kernel::kErrorDisk);
+ }
+
+ auto sb = reinterpret_cast<EXT2_SUPER_BLOCK*>(buf);
+ if (sb->fMagic != kExt2FSMagic) {
+ Kernel::mm_free_ptr(buf);
+ return Kernel::ErrorOr<EXT2_SUPER_BLOCK*>(Kernel::kErrorInvalidData);
+ }
+
+ ctx->superblock = sb;
+ return Kernel::ErrorOr<EXT2_SUPER_BLOCK*>(sb);
+}
+
+// Load inode
+inline Kernel::ErrorOr<Ext2Node*> ext2_load_inode(Ext2Context* ctx, Kernel::UInt32 inodeNumber) {
+ if (!ctx || !ctx->superblock) return Kernel::ErrorOr<Ext2Node*>(Kernel::kErrorInvalidData);
+
+ auto nodePtr = Kernel::mm_alloc_ptr(sizeof(Ext2Node), true, false);
+ if (!nodePtr) return Kernel::ErrorOr<Ext2Node*>(Kernel::kErrorHeapOutOfMemory);
+
+ auto ext2Node = reinterpret_cast<Ext2Node*>(nodePtr);
+ ext2Node->inodeNumber = inodeNumber;
+
+ // Compute block group and index within group
+ Kernel::UInt32 inodesPerGroup = ctx->superblock->fInodesPerGroup;
+ Kernel::UInt32 group = (inodeNumber - 1) / inodesPerGroup;
+
+ // dummy: just offset first inode
+ Kernel::UInt32 inodeTableBlock = ctx->superblock->fFirstInode + group;
+
+ if (!ext2_read_block(ctx->drive, inodeTableBlock, &ext2Node->inode, sizeof(EXT2_INODE))) {
+ Kernel::mm_free_ptr(nodePtr);
+ return Kernel::ErrorOr<Ext2Node*>(Kernel::kErrorDisk);
+ }
+
+ ext2Node->cursor = 0;
+ return Kernel::ErrorOr<Ext2Node*>(ext2Node);
+}
+
+/*
+ * Ext2FileSystemParser Class
+ *
+ * Provides high-level interface for EXT2 filesystem operations
+ */
+class Ext2FileSystemParser final {
+ private:
+ Ext2Context fCtx; // Internal EXT2 context
+
+ public:
+ /*
+ * Constructor
+ * Initializes the parser with a drive interface
+ *
+ * @param drive: Pointer to drive trait for disk I/O operations
+ */
+ explicit Ext2FileSystemParser(DriveTrait* drive);
+
+ NE_COPY_DELETE(Ext2FileSystemParser)
+
+ /*
+ * Open a file or directory by path
+ *
+ * @param path: Full path to the file/directory (e.g., "/home/user/file.txt")
+ * @param restrict_type: Access mode restriction (e.g., "r", "w", "rw")
+ * @return: VoidPtr handle to the opened file/directory, or nullptr on failure
+ */
+ VoidPtr Open(const char* path, const char* restrict_type);
+
+ /*
+ * Read data from an open file node
+ *
+ * @param node: File node handle returned by Open()
+ * @param flags: Read operation flags
+ * @param size: Number of bytes to read
+ * @return: Pointer to allocated buffer containing read data, or nullptr on failure
+ * Caller is responsible for freeing the returned buffer
+ */
+ VoidPtr Read(VoidPtr node, Int32 flags, SizeT size);
+
+ /*
+ * Write data to an open file node
+ *
+ * @param node: File node handle returned by Open()
+ * @param data: Buffer containing data to write
+ * @param flags: Write operation flags
+ * @param size: Number of bytes to write
+ */
+ Void Write(VoidPtr node, VoidPtr data, Int32 flags, SizeT size);
+
+ /*
+ * Seek to a specific position in the file
+ *
+ * @param node: File node handle
+ * @param offset: Byte offset from beginning of file
+ * @return: true on success, false on failure
+ */
+ BOOL Seek(VoidPtr node, SizeT offset);
+
+ /*
+ * Get current position in the file
+ *
+ * @param node: File node handle
+ * @return: Current byte offset from beginning of file
+ */
+ SizeT Tell(VoidPtr node);
+
+ /*
+ * Reset file position to beginning
+ *
+ * @param node: File node handle
+ * @return: true on success, false on failure
+ */
+ BOOL Rewind(VoidPtr node);
+
+ /*
+ * Read data from a named file within a directory node
+ *
+ * @param name: Name of file within the directory
+ * @param node: Directory node handle
+ * @param flags: Read operation flags
+ * @param size: Number of bytes to read
+ * @return: Pointer to allocated buffer containing read data, or nullptr on failure
+ */
+ VoidPtr Read(const char* name, VoidPtr node, Int32 flags, SizeT size);
+
+ /*
+ * Write data to a named file within a directory node
+ *
+ * @param name: Name of file within the directory
+ * @param node: Directory node handle
+ * @param data: Buffer containing data to write
+ * @param flags: Write operation flags
+ * @param size: Number of bytes to write
+ */
+ Void Write(const char* name, VoidPtr node, VoidPtr data, Int32 flags, SizeT size);
+
+ /*
+ * Create a new regular file
+ *
+ * @param path: Full path for the new file
+ * @return: VoidPtr handle to the created file, or nullptr on failure
+ */
+ VoidPtr Create(const char* path);
+
+ /*
+ * Create a new directory
+ *
+ * @param path: Full path for the new directory
+ * @return: VoidPtr handle to the created directory, or nullptr on failure
+ */
+ VoidPtr CreateDirectory(const char* path);
+
+ /*
+ * Close and free a file/directory node
+ * Note: This method is not shown in the implementation but would typically be needed
+ *
+ * @param node: Node handle to close and free
+ */
+ Void Close(VoidPtr node);
+
+ /*
+ * Get file/directory information
+ * Note: This method is not shown in the implementation but would typically be needed
+ *
+ * @param node: Node handle
+ * @param info: Structure to fill with file information (size, type, permissions, etc.)
+ * @return: true on success, false on failure
+ */
+ BOOL GetInfo(VoidPtr node, VoidPtr info);
+};
+} // namespace Kernel
diff --git a/src/kernel/FSKit/Ext2.h b/src/kernel/FSKit/Ext2.h
new file mode 100644
index 00000000..e979e556
--- /dev/null
+++ b/src/kernel/FSKit/Ext2.h
@@ -0,0 +1,148 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#pragma once
+
+#include <CompilerKit/CompilerKit.h>
+#include <KernelKit/DriveMgr.h>
+#include <NeKit/Defines.h>
+#include <NeKit/KString.h>
+#include <hint/CompilerHint.h>
+
+/// @file Ext2.h
+/// @brief EXT2 filesystem structures, constants, and base wrappers.
+
+/// EXT2 Constants
+#define kExt2FSMagic (0xEF53)
+#define kExt2FSMaxFileNameLen (255U)
+#define kExt2FSSuperblockOffset (1024)
+#define kExt2FSRootInodeNumber (2)
+#define kExt2FSInodeSize (128U)
+#define kExt2FSBlockSizeBase (1024U)
+
+#define kExt2FSRev0 (0)
+#define kExt2FSRev1 (1)
+
+/// EXT2 file types
+enum {
+ kExt2FileTypeUnknown = 0,
+ kExt2FileTypeRegular = 1,
+ kExt2FileTypeDirectory = 2,
+ kExt2FileTypeCharDevice = 3,
+ kExt2FileTypeBlockDevice = 4,
+ kExt2FileTypeFIFO = 5,
+ kExt2FileTypeSocket = 6,
+ kExt2FileTypeSymbolicLink = 7
+};
+
+typedef struct EXT2_GROUP_DESCRIPTOR final {
+ UInt32 fBlockBitmap;
+ UInt32 fInodeBitmap;
+ UInt32 fInodeTable;
+ UInt16 fFreeBlocksCount;
+ UInt16 fFreeInodesCount;
+ UInt16 fBgUsedDirsCount;
+ UInt16 fBgPad;
+ UInt32 fBgReserved[3];
+} EXT2_GROUP_DESCRIPTOR;
+
+struct PACKED EXT2_SUPER_BLOCK final {
+ Kernel::UInt32 fInodeCount;
+ Kernel::UInt32 fBlockCount;
+ Kernel::UInt32 fReservedBlockCount;
+ Kernel::UInt32 fFreeBlockCount;
+ Kernel::UInt32 fFreeInodeCount;
+ Kernel::UInt32 fFirstDataBlock;
+ Kernel::UInt32 fLogBlockSize;
+ Kernel::UInt32 fLogFragmentSize;
+ Kernel::UInt32 fBlocksPerGroup;
+ Kernel::UInt32 fFragmentsPerGroup;
+ Kernel::UInt32 fInodesPerGroup;
+ Kernel::UInt32 fMountTime;
+ Kernel::UInt32 fWriteTime;
+ Kernel::UInt16 fMountCount;
+ Kernel::UInt16 fMaxMountCount;
+ Kernel::UInt16 fMagic;
+ Kernel::UInt16 fState;
+ Kernel::UInt16 fErrors;
+ Kernel::UInt16 fMinorRevision;
+ Kernel::UInt32 fLastCheck;
+ Kernel::UInt32 fCheckInterval;
+ Kernel::UInt32 fCreatorOS;
+ Kernel::UInt32 fRevisionLevel;
+ Kernel::UInt16 fDefaultUID;
+ Kernel::UInt16 fDefaultGID;
+
+ // EXT2_DYNAMIC_REV fields
+ Kernel::UInt32 fFirstInode;
+ Kernel::UInt16 fInodeSize;
+ Kernel::UInt16 fBlockGroupNumber;
+ Kernel::UInt32 fFeatureCompat;
+ Kernel::UInt32 fFeatureIncompat;
+ Kernel::UInt32 fFeatureROCompat;
+ Kernel::UInt8 fUUID[16];
+ Kernel::Char fVolumeName[16];
+ Kernel::Char fLastMounted[64];
+ Kernel::UInt32 fAlgoBitmap;
+
+ Kernel::UInt8 fPreallocBlocks;
+ Kernel::UInt8 fPreallocDirBlocks;
+ Kernel::UInt16 fReservedGDTBlocks;
+
+ Kernel::UInt8 fJournalUUID[16];
+ Kernel::UInt32 fJournalInode;
+ Kernel::UInt32 fJournalDevice;
+ Kernel::UInt32 fLastOrphan;
+
+ Kernel::UInt32 fHashSeed[4];
+ Kernel::UInt8 fDefHashVersion;
+ Kernel::UInt8 fReservedCharPad;
+ Kernel::UInt16 fReservedWordPad;
+ Kernel::UInt32 fDefaultMountOpts;
+ Kernel::UInt32 fFirstMetaBlockGroup;
+
+ Kernel::UInt8 fReserved[760]; // Padding to make 1024 bytes
+};
+
+struct PACKED EXT2_INODE final {
+ Kernel::UInt16 fMode;
+ Kernel::UInt16 fUID;
+ Kernel::UInt32 fSize;
+ Kernel::UInt32 fAccessTime;
+ Kernel::UInt32 fCreateTime;
+ Kernel::UInt32 fModifyTime;
+ Kernel::UInt32 fDeleteTime;
+ Kernel::UInt16 fGID;
+ Kernel::UInt16 fLinksCount;
+ Kernel::UInt32 fBlocks;
+ Kernel::UInt32 fFlags;
+ Kernel::UInt32 fOSD1;
+
+ Kernel::UInt32 fBlock[15]; // direct 0-11, indirect 12, double 13, triple 14
+
+ Kernel::UInt32 fGeneration;
+ Kernel::UInt32 fFileACL;
+ Kernel::UInt32 fDirACL;
+ Kernel::UInt32 fFragmentAddr;
+
+ Kernel::UInt8 fOSD2[12];
+};
+
+/// Directory entry
+struct PACKED EXT2_DIR_ENTRY final {
+ Kernel::UInt32 fInode;
+ Kernel::UInt16 fRecordLength;
+ Kernel::UInt8 fNameLength;
+ Kernel::UInt8 fFileType;
+ Kernel::Char fName[kExt2FSMaxFileNameLen];
+};
+
+/// VFS usage
+struct Ext2Node {
+ Kernel::UInt32 inodeNumber;
+ EXT2_INODE inode;
+ Kernel::UInt32 cursor{0};
+};
diff --git a/src/kernel/FSKit/IndexableProperty.h b/src/kernel/FSKit/IndexableProperty.h
new file mode 100644
index 00000000..a89e78b8
--- /dev/null
+++ b/src/kernel/FSKit/IndexableProperty.h
@@ -0,0 +1,58 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#pragma once
+
+#include <CFKit/Property.h>
+#include <CompilerKit/CompilerKit.h>
+#include <KernelKit/DriveMgr.h>
+
+#define kIndexerCatalogNameLength (256U)
+#define kIndexerClaimed (0xCF)
+#define kIndexerUnclaimed (0xCA)
+
+namespace Kernel {
+namespace Indexer {
+ struct Index final {
+ public:
+ Char Drive[kDriveNameLen]{};
+ Char Path[kIndexerCatalogNameLength]{};
+ };
+
+ class IndexableProperty final : public Property {
+ public:
+ explicit IndexableProperty() : Property() {
+ KBasicString<> strProp(kMaxPropLen);
+ strProp += "/prop/indexable";
+
+ this->GetKey() = strProp;
+ }
+
+ ~IndexableProperty() override = default;
+
+ NE_COPY_DEFAULT(IndexableProperty)
+
+ public:
+ Index& Leak() noexcept;
+
+ public:
+ Void AddFlag(UInt16 flag);
+ Void RemoveFlag(UInt16 flag);
+ UInt16 HasFlag(UInt16 flag);
+
+ private:
+ Index fIndex;
+ UInt32 fFlags{};
+ };
+
+ /// @brief Index a file into the indexer instance.
+ /// @param filename path
+ /// @param filenameLen used bytes in path.
+ /// @param indexer the filesystem indexer.
+ /// @return none.
+ Void fs_index_file(const Char* filename, SizeT filenameLen, IndexableProperty& indexer);
+} // namespace Indexer
+} // namespace Kernel
diff --git a/src/kernel/FSKit/NeFS.h b/src/kernel/FSKit/NeFS.h
new file mode 100644
index 00000000..54861dec
--- /dev/null
+++ b/src/kernel/FSKit/NeFS.h
@@ -0,0 +1,413 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+ FILE: NeFS.h
+ PURPOSE: NeFS (New extended File System) support.
+
+ Revision History:
+
+ ?/?/?: Added file (amlel)
+ 12/02/24: Add UUID macro for EPM and GPT partition schemes.
+ 3/16/24: Add mandatory sector size, kNeFSSectorSz is set to 2048 by
+default.
+
+======================================== */
+
+#pragma once
+
+#include <CompilerKit/CompilerKit.h>
+#include <KernelKit/DriveMgr.h>
+#include <NeKit/Defines.h>
+#include <NeKit/KString.h>
+#include <hint/CompilerHint.h>
+
+/**
+ @brief New extended File System specification.
+ @author Amlal El Mahrouss (Amlal El Mahrouss, amlalelmahrouss at icloud dot com)
+*/
+
+#define kNeFSInvalidFork (-1)
+#define kNeFSInvalidCatalog (-1)
+#define kNeFSCatalogNameLen (256)
+
+#define kNeFSVolumeName "NeFS Volume"
+
+#define kNeFSMinimumDiskSize (mib_cast(8))
+
+#define kNeFSSectorSz (512)
+
+#define kNeFSIdentLen (8)
+#define kNeFSIdent " NeFS"
+#define kNeFSPadLen (392)
+
+#define kNeFSMetaFilePrefix '$'
+
+#define kNeFSVersionInteger (0x0129)
+#define kNeFSVerionString "1.2.9"
+
+/// @brief Standard fork types.
+#define kNeFSDataFork "main_data"
+#define kNeFSResourceFork "main_rsrc"
+
+#define kNeFSForkSize (sizeof(NEFS_FORK_STRUCT))
+
+#define kNeFSPartitionTypeStandard (7)
+#define kNeFSPartitionTypePage (8)
+#define kNeFSPartitionTypeBoot (9)
+
+#define kNeFSCatalogKindFile (1)
+#define kNeFSCatalogKindDir (2)
+#define kNeFSCatalogKindAlias (3)
+
+//! Shared between network and/or partitions. Export forks as .zip when copying.
+#define kNeFSCatalogKindShared (4)
+
+#define kNeFSCatalogKindResource (5)
+#define kNeFSCatalogKindExecutable (6)
+
+#define kNeFSCatalogKindPage (8)
+
+#define kNeFSCatalogKindDevice (9)
+#define kNeFSCatalogKindLock (10)
+
+#define kNeFSCatalogKindRLE (11)
+#define kNeFSCatalogKindMetaFile (12)
+
+#define kNeFSCatalogKindTTF (13)
+#define kNeFSCatalogKindRIFF (14)
+#define kNeFSCatalogKindMPEG (15)
+#define kNeFSCatalogKindMOFF (16)
+
+#define kNeFSSeparator '/'
+#define kNeFSSeparatorAlt '/'
+
+#define kNeFSUpDir ".."
+#define kNeFSRoot "/"
+#define kNeFSRootAlt "/"
+
+#define kNeFSLF '\r'
+#define kNeFSEOF (-1)
+
+#define kNeFSBitWidth (sizeof(Kernel::Char))
+#define kNeFSLbaType (Kernel::Lba)
+
+/// @note Start after the partition map header. (Virtual addressing)
+#define kNeFSRootCatalogStartAddress (1024)
+#define kNeFSCatalogStartAddress (kNeFSRootCatalogStartAddress + sizeof(NEFS_ROOT_PARTITION_BLOCK))
+
+#define kResourceTypeDialog (10)
+#define kResourceTypeString (11)
+#define kResourceTypeMenu (12)
+#define kResourceTypeSound (13)
+#define kResourceTypeFont (14)
+#define kNeFSPartLen (32)
+
+#define kNeFSFlagDeleted (70)
+#define kNeFSFlagUnallocated (0)
+#define kNeFSFlagCreated (71)
+
+#define kNeFSMimeNameLen (200)
+#define kNeFSForkNameLen (199)
+
+#define kNeFSFrameworkExt ".fwrk/"
+#define kNeFSStepsExt ".step/"
+#define kNeFSApplicationExt ".app/"
+#define kNeFSJournalExt ".jrnl"
+
+struct NEFS_CATALOG_STRUCT;
+struct NEFS_FORK_STRUCT;
+struct NEFS_ROOT_PARTITION_BLOCK;
+
+enum {
+ kNeFSHardDrive = 0xC0, // Hard Drive
+ kNeFSSolidStateDrive = 0xC1, // Solid State Drive
+ kNeFSOpticalDrive = 0x0C, // Blu-Ray/DVD
+ kNeFSMassStorageDevice = 0xCC, // USB
+ kNeFSScsiDrive = 0xC4, // SCSI Hard Drive
+ kNeFSFlashDrive = 0xC6,
+ kNeFSUnknown = 0xFF, // Unknown device.
+ kNeFSDriveCount = 7,
+};
+
+enum {
+ kNeFSStatusUnlocked = 0x18,
+ kNeFSStatusLocked,
+ kNeFSStatusError,
+ kNeFSStatusInvalid,
+ kNeFSStatusCount,
+};
+
+/// @brief Catalog record type.
+struct PACKED NEFS_CATALOG_STRUCT final {
+ BOOL ForkOrCatalog : 1 {0};
+
+ Kernel::Char Name[kNeFSCatalogNameLen] = {0};
+ Kernel::Char Mime[kNeFSMimeNameLen] = {0};
+
+ /// Catalog flags.
+ Kernel::UInt16 Flags;
+
+ /// Catalog allocation status.
+ Kernel::UInt16 Status;
+
+ /// Custom catalog flags.
+ Kernel::UInt16 CatalogFlags;
+
+ /// Catalog kind.
+ Kernel::Int32 Kind;
+
+ /// Size of the data fork.
+ Kernel::Lba DataForkSize;
+
+ /// Size of all resource forks.
+ Kernel::Lba ResourceForkSize;
+
+ /// Forks LBA.
+ Kernel::Lba DataFork;
+ Kernel::Lba ResourceFork;
+
+ /// Buddy allocation tracker.
+ Kernel::Lba NextSibling;
+ Kernel::Lba PrevSibling;
+
+ /// Best-buddy tracker.
+ Kernel::Lba NextBestSibling;
+ Kernel::Lba NextPrevSibling;
+
+ Kernel::UInt32 Checksum;
+};
+
+/// @brief Fork type, contains a data page.
+/// @note The way we store is way different than how other filesystems do, specific chunk of code
+/// are written into either the data fork or resource fork, the resource fork is reserved for file
+/// metadata. whereas the data fork is reserved for file data.
+struct PACKED NEFS_FORK_STRUCT final {
+ BOOL ForkOrCatalog : 1 {1};
+
+ Kernel::Char ForkName[kNeFSForkNameLen] = {0};
+ Kernel::Char CatalogName[kNeFSCatalogNameLen] = {0};
+
+ Kernel::Int32 Flags;
+ Kernel::Int32 Kind;
+
+ Kernel::Int64 ResourceId;
+ Kernel::Int32 ResourceKind;
+ Kernel::Int32 ResourceFlags;
+
+ Kernel::Lba DataOffset; // 8 Where to look for this data?
+ Kernel::SizeT DataSize; /// Data size according using sector count.
+
+ Kernel::Lba NextSibling;
+ Kernel::Lba PreviousSibling;
+};
+
+/// @brief Partition block type
+struct PACKED NEFS_ROOT_PARTITION_BLOCK final {
+ Kernel::Char Ident[kNeFSIdentLen] = {0};
+ Kernel::Char PartitionName[kNeFSPartLen] = {0};
+
+ Kernel::Int32 Flags;
+ Kernel::Int32 Kind;
+
+ Kernel::Lba StartCatalog;
+ Kernel::SizeT CatalogCount;
+
+ Kernel::SizeT DiskSize;
+
+ Kernel::SizeT FreeCatalog;
+ Kernel::SizeT FreeSectors;
+
+ Kernel::SizeT SectorCount;
+ Kernel::SizeT SectorSize;
+
+ Kernel::UInt64 Version;
+
+ Kernel::Lba EpmBlock;
+
+ Kernel::Char Pad[kNeFSPadLen];
+};
+
+namespace Kernel {
+class NeFileSystemParser;
+class NeFileSystemJournal;
+class NeFileSystemHelper;
+
+enum {
+ kNeFSSubDriveA,
+ kNeFSSubDriveB,
+ kNeFSSubDriveC,
+ kNeFSSubDriveD,
+ kNeFSSubDriveInvalid,
+ kNeFSSubDriveCount,
+};
+
+/// \brief Resource fork kind.
+enum { kNeFSRsrcForkKind = 0, kNeFSDataForkKind = 1 };
+
+///
+/// \name NeFileSystemParser
+/// \brief NeFS parser class. (catalog creation, remove removal, root,
+/// forks...) Designed like the DOM, detects the filesystem automatically.
+///
+class NeFileSystemParser final {
+ public:
+ explicit NeFileSystemParser() = default;
+ ~NeFileSystemParser() = default;
+
+ public:
+ NE_COPY_DELETE(NeFileSystemParser)
+
+ NE_MOVE_DELETE(NeFileSystemParser)
+
+ public:
+ /// @brief Creates a new fork inside the NeFS partition.
+ /// @param catalog it's catalog
+ /// @param theFork the fork itself.
+ /// @return the fork
+ _Output BOOL CreateFork(_Input NEFS_FORK_STRUCT& in);
+
+ /// @brief Find fork inside New filesystem.
+ /// @param catalog the catalog.
+ /// @param name the fork name.
+ /// @return the fork.
+ _Output NEFS_FORK_STRUCT* FindFork(_Input NEFS_CATALOG_STRUCT* catalog, _Input const Char* name,
+ Boolean data);
+
+ _Output Void RemoveFork(_Input NEFS_FORK_STRUCT* fork);
+
+ _Output Void CloseFork(_Input NEFS_FORK_STRUCT* fork);
+
+ _Output NEFS_CATALOG_STRUCT* FindCatalog(_Input const Char* catalog_name, Lba& ou_lba,
+ Bool search_hidden = YES, Bool local_search = NO);
+
+ _Output NEFS_CATALOG_STRUCT* GetCatalog(_Input const Char* name);
+
+ _Output NEFS_CATALOG_STRUCT* CreateCatalog(_Input const Char* name, _Input const Int32& flags,
+ _Input const Int32& kind);
+
+ _Output NEFS_CATALOG_STRUCT* CreateCatalog(_Input const Char* name);
+
+ _Output Bool WriteCatalog(_Input const Char* catalog, _Input Bool rsrc, _Input VoidPtr data,
+ _Input SizeT sz, _Input const Char* name);
+
+ _Output VoidPtr ReadCatalog(_Input _Output NEFS_CATALOG_STRUCT* catalog, _Input Bool isRsrcFork,
+ _Input SizeT dataSz, _Input const Char* forkName);
+
+ _Output Bool Seek(_Input _Output NEFS_CATALOG_STRUCT* catalog, SizeT off);
+
+ _Output SizeT Tell(_Input _Output NEFS_CATALOG_STRUCT* catalog);
+
+ _Output Bool RemoveCatalog(_Input const Char* catalog);
+
+ _Output Bool CloseCatalog(_InOut NEFS_CATALOG_STRUCT* catalog);
+
+ /// @brief Make a EPM+NeFS 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 Char* part_name);
+
+ public:
+ UInt32 mDriveIndex{kNeFSSubDriveA};
+};
+
+///
+/// \name NeFileSystemHelper
+/// \brief Filesystem helper class.
+///
+
+class NeFileSystemHelper final {
+ public:
+ STATIC const Char* Root();
+ STATIC const Char* UpDir();
+ STATIC Char Separator();
+ STATIC Char MetaFile();
+};
+
+/// @brief Journal class for NeFS.
+class NeFileSystemJournal final {
+ private:
+ NEFS_CATALOG_STRUCT* mNode{nullptr};
+
+ public:
+ explicit NeFileSystemJournal(const char* stamp = nullptr) {
+ if (!stamp) {
+ kout << "Invalid: Journal stamp, using default name.\r";
+ return;
+ }
+
+ (Void)(kout << "Info: Journal stamp: " << stamp << kendl);
+ rt_copy_memory((VoidPtr) stamp, this->mStamp, rt_string_len(stamp));
+ }
+
+ ~NeFileSystemJournal() = default;
+
+ NE_COPY_DEFAULT(NeFileSystemJournal)
+
+ Bool CreateJournal(NeFileSystemParser* parser) {
+ if (!parser) return NO;
+
+ delete parser->CreateCatalog("/etc/xml/", 0, kNeFSCatalogKindDir);
+ mNode = parser->CreateCatalog(mStamp);
+
+ if (!mNode) return NO;
+
+ return YES;
+ }
+
+ Bool GetJournal(NeFileSystemParser* parser) {
+ if (!parser) return NO;
+
+ auto node = parser->GetCatalog(mStamp);
+
+ if (node) {
+ mNode = node;
+ return YES;
+ }
+
+ return NO;
+ }
+
+ Bool ReleaseJournal() {
+ if (mNode) {
+ delete mNode;
+ mNode = nullptr;
+ return YES;
+ }
+
+ return NO;
+ }
+
+ Bool CommitJournal(NeFileSystemParser* parser, Char* xml_data, Char* journal_name) {
+ if (!parser || !mNode) return NO;
+
+ NEFS_FORK_STRUCT new_fork{};
+
+ rt_copy_memory(mStamp, new_fork.CatalogName, rt_string_len(mStamp));
+ rt_copy_memory(journal_name, new_fork.ForkName, rt_string_len(journal_name));
+
+ new_fork.ResourceKind = 0;
+ new_fork.ResourceId = 0;
+ new_fork.ResourceFlags = 0;
+ new_fork.DataSize = rt_string_len(xml_data);
+ new_fork.Kind = kNeFSRsrcForkKind;
+
+ if (!parser->CreateFork(new_fork)) return NO;
+
+ (Void)(kout << "XML commit: " << xml_data << " to fork: " << journal_name << kendl);
+
+ auto ret = parser->WriteCatalog(new_fork.CatalogName, YES, xml_data, rt_string_len(xml_data),
+ new_fork.ForkName);
+
+ return ret;
+ }
+
+ private:
+ Char mStamp[kNeFSCatalogNameLen] = {"/etc/xml/journal" kNeFSJournalExt};
+};
+
+namespace NeFS {
+ Boolean fs_init_nefs(Void) noexcept;
+} // namespace NeFS
+} // namespace Kernel
diff --git a/src/kernel/FSKit/OpenHeFS.h b/src/kernel/FSKit/OpenHeFS.h
new file mode 100644
index 00000000..bd392fc3
--- /dev/null
+++ b/src/kernel/FSKit/OpenHeFS.h
@@ -0,0 +1,434 @@
+/* ========================================
+
+ Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.
+
+======================================== */
+
+#pragma once
+
+#include <CompilerKit/CompilerKit.h>
+#include <KernelKit/DriveMgr.h>
+#include <KernelKit/UserMgr.h>
+#include <NeKit/Crc32.h>
+#include <NeKit/Defines.h>
+#include <NeKit/KString.h>
+#include <hint/CompilerHint.h>
+
+/// @file OpenHeFS.h
+/// @brief OpenHeFS filesystem support.
+
+#define kOpenHeFSVersion (0x0104)
+#define kOpenHeFSMagic "OpenHeFS"
+#define kOpenHeFSMagicLen (9U)
+
+#define kOpenHeFSBlockLen (512U)
+#define kOpenHeFSFileNameLen (256U)
+#define kOpenHeFSPartNameLen (128U)
+
+#define kOpenHeFSMinimumDiskSize (gib_cast(128))
+
+#define kOpenHeFSDefaultVolumeName u8"OpenHeFS Volume"
+
+#define kOpenHeFSINDStartOffset (sizeof(HEFS_BOOT_NODE))
+#define kOpenHeFSINStartOffset (sizeof(HEFS_INDEX_NODE_DIRECTORY))
+
+#define kOpenHeFSRootDirectory "/"
+#define kOpenHeFSRootDirectoryU8 u8"/"
+
+#define kOpenHeFSSeparator '/'
+#define kOpenHeFSUpDir ".."
+
+#define kOpenHeFSRootDirectoryLen (2U)
+
+#define kOpenHeFSSearchAllStr u8"*"
+
+struct HEFS_BOOT_NODE;
+struct HEFS_INDEX_NODE;
+struct HEFS_INDEX_NODE_DIRECTORY;
+struct HEFS_JOURNAL_NODE;
+
+enum : UInt8 {
+ kOpenHeFSHardDrive = 0xC0, // Hard Drive
+ kOpenHeFSSolidStateDrive = 0xC1, // Solid State Drive
+ kOpenHeFSOpticalDrive = 0x0C, // Blu-Ray/DVD
+ kOpenHeFSMassStorageDevice = 0xCC, // USB
+ kOpenHeFSScsiDrive = 0xC4, // SCSI Hard Drive
+ kOpenHeFSFlashDrive = 0xC6,
+ kOpenHeFSUnknown = 0xFF, // Unknown device.
+ kOpenHeFSDriveCount = 8,
+};
+
+enum : UInt8 {
+ kOpenHeFSStatusUnlocked = 0x18,
+ kOpenHeFSStatusLocked,
+ kOpenHeFSStatusError,
+ kOpenHeFSStatusInvalid,
+ kOpenHeFSStatusCount,
+};
+
+enum : UInt16 {
+ kOpenHeFSEncodingFlagsUTF8 = 0x50,
+ kOpenHeFSEncodingFlagsUTF16,
+ kOpenHeFSEncodingFlagsUTF32,
+ kOpenHeFSEncodingFlagsUTF16BE,
+ kOpenHeFSEncodingFlagsUTF16LE,
+ kOpenHeFSEncodingFlagsUTF32BE,
+ kOpenHeFSEncodingFlagsUTF32LE,
+ kOpenHeFSEncodingFlagsUTF8BE,
+ kOpenHeFSEncodingFlagsUTF8LE,
+ kOpenHeFSEncodingFlagsBinary,
+ kOpenHeFSEncodingFlagsCount = 11,
+ kOpenHeFSFlagsNone = 0,
+ kOpenHeFSFlagsReadOnly = 0x100,
+ kOpenHeFSFlagsHidden,
+ kOpenHeFSFlagsSystem,
+ kOpenHeFSFlagsArchive,
+ kOpenHeFSFlagsDevice,
+ kOpenHeFSFlagsCount = 7
+};
+
+inline constexpr UInt16 kOpenHeFSFileKindRegular = 0x00;
+inline constexpr UInt16 kOpenHeFSFileKindDirectory = 0x01;
+inline constexpr UInt16 kOpenHeFSFileKindBlock = 0x02;
+inline constexpr UInt16 kOpenHeFSFileKindCharacter = 0x03;
+inline constexpr UInt16 kOpenHeFSFileKindFIFO = 0x04;
+inline constexpr UInt16 kOpenHeFSFileKindSocket = 0x05;
+inline constexpr UInt16 kOpenHeFSFileKindSymbolicLink = 0x06;
+inline constexpr UInt16 kOpenHeFSFileKindUnknown = 0x07;
+inline constexpr UInt16 kOpenHeFSFileKindCount = 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 kOpenHeFSSliceCount = 0x10;
+
+inline constexpr UInt16 kOpenHeFSInvalidVID = 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[kOpenHeFSMagicLen]; /// @brief Magic number of the filesystem.
+ Utf8Char fVolName[kOpenHeFSPartNameLen]; /// @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 kOpenHeFSTimeInvalid = 0x0000000000000000;
+inline constexpr ATime kOpenHeFSTimeMax = 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 {
+ kOpenHeFSInvalidColor = 0,
+ kOpenHeFSRed = 100,
+ kOpenHeFSBlack,
+ kOpenHeFSColorCount,
+};
+
+/// @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[kOpenHeFSSliceCount]; /// @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 kOpenHeFSBaseYear = 1970;
+inline constexpr UInt32 kOpenHeFSBaseMonth = 1;
+inline constexpr UInt32 kOpenHeFSBaseDay = 1;
+inline constexpr UInt32 kOpenHeFSBaseHour = 0;
+inline constexpr UInt32 kOpenHeFSBaseMinute = 0;
+
+inline const Char* hefs_status_to_string(UInt16 status) noexcept {
+ switch (status) {
+ case kOpenHeFSStatusUnlocked:
+ return "Unlocked";
+ case kOpenHeFSStatusLocked:
+ return "Locked";
+ case kOpenHeFSStatusError:
+ return "Error";
+ case kOpenHeFSStatusInvalid:
+ return "Invalid";
+ default:
+ return "Unknown";
+ }
+}
+
+inline const Char* hefs_drive_kind_to_string(UInt8 kind) noexcept {
+ switch (kind) {
+ case kOpenHeFSHardDrive:
+ return "Hard Drive";
+ case kOpenHeFSSolidStateDrive:
+ return "Solid State Drive";
+ case kOpenHeFSOpticalDrive:
+ return "Optical Drive";
+ case kOpenHeFSMassStorageDevice:
+ return "Mass Storage Device";
+ case kOpenHeFSScsiDrive:
+ return "SCSI/SAS Drive";
+ case kOpenHeFSFlashDrive:
+ return "Flash Drive";
+ case kOpenHeFSUnknown:
+ default:
+ return "Unknown";
+ }
+}
+
+inline const Char* hefs_encoding_to_string(UInt8 encoding) noexcept {
+ switch (encoding) {
+ case kOpenHeFSEncodingFlagsUTF8:
+ return "UTF-8";
+ case kOpenHeFSEncodingFlagsUTF16:
+ return "UTF-16";
+ case kOpenHeFSEncodingFlagsUTF32:
+ return "UTF-32";
+ case kOpenHeFSEncodingFlagsUTF16BE:
+ return "UTF-16BE";
+ case kOpenHeFSEncodingFlagsUTF16LE:
+ return "UTF-16LE";
+ case kOpenHeFSEncodingFlagsUTF32BE:
+ return "UTF-32BE";
+ case kOpenHeFSEncodingFlagsUTF32LE:
+ return "UTF-32LE";
+ case kOpenHeFSEncodingFlagsUTF8BE:
+ return "UTF-8BE";
+ case kOpenHeFSEncodingFlagsUTF8LE:
+ return "UTF-8LE";
+ default:
+ return "Unknown";
+ }
+}
+
+inline const Char* hefs_file_kind_to_string(UInt16 kind) noexcept {
+ switch (kind) {
+ case kOpenHeFSFileKindRegular:
+ return "Regular File";
+ case kOpenHeFSFileKindDirectory:
+ return "Directory";
+ case kOpenHeFSFileKindBlock:
+ return "Block Device";
+ case kOpenHeFSFileKindCharacter:
+ return "Character Device";
+ case kOpenHeFSFileKindFIFO:
+ return "FIFO";
+ case kOpenHeFSFileKindSocket:
+ return "Socket";
+ case kOpenHeFSFileKindSymbolicLink:
+ return "Symbolic Link";
+ case kOpenHeFSFileKindUnknown:
+ default:
+ return "Unknown";
+ }
+}
+
+inline const Char* hefs_file_flags_to_string(UInt32 flags) noexcept {
+ switch (flags) {
+ case kOpenHeFSFlagsNone:
+ return "No Flags";
+ case kOpenHeFSFlagsReadOnly:
+ return "Read Only";
+ case kOpenHeFSFlagsHidden:
+ return "Hidden";
+ case kOpenHeFSFlagsSystem:
+ return "System";
+ case kOpenHeFSFlagsArchive:
+ return "Archive";
+ case kOpenHeFSFlagsDevice:
+ 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_openhefs(Void) noexcept;
+} // namespace OpenHeFS
+} // namespace Kernel