diff --git a/DiscImageChef.Filesystems/FATX/Consts.cs b/DiscImageChef.Filesystems/FATX/Consts.cs index 7469cd8e1..eea4fcbd9 100644 --- a/DiscImageChef.Filesystems/FATX/Consts.cs +++ b/DiscImageChef.Filesystems/FATX/Consts.cs @@ -40,11 +40,20 @@ namespace DiscImageChef.Filesystems.FATX const uint FATX_CIGAM = 0x46415458; const byte UNUSED_DIRENTRY = 0x00; const byte DELETED_DIRENTRY = 0xE5; + const byte FINISHED_DIRENTRY = 0xFF; const byte MAX_FILENAME = 42; const int MAX_XFAT16_CLUSTERS = 65525; const int FAT_START = 4096; const uint FATX32_ID = 0xFFFFFFF8; const ushort FATX16_ID = 0xFFF8; + const uint FAT32_MASK = 0x0FFFFFFF; + const uint FAT32_END_MASK = 0xFFFFFF8; + const uint FAT32_FORMATTED = 0xFFFFFF6; + const uint FAT32_BAD = 0xFFFFFF7; + const ushort FAT16_END_MASK = 0xFFF8; + const ushort FAT16_FORMATTED = 0xFFF6; + const ushort FAT16_BAD = 0xFFF7; + const ushort FAT_RESERVED = 1; [Flags] enum Attributes : byte diff --git a/DiscImageChef.Filesystems/FATX/FATX.cs b/DiscImageChef.Filesystems/FATX/FATX.cs index f22a35934..f01c0057a 100644 --- a/DiscImageChef.Filesystems/FATX/FATX.cs +++ b/DiscImageChef.Filesystems/FATX/FATX.cs @@ -42,16 +42,18 @@ namespace DiscImageChef.Filesystems.FATX { public partial class XboxFatPlugin : IReadOnlyFilesystem { - ushort[] fat16; - uint[] fat32; - ulong fatStartSector; - ulong firstClusterSector; - IMediaImage imagePlugin; - bool littleEndian; - bool mounted; - Partition partition; - uint sectorsPerCluster; - FileSystemInfo stat; + uint bytesPerCluster; + ushort[] fat16; + uint[] fat32; + ulong fatStartSector; + ulong firstClusterSector; + IMediaImage imagePlugin; + bool littleEndian; + bool mounted; + Partition partition; + Dictionary rootDirectory; + uint sectorsPerCluster; + FileSystemInfo stat; Superblock superblock; public FileSystemType XmlFsType { get; private set; } diff --git a/DiscImageChef.Filesystems/FATX/File.cs b/DiscImageChef.Filesystems/FATX/File.cs index d50c59481..66a2fc512 100644 --- a/DiscImageChef.Filesystems/FATX/File.cs +++ b/DiscImageChef.Filesystems/FATX/File.cs @@ -31,6 +31,7 @@ // ****************************************************************************/ using System; +using System.Collections.Generic; using DiscImageChef.CommonTypes.Structs; namespace DiscImageChef.Filesystems.FATX @@ -67,5 +68,35 @@ namespace DiscImageChef.Filesystems.FATX throw new NotImplementedException(); } + + uint[] GetClusters(uint startCluster) + { + if(startCluster == 0) return null; + + if(fat16 is null) + { + if(startCluster >= fat32.Length) return null; + } + else if(startCluster >= fat16.Length) return null; + + List clusters = new List(); + + uint nextCluster = startCluster; + + if(fat16 is null) + while((nextCluster & FAT32_MASK) > 0 && (nextCluster & FAT32_MASK) <= FAT32_BAD) + { + clusters.Add(nextCluster); + nextCluster = fat32[nextCluster]; + } + else + while(nextCluster > 0 && nextCluster <= FAT16_BAD) + { + clusters.Add(nextCluster); + nextCluster = fat16[nextCluster]; + } + + return clusters.ToArray(); + } } } \ No newline at end of file diff --git a/DiscImageChef.Filesystems/FATX/Super.cs b/DiscImageChef.Filesystems/FATX/Super.cs index 9959aa8ec..6d01a1bac 100644 --- a/DiscImageChef.Filesystems/FATX/Super.cs +++ b/DiscImageChef.Filesystems/FATX/Super.cs @@ -159,11 +159,55 @@ namespace DiscImageChef.Filesystems.FATX this.partition = partition; this.imagePlugin = imagePlugin; firstClusterSector = fatStartSector + fatSize; + bytesPerCluster = sectorsPerCluster * imagePlugin.Info.SectorSize; DicConsole.DebugWriteLine("Xbox FAT plugin", "sectorsPerCluster = {0}", sectorsPerCluster); + DicConsole.DebugWriteLine("Xbox FAT plugin", "bytesPerCluster = {0}", bytesPerCluster); DicConsole.DebugWriteLine("Xbox FAT plugin", "firstClusterSector = {0}", firstClusterSector); - throw new NotImplementedException(); + uint[] rootDirectoryClusters = GetClusters(superblock.rootDirectoryCluster); + + if(rootDirectoryClusters is null) return Errno.InvalidArgument; + + byte[] rootDirectoryBuffer = new byte[bytesPerCluster * rootDirectoryClusters.Length]; + + DicConsole.DebugWriteLine("Xbox FAT plugin", "Reading root directory"); + for(int i = 0; i < rootDirectoryClusters.Length; i++) + { + buffer = + imagePlugin.ReadSectors(firstClusterSector + (rootDirectoryClusters[i] - 1) * sectorsPerCluster, + sectorsPerCluster); + Array.Copy(buffer, 0, rootDirectoryBuffer, i * bytesPerCluster, bytesPerCluster); + } + + rootDirectory = new Dictionary(); + + int pos = 0; + while(pos < rootDirectoryBuffer.Length) + { + DirectoryEntry entry = littleEndian + ? Marshal + .ByteArrayToStructureLittleEndian(rootDirectoryBuffer, pos, Marshal.SizeOf()) + : Marshal.ByteArrayToStructureBigEndian(rootDirectoryBuffer, + pos, + Marshal + .SizeOf< + DirectoryEntry + >()); + + pos += Marshal.SizeOf(); + + if(entry.filenameSize == UNUSED_DIRENTRY || entry.filenameSize == FINISHED_DIRENTRY) break; + + if(entry.filenameSize == DELETED_DIRENTRY || entry.filenameSize > MAX_FILENAME) continue; + + string filename = Encoding.GetString(entry.filename, 0, entry.filenameSize); + + rootDirectory.Add(filename, entry); + } + + return Errno.NoError; } public Errno Unmount()