summaryrefslogtreecommitdiffhomepage
path: root/dev/kernel/src/FS/Ext2+FileMgr.cc
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal@nekernel.org>2025-09-28 14:58:47 +0200
committerAmlal El Mahrouss <amlal@nekernel.org>2025-09-28 14:58:47 +0200
commit84a7325b22f1f90c0c719a2ec8ba131263e1208c (patch)
treea7b706349a1fcefc2490acb624a023d010c03f7d /dev/kernel/src/FS/Ext2+FileMgr.cc
parent49047f8f1d799966d9204118351c25a6379b2e5b (diff)
feat: final changes before nekernel v0.0.6
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
Diffstat (limited to 'dev/kernel/src/FS/Ext2+FileMgr.cc')
-rw-r--r--dev/kernel/src/FS/Ext2+FileMgr.cc2599
1 files changed, 1309 insertions, 1290 deletions
diff --git a/dev/kernel/src/FS/Ext2+FileMgr.cc b/dev/kernel/src/FS/Ext2+FileMgr.cc
index d5d23c3f..c205fb10 100644
--- a/dev/kernel/src/FS/Ext2+FileMgr.cc
+++ b/dev/kernel/src/FS/Ext2+FileMgr.cc
@@ -1,1540 +1,1559 @@
#ifndef __NE_MINIMAL_OS__
#ifdef __FSKIT_INCLUDES_EXT2__
-#include <FSKit/Ext2.h>
-#include <FSKit/Ext2IFS.h>
-#include <KernelKit/FileMgr.h>
+#include <FSKit/Ext2+IFS.h>
+#include <FSKit/Ext2.h>
#include <KernelKit/DebugOutput.h>
+#include <KernelKit/FileMgr.h>
#include <KernelKit/HeapMgr.h>
-#include <NeKit/Utils.h>
-#include <NeKit/KString.h>
#include <NeKit/ErrorOr.h>
+#include <NeKit/KString.h>
#include <NeKit/KernelPanic.h>
+#include <NeKit/Utils.h>
-namespace Ext2 {
-
-constexpr UInt32 EXT2_DIRECT_BLOCKS = 12;
-constexpr UInt32 EXT2_SINGLE_INDIRECT_INDEX = 12;
-constexpr UInt32 EXT2_DOUBLE_INDIRECT_INDEX = 13;
-constexpr UInt32 EXT2_TRIPLE_INDIRECT_INDEX = 14;
-constexpr UInt32 EXT2_ROOT_INODE = 2;
-constexpr UInt32 EXT2_SUPERBLOCK_BLOCK = 1;
+constexpr UInt32 EXT2_DIRECT_BLOCKS = 12;
+constexpr UInt32 EXT2_SINGLE_INDIRECT_INDEX = 12;
+constexpr UInt32 EXT2_DOUBLE_INDIRECT_INDEX = 13;
+constexpr UInt32 EXT2_TRIPLE_INDIRECT_INDEX = 14;
+constexpr UInt32 EXT2_ROOT_INODE = 2;
+constexpr UInt32 EXT2_SUPERBLOCK_BLOCK = 1;
constexpr UInt32 EXT2_GROUP_DESC_BLOCK_SMALL = 2;
constexpr UInt32 EXT2_GROUP_DESC_BLOCK_LARGE = 1;
-static inline SizeT ext2_min(SizeT a, SizeT b) { return a < b ? a : b; }
+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;
+ EXT2_GROUP_DESCRIPTOR* groupDesc;
+ UInt32 groupDescriptorBlock;
+ UInt32 offsetInGroupDescBlock;
+ UInt8* blockBuffer;
};
// Convert EXT2 block number -> LBA (sector index) for Drive I/O.
-static inline Kernel::UInt32 ext2_block_to_lba(Context* ctx, Kernel::UInt32 blockNumber) {
- if (!ctx || !ctx->drive) return 0;
- Kernel::UInt32 blockSize = ctx->BlockSize();
- Kernel::UInt32 sectorSize = ctx->drive->fSectorSz;
- Kernel::UInt32 sectorsPerBlock = blockSize / sectorSize;
- return blockNumber * sectorsPerBlock;
+static inline Kernel::UInt32 ext2_block_to_lba(Kernel::Ext2Context* ctx,
+ Kernel::UInt32 blockNumber) {
+ if (!ctx || !ctx->drive) return 0;
+ Kernel::UInt32 blockSize = ctx->BlockSize();
+ Kernel::UInt32 sectorSize = ctx->drive->fSectorSz;
+ Kernel::UInt32 sectorsPerBlock = blockSize / sectorSize;
+ return blockNumber * sectorsPerBlock;
}
// Read a block and return a pointer to its content
-static ErrorOr<Kernel::UInt32*> ext2_read_block_ptr(Context* ctx, Kernel::UInt32 blockNumber) {
- if (!ctx || !ctx->drive || !ctx->superblock)
- return ErrorOr<Kernel::UInt32*>(Kernel::kErrorInvalidData);
-
- Kernel::UInt32 blockSize = ctx->BlockSize();
- auto buf = (Kernel::UInt32*)mm_alloc_ptr(blockSize, true, false);
- if (!buf) return ErrorOr<Kernel::UInt32*>(Kernel::kErrorHeapOutOfMemory);
-
- Kernel::UInt32 lba = ext2_block_to_lba(ctx, blockNumber);
- if (!ext2_read_block(ctx->drive, lba, buf, blockSize)) {
- mm_free_ptr(buf);
- return ErrorOr<Kernel::UInt32*>(Kernel::kErrorDisk);
- }
- return ErrorOr<Kernel::UInt32*>(buf);
+static ErrorOr<Kernel::UInt32*> ext2_read_block_ptr(Kernel::Ext2Context* ctx,
+ Kernel::UInt32 blockNumber) {
+ if (!ctx || !ctx->drive || !ctx->superblock)
+ return ErrorOr<Kernel::UInt32*>(Kernel::kErrorInvalidData);
+
+ Kernel::UInt32 blockSize = ctx->BlockSize();
+ auto buf = (Kernel::UInt32*) mm_alloc_ptr(blockSize, true, false);
+ if (!buf) return ErrorOr<Kernel::UInt32*>(Kernel::kErrorHeapOutOfMemory);
+
+ Kernel::UInt32 lba = ext2_block_to_lba(ctx, blockNumber);
+ if (!ext2_read_block(ctx->drive, lba, buf, blockSize)) {
+ mm_free_ptr(buf);
+ return ErrorOr<Kernel::UInt32*>(Kernel::kErrorDisk);
+ }
+ return ErrorOr<Kernel::UInt32*>(buf);
}
// Get the block address for a given logical block index
-static ErrorOr<Kernel::UInt32> ext2_get_block_address(Context* ctx, Ext2Node* node, Kernel::UInt32 logicalIndex) {
- if (!ctx || !node || !ctx->drive)
- return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
-
- Kernel::UInt32 blockSize = ctx->BlockSize();
- Kernel::UInt32 pointersPerBlock = blockSize / sizeof(Kernel::UInt32);
-
- // Direct blocks
- if (logicalIndex < EXT2_DIRECT_BLOCKS) {
- Kernel::UInt32 bn = node->inode.fBlock[logicalIndex];
- if (bn == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
- return ErrorOr<Kernel::UInt32>(bn);
- }
+static ErrorOr<Kernel::UInt32> ext2_get_block_address(Kernel::Ext2Context* ctx, Ext2Node* node,
+ Kernel::UInt32 logicalIndex) {
+ if (!ctx || !node || !ctx->drive) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
- // Single indirect blocks
- if (logicalIndex < (EXT2_DIRECT_BLOCKS + pointersPerBlock)) {
- Kernel::UInt32 iblock = node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX];
- if (iblock == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
-
- auto res = ext2_read_block_ptr(ctx, iblock);
- if (!res) return ErrorOr<Kernel::UInt32>(res.Error());
-
- // Using dereference operator
- Kernel::UInt32* ptr = *res.Leak(); // operator* returns T (UInt32*)
-
- Kernel::UInt32 val = ptr[logicalIndex - EXT2_DIRECT_BLOCKS];
- mm_free_ptr(ptr);
-
- if (val == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
- return ErrorOr<Kernel::UInt32>(val);
- }
+ Kernel::UInt32 blockSize = ctx->BlockSize();
+ Kernel::UInt32 pointersPerBlock = blockSize / sizeof(Kernel::UInt32);
- // Double indirect blocks
- Kernel::UInt32 doubleStart = EXT2_DIRECT_BLOCKS + pointersPerBlock;
- Kernel::UInt32 doubleSpan = pointersPerBlock * pointersPerBlock;
- if (logicalIndex < (doubleStart + doubleSpan)) {
- Kernel::UInt32 db = node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX];
- if (db == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
-
- auto dblRes = ext2_read_block_ptr(ctx, db);
- if (!dblRes) return ErrorOr<Kernel::UInt32>(dblRes.Error());
-
- Kernel::UInt32* dblPtr = *dblRes.Leak();
-
- Kernel::UInt32 idxWithin = logicalIndex - doubleStart;
- Kernel::UInt32 firstIdx = idxWithin / pointersPerBlock;
- Kernel::UInt32 secondIdx = idxWithin % pointersPerBlock;
- Kernel::UInt32 singleBlockNum = dblPtr[firstIdx];
-
- mm_free_ptr(dblPtr);
- if (singleBlockNum == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
-
- auto singleRes = ext2_read_block_ptr(ctx, singleBlockNum);
- if (!singleRes) return ErrorOr<Kernel::UInt32>(singleRes.Error());
-
- Kernel::UInt32* singlePtr = *singleRes.Leak();
- Kernel::UInt32 val = singlePtr[secondIdx];
- mm_free_ptr(singlePtr);
-
- if (val == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
- return ErrorOr<Kernel::UInt32>(val);
- }
+ // Direct blocks
+ if (logicalIndex < EXT2_DIRECT_BLOCKS) {
+ Kernel::UInt32 bn = node->inode.fBlock[logicalIndex];
+ if (bn == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
+ return ErrorOr<Kernel::UInt32>(bn);
+ }
- return ErrorOr<Kernel::UInt32>(Kernel::kErrorUnimplemented);
-}
+ // Single indirect blocks
+ if (logicalIndex < (EXT2_DIRECT_BLOCKS + pointersPerBlock)) {
+ Kernel::UInt32 iblock = node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX];
+ if (iblock == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
-static Kernel::ErrorOr<voidPtr> ext2_read_inode_data(Context* ctx, Ext2Node* node, SizeT size) {
- using Kernel::ErrorOr;
- using Kernel::UInt8;
- using Kernel::UInt32;
+ auto res = ext2_read_block_ptr(ctx, iblock);
+ if (!res) return ErrorOr<Kernel::UInt32>(res.Error());
- if (!ctx || !ctx->drive || !node || size == 0)
- return ErrorOr<voidPtr>(1);
+ // Using dereference operator
+ Kernel::UInt32* ptr = *res.Leak(); // operator* returns T (UInt32*)
- 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<voidPtr>(2); // nothing to read
+ Kernel::UInt32 val = ptr[logicalIndex - EXT2_DIRECT_BLOCKS];
+ mm_free_ptr(ptr);
- auto buffer = mm_alloc_ptr(bytesToRead, true, false);
- if (!buffer)
- return ErrorOr<voidPtr>(3); // allocation failed
+ if (val == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
+ return ErrorOr<Kernel::UInt32>(val);
+ }
- UInt32 currentOffset = node->cursor;
- SizeT remaining = bytesToRead;
- UInt8* dest = reinterpret_cast<UInt8*>(buffer);
+ // Double indirect blocks
+ Kernel::UInt32 doubleStart = EXT2_DIRECT_BLOCKS + pointersPerBlock;
+ Kernel::UInt32 doubleSpan = pointersPerBlock * pointersPerBlock;
+ if (logicalIndex < (doubleStart + doubleSpan)) {
+ Kernel::UInt32 db = node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX];
+ if (db == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
- while (remaining > 0) {
- UInt32 logicalIndex = currentOffset / blockSize;
- UInt32 offsetInBlock = currentOffset % blockSize;
+ auto dblRes = ext2_read_block_ptr(ctx, db);
+ if (!dblRes) return ErrorOr<Kernel::UInt32>(dblRes.Error());
- auto phys = ext2_get_block_address(ctx, node, logicalIndex);
- if (phys.HasError()) {
- mm_free_ptr(buffer);
- return ErrorOr<voidPtr>(phys.Error());
- }
+ Kernel::UInt32* dblPtr = *dblRes.Leak();
- UInt32 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<voidPtr>(4); // block buffer allocation failed
- }
+ Kernel::UInt32 idxWithin = logicalIndex - doubleStart;
+ Kernel::UInt32 firstIdx = idxWithin / pointersPerBlock;
+ Kernel::UInt32 secondIdx = idxWithin % pointersPerBlock;
+ Kernel::UInt32 singleBlockNum = dblPtr[firstIdx];
- if (!ext2_read_block(ctx->drive, lba, blockBuf, blockSize)) {
- mm_free_ptr(blockBuf);
- mm_free_ptr(buffer);
- return ErrorOr<voidPtr>(5); // block read failed
- }
+ mm_free_ptr(dblPtr);
+ if (singleBlockNum == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
- SizeT chunk = ext2_min(remaining, blockSize - offsetInBlock);
- rt_copy_memory_safe(static_cast<void*>(static_cast<UInt8*>(blockBuf) + offsetInBlock),
- static_cast<void*>(dest), chunk, chunk);
+ auto singleRes = ext2_read_block_ptr(ctx, singleBlockNum);
+ if (!singleRes) return ErrorOr<Kernel::UInt32>(singleRes.Error());
- mm_free_ptr(blockBuf);
+ Kernel::UInt32* singlePtr = *singleRes.Leak();
+ Kernel::UInt32 val = singlePtr[secondIdx];
+ mm_free_ptr(singlePtr);
- currentOffset += static_cast<UInt32>(chunk);
- dest += chunk;
- remaining -= chunk;
- }
+ if (val == 0) return ErrorOr<Kernel::UInt32>(Kernel::kErrorInvalidData);
+ return ErrorOr<Kernel::UInt32>(val);
+ }
- node->cursor += static_cast<UInt32>(bytesToRead);
- return ErrorOr<voidPtr>(buffer);
+ return ErrorOr<Kernel::UInt32>(Kernel::kErrorUnimplemented);
}
+static Kernel::ErrorOr<voidPtr> ext2_read_inode_data(Kernel::Ext2Context* ctx, Ext2Node* node,
+ SizeT size) {
+ using Kernel::ErrorOr;
+ using Kernel::UInt32;
+ using Kernel::UInt8;
-// Get group descriptor information for a given block/inode number
-static ErrorOr<Ext2GroupInfo*> ext2_get_group_descriptor_info(Context* ctx, UInt32 targetBlockOrInode) {
- if (!ctx || !ctx->superblock || !ctx->drive)
- return ErrorOr<Ext2GroupInfo*>(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<Ext2GroupInfo*>(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;
- }
- }
+ if (!ctx || !ctx->drive || !node || size == 0) return ErrorOr<voidPtr>(1);
- // Calculate number of block groups
- UInt32 groupsCount = static_cast<UInt32>((totalBlocks + blocksPerGroup - 1) / blocksPerGroup);
- if (groupIndex >= groupsCount)
- return ErrorOr<Ext2GroupInfo*>(kErrorInvalidData);
+ 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<voidPtr>(2); // nothing to read
- // Determine GDT start block
- UInt32 gdtStartBlock = (blockSize == 1024) ? EXT2_GROUP_DESC_BLOCK_SMALL : EXT2_GROUP_DESC_BLOCK_LARGE;
+ auto buffer = mm_alloc_ptr(bytesToRead, true, false);
+ if (!buffer) return ErrorOr<voidPtr>(3); // allocation failed
- // Compute byte offset of descriptor within the GDT
- const UInt32 descSize = sizeof(EXT2_GROUP_DESCRIPTOR);
- UInt64 descByteOffset = static_cast<UInt64>(groupIndex) * descSize;
+ UInt32 currentOffset = node->cursor;
+ SizeT remaining = bytesToRead;
+ UInt8* dest = reinterpret_cast<UInt8*>(buffer);
- // Which EXT2 block contains that descriptor?
- UInt32 blockOffsetWithinGdt = static_cast<UInt32>(descByteOffset / blockSize);
- UInt32 offsetInGroupDescBlock = static_cast<UInt32>(descByteOffset % blockSize);
- UInt32 groupDescriptorBlock = gdtStartBlock + blockOffsetWithinGdt;
+ 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<voidPtr>(phys.Error());
+ }
- // Allocate buffer and read the block containing the descriptor
- auto blockBuffer = mm_alloc_ptr(blockSize, true, false);
- if (!blockBuffer) return ErrorOr<Ext2GroupInfo*>(kErrorHeapOutOfMemory);
+ auto blockNumber = phys.Value();
+ UInt32 lba = ext2_block_to_lba(ctx, blockNumber);
- UInt32 groupDescriptorLba = ext2_block_to_lba(ctx, groupDescriptorBlock);
- if (!ext2_read_block(ctx->drive, groupDescriptorLba, blockBuffer, blockSize)) {
- mm_free_ptr(blockBuffer);
- return ErrorOr<Ext2GroupInfo*>(kErrorDisk);
+ auto blockBuf = mm_alloc_ptr(blockSize, true, false);
+ if (!blockBuf) {
+ mm_free_ptr(buffer);
+ return ErrorOr<voidPtr>(4); // block buffer allocation failed
}
- auto groupInfo = (Ext2GroupInfo*)mm_alloc_ptr(sizeof(Ext2GroupInfo), true, false);
- if (!groupInfo) {
- mm_free_ptr(blockBuffer);
- return ErrorOr<Ext2GroupInfo*>(kErrorHeapOutOfMemory);
+ if (!ext2_read_block(ctx->drive, lba, blockBuf, blockSize)) {
+ mm_free_ptr(blockBuf);
+ mm_free_ptr(buffer);
+ return ErrorOr<voidPtr>(5); // block read failed
}
- groupInfo->groupDesc = reinterpret_cast<EXT2_GROUP_DESCRIPTOR*>(
- reinterpret_cast<UInt8*>(blockBuffer) + offsetInGroupDescBlock);
- groupInfo->groupDescriptorBlock = groupDescriptorBlock;
- groupInfo->offsetInGroupDescBlock = offsetInGroupDescBlock;
- groupInfo->blockBuffer = reinterpret_cast<UInt8*>(blockBuffer);
+ SizeT chunk = ext2_min(remaining, blockSize - offsetInBlock);
+ rt_copy_memory_safe(static_cast<void*>(static_cast<UInt8*>(blockBuf) + offsetInBlock),
+ static_cast<void*>(dest), chunk, chunk);
+
+ mm_free_ptr(blockBuf);
+
+ currentOffset += static_cast<UInt32>(chunk);
+ dest += chunk;
+ remaining -= chunk;
+ }
- return ErrorOr<Ext2GroupInfo*>(groupInfo);
+ node->cursor += static_cast<UInt32>(bytesToRead);
+ return ErrorOr<voidPtr>(buffer);
}
-// Allocate a new block
-inline ErrorOr<UInt32> ext2_alloc_block(Context* ctx, EXT2_GROUP_DESCRIPTOR* groupDesc) {
- if (!ctx || !ctx->superblock || !groupDesc)
- return ErrorOr<UInt32>(kErrorInvalidData);
+// Get group descriptor information for a given block/inode number
+static ErrorOr<Ext2GroupInfo*> ext2_get_group_descriptor_info(Kernel::Ext2Context* ctx,
+ UInt32 targetBlockOrInode) {
+ if (!ctx || !ctx->superblock || !ctx->drive) return ErrorOr<Ext2GroupInfo*>(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<Ext2GroupInfo*>(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<UInt32>((totalBlocks + blocksPerGroup - 1) / blocksPerGroup);
+ if (groupIndex >= groupsCount) return ErrorOr<Ext2GroupInfo*>(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<UInt64>(groupIndex) * descSize;
+
+ // Which EXT2 block contains that descriptor?
+ UInt32 blockOffsetWithinGdt = static_cast<UInt32>(descByteOffset / blockSize);
+ UInt32 offsetInGroupDescBlock = static_cast<UInt32>(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<Ext2GroupInfo*>(kErrorHeapOutOfMemory);
+
+ UInt32 groupDescriptorLba = ext2_block_to_lba(ctx, groupDescriptorBlock);
+ if (!ext2_read_block(ctx->drive, groupDescriptorLba, blockBuffer, blockSize)) {
+ mm_free_ptr(blockBuffer);
+ return ErrorOr<Ext2GroupInfo*>(kErrorDisk);
+ }
+
+ auto groupInfo = (Ext2GroupInfo*) mm_alloc_ptr(sizeof(Ext2GroupInfo), true, false);
+ if (!groupInfo) {
+ mm_free_ptr(blockBuffer);
+ return ErrorOr<Ext2GroupInfo*>(kErrorHeapOutOfMemory);
+ }
+
+ groupInfo->groupDesc = reinterpret_cast<EXT2_GROUP_DESCRIPTOR*>(
+ reinterpret_cast<UInt8*>(blockBuffer) + offsetInGroupDescBlock);
+ groupInfo->groupDescriptorBlock = groupDescriptorBlock;
+ groupInfo->offsetInGroupDescBlock = offsetInGroupDescBlock;
+ groupInfo->blockBuffer = reinterpret_cast<UInt8*>(blockBuffer);
+
+ return ErrorOr<Ext2GroupInfo*>(groupInfo);
+}
- UInt32 blockSize = ctx->BlockSize();
+// Allocate a new block
+inline ErrorOr<UInt32> ext2_alloc_block(Kernel::Ext2Context* ctx,
+ EXT2_GROUP_DESCRIPTOR* groupDesc) {
+ if (!ctx || !ctx->superblock || !groupDesc) return ErrorOr<UInt32>(kErrorInvalidData);
- // for the bitmap
- auto bitmap = mm_alloc_ptr(blockSize, true, false);
- if (!bitmap) return ErrorOr<UInt32>(kErrorHeapOutOfMemory);
+ UInt32 blockSize = ctx->BlockSize();
- // Read block bitmap
- if (!ext2_read_block(ctx->drive, groupDesc->fBlockBitmap, bitmap, blockSize)) {
- mm_free_ptr(bitmap);
- return ErrorOr<UInt32>(kErrorDisk);
- }
+ // for the bitmap
+ auto bitmap = mm_alloc_ptr(blockSize, true, false);
+ if (!bitmap) return ErrorOr<UInt32>(kErrorHeapOutOfMemory);
- // bit = 0
- for (UInt32 byteIdx = 0; byteIdx < blockSize; ++byteIdx) {
- auto byte = reinterpret_cast<unsigned char*>(bitmap)[byteIdx];
- if (byte != 0xFF) {
- for (int bit = 0; bit < 8; ++bit) {
- if (!(byte & (1 << bit))) {
- // Mark bit as used
- reinterpret_cast<unsigned char*>(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<UInt32>(kErrorDisk);
- }
-
- // Update group descriptor free count
- groupDesc->fFreeBlocksCount--;
- mm_free_ptr(bitmap);
- return ErrorOr<UInt32>(blockNumber);
- }
- }
+ // Read block bitmap
+ if (!ext2_read_block(ctx->drive, groupDesc->fBlockBitmap, bitmap, blockSize)) {
+ mm_free_ptr(bitmap);
+ return ErrorOr<UInt32>(kErrorDisk);
+ }
+
+ // bit = 0
+ for (UInt32 byteIdx = 0; byteIdx < blockSize; ++byteIdx) {
+ auto byte = reinterpret_cast<unsigned char*>(bitmap)[byteIdx];
+ if (byte != 0xFF) {
+ for (int bit = 0; bit < 8; ++bit) {
+ if (!(byte & (1 << bit))) {
+ // Mark bit as used
+ reinterpret_cast<unsigned char*>(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<UInt32>(kErrorDisk);
+ }
+
+ // Update group descriptor free count
+ groupDesc->fFreeBlocksCount--;
+ mm_free_ptr(bitmap);
+ return ErrorOr<UInt32>(blockNumber);
}
+ }
}
+ }
- mm_free_ptr(bitmap);
- return ErrorOr<UInt32>(kErrorDiskIsFull);
+ mm_free_ptr(bitmap);
+ return ErrorOr<UInt32>(kErrorDiskIsFull);
}
// Indirect blocks
-static Kernel::ErrorOr<Kernel::Void> ext2_set_block_address(Context* ctx, Ext2Node* node,
- Kernel::UInt32 logicalBlockIndex,
- Kernel::UInt32 physicalBlockNumber) {
- using namespace Kernel;
+static Kernel::ErrorOr<Kernel::Void*> ext2_set_block_address(Kernel::Ext2Context* ctx,
+ Ext2Node* node,
+ Kernel::UInt32 logicalBlockIndex,
+ Kernel::UInt32 physicalBlockNumber) {
+ using namespace Kernel;
+
+ if (!ctx || !ctx->drive || !node) return ErrorOr<Void*>(kErrorInvalidData);
+
+ auto blockSize = ctx->BlockSize();
+ UInt32 blocksPerPointerBlock = blockSize / sizeof(UInt32);
+
+ // Direct blocks
+ if (logicalBlockIndex < EXT2_DIRECT_BLOCKS) {
+ node->inode.fBlock[logicalBlockIndex] = physicalBlockNumber;
+ return ErrorOr<Void*>(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<Void*>(groupInfoRes.Error());
+
+ auto groupInfo = groupInfoRes.Leak().Leak(); // Ref<Ext2GroupInfo*>
+ auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc);
+ if (newBlockRes.HasError()) {
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return ErrorOr<Void*>(newBlockRes.Error());
+ }
- if (!ctx || !ctx->drive || !node)
- return ErrorOr<Void>(kErrorInvalidData);
+ node->inode.fBlock[EXT2_SINGLE_INDIRECT_INDEX] = newBlockRes.Leak();
- auto blockSize = ctx->BlockSize();
- UInt32 blocksPerPointerBlock = blockSize / sizeof(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<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return ErrorOr<Void*>(kErrorDisk);
+ }
+
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
- // Direct blocks
- if (logicalBlockIndex < EXT2_DIRECT_BLOCKS) {
- node->inode.fBlock[logicalBlockIndex] = physicalBlockNumber;
- return ErrorOr<Void>(nullptr);
+ // Zero out new indirect block
+ auto zeroBuf = mm_alloc_ptr(blockSize, true, false);
+ if (!zeroBuf) return ErrorOr<Void*>(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<Void*>(kErrorDisk);
+ }
+
+ mm_free_ptr(zeroBuf);
}
- // 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<Void>(groupInfoRes.Error());
-
- auto groupInfo = groupInfoRes.Leak().Leak(); // Ref<Ext2GroupInfo*>
- auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc);
- if (newBlockRes.HasError()) {
- mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- return ErrorOr<Void>(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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- return ErrorOr<Void>(kErrorDisk);
- }
-
- mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
-
- // Zero out new indirect block
- auto zeroBuf = mm_alloc_ptr(blockSize, true, false);
- if (!zeroBuf) return ErrorOr<Void>(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<Void>(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<Void*>(indirectRes.Error());
- // 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<Void>(indirectRes.Error());
+ UInt32* indirectPtr = indirectRes.Leak().Leak(); // Ref<UInt32*>
+ indirectPtr[logicalBlockIndex - EXT2_DIRECT_BLOCKS] = physicalBlockNumber;
- UInt32* indirectPtr = indirectRes.Leak().Leak(); // Ref<UInt32*>
- 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<Void*>(kErrorDisk);
+ }
- 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<Void>(kErrorDisk);
- }
+ mm_free_ptr(indirectPtr);
+ return ErrorOr<Void*>(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<Void*>(groupInfoRes.Error());
- mm_free_ptr(indirectPtr);
- return ErrorOr<Void>(nullptr);
+ auto groupInfo = groupInfoRes.Leak().Leak();
+ auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc);
+ if (newBlockRes.HasError()) {
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return ErrorOr<Void*>(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<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return ErrorOr<Void*>(kErrorDisk);
+ }
+
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+
+ // Zero new double-indirect block
+ auto zeroBuf = mm_alloc_ptr(blockSize, true, false);
+ if (!zeroBuf) return ErrorOr<Void*>(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<Void*>(kErrorDisk);
+ }
+
+ mm_free_ptr(zeroBuf);
}
- // 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<Void>(groupInfoRes.Error());
-
- auto groupInfo = groupInfoRes.Leak().Leak();
- auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc);
- if (newBlockRes.HasError()) {
- mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- return ErrorOr<Void>(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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- return ErrorOr<Void>(kErrorDisk);
- }
-
- mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
-
- // Zero new double-indirect block
- auto zeroBuf = mm_alloc_ptr(blockSize, true, false);
- if (!zeroBuf) return ErrorOr<Void>(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<Void>(kErrorDisk);
- }
-
- mm_free_ptr(zeroBuf);
- }
+ // Compute indices
+ UInt32 idxWithin = logicalBlockIndex - doubleStart;
+ UInt32 firstIdx = idxWithin / blocksPerPointerBlock;
+ UInt32 secondIdx = idxWithin % blocksPerPointerBlock;
- // 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<Void>(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<Void>(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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- return ErrorOr<Void>(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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- return ErrorOr<Void>(kErrorDisk);
- }
-
- mm_free_ptr(reinterpret_cast<void*>(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<Void>(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<Void>(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<Void>(kErrorDisk);
- }
- }
+ auto doubleRes = ext2_read_block_ptr(ctx, node->inode.fBlock[EXT2_DOUBLE_INDIRECT_INDEX]);
+ if (doubleRes.HasError()) return ErrorOr<Void*>(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<Void*>(groupInfoRes.Error());
+ }
- // Write to single-indirect block
- auto singleRes = ext2_read_block_ptr(ctx, singleIndirectBlock);
- if (singleRes.HasError()) return ErrorOr<Void>(singleRes.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<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return ErrorOr<Void*>(newBlockRes.Error());
+ }
- UInt32* singlePtr = singleRes.Leak().Leak();
- singlePtr[secondIdx] = physicalBlockNumber;
+ singleIndirectBlock = newBlockRes.Leak();
+ doublePtr[firstIdx] = singleIndirectBlock;
- UInt32 singleLba = ext2_block_to_lba(ctx, singleIndirectBlock);
- if (!ext2_write_block(ctx->drive, singleLba, singlePtr, blockSize)) {
- mm_free_ptr(singlePtr);
- return ErrorOr<Void>(kErrorDisk);
- }
+ // 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<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return ErrorOr<Void*>(kErrorDisk);
+ }
- mm_free_ptr(singlePtr);
- return ErrorOr<Void>(nullptr);
- }
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
- // Triple indirect blocks not implemented
- return ErrorOr<Void>(kErrorUnimplemented);
-}
+ // Zero single-indirect block
+ auto zeroBuf = mm_alloc_ptr(blockSize, true, false);
+ if (!zeroBuf) {
+ mm_free_ptr(doublePtr);
+ return ErrorOr<Void*>(kErrorHeapOutOfMemory);
+ }
-// Find a directory entry by name within a directory inode
-static ErrorOr<EXT2_DIR_ENTRY*> ext2_find_dir_entry(Context* ctx, Ext2Node* dirNode, const char* name) {
- if (!ctx || !ctx->drive || !dirNode || !name)
- return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorInvalidData);
-
- // Check directory type
- auto type = (dirNode->inode.fMode >> 12) & 0xF;
- if (type != kExt2FileTypeDirectory)
- return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorInvalidData);
-
- Kernel::UInt32 blockSize = ctx->BlockSize();
- auto blockBuf = mm_alloc_ptr(blockSize, true, false);
- if (!blockBuf) return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorHeapOutOfMemory);
-
- SizeT nameLen = rt_string_len(name);
- for (int i = 0; i < EXT2_DIRECT_BLOCKS; ++i) {
- Kernel::UInt32 blockNum = dirNode->inode.fBlock[i];
- if (blockNum == 0) continue;
-
- Kernel::UInt32 lba = ext2_block_to_lba(ctx, blockNum);
- if (!ext2_read_block(ctx->drive, lba, blockBuf, blockSize)) {
- mm_free_ptr(blockBuf);
- return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorDisk);
- }
+ 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<Void*>(kErrorDisk);
+ }
- Kernel::UInt32 offset = 0;
- while (offset + sizeof(Kernel::UInt32) + sizeof(Kernel::UInt16) <= blockSize) {
- auto onDiskEntry = reinterpret_cast<EXT2_DIR_ENTRY*>((Kernel::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<EXT2_DIR_ENTRY*>(Kernel::kErrorHeapOutOfMemory);
- }
-
- // Copy only record-length bytes
- rt_copy_memory_safe(onDiskEntry, found, onDiskEntry->fRecordLength, recSize);
- mm_free_ptr(blockBuf);
- return ErrorOr<EXT2_DIR_ENTRY*>(found);
- }
- }
- offset += onDiskEntry->fRecordLength;
- }
+ 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<Void*>(kErrorDisk);
+ }
}
-
- mm_free_ptr(blockBuf);
- return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorFileNotFound);
-}
-// Compute ideal record length for a directory name
-static inline UInt16 ext2_dir_entry_ideal_len(UInt8 nameLen) {
- UInt16 raw = static_cast<UInt16>(8 + nameLen); // 8 = inode(4)+rec_len(2)+name_len(1)+file_type(1)
- return static_cast<UInt16>((raw + 3) & ~3u); // align up to 4
-}
+ mm_free_ptr(doublePtr);
-static ErrorOr<Kernel::Void> ext2_add_dir_entry(Context* ctx, Ext2Node* parentDirNode,
- const char* name, Kernel::UInt32 inodeNumber, Kernel::UInt8 fileType) {
- using namespace Kernel;
+ // Write to single-indirect block
+ auto singleRes = ext2_read_block_ptr(ctx, singleIndirectBlock);
+ if (singleRes.HasError()) return ErrorOr<Void*>(singleRes.Error());
- if (!ctx || !ctx->drive || !parentDirNode || !name)
- return ErrorOr<Void>(kErrorInvalidData);
+ UInt32* singlePtr = singleRes.Leak().Leak();
+ singlePtr[secondIdx] = physicalBlockNumber;
- UInt32 blockSize = ctx->BlockSize();
- SizeT nameLen = rt_string_len(name);
- if (nameLen == 0 || nameLen > 255)
- return ErrorOr<Void>(kErrorInvalidData);
+ UInt32 singleLba = ext2_block_to_lba(ctx, singleIndirectBlock);
+ if (!ext2_write_block(ctx->drive, singleLba, singlePtr, blockSize)) {
+ mm_free_ptr(singlePtr);
+ return ErrorOr<Void*>(kErrorDisk);
+ }
- UInt16 newRecIdeal = ext2_dir_entry_ideal_len(static_cast<UInt8>(nameLen));
+ mm_free_ptr(singlePtr);
+ return ErrorOr<Void*>(nullptr);
+ }
- auto blockBuf = mm_alloc_ptr(blockSize, true, false);
- if (!blockBuf) return ErrorOr<Void>(kErrorHeapOutOfMemory);
-
- for (int 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<Void>(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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- mm_free_ptr(blockBuf);
- return ErrorOr<Void>(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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- mm_free_ptr(blockBuf);
- return ErrorOr<Void>(kErrorDisk);
- }
-
- mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
-
- // Zero block & insert entry
- rt_zero_memory(blockBuf, blockSize);
- auto entry = reinterpret_cast<EXT2_DIR_ENTRY*>(blockBuf);
- entry->fInode = inodeNumber;
- entry->fNameLength = static_cast<UInt8>(nameLen);
- entry->fFileType = fileType;
- entry->fRecordLength = static_cast<UInt16>(blockSize);
- rt_copy_memory_safe(const_cast<char*>(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<Void>(kErrorDisk);
- }
-
- auto setRes = ext2_set_block_address(ctx, parentDirNode, bi, newBlock);
- if (!setRes) {
- mm_free_ptr(blockBuf);
- return ErrorOr<Void>(setRes.Error());
- }
+ // Triple indirect blocks not implemented
+ return ErrorOr<Void*>(kErrorUnimplemented);
+}
+// Find a directory entry by name within a directory inode
+static ErrorOr<EXT2_DIR_ENTRY*> ext2_find_dir_entry(Kernel::Ext2Context* ctx, Ext2Node* dirNode,
+ const char* name) {
+ if (!ctx || !ctx->drive || !dirNode || !name)
+ return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorInvalidData);
+
+ // Check directory type
+ auto type = (dirNode->inode.fMode >> 12) & 0xF;
+ if (type != kExt2FileTypeDirectory) return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorInvalidData);
+
+ Kernel::UInt32 blockSize = ctx->BlockSize();
+ auto blockBuf = mm_alloc_ptr(blockSize, true, false);
+ if (!blockBuf) return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorHeapOutOfMemory);
+
+ SizeT nameLen = rt_string_len(name);
+ for (Kernel::UInt32 i = 0; i < EXT2_DIRECT_BLOCKS; ++i) {
+ Kernel::UInt32 blockNum = dirNode->inode.fBlock[i];
+ if (blockNum == 0) continue;
+
+ Kernel::UInt32 lba = ext2_block_to_lba(ctx, blockNum);
+ if (!ext2_read_block(ctx->drive, lba, blockBuf, blockSize)) {
+ mm_free_ptr(blockBuf);
+ return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorDisk);
+ }
+
+ Kernel::UInt32 offset = 0;
+ while (offset + sizeof(Kernel::UInt32) + sizeof(Kernel::UInt16) <= blockSize) {
+ auto onDiskEntry = reinterpret_cast<EXT2_DIR_ENTRY*>((Kernel::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<Void>(nullptr);
- }
+ return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorHeapOutOfMemory);
+ }
- // 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<Void>(kErrorDisk);
+ // Copy only record-length bytes
+ rt_copy_memory_safe(onDiskEntry, found, onDiskEntry->fRecordLength, recSize);
+ mm_free_ptr(blockBuf);
+ return ErrorOr<EXT2_DIR_ENTRY*>(found);
}
+ }
+ offset += onDiskEntry->fRecordLength;
+ }
+ }
- UInt32 offset = 0;
- EXT2_DIR_ENTRY* lastEntry = nullptr;
- UInt32 lastOffset = 0;
-
- while (offset < blockSize) {
- if (offset + 8 > blockSize) break;
- auto e = reinterpret_cast<EXT2_DIR_ENTRY*>((UInt8*)blockBuf + offset);
- if (e->fRecordLength == 0) break;
- lastEntry = e;
- lastOffset = offset;
- offset += e->fRecordLength;
- }
+ mm_free_ptr(blockBuf);
+ return ErrorOr<EXT2_DIR_ENTRY*>(Kernel::kErrorFileNotFound);
+}
- if (!lastEntry) continue;
+// Compute ideal record length for a directory name
+static inline UInt16 ext2_dir_entry_ideal_len(UInt8 nameLen) {
+ UInt16 raw =
+ static_cast<UInt16>(8 + nameLen); // 8 = inode(4)+rec_len(2)+name_len(1)+file_type(1)
+ return static_cast<UInt16>((raw + 3) & ~3u); // align up to 4
+}
- UInt16 lastIdeal = ext2_dir_entry_ideal_len(lastEntry->fNameLength);
+static ErrorOr<Kernel::Void*> ext2_add_dir_entry(Kernel::Ext2Context* ctx, Ext2Node* parentDirNode,
+ const char* name, Kernel::UInt32 inodeNumber,
+ Kernel::UInt8 fileType) {
+ using namespace Kernel;
- if (lastEntry->fRecordLength >= (UInt16)(lastIdeal + newRecIdeal)) {
- UInt16 origRec = lastEntry->fRecordLength;
- lastEntry->fRecordLength = lastIdeal;
+ if (!ctx || !ctx->drive || !parentDirNode || !name) return ErrorOr<Void*>(kErrorInvalidData);
- UInt32 newOffset = lastOffset + lastIdeal;
- auto newEntry = reinterpret_cast<EXT2_DIR_ENTRY*>((UInt8*)blockBuf + newOffset);
- newEntry->fInode = inodeNumber;
- newEntry->fNameLength = static_cast<UInt8>(nameLen);
- newEntry->fFileType = fileType;
- newEntry->fRecordLength = static_cast<UInt16>(origRec - lastIdeal);
- rt_copy_memory_safe(const_cast<char*>(name), newEntry->fName, nameLen, newEntry->fRecordLength);
+ UInt32 blockSize = ctx->BlockSize();
+ SizeT nameLen = rt_string_len(name);
+ if (nameLen == 0 || nameLen > 255) return ErrorOr<Void*>(kErrorInvalidData);
- if (!ext2_write_block(ctx->drive, blockLba, blockBuf, blockSize)) {
- mm_free_ptr(blockBuf);
- return ErrorOr<Void>(kErrorDisk);
- }
+ UInt16 newRecIdeal = ext2_dir_entry_ideal_len(static_cast<UInt8>(nameLen));
- mm_free_ptr(blockBuf);
- return ErrorOr<Void>(nullptr);
- }
- }
+ auto blockBuf = mm_alloc_ptr(blockSize, true, false);
+ if (!blockBuf) return ErrorOr<Void*>(kErrorHeapOutOfMemory);
- // No space in direct blocks -> allocate new block
- int targetIndex = -1;
- for (int 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<Void>(kErrorUnimplemented);
- }
+ for (int bi = 0; bi < EXT2_DIRECT_BLOCKS; ++bi) {
+ UInt32 blockNum = parentDirNode->inode.fBlock[bi];
- auto groupInfoResult = ext2_get_group_descriptor_info(ctx, parentDirNode->inodeNumber);
- if (!groupInfoResult) {
- mm_free_ptr(blockBuf);
- return ErrorOr<Void>(groupInfoResult.Error());
- }
+ if (blockNum == 0) {
+ // Allocate new block
+ auto groupInfoRes = ext2_get_group_descriptor_info(ctx, parentDirNode->inodeNumber);
+ if (!groupInfoRes) {
+ mm_free_ptr(blockBuf);
+ return ErrorOr<Void*>(groupInfoRes.Error());
+ }
- auto groupInfo = *groupInfoResult.Leak(); // Dereference to get Ext2GroupInfo*
- auto newBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc);
- if (!newBlockRes) {
+ auto groupInfo = *groupInfoRes.Leak(); // Dereference to get Ext2GroupInfo*
+ auto allocBlockRes = ext2_alloc_block(ctx, groupInfo->groupDesc);
+ if (!allocBlockRes) {
mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
mm_free_ptr(groupInfo);
mm_free_ptr(blockBuf);
- return ErrorOr<Void>(newBlockRes.Error());
- }
+ return ErrorOr<Void*>(allocBlockRes.Error());
+ }
+
+ UInt32 newBlock = *allocBlockRes.Leak(); // Dereference to get UInt32
+ UInt32 gdtLba = ext2_block_to_lba(ctx, groupInfo->groupDescriptorBlock);
- 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)) {
+ if (!ext2_write_block(ctx->drive, gdtLba, groupInfo->blockBuffer, blockSize)) {
mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
mm_free_ptr(groupInfo);
mm_free_ptr(blockBuf);
- return ErrorOr<Void>(kErrorDisk);
+ return ErrorOr<Void*>(kErrorDisk);
+ }
+
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+
+ // Zero block & insert entry
+ rt_zero_memory(blockBuf, blockSize);
+ auto entry = reinterpret_cast<EXT2_DIR_ENTRY*>(blockBuf);
+ entry->fInode = inodeNumber;
+ entry->fNameLength = static_cast<UInt8>(nameLen);
+ entry->fFileType = fileType;
+ entry->fRecordLength = static_cast<UInt16>(blockSize);
+ rt_copy_memory_safe(const_cast<char*>(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<Void*>(kErrorDisk);
+ }
+
+ auto setRes = ext2_set_block_address(ctx, parentDirNode, bi, newBlock);
+ if (!setRes) {
+ mm_free_ptr(blockBuf);
+ return ErrorOr<Void*>(setRes.Error());
+ }
+
+ mm_free_ptr(blockBuf);
+ return ErrorOr<Void*>(nullptr);
}
- mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
+ // 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<Void*>(kErrorDisk);
+ }
+
+ UInt32 offset = 0;
+ EXT2_DIR_ENTRY* lastEntry = nullptr;
+ UInt32 lastOffset = 0;
- rt_zero_memory(blockBuf, blockSize);
- auto entry = reinterpret_cast<EXT2_DIR_ENTRY*>(blockBuf);
- entry->fInode = inodeNumber;
- entry->fNameLength = static_cast<UInt8>(nameLen);
- entry->fFileType = fileType;
- entry->fRecordLength = static_cast<UInt16>(blockSize);
- rt_copy_memory_safe(const_cast<char*>(name), entry->fName, nameLen, blockSize);
+ while (offset < blockSize) {
+ if (offset + 8 > blockSize) break;
+ auto e = reinterpret_cast<EXT2_DIR_ENTRY*>((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<EXT2_DIR_ENTRY*>((UInt8*) blockBuf + newOffset);
+ newEntry->fInode = inodeNumber;
+ newEntry->fNameLength = static_cast<UInt8>(nameLen);
+ newEntry->fFileType = fileType;
+ newEntry->fRecordLength = static_cast<UInt16>(origRec - lastIdeal);
+ rt_copy_memory_safe(const_cast<char*>(name), newEntry->fName, nameLen,
+ newEntry->fRecordLength);
- UInt32 newBlockLba = ext2_block_to_lba(ctx, newBlockNum);
- if (!ext2_write_block(ctx->drive, newBlockLba, blockBuf, blockSize)) {
+ if (!ext2_write_block(ctx->drive, blockLba, blockBuf, blockSize)) {
mm_free_ptr(blockBuf);
- return ErrorOr<Void>(kErrorDisk);
+ return ErrorOr<Void*>(kErrorDisk);
+ }
+
+ mm_free_ptr(blockBuf);
+ return ErrorOr<Void*>(nullptr);
}
+ }
- auto setRes = ext2_set_block_address(ctx, parentDirNode, targetIndex, newBlockNum);
- if (!setRes) {
- mm_free_ptr(blockBuf);
- return ErrorOr<Void>(setRes.Error());
+ // No space in direct blocks -> allocate new block
+ int targetIndex = -1;
+ for (Kernel::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<Void*>(kErrorUnimplemented);
+ }
+ auto groupInfoResult = ext2_get_group_descriptor_info(ctx, parentDirNode->inodeNumber);
+ if (!groupInfoResult) {
mm_free_ptr(blockBuf);
- return ErrorOr<Void>(nullptr);
+ return ErrorOr<Void*>(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<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ mm_free_ptr(blockBuf);
+ return ErrorOr<Void*>(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<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ mm_free_ptr(blockBuf);
+ return ErrorOr<Void*>(kErrorDisk);
+ }
+
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+
+ rt_zero_memory(blockBuf, blockSize);
+ auto entry = reinterpret_cast<EXT2_DIR_ENTRY*>(blockBuf);
+ entry->fInode = inodeNumber;
+ entry->fNameLength = static_cast<UInt8>(nameLen);
+ entry->fFileType = fileType;
+ entry->fRecordLength = static_cast<UInt16>(blockSize);
+ rt_copy_memory_safe(const_cast<char*>(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<Void*>(kErrorDisk);
+ }
+
+ auto setRes = ext2_set_block_address(ctx, parentDirNode, targetIndex, newBlockNum);
+ if (!setRes) {
+ mm_free_ptr(blockBuf);
+ return ErrorOr<Void*>(setRes.Error());
+ }
+
+ mm_free_ptr(blockBuf);
+ return ErrorOr<Void*>(nullptr);
}
// Soon
-static ErrorOr<UInt32> ext2_alloc_inode(Context* ctx, EXT2_GROUP_DESCRIPTOR* groupDesc) {
- if (!ctx || !ctx->superblock || !groupDesc)
- return ErrorOr<UInt32>(kErrorInvalidData);
-
- UInt32 blockSize = ctx->BlockSize();
+static ErrorOr<UInt32> ext2_alloc_inode(Kernel::Ext2Context* ctx,
+ EXT2_GROUP_DESCRIPTOR* groupDesc) {
+ if (!ctx || !ctx->superblock || !groupDesc) return ErrorOr<UInt32>(kErrorInvalidData);
- // buffer for the inode bitmap
- auto bitmap = mm_alloc_ptr(blockSize, true, false);
- if (!bitmap) return ErrorOr<UInt32>(kErrorHeapOutOfMemory);
+ UInt32 blockSize = ctx->BlockSize();
- // Read inode bitmap
- if (!ext2_read_block(ctx->drive, groupDesc->fInodeBitmap, bitmap, blockSize)) {
- mm_free_ptr(bitmap);
- return ErrorOr<UInt32>(kErrorDisk);
- }
+ // buffer for the inode bitmap
+ auto bitmap = mm_alloc_ptr(blockSize, true, false);
+ if (!bitmap) return ErrorOr<UInt32>(kErrorHeapOutOfMemory);
- // Find first free inode (bit = 0)
- for (UInt32 byteIdx = 0; byteIdx < blockSize; ++byteIdx) {
- auto byte = reinterpret_cast<unsigned char*>(bitmap)[byteIdx];
- if (byte != 0xFF) {
- for (int bit = 0; bit < 8; ++bit) {
- if (!(byte & (1 << bit))) {
- // Mark bit as used
- reinterpret_cast<unsigned char*>(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<UInt32>(kErrorDisk);
- }
-
- // Update group descriptor free count
- groupDesc->fFreeInodesCount--;
- mm_free_ptr(bitmap);
- return ErrorOr<UInt32>(inodeNumber);
- }
- }
+ // Read inode bitmap
+ if (!ext2_read_block(ctx->drive, groupDesc->fInodeBitmap, bitmap, blockSize)) {
+ mm_free_ptr(bitmap);
+ return ErrorOr<UInt32>(kErrorDisk);
+ }
+
+ // Find first free inode (bit = 0)
+ for (UInt32 byteIdx = 0; byteIdx < blockSize; ++byteIdx) {
+ auto byte = reinterpret_cast<unsigned char*>(bitmap)[byteIdx];
+ if (byte != 0xFF) {
+ for (int bit = 0; bit < 8; ++bit) {
+ if (!(byte & (1 << bit))) {
+ // Mark bit as used
+ reinterpret_cast<unsigned char*>(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<UInt32>(kErrorDisk);
+ }
+
+ // Update group descriptor free count
+ groupDesc->fFreeInodesCount--;
+ mm_free_ptr(bitmap);
+ return ErrorOr<UInt32>(inodeNumber);
}
+ }
}
+ }
- mm_free_ptr(bitmap);
- return ErrorOr<UInt32>(kErrorDiskIsFull);
+ mm_free_ptr(bitmap);
+ return ErrorOr<UInt32>(kErrorDiskIsFull);
}
// to write an inode to its correct location on disk
-static ErrorOr<Void> ext2_write_inode(Context* ctx, Ext2Node* node) {
- using namespace Kernel;
-
- if (!ctx || !ctx->superblock || !ctx->drive || !node)
- return ErrorOr<Void>(kErrorInvalidData);
-
- auto blockSize = ctx->BlockSize();
- UInt32 inodesPerGroup = ctx->superblock->fInodesPerGroup;
-
- if (inodesPerGroup == 0) return ErrorOr<Void>(kErrorInvalidData);
-
- // Calculate which group this inode belongs to
- UInt32 groupIndex = (node->inodeNumber - 1) / inodesPerGroup;
- UInt32 inodeIndexInGroup = (node->inodeNumber - 1) % inodesPerGroup;
-
- // Get group descriptor
- auto groupInfoResult = ext2_get_group_descriptor_info(ctx, node->inodeNumber);
- if (!groupInfoResult) return ErrorOr<Void>(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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- return ErrorOr<Void>(kErrorHeapOutOfMemory);
- }
+static ErrorOr<Void*> ext2_write_inode(Kernel::Ext2Context* ctx, Ext2Node* node) {
+ using namespace Kernel;
- if (!ext2_read_block(ctx->drive, inodeLba, blockBuf, blockSize)) {
- mm_free_ptr(blockBuf);
- mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- return ErrorOr<Void>(kErrorDisk);
- }
+ if (!ctx || !ctx->superblock || !ctx->drive || !node) return ErrorOr<Void*>(kErrorInvalidData);
- // Copy the updated inode into the block buffer
- rt_copy_memory_safe(&node->inode, static_cast<void*>((UInt8*)blockBuf + offsetInBlock),
- sizeof(EXT2_INODE), blockSize - offsetInBlock);
+ auto blockSize = ctx->BlockSize();
+ UInt32 inodesPerGroup = ctx->superblock->fInodesPerGroup;
- // Write the block back
- if (!ext2_write_block(ctx->drive, inodeLba, blockBuf, blockSize)) {
- mm_free_ptr(blockBuf);
- mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- return ErrorOr<Void>(kErrorDisk);
- }
+ if (inodesPerGroup == 0) return ErrorOr<Void*>(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<Void*>(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<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return ErrorOr<Void*>(kErrorHeapOutOfMemory);
+ }
+
+ if (!ext2_read_block(ctx->drive, inodeLba, blockBuf, blockSize)) {
+ mm_free_ptr(blockBuf);
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return ErrorOr<Void*>(kErrorDisk);
+ }
+
+ // Copy the updated inode into the block buffer
+ rt_copy_memory_safe(&node->inode, static_cast<void*>((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<void*>(groupInfo->blockBuffer));
mm_free_ptr(groupInfo);
-
- return ErrorOr<Void>(nullptr);
+ return ErrorOr<Void*>(kErrorDisk);
+ }
+
+ mm_free_ptr(blockBuf);
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+
+ return ErrorOr<Void*>(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;
- }
+// new
+struct PathComponents {
+ const char** components;
+ int count;
+ Char* buffer;
- int 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;
- }
+ PathComponents(const char* path) : components(nullptr), count(0), buffer(nullptr) {
+ if (!path || *path == '\0') return;
- if (compCount == 0) {
- mm_free_ptr(temp);
- return;
- }
+ SizeT pathLen = rt_string_len(path);
+ buffer = (Char*) mm_alloc_ptr(pathLen + 1, true, false);
+ if (!buffer) return;
- components = (const char**)mm_alloc_ptr(sizeof(char*) * compCount, true, false);
- if (!components) {
- mm_free_ptr(temp);
- return;
- }
+ rt_copy_memory_safe((void*) path, buffer, pathLen, pathLen + 1);
+ buffer[pathLen] = '\0';
- for (int i = 0; i < compCount; i++) components[i] = temp[i];
- count = compCount;
-
- mm_free_ptr(temp);
+ // 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;
}
- ~PathComponents() {
- if (components) mm_free_ptr(components);
- if (buffer) mm_free_ptr(buffer);
- }
-};
-} // anonymous namespace
+ int compCount = 0;
+ Char* p = buffer;
-// The Ext2FileSystemMgr
-Ext2FileSystemMgr::Ext2FileSystemMgr(DriveTrait* drive) : ctx(drive) {}
-NodePtr Ext2FileSystemMgr::Open(const char* path, const char* restrict_type) {
- if (!path || *path == '\0' || !this->ctx.drive) {
- return nullptr;
- }
+ while (*p != '\0') {
+ // skip slashes
+ while (*p == '/') p++;
+ if (*p == '\0') break;
- // 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;
- }
+ Char* start = p;
+ while (*p != '/' && *p != '\0') p++;
+ Char saved = *p;
+ *p = '\0';
- auto heapNode = (Ext2Node*)mm_alloc_ptr(sizeof(Ext2Node), true, false);
- if (!heapNode) return nullptr;
+ // 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;
+ }
- *heapNode = *inodeResult.Leak();
- heapNode->cursor = 0;
- return reinterpret_cast<NodePtr>(heapNode);
+ *p = saved;
}
- PathComponents pathComponents(path);
- if (pathComponents.count == 0) {
- return nullptr;
+ if (compCount == 0) {
+ mm_free_ptr(temp);
+ return;
}
- UInt32 currentInodeNumber = EXT2_ROOT_INODE;
- Ext2Node* currentDirNode = nullptr;
+ components = (const char**) mm_alloc_ptr(sizeof(char*) * compCount, true, false);
+ if (!components) {
+ mm_free_ptr(temp);
+ return;
+ }
- for (int i = 0; i < pathComponents.count; ++i) {
- auto inodeResult = ext2_load_inode(&this->ctx, currentInodeNumber);
- if (!inodeResult) {
- if (currentDirNode) mm_free_ptr(currentDirNode);
- return nullptr;
- }
+ for (Kernel::UInt32 i = 0; i < compCount; i++) components[i] = temp[i];
+ count = compCount;
- if (currentDirNode) {
- mm_free_ptr(currentDirNode);
- currentDirNode = nullptr;
- }
+ mm_free_ptr(temp);
+ }
- currentDirNode = (Ext2Node*)mm_alloc_ptr(sizeof(Ext2Node), true, false);
- if (!currentDirNode) {
- return nullptr;
- }
+ ~PathComponents() {
+ if (components) mm_free_ptr(components);
+ if (buffer) mm_free_ptr(buffer);
+ }
+};
+} // anonymous namespace
- *currentDirNode = *inodeResult.Leak();
- currentDirNode->cursor = 0;
+// 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;
+ }
- if (i < pathComponents.count - 1) {
- UInt32 type = (currentDirNode->inode.fMode >> 12) & 0xF;
- if (type != kExt2FileTypeDirectory) {
- mm_free_ptr(currentDirNode);
- 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 dirEntryResult = ext2_find_dir_entry(&this->ctx, currentDirNode, pathComponents.components[i]);
- if (!dirEntryResult) {
- mm_free_ptr(currentDirNode);
- return nullptr;
- }
+ auto heapNode = (Ext2Node*) mm_alloc_ptr(sizeof(Ext2Node), true, false);
+ if (!heapNode) return nullptr;
- EXT2_DIR_ENTRY* entryPtr = *dirEntryResult.Leak();
- currentInodeNumber = entryPtr->fInode;
- mm_free_ptr(entryPtr);
- }
+ *heapNode = *inodeResult.Leak().Leak();
+ heapNode->cursor = 0;
+ return reinterpret_cast<NodePtr>(heapNode);
+ }
- auto finalInodeResult = ext2_load_inode(&this->ctx, currentInodeNumber);
- if (!finalInodeResult) {
- if (currentDirNode) mm_free_ptr(currentDirNode);
- return nullptr;
+ PathComponents pathComponents(path);
+ if (pathComponents.count == 0) {
+ return nullptr;
+ }
+
+ UInt32 currentInodeNumber = EXT2_ROOT_INODE;
+ Ext2Node* currentDirNode = nullptr;
+
+ for (Kernel::UInt32 i = 0; i < 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);
+ mm_free_ptr(currentDirNode);
+ currentDirNode = nullptr;
}
- auto resultNode = (Ext2Node*)mm_alloc_ptr(sizeof(Ext2Node), true, false);
- if (!resultNode) {
+ currentDirNode = (Ext2Node*) mm_alloc_ptr(sizeof(Ext2Node), true, false);
+ if (!currentDirNode) {
+ return nullptr;
+ }
+
+ *currentDirNode = *inodeResult.Leak().Leak();
+ currentDirNode->cursor = 0;
+
+ if (i < pathComponents.count - 1) {
+ 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;
}
- *resultNode = *finalInodeResult.Leak();
- resultNode->cursor = 0;
- return reinterpret_cast<NodePtr>(resultNode);
+ 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<NodePtr>(resultNode);
}
+void* Ext2FileSystemParser::Read(NodePtr node, Int32 flags, SizeT size) {
+ if (!node) return nullptr;
-void* Ext2FileSystemMgr::Read(NodePtr node, Int32 flags, SizeT size) {
- if (!node) return nullptr;
+ NE_UNUSED(flags);
- auto extNode = reinterpret_cast<Ext2Node*>(node);
- auto dataResult = ext2_read_inode_data(&this->ctx, extNode, size);
+ auto extNode = reinterpret_cast<Ext2Node*>(node);
+ auto dataResult = ext2_read_inode_data(&this->ctx, extNode, size);
- if (!dataResult) {
- return nullptr; // error, nothing to return
- }
+ if (!dataResult) {
+ return nullptr; // error, nothing to return
+ }
- void* data = *dataResult.Leak();
- if (data) {
- extNode->cursor += static_cast<UInt32>(size);
- }
+ void* data = *dataResult.Leak();
+ if (data) {
+ extNode->cursor += static_cast<UInt32>(size);
+ }
- return data;
+ return data;
}
+void Ext2FileSystemParser::Write(NodePtr node, void* data, Int32 flags, SizeT size) {
+ if (!node || !data || size == 0) return;
-void Ext2FileSystemMgr::Write(NodePtr node, void* data, Int32 flags, SizeT size) {
- if (!node || !data || size == 0) return;
-
- auto extNode = reinterpret_cast<Ext2Node*>(node);
- auto blockSize = this->ctx.BlockSize();
- SizeT bytesWritten = 0;
-
- UInt32 currentOffset = extNode->cursor;
- UInt8* src = reinterpret_cast<UInt8*>(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<void*>(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<void*>(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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- return;
- }
-
- mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- } else {
- return;
- }
- } else {
- physicalBlock = physBlockResult.Value();
- }
+ NE_UNUSED(flags);
+
+ auto extNode = reinterpret_cast<Ext2Node*>(node);
+ auto blockSize = this->ctx.BlockSize();
+ SizeT bytesWritten = 0;
+
+ UInt32 currentOffset = extNode->cursor;
+ UInt8* src = reinterpret_cast<UInt8*>(data);
- UInt32 physicalLba = ext2_block_to_lba(&this->ctx, physicalBlock);
+ while (bytesWritten < size) {
+ UInt32 logicalBlockIndex = currentOffset / blockSize;
+ UInt32 offsetInBlock = currentOffset % blockSize;
- auto blockBuf = mm_alloc_ptr(blockSize, true, false);
- if (!blockBuf) return;
+ auto physBlockResult = ext2_get_block_address(&this->ctx, extNode, logicalBlockIndex);
+ UInt32 physicalBlock = 0;
- 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);
+ 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;
}
- UInt32 bytesInCurrentBlock = static_cast<UInt32>(ext2_min(size - bytesWritten, blockSize - offsetInBlock));
- rt_copy_memory_safe(src, static_cast<void*>((UInt8*)blockBuf + offsetInBlock),
- bytesInCurrentBlock, blockSize - offsetInBlock);
+ auto groupInfo = *groupInfoResult.Leak();
+ auto allocResult = ext2_alloc_block(&this->ctx, groupInfo->groupDesc);
+ if (!allocResult) {
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return;
+ }
- if (!ext2_write_block(this->ctx.drive, physicalLba, blockBuf, blockSize)) {
- mm_free_ptr(blockBuf);
- return;
+ physicalBlock = *allocResult.Leak();
+
+ auto setRes = ext2_set_block_address(&this->ctx, extNode, logicalBlockIndex, physicalBlock);
+ if (!setRes) {
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return;
}
- mm_free_ptr(blockBuf);
+ 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<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ return;
+ }
- currentOffset += bytesInCurrentBlock;
- src += bytesInCurrentBlock;
- bytesWritten += bytesInCurrentBlock;
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ } else {
+ return;
+ }
+ } else {
+ physicalBlock = physBlockResult.Value();
}
- if (currentOffset > extNode->inode.fSize) {
- extNode->inode.fSize = currentOffset;
+ 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);
}
- extNode->inode.fBlocks = (extNode->inode.fSize + blockSize - 1) / blockSize;
- extNode->inode.fModifyTime = 0;
+ UInt32 bytesInCurrentBlock =
+ static_cast<UInt32>(ext2_min(size - bytesWritten, blockSize - offsetInBlock));
+ rt_copy_memory_safe(src, static_cast<void*>((UInt8*) blockBuf + offsetInBlock),
+ bytesInCurrentBlock, blockSize - offsetInBlock);
- auto writeInodeRes = ext2_write_inode(&this->ctx, extNode);
- if (!writeInodeRes) {
- // Failed to persist inode
+ if (!ext2_write_block(this->ctx.drive, physicalLba, blockBuf, blockSize)) {
+ mm_free_ptr(blockBuf);
+ return;
}
- extNode->cursor = currentOffset;
-}
+ mm_free_ptr(blockBuf);
+
+ currentOffset += bytesInCurrentBlock;
+ src += bytesInCurrentBlock;
+ bytesWritten += bytesInCurrentBlock;
+ }
-bool Ext2FileSystemMgr::Seek(NodePtr node, SizeT offset) {
- if (!node) return false;
- auto extNode = reinterpret_cast<Ext2Node*>(node);
- extNode->cursor = static_cast<UInt32>(offset);
- return true;
+ 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;
}
-SizeT Ext2FileSystemMgr::Tell(NodePtr node) {
- if (!node) return 0;
- auto extNode = reinterpret_cast<Ext2Node*>(node);
- return extNode->cursor;
+bool Ext2FileSystemParser::Seek(NodePtr node, SizeT offset) {
+ if (!node) return false;
+ auto extNode = reinterpret_cast<Ext2Node*>(node);
+ extNode->cursor = static_cast<UInt32>(offset);
+ return true;
}
-bool Ext2FileSystemMgr::Rewind(NodePtr node) {
- if (!node) return false;
- auto extNode = reinterpret_cast<Ext2Node*>(node);
- extNode->cursor = 0;
- return true;
+SizeT Ext2FileSystemParser::Tell(NodePtr node) {
+ if (!node) return 0;
+ auto extNode = reinterpret_cast<Ext2Node*>(node);
+ return extNode->cursor;
}
-void* Ext2FileSystemMgr::Read(const char* name, NodePtr node, Int32 flags, SizeT size) {
- return Read(node, flags, size);
+bool Ext2FileSystemParser::Rewind(NodePtr node) {
+ if (!node) return false;
+ auto extNode = reinterpret_cast<Ext2Node*>(node);
+ extNode->cursor = 0;
+ return true;
}
-void Ext2FileSystemMgr::Write(const char* name, NodePtr node, void* data, Int32 flags, SizeT size) {
- Write(node, data, flags, size);
+void* Ext2FileSystemParser::Read(const char* name, NodePtr node, Int32 flags, SizeT size) {
+ NE_UNUSED(name);
+ return Read(node, flags, size);
}
-NodePtr Ext2FileSystemMgr::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 (int i = 0; i < pathComponents.count - 1; ++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<char*>(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<Ext2Node*>(parentDirNodePtr) = *inodeRes.Leak();
- reinterpret_cast<Ext2Node*>(parentDirNodePtr)->cursor = 0;
- } else {
- parentDirNodePtr = Open(parentPathBuf, "r");
- }
+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 (Kernel::UInt32 i = 0; (i < pathComponents.count - 1); ++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<char*>(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<Ext2Node*>(parentDirNodePtr) = *inodeRes.Leak().Leak();
+ reinterpret_cast<Ext2Node*>(parentDirNodePtr)->cursor = 0;
+ } else {
+ parentDirNodePtr = Open(parentPathBuf, "r");
+ }
- auto parentDirNode = reinterpret_cast<Ext2Node*>(parentDirNodePtr);
+ if (!parentDirNodePtr) return nullptr;
- // Ensure parent is a directory
- UInt32 type = (parentDirNode->inode.fMode >> 12) & 0xF;
- if (type != kExt2FileTypeDirectory) {
- mm_free_ptr(parentDirNode);
- return nullptr;
- }
+ auto parentDirNode = reinterpret_cast<Ext2Node*>(parentDirNodePtr);
- // 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();
+ // Ensure parent is a directory
+ UInt32 type = (parentDirNode->inode.fMode >> 12) & 0xF;
+ if (type != kExt2FileTypeDirectory) {
+ mm_free_ptr(parentDirNode);
+ return nullptr;
+ }
- // Allocate new inode
- auto newInodeRes = ext2_alloc_inode(&this->ctx, groupInfo->groupDesc);
- if (!newInodeRes) {
- mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo); // so this works
- mm_free_ptr(parentDirNode);
- return nullptr;
- }
- UInt32 newInodeNumber = newInodeRes.Value();
+ // 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();
- 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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- mm_free_ptr(parentDirNode);
- return nullptr;
- }
+ // Allocate new inode
+ auto newInodeRes = ext2_alloc_inode(&this->ctx, groupInfo->groupDesc);
+ if (!newInodeRes) {
+ mm_free_ptr(reinterpret_cast<void*>(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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
+ mm_free_ptr(groupInfo);
+ mm_free_ptr(parentDirNode);
+ return nullptr;
+ }
- // Create new Ext2Node
- Ext2Node* newFileNode = reinterpret_cast<Ext2Node*>(mm_alloc_ptr(sizeof(Ext2Node), true, false));
- if (!newFileNode) {
- mm_free_ptr(parentDirNode);
- return nullptr;
- }
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
- 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;
- }
+ // Create new Ext2Node
+ Ext2Node* newFileNode = reinterpret_cast<Ext2Node*>(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;
+ }
- // 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
- // Update parent inode
- auto parentWriteRes = ext2_write_inode(&this->ctx, parentDirNode);
- // ignore failure
+ NE_UNUSED(parentWriteRes);
- mm_free_ptr(parentDirNode);
- return reinterpret_cast<NodePtr>(newFileNode);
+ mm_free_ptr(parentDirNode);
+ return reinterpret_cast<NodePtr>(newFileNode);
}
-NodePtr Ext2FileSystemMgr::CreateDirectory(const char* path) {
- if (!path || *path == '\0') return nullptr;
+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;
- }
+ 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;
- }
+ 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 (int i = 0; i < pathComponents.count - 1; ++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<void*>(const_cast<char*>(pathComponents.components[i])),
- static_cast<void*>(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<NodePtr>(mm_alloc_ptr(sizeof(Ext2Node), true, false));
- if (!parentDirNodePtr) return nullptr;
-
- *reinterpret_cast<Ext2Node*>(parentDirNodePtr) = *inodeRes.Leak();
- reinterpret_cast<Ext2Node*>(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<Ext2Node*>(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;
+ // Build parent path
+ Char parentPathBuf[256];
+ SizeT currentPathLen = 0;
+ for (Kernel::UInt32 i = 0; (i < pathComponents.count - 1); ++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;
}
- // 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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- mm_free_ptr(parentDirNode);
- return nullptr;
- }
-
- UInt32 newInodeNumber = *newInodeRes.Leak();
+ if (i > 0) parentPathBuf[currentPathLen++] = '/';
- // 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<void*>(groupInfo->blockBuffer));
- mm_free_ptr(groupInfo);
- mm_free_ptr(parentDirNode);
- return nullptr;
+ rt_copy_memory_safe(static_cast<void*>(const_cast<char*>(pathComponents.components[i])),
+ static_cast<void*>(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<NodePtr>(mm_alloc_ptr(sizeof(Ext2Node), true, false));
+ if (!parentDirNodePtr) return nullptr;
+
+ *reinterpret_cast<Ext2Node*>(parentDirNodePtr) = *inodeRes.Leak().Leak();
+ reinterpret_cast<Ext2Node*>(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<Ext2Node*>(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<void*>(groupInfo->blockBuffer));
mm_free_ptr(groupInfo);
+ mm_free_ptr(parentDirNode);
+ return nullptr;
+ }
- // Create new Ext2Node and initialize inode fields
- Ext2Node* newDirNode = reinterpret_cast<Ext2Node*>(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<void*>(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<void*>(groupForBlock->blockBuffer));
- mm_free_ptr(groupForBlock);
- mm_free_ptr(parentDirNode);
- mm_free_ptr(newDirNode);
- 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<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+ mm_free_ptr(parentDirNode);
+ return nullptr;
+ }
+
+ mm_free_ptr(reinterpret_cast<void*>(groupInfo->blockBuffer));
+ mm_free_ptr(groupInfo);
+
+ // Create new Ext2Node and initialize inode fields
+ Ext2Node* newDirNode = reinterpret_cast<Ext2Node*>(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<void*>(groupForBlock->blockBuffer));
mm_free_ptr(groupForBlock);
+ mm_free_ptr(parentDirNode);
+ mm_free_ptr(newDirNode);
+ return nullptr;
+ }
- // 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;
- }
+ UInt32 newDirBlockNum = *newBlockRes.Leak();
- // 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<EXT2_DIR_ENTRY*>(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<EXT2_DIR_ENTRY*>((UInt8*)dirBlockBuf + dot->fRecordLength);
- dotdot->fInode = parentDirNode->inodeNumber;
- dotdot->fNameLength = 2;
- dotdot->fFileType = kExt2FileTypeDirectory;
- dotdot->fRecordLength = static_cast<UInt16>(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);
+ // 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<void*>(groupForBlock->blockBuffer));
+ mm_free_ptr(groupForBlock);
+ mm_free_ptr(parentDirNode);
+ mm_free_ptr(newDirNode);
+ return nullptr;
+ }
- // 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;
- }
+ mm_free_ptr(reinterpret_cast<void*>(groupForBlock->blockBuffer));
+ mm_free_ptr(groupForBlock);
- // 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;
- }
+ // 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<EXT2_DIR_ENTRY*>(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<EXT2_DIR_ENTRY*>((UInt8*) dirBlockBuf + dot->fRecordLength);
+ dotdot->fInode = parentDirNode->inodeNumber;
+ dotdot->fNameLength = 2;
+ dotdot->fFileType = kExt2FileTypeDirectory;
+ dotdot->fRecordLength = static_cast<UInt16>(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;
+ }
- // 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(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);
- return reinterpret_cast<NodePtr>(newDirNode);
+ 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<NodePtr>(newDirNode);
}
-} // namespace Ext2
-
#endif
-#endif
+#endif