diff options
| author | Amlal El Mahrouss <amlal@nekernel.org> | 2025-11-23 21:06:27 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-23 21:06:27 -0500 |
| commit | 23040fad647634c08697451fc22ee2ca999629c8 (patch) | |
| tree | 72888f88c7728c82f3f6df1f4f70591de15eab36 /src/kernel/FSKit/NeFS.h | |
| parent | e5cc7351f0577b54c528fb827a7c7e6306c3e843 (diff) | |
| parent | 83d870e58457a1d335a1d9b9966a6a1887cc297b (diff) | |
Merge pull request #81 from nekernel-org/dev
feat! breaking changes on kernel sources.
Diffstat (limited to 'src/kernel/FSKit/NeFS.h')
| -rw-r--r-- | src/kernel/FSKit/NeFS.h | 413 |
1 files changed, 413 insertions, 0 deletions
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 |
