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)]