diff --git a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj index cd0461a9..57ef2b4a 100644 --- a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj +++ b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj @@ -114,6 +114,7 @@ + diff --git a/DiscImageChef.Filesystems/FATX.cs b/DiscImageChef.Filesystems/FATX.cs index 7d40a485..f7da0766 100644 --- a/DiscImageChef.Filesystems/FATX.cs +++ b/DiscImageChef.Filesystems/FATX.cs @@ -9,7 +9,7 @@ // // --[ Description ] ---------------------------------------------------------- // -// Description +// Identifies the FATX filesystem and shows information. // // --[ License ] -------------------------------------------------------------- // @@ -29,14 +29,140 @@ // ---------------------------------------------------------------------------- // Copyright © 2011-2016 Natalia Portillo // ****************************************************************************/ + using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + namespace DiscImageChef.Filesystems { - public class FATX + class FATX : Filesystem { + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct FATX_Superblock + { + public uint magic; + public uint id; + public uint sectorsPerCluster; + public uint rootDirectoryCluster; + } + + const uint FATX_Magic = 0x58544146; + public FATX() { + Name = "FATX Filesystem Plugin"; + PluginUUID = new Guid("ED27A721-4A17-4649-89FD-33633B46E228"); + } + + public FATX(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + Name = "FATX Filesystem Plugin"; + PluginUUID = new Guid("ED27A721-4A17-4649-89FD-33633B46E228"); + } + + public override bool Identify(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd) + { + if(imagePlugin.GetSectorSize() < 512) + return false; + + FATX_Superblock fatxSb = new FATX_Superblock(); + byte[] sector = imagePlugin.ReadSector(partitionStart); + + fatxSb = BigEndianMarshal.ByteArrayToStructureBigEndian(sector); + + return fatxSb.magic == FATX_Magic; + } + + public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, ulong partitionStart, ulong partitionEnd, out string information) + { + information = ""; + if(imagePlugin.GetSectorSize() < 512) + return; + + FATX_Superblock fatxSb = new FATX_Superblock(); + + byte[] sector = imagePlugin.ReadSector(partitionStart); + + fatxSb = BigEndianMarshal.ByteArrayToStructureBigEndian(sector); + + if(fatxSb.magic != FATX_Magic) + return; + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("FATX filesystem"); + sb.AppendFormat("Filesystem id {0}", fatxSb.id).AppendLine(); + sb.AppendFormat("{0} sectors ({1} bytes) per cluster", fatxSb.sectorsPerCluster, fatxSb.sectorsPerCluster * imagePlugin.ImageInfo.sectorSize).AppendLine(); + sb.AppendFormat("Root directory starts on cluster {0}", fatxSb.rootDirectoryCluster).AppendLine(); + + information = sb.ToString(); + + xmlFSType = new Schemas.FileSystemType(); + xmlFSType.Type = "FATX filesystem"; + xmlFSType.ClusterSize = (int)(fatxSb.sectorsPerCluster * imagePlugin.ImageInfo.sectorSize); + xmlFSType.Clusters = (long)((partitionEnd - partitionStart + 1) * imagePlugin.ImageInfo.sectorSize / (ulong)xmlFSType.ClusterSize); + } + + public override Errno Mount() + { + return Errno.NotImplemented; + } + + public override Errno Mount(bool debug) + { + return Errno.NotImplemented; + } + + public override Errno Unmount() + { + return Errno.NotImplemented; + } + + public override Errno MapBlock(string path, long fileBlock, ref long deviceBlock) + { + return Errno.NotImplemented; + } + + public override Errno GetAttributes(string path, ref FileAttributes attributes) + { + return Errno.NotImplemented; + } + + public override Errno ListXAttr(string path, ref List xattrs) + { + return Errno.NotImplemented; + } + + public override Errno GetXattr(string path, string xattr, ref byte[] buf) + { + return Errno.NotImplemented; + } + + public override Errno Read(string path, long offset, long size, ref byte[] buf) + { + return Errno.NotImplemented; + } + + public override Errno ReadDir(string path, ref List contents) + { + return Errno.NotImplemented; + } + + public override Errno StatFs(ref FileSystemInfo stat) + { + return Errno.NotImplemented; + } + + public override Errno Stat(string path, ref FileEntryInfo stat) + { + return Errno.NotImplemented; + } + + public override Errno ReadLink(string path, ref string dest) + { + return Errno.NotImplemented; } } -} - +} \ No newline at end of file diff --git a/DiscImageChef.Partitions/DiscImageChef.Partitions.csproj b/DiscImageChef.Partitions/DiscImageChef.Partitions.csproj index 226d7801..efa09ce4 100644 --- a/DiscImageChef.Partitions/DiscImageChef.Partitions.csproj +++ b/DiscImageChef.Partitions/DiscImageChef.Partitions.csproj @@ -51,6 +51,7 @@ + diff --git a/DiscImageChef.Partitions/Xbox.cs b/DiscImageChef.Partitions/Xbox.cs index d0740e57..bfa2f3ad 100644 --- a/DiscImageChef.Partitions/Xbox.cs +++ b/DiscImageChef.Partitions/Xbox.cs @@ -5,11 +5,11 @@ // Filename : Xbox.cs // Author(s) : Natalia Portillo // -// Component : Component +// Component : Partitioning scheme plugins. // // --[ Description ] ---------------------------------------------------------- // -// Description +// Manages Xbox partitions. // // --[ License ] -------------------------------------------------------------- // @@ -29,14 +29,197 @@ // ---------------------------------------------------------------------------- // Copyright © 2011-2016 Natalia Portillo // ****************************************************************************/ + using System; -namespace DiscImageChef.Partitions +using System.Collections.Generic; +using System.Runtime.InteropServices; +using DiscImageChef.CommonTypes; +using DiscImageChef.ImagePlugins; + +namespace DiscImageChef.PartPlugins { - public class Xbox + class Xbox : PartPlugin { + const uint XboxCigam = 0x46415458; + const uint XboxMagic = 0x58544146; + const long MemoryUnitDataOff = 0x7FF000; + const long Xbox360SecuritySectorOff = 0x2000; + const long Xbox360SystemCacheOff = 0x80000; + const long Xbox360GameCacheOff = 0x8008000; + const long Xbox368SysExtOff = 0x10C080000; + const long Xbox360SysExt2Off = 0x118EB0000; + const long Xbox360CompatOff = 0x120EB0000; + const long Xbox360DataOff = 0x130EB0000; + + const long Xbox360SecuritySectorLen = 0x80000; + const long Xbox360SystemCacheLen = 0x80000000; + const long Xbox360GameCacheLen = 0xA0E30000; + const long Xbox368SysExtLen = 0xCE30000; + const long Xbox360SysExt2Len = 0x8000000; + const long Xbox360CompatLen = 0x10000000; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct Xbox360DevKitPartitionTable + { + public uint magic; + public uint unknown; + public uint contentOff; + public uint contentLen; + public uint dashboardOff; + public uint dashboardLen; + } + + const uint Xbox360DevKitMagic = 0x00020000; + public Xbox() { + Name = "Xbox partitioning"; + PluginUUID = new Guid("E3F6FB91-D358-4F22-A550-81E92D50EB78"); + } + + public override bool GetInformation(ImagePlugin imagePlugin, out List partitions) + { + partitions = new List(); + + byte[] sector = imagePlugin.ReadSector(0); + if(sector.Length < 512) + return false; + + Xbox360DevKitPartitionTable table = BigEndianMarshal.ByteArrayToStructureBigEndian(sector); + + if(table.magic == Xbox360DevKitMagic && table.contentOff + table.contentLen <= imagePlugin.ImageInfo.sectors && + table.dashboardOff + table.dashboardLen <= imagePlugin.ImageInfo.sectors) + { + Partition contentPart = new Partition(); + contentPart.PartitionDescription = "Content volume"; + contentPart.PartitionLength = (ulong)table.contentLen * (ulong)imagePlugin.ImageInfo.sectorSize; + contentPart.PartitionSectors = table.contentLen; + contentPart.PartitionSequence = 1; + contentPart.PartitionStart = (ulong)table.contentOff * (ulong)imagePlugin.ImageInfo.sectorSize; + contentPart.PartitionStartSector = table.contentOff; + + Partition dashboardPart = new Partition(); + dashboardPart.PartitionDescription = "Dashboard volume"; + dashboardPart.PartitionLength = (ulong)table.dashboardLen * (ulong)imagePlugin.ImageInfo.sectorSize; + dashboardPart.PartitionSectors = table.dashboardLen; + dashboardPart.PartitionSequence = 2; + dashboardPart.PartitionStart = (ulong)table.dashboardOff * (ulong)imagePlugin.ImageInfo.sectorSize; + dashboardPart.PartitionStartSector = table.dashboardOff; + + partitions.Add(contentPart); + partitions.Add(dashboardPart); + + return true; + } + + uint temp = 0; + + if(imagePlugin.ImageInfo.sectors > (ulong)(MemoryUnitDataOff / imagePlugin.ImageInfo.sectorSize)) + { + sector = imagePlugin.ReadSector((ulong)(MemoryUnitDataOff / imagePlugin.ImageInfo.sectorSize)); + temp = BitConverter.ToUInt32(sector, 0); + + if(temp == XboxCigam) + { + Partition sysCachePart = new Partition(); + sysCachePart.PartitionDescription = "System cache"; + sysCachePart.PartitionLength = MemoryUnitDataOff; + sysCachePart.PartitionSectors = (ulong)(MemoryUnitDataOff / imagePlugin.ImageInfo.sectorSize); + sysCachePart.PartitionSequence = 1; + sysCachePart.PartitionStart = 0; + sysCachePart.PartitionStartSector = 0; + + Partition dataPart = new Partition(); + dataPart.PartitionDescription = "Data volume"; + dataPart.PartitionLength = (ulong)imagePlugin.ImageInfo.sectors * (ulong)imagePlugin.ImageInfo.sectorSize - MemoryUnitDataOff; + dataPart.PartitionSectors = imagePlugin.ImageInfo.sectors - sysCachePart.PartitionSectors; + dataPart.PartitionSequence = 2; + dataPart.PartitionStart = MemoryUnitDataOff; + dataPart.PartitionStartSector = sysCachePart.PartitionSectors; + + partitions.Add(sysCachePart); + partitions.Add(dataPart); + + return true; + } + } + + if(imagePlugin.ImageInfo.sectors > (ulong)(Xbox360DataOff / imagePlugin.ImageInfo.sectorSize)) + { + sector = imagePlugin.ReadSector((ulong)(Xbox360DataOff / imagePlugin.ImageInfo.sectorSize)); + temp = BitConverter.ToUInt32(sector, 0); + + if(temp == XboxCigam) + { + Partition securityPart = new Partition(); + securityPart.PartitionDescription = "Security sectors"; + securityPart.PartitionLength = Xbox360SecuritySectorLen; + securityPart.PartitionSectors = (ulong)(Xbox360SecuritySectorLen / imagePlugin.ImageInfo.sectorSize); + securityPart.PartitionSequence = 1; + securityPart.PartitionStart = Xbox360SecuritySectorOff; + securityPart.PartitionStartSector = (ulong)(Xbox360SecuritySectorOff / imagePlugin.ImageInfo.sectorSize); + + Partition sysCachePart = new Partition(); + sysCachePart.PartitionDescription = "System cache"; + sysCachePart.PartitionLength = Xbox360SystemCacheLen; + sysCachePart.PartitionSectors = (ulong)(Xbox360SystemCacheLen / imagePlugin.ImageInfo.sectorSize); + sysCachePart.PartitionSequence = 2; + sysCachePart.PartitionStart = Xbox360SystemCacheOff; + sysCachePart.PartitionStartSector = (ulong)(Xbox360SystemCacheOff / imagePlugin.ImageInfo.sectorSize); + + Partition gameCachePart = new Partition(); + gameCachePart.PartitionDescription = "Game cache"; + gameCachePart.PartitionLength = Xbox360GameCacheLen; + gameCachePart.PartitionSectors = (ulong)(Xbox360GameCacheLen / imagePlugin.ImageInfo.sectorSize); + gameCachePart.PartitionSequence = 3; + gameCachePart.PartitionStart = Xbox360GameCacheOff; + gameCachePart.PartitionStartSector = (ulong)(Xbox360GameCacheOff / imagePlugin.ImageInfo.sectorSize); + + Partition sysExtPart = new Partition(); + sysExtPart.PartitionDescription = "System volume"; + sysExtPart.PartitionLength = Xbox368SysExtLen; + sysExtPart.PartitionSectors = (ulong)(Xbox368SysExtLen / imagePlugin.ImageInfo.sectorSize); + sysExtPart.PartitionSequence = 4; + sysExtPart.PartitionStart = Xbox368SysExtOff; + sysExtPart.PartitionStartSector = (ulong)(Xbox368SysExtOff / imagePlugin.ImageInfo.sectorSize); + + Partition sysExt2Part = new Partition(); + sysExt2Part.PartitionDescription = "System volume 2"; + sysExt2Part.PartitionLength = Xbox360SysExt2Len; + sysExt2Part.PartitionSectors = (ulong)(Xbox360SysExt2Len / imagePlugin.ImageInfo.sectorSize); + sysExt2Part.PartitionSequence = 5; + sysExt2Part.PartitionStart = Xbox360SysExt2Off; + sysExt2Part.PartitionStartSector = (ulong)(Xbox360SysExt2Off / imagePlugin.ImageInfo.sectorSize); + + Partition xbox1Part = new Partition(); + xbox1Part.PartitionDescription = "Xbox backwards compatibility"; + xbox1Part.PartitionLength = Xbox360CompatLen; + xbox1Part.PartitionSectors = (ulong)(Xbox360CompatLen / imagePlugin.ImageInfo.sectorSize); + xbox1Part.PartitionSequence = 6; + xbox1Part.PartitionStart = Xbox360CompatOff; + xbox1Part.PartitionStartSector = (ulong)(Xbox360CompatOff / imagePlugin.ImageInfo.sectorSize); + + Partition dataPart = new Partition(); + dataPart.PartitionDescription = "Data volume"; + dataPart.PartitionSequence = 7; + dataPart.PartitionStart = Xbox360DataOff; + dataPart.PartitionStartSector = (ulong)(Xbox360DataOff / imagePlugin.ImageInfo.sectorSize); + dataPart.PartitionSectors = imagePlugin.ImageInfo.sectors - dataPart.PartitionStartSector; + dataPart.PartitionLength = (ulong)dataPart.PartitionSectors * (ulong)imagePlugin.ImageInfo.sectorSize; + + partitions.Add(securityPart); + partitions.Add(sysCachePart); + partitions.Add(gameCachePart); + partitions.Add(sysExtPart); + partitions.Add(sysExt2Part); + partitions.Add(xbox1Part); + partitions.Add(dataPart); + + return true; + } + } + + return false; } } -} - +} \ No newline at end of file diff --git a/DiscImageChef/DiscImageChef.csproj b/DiscImageChef/DiscImageChef.csproj index 18593844..da2fa1f4 100644 --- a/DiscImageChef/DiscImageChef.csproj +++ b/DiscImageChef/DiscImageChef.csproj @@ -20,7 +20,8 @@ prompt 4 x86 - True + false + false none @@ -29,7 +30,8 @@ prompt 4 x86 - True + false + false diff --git a/README.md b/README.md index 7804724c..c35527be 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ Supported partitioning schemes * Rio Karma partitions * UNIX VTOC and disklabel * Human68k (Sharp X68000) partitions table +* Xbox 360 hard coded partitions Supported file systems for read-only operations =============================================== @@ -140,6 +141,7 @@ Supported file systems for identification and information only * Commodore 1540/1541/1571/1581 filesystems * Universal Disk Format (UDF) * ECMA-67: 130mm Flexible Disk Cartridge Labelling and File Structure for Information Interchange +* Xbox filesystems Supported checksums =================== diff --git a/TODO b/TODO index 8dd4fe10..4ba122df 100644 --- a/TODO +++ b/TODO @@ -12,7 +12,6 @@ Filesystem plugins: --- Add support for Apple DOS filesystems --- Add support for ZFS --- Add support for NwFS ---- Add support for X-Box filesystems --- Add support for ReFS Partitioning scheme plugins: