mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Corrected detection and reading of misaligned partitions on
optical media (e.g. map says sector 17 on 512 byte units, that would fall on sector 4.25 on 2048 units).
This commit is contained in:
@@ -81,25 +81,17 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
if(imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448 || imagePlugin.GetSectorSize() == 2048)
|
||||
{
|
||||
mdb_sector = imagePlugin.ReadSector(2 + partition.Start);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
|
||||
mdb_sector = imagePlugin.ReadSectors(partition.Start, 2);
|
||||
|
||||
foreach(int offset in new[] { 0, 0x200, 0x400, 0x600, 0x800, 0xA00 })
|
||||
{
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, offset);
|
||||
if(drSigWord == HFS_MAGIC)
|
||||
{
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0x7C); // Seek to embedded HFS+ signature
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, offset + 0x7C); // Seek to embedded HFS+ signature
|
||||
|
||||
return drSigWord != HFSP_MAGIC;
|
||||
}
|
||||
mdb_sector = Read2048SectorAs512(imagePlugin, 2 + partition.Start * 4);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
|
||||
|
||||
if(drSigWord == HFS_MAGIC)
|
||||
{
|
||||
DicConsole.DebugWriteLine("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
|
||||
@@ -126,37 +118,35 @@ namespace DiscImageChef.Filesystems
|
||||
HFS_MasterDirectoryBlock MDB = new HFS_MasterDirectoryBlock();
|
||||
HFS_BootBlock BB = new HFS_BootBlock();
|
||||
|
||||
byte[] pString;
|
||||
|
||||
byte[] bb_sector;
|
||||
byte[] mdb_sector;
|
||||
byte[] bb_sector = null;
|
||||
byte[] mdb_sector = null;
|
||||
ushort drSigWord;
|
||||
|
||||
bool APMFromHDDOnCD = false;
|
||||
|
||||
// TODO: I don't like this, I can do better
|
||||
if(imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448 || imagePlugin.GetSectorSize() == 2048)
|
||||
{
|
||||
mdb_sector = imagePlugin.ReadSector(2 + partition.Start);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
|
||||
byte[] tmp_sector = imagePlugin.ReadSectors(partition.Start, 2);
|
||||
|
||||
foreach(int offset in new[] { 0, 0x200, 0x400, 0x600, 0x800, 0xA00 })
|
||||
{
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(tmp_sector, offset);
|
||||
if(drSigWord == HFS_MAGIC)
|
||||
{
|
||||
bb_sector = imagePlugin.ReadSector(partition.Start);
|
||||
}
|
||||
else
|
||||
{
|
||||
mdb_sector = Read2048SectorAs512(imagePlugin, 2 + partition.Start * 4);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(mdb_sector, 0);
|
||||
|
||||
if(drSigWord == HFS_MAGIC)
|
||||
{
|
||||
bb_sector = Read2048SectorAs512(imagePlugin, partition.Start * 4);
|
||||
bb_sector = new byte[1024];
|
||||
mdb_sector = new byte[512];
|
||||
if(offset >= 0x400)
|
||||
Array.Copy(tmp_sector, offset - 0x400, bb_sector, 0, 1024);
|
||||
Array.Copy(tmp_sector, offset, mdb_sector, 0, 512);
|
||||
APMFromHDDOnCD = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
if(!APMFromHDDOnCD)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mdb_sector = imagePlugin.ReadSector(2 + partition.Start);
|
||||
@@ -174,7 +164,7 @@ namespace DiscImageChef.Filesystems
|
||||
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("HFS uses 512 bytes/sector while device 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();
|
||||
@@ -235,6 +225,7 @@ namespace DiscImageChef.Filesystems
|
||||
sb.AppendFormat("CNID of previously opened directory: {0}", MDB.drFndrInfo2).AppendLine();
|
||||
sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", MDB.drFndrInfo3).AppendLine();
|
||||
sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", MDB.drFndrInfo5).AppendLine();
|
||||
if(MDB.drFndrInfo6 != 0 && MDB.drFndrInfo7 != 0)
|
||||
sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", MDB.drFndrInfo6, MDB.drFndrInfo7).AppendLine();
|
||||
|
||||
if(MDB.drEmbedSigWord == HFSP_MAGIC)
|
||||
|
||||
@@ -35,6 +35,7 @@ using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using DiscImageChef.CommonTypes;
|
||||
using DiscImageChef.Console;
|
||||
|
||||
namespace DiscImageChef.Filesystems
|
||||
{
|
||||
@@ -82,23 +83,27 @@ namespace DiscImageChef.Filesystems
|
||||
byte[] vh_sector;
|
||||
ulong hfsp_offset;
|
||||
|
||||
vh_sector = imagePlugin.ReadSector(2 + partition.Start); // Read volume header, of HFS Wrapper MDB
|
||||
uint sectorsToRead = 0x800 / imagePlugin.ImageInfo.sectorSize;
|
||||
if(0x800 % imagePlugin.ImageInfo.sectorSize > 0)
|
||||
sectorsToRead++;
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0); // Check for HFS Wrapper MDB
|
||||
vh_sector = imagePlugin.ReadSectors(partition.Start, sectorsToRead); // Read volume header, of HFS Wrapper MDB
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x400); // Check for HFS Wrapper MDB
|
||||
|
||||
if(drSigWord == HFS_MAGIC) // "BD"
|
||||
{
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x07C); // Read embedded HFS+ signature
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x47C); // Read embedded HFS+ signature
|
||||
|
||||
if(drSigWord == HFSP_MAGIC) // "H+"
|
||||
{
|
||||
xdrStABNt = BigEndianBitConverter.ToUInt16(vh_sector, 0x07E); // Starting block number of embedded HFS+ volume
|
||||
xdrStABNt = BigEndianBitConverter.ToUInt16(vh_sector, 0x47E); // Starting block number of embedded HFS+ volume
|
||||
|
||||
drAlBlkSiz = BigEndianBitConverter.ToUInt32(vh_sector, 0x014); // Block size
|
||||
drAlBlkSiz = BigEndianBitConverter.ToUInt32(vh_sector, 0x414); // Block size
|
||||
|
||||
drAlBlSt = BigEndianBitConverter.ToUInt16(vh_sector, 0x01C); // Start of allocated blocks (in 512-byte/block)
|
||||
drAlBlSt = BigEndianBitConverter.ToUInt16(vh_sector, 0x41C); // Start of allocated blocks (in 512-byte/block)
|
||||
|
||||
hfsp_offset = (drAlBlSt + xdrStABNt * (drAlBlkSiz / 512)) * (imagePlugin.GetSectorSize() / 512);
|
||||
hfsp_offset = (ulong)(((drAlBlSt * 512) + (xdrStABNt * drAlBlkSiz)) / imagePlugin.GetSectorSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -110,9 +115,9 @@ namespace DiscImageChef.Filesystems
|
||||
hfsp_offset = 0;
|
||||
}
|
||||
|
||||
vh_sector = imagePlugin.ReadSector(2 + partition.Start + hfsp_offset); // Read volume header
|
||||
vh_sector = imagePlugin.ReadSectors(partition.Start + hfsp_offset, sectorsToRead); // Read volume header
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0);
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x400);
|
||||
if(drSigWord == HFSP_MAGIC || drSigWord == HFSX_MAGIC)
|
||||
return true;
|
||||
return false;
|
||||
@@ -132,23 +137,27 @@ namespace DiscImageChef.Filesystems
|
||||
bool wrapped;
|
||||
byte[] vh_sector;
|
||||
|
||||
vh_sector = imagePlugin.ReadSector(2 + partition.Start); // Read volume header, of HFS Wrapper MDB
|
||||
uint sectorsToRead = 0x800 / imagePlugin.ImageInfo.sectorSize;
|
||||
if(0x800 % imagePlugin.ImageInfo.sectorSize > 0)
|
||||
sectorsToRead++;
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0); // Check for HFS Wrapper MDB
|
||||
vh_sector = imagePlugin.ReadSectors(partition.Start, sectorsToRead); // Read volume header, of HFS Wrapper MDB
|
||||
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x400); // Check for HFS Wrapper MDB
|
||||
|
||||
if(drSigWord == HFS_MAGIC) // "BD"
|
||||
{
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x07C); // Read embedded HFS+ signature
|
||||
drSigWord = BigEndianBitConverter.ToUInt16(vh_sector, 0x47C); // Read embedded HFS+ signature
|
||||
|
||||
if(drSigWord == HFSP_MAGIC) // "H+"
|
||||
{
|
||||
xdrStABNt = BigEndianBitConverter.ToUInt16(vh_sector, 0x07E); // Starting block number of embedded HFS+ volume
|
||||
xdrStABNt = BigEndianBitConverter.ToUInt16(vh_sector, 0x47E); // Starting block number of embedded HFS+ volume
|
||||
|
||||
drAlBlkSiz = BigEndianBitConverter.ToUInt32(vh_sector, 0x014); // Block size
|
||||
drAlBlkSiz = BigEndianBitConverter.ToUInt32(vh_sector, 0x414); // Block size
|
||||
|
||||
drAlBlSt = BigEndianBitConverter.ToUInt16(vh_sector, 0x01C); // Start of allocated blocks (in 512-byte/block)
|
||||
drAlBlSt = BigEndianBitConverter.ToUInt16(vh_sector, 0x41C); // Start of allocated blocks (in 512-byte/block)
|
||||
|
||||
hfsp_offset = (drAlBlSt + xdrStABNt * (drAlBlkSiz / 512)) * (imagePlugin.GetSectorSize() / 512);
|
||||
hfsp_offset = (ulong)(((drAlBlSt * 512) + (xdrStABNt * drAlBlkSiz)) / imagePlugin.GetSectorSize());
|
||||
wrapped = true;
|
||||
}
|
||||
else
|
||||
@@ -163,9 +172,9 @@ namespace DiscImageChef.Filesystems
|
||||
wrapped = false;
|
||||
}
|
||||
|
||||
vh_sector = imagePlugin.ReadSector(2 + partition.Start + hfsp_offset); // Read volume header
|
||||
vh_sector = imagePlugin.ReadSectors(partition.Start + hfsp_offset, sectorsToRead); // Read volume header
|
||||
|
||||
HPVH.signature = BigEndianBitConverter.ToUInt16(vh_sector, 0x000);
|
||||
HPVH.signature = BigEndianBitConverter.ToUInt16(vh_sector, 0x400);
|
||||
if(HPVH.signature == HFSP_MAGIC || HPVH.signature == HFSX_MAGIC)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -177,6 +186,10 @@ namespace DiscImageChef.Filesystems
|
||||
if(wrapped)
|
||||
sb.AppendLine("Volume is wrapped inside an HFS volume.");
|
||||
|
||||
byte[] tmp = new byte[0x400];
|
||||
Array.Copy(vh_sector, 0x400, tmp, 0, 0x400);
|
||||
vh_sector = tmp;
|
||||
|
||||
HPVH = BigEndianMarshal.ByteArrayToStructureBigEndian<HFSPlusVolumeHeader>(vh_sector);
|
||||
|
||||
if(HPVH.version == 4 || HPVH.version == 5)
|
||||
|
||||
@@ -101,6 +101,25 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
// Blocks 0 and 1 are boot code
|
||||
byte[] rootDirectoryKeyBlock = imagePlugin.ReadSector(2 + partition.Start);
|
||||
bool APMFromHDDOnCD = false;
|
||||
|
||||
if(imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448 || imagePlugin.GetSectorSize() == 2048)
|
||||
{
|
||||
byte[] tmp = imagePlugin.ReadSectors(partition.Start, 2);
|
||||
|
||||
foreach(int offset in new[] { 0, 0x200, 0x400, 0x600, 0x800, 0xA00 })
|
||||
{
|
||||
if(BitConverter.ToUInt16(tmp, offset) == 0 &&
|
||||
(byte)((tmp[offset + 0x04] & ProDOSStorageTypeMask) >> 4) == RootDirectoryType &&
|
||||
tmp[offset + 0x23] == ProDOSEntryLength &&
|
||||
tmp[offset + 0x24] == ProDOSEntriesPerBlock)
|
||||
{
|
||||
Array.Copy(tmp, offset, rootDirectoryKeyBlock, 0, 0x200);
|
||||
APMFromHDDOnCD = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ushort prePointer = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0);
|
||||
DicConsole.DebugWriteLine("ProDOS plugin", "prePointer = {0}", prePointer);
|
||||
@@ -128,6 +147,9 @@ namespace DiscImageChef.Filesystems
|
||||
return false;
|
||||
|
||||
ushort total_blocks = BitConverter.ToUInt16(rootDirectoryKeyBlock, 0x29);
|
||||
if(APMFromHDDOnCD)
|
||||
total_blocks /= 4;
|
||||
|
||||
DicConsole.DebugWriteLine("ProDOS plugin", "{0} <= ({1} - {2} + 1)? {3}", total_blocks, partition.End, partition.Start, total_blocks <= (partition.End - partition.Start + 1));
|
||||
return total_blocks <= (partition.End - partition.Start + 1);
|
||||
}
|
||||
@@ -139,6 +161,26 @@ namespace DiscImageChef.Filesystems
|
||||
// Blocks 0 and 1 are boot code
|
||||
byte[] rootDirectoryKeyBlockBytes = imagePlugin.ReadSector(2 + partition.Start);
|
||||
|
||||
bool APMFromHDDOnCD = false;
|
||||
|
||||
if(imagePlugin.GetSectorSize() == 2352 || imagePlugin.GetSectorSize() == 2448 || imagePlugin.GetSectorSize() == 2048)
|
||||
{
|
||||
byte[] tmp = imagePlugin.ReadSectors(partition.Start, 2);
|
||||
|
||||
foreach(int offset in new[] { 0, 0x200, 0x400, 0x600, 0x800, 0xA00 })
|
||||
{
|
||||
if(BitConverter.ToUInt16(tmp, offset) == 0 &&
|
||||
(byte)((tmp[offset + 0x04] & ProDOSStorageTypeMask) >> 4) == RootDirectoryType &&
|
||||
tmp[offset + 0x23] == ProDOSEntryLength &&
|
||||
tmp[offset + 0x24] == ProDOSEntriesPerBlock)
|
||||
{
|
||||
Array.Copy(tmp, offset, rootDirectoryKeyBlockBytes, 0, 0x200);
|
||||
APMFromHDDOnCD = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProDOSRootDirectoryKeyBlock rootDirectoryKeyBlock = new ProDOSRootDirectoryKeyBlock();
|
||||
rootDirectoryKeyBlock.header = new ProDOSRootDirectoryHeader();
|
||||
|
||||
@@ -158,6 +200,10 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
temp_timestamp_left = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1C);
|
||||
temp_timestamp_right = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x1E);
|
||||
|
||||
bool dateCorrect;
|
||||
try
|
||||
{
|
||||
temp_timestamp = (uint)((temp_timestamp_left << 16) + temp_timestamp_right);
|
||||
year = (int)((temp_timestamp & ProDOSYearMask) >> 25);
|
||||
month = (int)((temp_timestamp & ProDOSMonthMask) >> 21);
|
||||
@@ -174,6 +220,12 @@ namespace DiscImageChef.Filesystems
|
||||
DicConsole.DebugWriteLine("ProDOS plugin", "Datetime field year {0}, month {1}, day {2}, hour {3}, minute {4}.", year, month, day, hour, minute);
|
||||
|
||||
rootDirectoryKeyBlock.header.creation_time = new DateTime(year, month, day, hour, minute, 0);
|
||||
dateCorrect = true;
|
||||
}
|
||||
catch(ArgumentOutOfRangeException)
|
||||
{
|
||||
dateCorrect = false;
|
||||
}
|
||||
|
||||
rootDirectoryKeyBlock.header.version = rootDirectoryKeyBlockBytes[0x20];
|
||||
rootDirectoryKeyBlock.header.min_version = rootDirectoryKeyBlockBytes[0x21];
|
||||
@@ -185,6 +237,9 @@ namespace DiscImageChef.Filesystems
|
||||
rootDirectoryKeyBlock.header.bit_map_pointer = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x27);
|
||||
rootDirectoryKeyBlock.header.total_blocks = BitConverter.ToUInt16(rootDirectoryKeyBlockBytes, 0x29);
|
||||
|
||||
if(APMFromHDDOnCD)
|
||||
sbInformation.AppendLine("ProDOS uses 512 bytes/sector while devices uses 2048 bytes/sector.").AppendLine();
|
||||
|
||||
if(rootDirectoryKeyBlock.header.version != ProDOSVersion1 || rootDirectoryKeyBlock.header.min_version != ProDOSVersion1)
|
||||
{
|
||||
sbInformation.AppendLine("Warning! Detected unknown ProDOS version ProDOS filesystem.");
|
||||
@@ -202,6 +257,7 @@ namespace DiscImageChef.Filesystems
|
||||
sbInformation.AppendFormat("Unknown ProDOS version with field {0} is at least required for reading this volume.", rootDirectoryKeyBlock.header.min_version).AppendLine();
|
||||
|
||||
sbInformation.AppendFormat("Volume name is {0}", rootDirectoryKeyBlock.header.volume_name).AppendLine();
|
||||
if(dateCorrect)
|
||||
sbInformation.AppendFormat("Volume created on {0}", rootDirectoryKeyBlock.header.creation_time).AppendLine();
|
||||
sbInformation.AppendFormat("{0} bytes per directory entry", rootDirectoryKeyBlock.header.entry_length).AppendLine();
|
||||
sbInformation.AppendFormat("{0} entries per directory block", rootDirectoryKeyBlock.header.entries_per_block).AppendLine();
|
||||
@@ -227,7 +283,7 @@ namespace DiscImageChef.Filesystems
|
||||
|
||||
xmlFSType = new Schemas.FileSystemType();
|
||||
xmlFSType.VolumeName = rootDirectoryKeyBlock.header.volume_name;
|
||||
if(year != 0 || month != 0 || day != 0 || hour != 0 || minute != 0)
|
||||
if(dateCorrect)
|
||||
{
|
||||
xmlFSType.CreationDate = rootDirectoryKeyBlock.header.creation_time;
|
||||
xmlFSType.CreationDateSpecified = true;
|
||||
|
||||
Reference in New Issue
Block a user