Workaround when HFS and Apple Partition Map where created on a

512 byte/sector device (like a HDD) but are present on a 2048
	byte/sector device (like a CD). Solves #1. HFS+ should not be
	affected (even if wrapped).
This commit is contained in:
2014-08-28 18:26:14 +01:00
parent 2f894c5461
commit 8c358a5084
2 changed files with 176 additions and 59 deletions

View File

@@ -96,34 +96,38 @@ namespace DiscImageChef.PartPlugins
first_sector = 1;
// Read first entry
byte[] APMEntry_sector = imagePlugin.ReadSector(first_sector);
APMEntry.signature = BigEndianBitConverter.ToUInt16(APMEntry_sector, 0x00);
APMEntry.reserved1 = BigEndianBitConverter.ToUInt16(APMEntry_sector, 0x02);
APMEntry.entries = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x04);
APMEntry.start = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x08);
APMEntry.sectors = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x0C);
cString = new byte[32];
Array.Copy(APMEntry_sector, 0x10, cString, 0, 32);
APMEntry.name = StringHandlers.CToString(cString);
cString = new byte[32];
Array.Copy(APMEntry_sector, 0x30, cString, 0, 32);
APMEntry.type = StringHandlers.CToString(cString);
APMEntry.first_data_block = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x50);
APMEntry.data_sectors = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x54);
APMEntry.status = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x58);
APMEntry.first_boot_block = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x5C);
APMEntry.boot_size = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x60);
APMEntry.load_address = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x64);
APMEntry.reserved2 = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x68);
APMEntry.entry_point = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x6C);
APMEntry.reserved3 = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x70);
APMEntry.checksum = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x74);
cString = new byte[16];
Array.Copy(APMEntry_sector, 0x78, cString, 0, 16);
APMEntry.processor = StringHandlers.CToString(cString);
byte[] APMEntry_sector;
bool APMFromHDDOnCD = false;
if (sector_size == 2048)
{
APMEntry_sector = Read2048SectorAs512(imagePlugin, first_sector);
APMEntry = DecodeAPMEntry(APMEntry_sector);
if (APMEntry.signature == APM_ENTRY || APMEntry.signature == APM_OLDENT)
{
sector_size = 512;
APMFromHDDOnCD = true;
if (MainClass.isDebug)
Console.WriteLine("DEBUG (Apple Partition Map Plugin): PM sector size is 512 bytes, but device's 2048");
}
else
{
APMEntry_sector = imagePlugin.ReadSector(first_sector);
APMEntry = DecodeAPMEntry(APMEntry_sector);
if (APMEntry.signature != APM_ENTRY && APMEntry.signature != APM_OLDENT)
return false;
}
}
else
{
APMEntry_sector = imagePlugin.ReadSector(first_sector);
APMEntry = DecodeAPMEntry(APMEntry_sector);
if (APMEntry.signature != APM_ENTRY && APMEntry.signature != APM_OLDENT)
return false;
}
if (APMEntry.entries <= 1)
return false;
@@ -133,31 +137,12 @@ namespace DiscImageChef.PartPlugins
for (ulong i = 0; i < apm_entries; i++) // For each partition
{
APMEntry = new AppleMapPartitionEntry();
if(APMFromHDDOnCD)
APMEntry_sector = Read2048SectorAs512(imagePlugin, first_sector + i);
else
APMEntry_sector = imagePlugin.ReadSector(first_sector + i);
APMEntry.signature = BigEndianBitConverter.ToUInt16(APMEntry_sector, 0x00);
APMEntry.reserved1 = BigEndianBitConverter.ToUInt16(APMEntry_sector, 0x02);
APMEntry.entries = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x04);
APMEntry.start = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x08);
APMEntry.sectors = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x0C);
cString = new byte[32];
Array.Copy(APMEntry_sector, 0x10, cString, 0, 32);
APMEntry.name = StringHandlers.CToString(cString);
cString = new byte[32];
Array.Copy(APMEntry_sector, 0x30, cString, 0, 32);
APMEntry.type = StringHandlers.CToString(cString);
APMEntry.first_data_block = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x50);
APMEntry.data_sectors = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x54);
APMEntry.status = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x58);
APMEntry.first_boot_block = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x5C);
APMEntry.boot_size = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x60);
APMEntry.load_address = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x64);
APMEntry.reserved2 = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x68);
APMEntry.entry_point = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x6C);
APMEntry.reserved3 = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x70);
APMEntry.checksum = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x74);
cString = new byte[16];
Array.Copy(APMEntry_sector, 0x78, cString, 0, 16);
APMEntry.processor = StringHandlers.CToString(cString);
APMEntry = DecodeAPMEntry(APMEntry_sector);
if (APMEntry.signature == APM_ENTRY || APMEntry.signature == APM_OLDENT) // It should have partition entry signature
{
@@ -209,6 +194,52 @@ namespace DiscImageChef.PartPlugins
return true;
}
byte[] Read2048SectorAs512(ImagePlugins.ImagePlugin imagePlugin, UInt64 LBA)
{
UInt64 LBA2k = LBA / 4;
int Remainder = (int)(LBA % 4);
byte[] buffer = imagePlugin.ReadSector(LBA2k);
byte[] sector = new byte[512];
Array.Copy(buffer, Remainder * 512, sector, 0, 512);
return sector;
}
AppleMapPartitionEntry DecodeAPMEntry(byte[] APMEntry_sector)
{
AppleMapPartitionEntry APMEntry = new AppleMapPartitionEntry();
byte[] cString;
APMEntry.signature = BigEndianBitConverter.ToUInt16(APMEntry_sector, 0x00);
APMEntry.reserved1 = BigEndianBitConverter.ToUInt16(APMEntry_sector, 0x02);
APMEntry.entries = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x04);
APMEntry.start = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x08);
APMEntry.sectors = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x0C);
cString = new byte[32];
Array.Copy(APMEntry_sector, 0x10, cString, 0, 32);
APMEntry.name = StringHandlers.CToString(cString);
cString = new byte[32];
Array.Copy(APMEntry_sector, 0x30, cString, 0, 32);
APMEntry.type = StringHandlers.CToString(cString);
APMEntry.first_data_block = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x50);
APMEntry.data_sectors = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x54);
APMEntry.status = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x58);
APMEntry.first_boot_block = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x5C);
APMEntry.boot_size = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x60);
APMEntry.load_address = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x64);
APMEntry.reserved2 = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x68);
APMEntry.entry_point = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x6C);
APMEntry.reserved3 = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x70);
APMEntry.checksum = BigEndianBitConverter.ToUInt32(APMEntry_sector, 0x74);
cString = new byte[16];
Array.Copy(APMEntry_sector, 0x78, cString, 0, 16);
APMEntry.processor = StringHandlers.CToString(cString);
return APMEntry;
}
public struct AppleMapBootEntry
{
// Signature ("ER")

View File

@@ -63,8 +63,13 @@ namespace DiscImageChef.Plugins
if ((2 + partitionOffset) >= imagePlugin.GetSectors())
return false;
byte[] mdb_sector = imagePlugin.ReadSector(2 + partitionOffset);
UInt16 drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
byte[] mdb_sector;
UInt16 drSigWord;
if (imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448 || imagePlugin.GetSectorSize() == 2048)
{
mdb_sector = imagePlugin.ReadSector(2 + partitionOffset);
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
if (drSigWord == HFS_MAGIC)
{
@@ -72,6 +77,34 @@ namespace DiscImageChef.Plugins
return drSigWord != HFSP_MAGIC;
}
else
{
mdb_sector = Read2048SectorAs512(imagePlugin, 2 + partitionOffset);
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
if (drSigWord == HFS_MAGIC)
{
if(MainClass.isDebug)
Console.WriteLine("DEBUG (HFS Plugin): HFS sector size is 512 bytes, but device's 2048");
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x7C); // Seek to embedded HFS+ signature
return drSigWord != HFSP_MAGIC;
}
}
}
else
{
mdb_sector = imagePlugin.ReadSector(2 + partitionOffset);
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
if (drSigWord == HFS_MAGIC)
{
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x7C); // Seek to embedded HFS+ signature
return drSigWord != HFSP_MAGIC;
}
}
return false;
}
@@ -86,8 +119,46 @@ namespace DiscImageChef.Plugins
byte[] pString;
byte[] bb_sector = imagePlugin.ReadSector(partitionOffset); // BB's first sector
byte[] mdb_sector = imagePlugin.ReadSector(2 + partitionOffset); // MDB sector
byte[] bb_sector;
byte[] mdb_sector;
UInt16 drSigWord;
bool APMFromHDDOnCD = false;
if (imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448 || imagePlugin.GetSectorSize() == 2048)
{
mdb_sector = imagePlugin.ReadSector(2 + partitionOffset);
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
if (drSigWord == HFS_MAGIC)
{
bb_sector = imagePlugin.ReadSector(partitionOffset);
}
else
{
mdb_sector = Read2048SectorAs512(imagePlugin, 2 + partitionOffset);
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
if (drSigWord == HFS_MAGIC)
{
bb_sector = Read2048SectorAs512(imagePlugin, partitionOffset);
APMFromHDDOnCD = true;
}
else
return;
}
}
else
{
mdb_sector = imagePlugin.ReadSector(2 + partitionOffset);
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
if (drSigWord == HFS_MAGIC)
bb_sector = imagePlugin.ReadSector(partitionOffset);
else
return;
}
MDB.drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x000);
if (MDB.drSigWord != HFS_MAGIC)
return;
@@ -181,6 +252,8 @@ namespace DiscImageChef.Plugins
sb.AppendLine("Apple Hierarchical File System");
sb.AppendLine();
if (APMFromHDDOnCD)
sb.AppendLine("HFS uses 512 bytes/sector while devices uses 2048 bytes/sector.").AppendLine();
sb.AppendLine("Master Directory Block:");
sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(MDB.drCrDate)).AppendLine();
sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(MDB.drLsMod)).AppendLine();
@@ -291,6 +364,19 @@ namespace DiscImageChef.Plugins
return;
}
byte[] Read2048SectorAs512(ImagePlugins.ImagePlugin imagePlugin, UInt64 LBA)
{
UInt64 LBA2k = LBA / 4;
int Remainder = (int)(LBA % 4);
byte[] buffer = imagePlugin.ReadSector(LBA2k);
byte[] sector = new byte[512];
Array.Copy(buffer, Remainder * 512, sector, 0, 512);
return sector;
}
struct HFS_MasterDirectoryBlock // Should be sector 2 in volume
{
public UInt16 drSigWord;