diff options
Diffstat (limited to 'dev/kernel/FSKit')
| -rw-r--r-- | dev/kernel/FSKit/Ext2+IFS.h | 271 | ||||
| -rw-r--r-- | dev/kernel/FSKit/Ext2.h | 39 |
2 files changed, 298 insertions, 12 deletions
diff --git a/dev/kernel/FSKit/Ext2+IFS.h b/dev/kernel/FSKit/Ext2+IFS.h new file mode 100644 index 00000000..661c8d5f --- /dev/null +++ b/dev/kernel/FSKit/Ext2+IFS.h @@ -0,0 +1,271 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025, Amlal El Mahrouss, all rights reserved. + +------------------------------------------- */ + +#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 { + private: + Ext2Context ctx; // 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); + + /* + * 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/dev/kernel/FSKit/Ext2.h b/dev/kernel/FSKit/Ext2.h index 35129dcd..be2e34a6 100644 --- a/dev/kernel/FSKit/Ext2.h +++ b/dev/kernel/FSKit/Ext2.h @@ -13,20 +13,20 @@ #include <hint/CompilerHint.h> /// @file Ext2.h -/// @brief EXT2 filesystem structures and constants. +/// @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) -/// @brief EXT2's file types. +/// EXT2 file types enum { kExt2FileTypeUnknown = 0, kExt2FileTypeRegular = 1, @@ -38,7 +38,17 @@ enum { kExt2FileTypeSymbolicLink = 7 }; -/// @brief The super block structure, located at LBA 1024. +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; @@ -55,7 +65,7 @@ struct PACKED EXT2_SUPER_BLOCK final { Kernel::UInt32 fWriteTime; Kernel::UInt16 fMountCount; Kernel::UInt16 fMaxMountCount; - Kernel::UInt16 fMagic; // should be 0xEF53 + Kernel::UInt16 fMagic; Kernel::UInt16 fState; Kernel::UInt16 fErrors; Kernel::UInt16 fMinorRevision; @@ -78,7 +88,6 @@ struct PACKED EXT2_SUPER_BLOCK final { Kernel::Char fLastMounted[64]; Kernel::UInt32 fAlgoBitmap; - // Optional journal fields and padding Kernel::UInt8 fPreallocBlocks; Kernel::UInt8 fPreallocDirBlocks; Kernel::UInt16 fReservedGDTBlocks; @@ -112,22 +121,28 @@ struct PACKED EXT2_INODE final { Kernel::UInt32 fFlags; Kernel::UInt32 fOSD1; - Kernel::UInt32 - fBlock[15]; // 0-11: direct, 12: indirect, 13: double indirect, 14: triple indirect + Kernel::UInt32 fBlock[15]; // direct 0-11, indirect 12, double 13, triple 14 Kernel::UInt32 fGeneration; Kernel::UInt32 fFileACL; - Kernel::UInt32 fDirACL; // Only for revision 1+ + 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]; // null-terminated, not fixed-length in actual on-disk layout -};
\ No newline at end of file + Kernel::Char fName[kExt2FSMaxFileNameLen]; +}; + +/// VFS usage +struct Ext2Node { + Kernel::UInt32 inodeNumber; + EXT2_INODE inode; + Kernel::UInt32 cursor{0}; +}; |
