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: