diff --git a/Aaru.Filesystems/extFS/Block.cs b/Aaru.Filesystems/extFS/Block.cs
index 2a9489c91..04919a9df 100644
--- a/Aaru.Filesystems/extFS/Block.cs
+++ b/Aaru.Filesystems/extFS/Block.cs
@@ -44,18 +44,15 @@ public sealed partial class extFS
{
blockData = null;
- // Calculate block size (1024 << log_zone_size)
- uint blockSize = 1024u << (int)_superblock.s_log_zone_size;
-
// Calculate the byte offset within the partition
- ulong byteOffset = (ulong)blockNumber * blockSize;
+ ulong byteOffset = (ulong)blockNumber * EXT_BLOCK_SIZE;
// Convert to sector address
ulong sectorAddress = byteOffset / _imagePlugin.Info.SectorSize;
var offsetInSector = (int)(byteOffset % _imagePlugin.Info.SectorSize);
// Calculate how many sectors to read
- uint sectorsToRead = (blockSize + (uint)offsetInSector + _imagePlugin.Info.SectorSize - 1) /
+ uint sectorsToRead = (EXT_BLOCK_SIZE + (uint)offsetInSector + _imagePlugin.Info.SectorSize - 1) /
_imagePlugin.Info.SectorSize;
ErrorNumber errno = _imagePlugin.ReadSectors(_partition.Start + sectorAddress,
@@ -66,8 +63,8 @@ public sealed partial class extFS
if(errno != ErrorNumber.NoError) return errno;
- blockData = new byte[blockSize];
- Array.Copy(sectorData, offsetInSector, blockData, 0, blockSize);
+ blockData = new byte[EXT_BLOCK_SIZE];
+ Array.Copy(sectorData, offsetInSector, blockData, 0, EXT_BLOCK_SIZE);
return ErrorNumber.NoError;
}
@@ -88,14 +85,13 @@ public sealed partial class extFS
{
physicalBlock = 0;
- uint addressesPerBlock = (1024u << (int)_superblock.s_log_zone_size) / 4; // 4 bytes per block pointer
// Check bounds: max blocks = 9 + 256 + 256*256 + 256*256*256
uint maxBlocks =
9 +
- addressesPerBlock +
- addressesPerBlock * addressesPerBlock +
- addressesPerBlock * addressesPerBlock * addressesPerBlock;
+ EXT_ADDR_PER_BLOCK +
+ EXT_ADDR_PER_BLOCK * EXT_ADDR_PER_BLOCK +
+ EXT_ADDR_PER_BLOCK * EXT_ADDR_PER_BLOCK * EXT_ADDR_PER_BLOCK;
if(logicalBlock >= maxBlocks)
{
@@ -115,7 +111,7 @@ public sealed partial class extFS
uint block = logicalBlock - 9;
// Single indirect block
- if(block < addressesPerBlock)
+ if(block < EXT_ADDR_PER_BLOCK)
{
uint indirectBlock = inode.i_zone[9];
@@ -135,10 +131,10 @@ public sealed partial class extFS
return ErrorNumber.NoError;
}
- block -= addressesPerBlock;
+ block -= EXT_ADDR_PER_BLOCK;
// Double indirect block
- if(block < addressesPerBlock * addressesPerBlock)
+ if(block < EXT_ADDR_PER_BLOCK * EXT_ADDR_PER_BLOCK)
{
uint dindirectBlock = inode.i_zone[10];
@@ -154,7 +150,7 @@ public sealed partial class extFS
if(err != ErrorNumber.NoError) return err;
- uint indirectIndex = block / addressesPerBlock;
+ uint indirectIndex = block / EXT_ADDR_PER_BLOCK;
var indirectAddr = BitConverter.ToUInt32(dindirectData, (int)(indirectIndex * 4));
if(indirectAddr == 0)
@@ -169,13 +165,13 @@ public sealed partial class extFS
if(err != ErrorNumber.NoError) return err;
- uint blockIndex = block % addressesPerBlock;
+ uint blockIndex = block % EXT_ADDR_PER_BLOCK;
physicalBlock = BitConverter.ToUInt32(indirectData2, (int)(blockIndex * 4));
return ErrorNumber.NoError;
}
- block -= addressesPerBlock * addressesPerBlock;
+ block -= EXT_ADDR_PER_BLOCK * EXT_ADDR_PER_BLOCK;
// Triple indirect block
uint tindirectBlock = inode.i_zone[11];
@@ -192,7 +188,7 @@ public sealed partial class extFS
if(errno3 != ErrorNumber.NoError) return errno3;
- uint dindirectIndex = block / (addressesPerBlock * addressesPerBlock);
+ uint dindirectIndex = block / (EXT_ADDR_PER_BLOCK * EXT_ADDR_PER_BLOCK);
var dindirectAddr = BitConverter.ToUInt32(tindirectData, (int)(dindirectIndex * 4));
if(dindirectAddr == 0)
@@ -207,7 +203,7 @@ public sealed partial class extFS
if(errno3 != ErrorNumber.NoError) return errno3;
- uint indirectIndex2 = block / addressesPerBlock % addressesPerBlock;
+ uint indirectIndex2 = block / EXT_ADDR_PER_BLOCK % EXT_ADDR_PER_BLOCK;
var indirectAddr2 = BitConverter.ToUInt32(dindirectData2, (int)(indirectIndex2 * 4));
if(indirectAddr2 == 0)
@@ -222,7 +218,7 @@ public sealed partial class extFS
if(errno3 != ErrorNumber.NoError) return errno3;
- uint blockIndex2 = block % addressesPerBlock;
+ uint blockIndex2 = block % EXT_ADDR_PER_BLOCK;
physicalBlock = BitConverter.ToUInt32(indirectData3, (int)(blockIndex2 * 4));
return ErrorNumber.NoError;
diff --git a/Aaru.Filesystems/extFS/Consts.cs b/Aaru.Filesystems/extFS/Consts.cs
index d39c3381f..e23186db4 100644
--- a/Aaru.Filesystems/extFS/Consts.cs
+++ b/Aaru.Filesystems/extFS/Consts.cs
@@ -39,6 +39,12 @@ public sealed partial class extFS
/// ext superblock magic
const ushort EXT_MAGIC = 0x137D;
+ /// ext block size is always 1024 bytes
+ const uint EXT_BLOCK_SIZE = 1024;
+
+ /// Number of addresses per indirect block (1024/4)
+ const uint EXT_ADDR_PER_BLOCK = 256;
+
const int EXT_NAME_LEN = 255;
const int EXT_ROOT_INO = 1;
diff --git a/Aaru.Filesystems/extFS/Dir.cs b/Aaru.Filesystems/extFS/Dir.cs
index 2d80ef78b..fe0caad32 100644
--- a/Aaru.Filesystems/extFS/Dir.cs
+++ b/Aaru.Filesystems/extFS/Dir.cs
@@ -33,6 +33,7 @@ using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
using Aaru.Helpers;
using Aaru.Logging;
+using Marshal = Aaru.Helpers.Marshal;
namespace Aaru.Filesystems;
@@ -182,7 +183,6 @@ public sealed partial class extFS
if(inode.i_size == 0) return ErrorNumber.NoError;
- uint blockSize = 1024u << (int)_superblock.s_log_zone_size;
uint bytesRead = 0;
// Process all blocks containing directory data
@@ -197,7 +197,7 @@ public sealed partial class extFS
{
AaruLogging.Debug(MODULE_NAME, "Error mapping block {0}: {1}", blockNum, errno);
blockNum++;
- bytesRead += blockSize;
+ bytesRead += EXT_BLOCK_SIZE;
continue;
}
@@ -206,7 +206,7 @@ public sealed partial class extFS
if(physicalBlock == 0)
{
blockNum++;
- bytesRead += blockSize;
+ bytesRead += EXT_BLOCK_SIZE;
continue;
}
@@ -218,17 +218,17 @@ public sealed partial class extFS
{
AaruLogging.Debug(MODULE_NAME, "Error reading block {0}: {1}", physicalBlock, errno);
blockNum++;
- bytesRead += blockSize;
+ bytesRead += EXT_BLOCK_SIZE;
continue;
}
// Parse directory entries in this block
- uint validBytes = Math.Min(blockSize, inode.i_size - bytesRead);
+ uint validBytes = Math.Min(EXT_BLOCK_SIZE, inode.i_size - bytesRead);
ParseDirectoryBlock(blockData, validBytes, entries);
blockNum++;
- bytesRead += blockSize;
+ bytesRead += EXT_BLOCK_SIZE;
}
return ErrorNumber.NoError;
@@ -240,22 +240,19 @@ public sealed partial class extFS
/// Dictionary to add entries to
void ParseDirectoryBlock(byte[] blockData, uint validBytes, Dictionary entries)
{
+ // Minimum directory entry is 8 bytes (inode + rec_len + name_len) + at least 1 byte name
+ const int minEntrySize = 8;
uint offset = 0;
while(offset < validBytes)
{
- // Directory entry structure:
- // - 4 bytes: inode number
- // - 2 bytes: record length (rec_len)
- // - 2 bytes: name length (name_len)
- // - N bytes: name
-
- if(offset + 8 > validBytes) // Minimum entry size
+ if(offset + minEntrySize > validBytes)
break;
- var inoNum = BitConverter.ToUInt32(blockData, (int)offset);
- var recLen = BitConverter.ToUInt16(blockData, (int)(offset + 4));
- var nameLen = BitConverter.ToUInt16(blockData, (int)(offset + 6));
+ // Read the fixed header fields manually since entries are variable-length on disk
+ uint inoNum = BitConverter.ToUInt32(blockData, (int)offset);
+ ushort recLen = BitConverter.ToUInt16(blockData, (int)(offset + 4));
+ ushort nameLen = BitConverter.ToUInt16(blockData, (int)(offset + 6));
// Validate record length (from Linux kernel validation)
// rec_len must be at least 8 and be a multiple of 8
@@ -289,9 +286,9 @@ public sealed partial class extFS
if(inoNum != 0 && nameLen > 0)
{
- // Extract filename
+ // Extract filename (starts at offset + 8)
var nameBytes = new byte[nameLen];
- Array.Copy(blockData, offset + 8, nameBytes, 0, nameLen);
+ Array.Copy(blockData, (int)(offset + 8), nameBytes, 0, nameLen);
string filename = StringHandlers.CToString(nameBytes, _encoding);
// Skip "." and ".." entries
diff --git a/Aaru.Filesystems/extFS/Inode.cs b/Aaru.Filesystems/extFS/Inode.cs
index d647708d2..36e9add67 100644
--- a/Aaru.Filesystems/extFS/Inode.cs
+++ b/Aaru.Filesystems/extFS/Inode.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
using System.Linq;
using Aaru.CommonTypes.Enums;
using Aaru.Logging;
+using Marshal = Aaru.Helpers.Marshal;
namespace Aaru.Filesystems;
@@ -39,13 +40,10 @@ namespace Aaru.Filesystems;
public sealed partial class extFS
{
/// ext inode size in bytes
- const int EXT_INODE_SIZE = 32;
-
- /// ext block size (always 1024)
- const int EXT_BLOCK_SIZE = 1024;
+ static readonly int EXT_INODE_SIZE = Marshal.SizeOf();
/// Number of inodes per block
- const int EXT_INODES_PER_BLOCK = EXT_BLOCK_SIZE / EXT_INODE_SIZE;
+ static readonly int EXT_INODES_PER_BLOCK = (int)EXT_BLOCK_SIZE / EXT_INODE_SIZE;
/// Reads an inode from disk
/// The inode number to read
@@ -65,7 +63,7 @@ public sealed partial class extFS
// Calculate the block containing this inode
// Inode table starts at block 2 (after boot block and superblock)
// From Linux kernel: block = 2 + (ino-1) / EXT_INODES_PER_BLOCK
- uint inodeBlock = 2 + (inodeNumber - 1) / EXT_INODES_PER_BLOCK;
+ uint inodeBlock = (uint)(2 + (inodeNumber - 1) / EXT_INODES_PER_BLOCK);
AaruLogging.Debug(MODULE_NAME,
"Reading inode {0} from block {1} (inodes per block: {2})",
@@ -84,24 +82,12 @@ public sealed partial class extFS
}
// Calculate offset within the block
- uint inodeOffset = (inodeNumber - 1) % EXT_INODES_PER_BLOCK * EXT_INODE_SIZE;
+ int inodeOffset = (int)((inodeNumber - 1) % (uint)EXT_INODES_PER_BLOCK) * EXT_INODE_SIZE;
AaruLogging.Debug(MODULE_NAME, "Inode offset within block: {0}", inodeOffset);
- // Parse the inode structure
- inode = new ext_inode
- {
- i_mode = BitConverter.ToUInt16(blockData, (int)inodeOffset),
- i_uid = BitConverter.ToUInt16(blockData, (int)(inodeOffset + 2)),
- i_size = BitConverter.ToUInt32(blockData, (int)(inodeOffset + 4)),
- i_time = BitConverter.ToUInt32(blockData, (int)(inodeOffset + 8)),
- i_gid = BitConverter.ToUInt16(blockData, (int)(inodeOffset + 12)),
- i_nlinks = BitConverter.ToUInt16(blockData, (int)(inodeOffset + 14)),
- i_zone = new uint[12]
- };
-
- // Read zone pointers (12 x 4 bytes = 48 bytes starting at offset 16)
- for(var i = 0; i < 12; i++) inode.i_zone[i] = BitConverter.ToUInt32(blockData, (int)(inodeOffset + 16 + i * 4));
+ // Parse the inode structure using marshalling
+ inode = Marshal.ByteArrayToStructureLittleEndian(blockData, inodeOffset, EXT_INODE_SIZE);
AaruLogging.Debug(MODULE_NAME,
"Inode {0}: mode=0x{1:X4}, size={2}, nlinks={3}",
diff --git a/Aaru.Filesystems/extFS/Structs.cs b/Aaru.Filesystems/extFS/Structs.cs
index 200a9ac00..eac43b03b 100644
--- a/Aaru.Filesystems/extFS/Structs.cs
+++ b/Aaru.Filesystems/extFS/Structs.cs
@@ -108,8 +108,9 @@ public sealed partial class extFS
public uint next;
}
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ext_dir_entry {
- public uint inode;
+ public uint inode;
public ushort rec_len;
public ushort name_len;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EXT_NAME_LEN)]