Fix structure naming in Apple filesystems.

This commit is contained in:
2020-02-19 03:44:44 +00:00
parent 5bbac37a21
commit aec893aeb5
10 changed files with 140 additions and 95 deletions

View File

@@ -145,7 +145,7 @@ namespace DiscImageChef.Filesystems
return;
}
HfsMasterDirectoryBlock mdb = Marshal.ByteArrayToStructureBigEndian<HfsMasterDirectoryBlock>(mdbSector);
MasterDirectoryBlock mdb = Marshal.ByteArrayToStructureBigEndian<MasterDirectoryBlock>(mdbSector);
sb.AppendLine("Apple Hierarchical File System");
sb.AppendLine();

View File

@@ -43,7 +43,7 @@ namespace DiscImageChef.Filesystems
{
/// <summary>Master Directory Block, should be sector 2 in volume</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct HfsMasterDirectoryBlock // Should be sector 2 in volume
struct MasterDirectoryBlock // Should be sector 2 in volume
{
/// <summary>0x000, Signature, 0x4244</summary>
public readonly ushort drSigWord;

View File

@@ -43,17 +43,11 @@ namespace DiscImageChef.Filesystems
// Information from Apple TechNote 1150: https://developer.apple.com/legacy/library/technotes/tn/tn1150.html
public class AppleHFSPlus : IFilesystem
{
/// <summary>
/// "BD", HFS magic
/// </summary>
/// <summary>"BD", HFS magic</summary>
const ushort HFS_MAGIC = 0x4244;
/// <summary>
/// "H+", HFS+ magic
/// </summary>
/// <summary>"H+", HFS+ magic</summary>
const ushort HFSP_MAGIC = 0x482B;
/// <summary>
/// "HX", HFSX magic
/// </summary>
/// <summary>"HX", HFSX magic</summary>
const ushort HFSX_MAGIC = 0x4858;
public FileSystemType XmlFsType { get; private set; }
@@ -64,12 +58,15 @@ namespace DiscImageChef.Filesystems
public bool Identify(IMediaImage imagePlugin, Partition partition)
{
if(2 + partition.Start >= partition.End) return false;
if(2 + partition.Start >= partition.End)
return false;
ulong hfspOffset;
uint sectorsToRead = 0x800 / imagePlugin.Info.SectorSize;
if(0x800 % imagePlugin.Info.SectorSize > 0) sectorsToRead++;
if(0x800 % imagePlugin.Info.SectorSize > 0)
sectorsToRead++;
byte[] vhSector = imagePlugin.ReadSectors(partition.Start, sectorsToRead);
@@ -87,31 +84,36 @@ namespace DiscImageChef.Filesystems
ushort drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C);
hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.Info.SectorSize);
hfspOffset = (ulong)(((drAlBlSt * 512) + (xdrStABNt * drAlBlkSiz)) / imagePlugin.Info.SectorSize);
}
else hfspOffset = 0;
else
hfspOffset = 0;
}
else hfspOffset = 0;
else
hfspOffset = 0;
vhSector = imagePlugin.ReadSectors(partition.Start + hfspOffset, sectorsToRead); // Read volume header
drSigWord = BigEndianBitConverter.ToUInt16(vhSector, 0x400);
return drSigWord == HFSP_MAGIC || drSigWord == HFSX_MAGIC;
}
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information,
Encoding encoding)
Encoding encoding)
{
Encoding = Encoding.BigEndianUnicode;
information = "";
HfsPlusVolumeHeader vh = new HfsPlusVolumeHeader();
var vh = new VolumeHeader();
ulong hfspOffset;
bool wrapped;
uint sectorsToRead = 0x800 / imagePlugin.Info.SectorSize;
if(0x800 % imagePlugin.Info.SectorSize > 0) sectorsToRead++;
if(0x800 % imagePlugin.Info.SectorSize > 0)
sectorsToRead++;
byte[] vhSector = imagePlugin.ReadSectors(partition.Start, sectorsToRead);
@@ -129,7 +131,7 @@ namespace DiscImageChef.Filesystems
ushort drAlBlSt = BigEndianBitConverter.ToUInt16(vhSector, 0x41C);
hfspOffset = (ulong)((drAlBlSt * 512 + xdrStABNt * drAlBlkSiz) / imagePlugin.Info.SectorSize);
hfspOffset = (ulong)(((drAlBlSt * 512) + (xdrStABNt * drAlBlkSiz)) / imagePlugin.Info.SectorSize);
wrapped = true;
}
else
@@ -148,45 +150,75 @@ namespace DiscImageChef.Filesystems
vh.signature = BigEndianBitConverter.ToUInt16(vhSector, 0x400);
if(vh.signature != HFSP_MAGIC && vh.signature != HFSX_MAGIC) return;
if(vh.signature != HFSP_MAGIC &&
vh.signature != HFSX_MAGIC)
return;
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
if(vh.signature == 0x482B) sb.AppendLine("HFS+ filesystem.");
if(vh.signature == 0x4858) sb.AppendLine("HFSX filesystem.");
if(wrapped) sb.AppendLine("Volume is wrapped inside an HFS volume.");
if(vh.signature == 0x482B)
sb.AppendLine("HFS+ filesystem.");
if(vh.signature == 0x4858)
sb.AppendLine("HFSX filesystem.");
if(wrapped)
sb.AppendLine("Volume is wrapped inside an HFS volume.");
byte[] tmp = new byte[0x400];
Array.Copy(vhSector, 0x400, tmp, 0, 0x400);
vhSector = tmp;
vh = Marshal.ByteArrayToStructureBigEndian<HfsPlusVolumeHeader>(vhSector);
vh = Marshal.ByteArrayToStructureBigEndian<VolumeHeader>(vhSector);
if(vh.version == 4 || vh.version == 5)
if(vh.version == 4 ||
vh.version == 5)
{
sb.AppendFormat("Filesystem version is {0}.", vh.version).AppendLine();
if((vh.attributes & 0x80) == 0x80) sb.AppendLine("Volume is locked on hardware.");
if((vh.attributes & 0x100) == 0x100) sb.AppendLine("Volume is unmounted.");
if((vh.attributes & 0x200) == 0x200) sb.AppendLine("There are bad blocks in the extents file.");
if((vh.attributes & 0x400) == 0x400) sb.AppendLine("Volume does not require cache.");
if((vh.attributes & 0x800) == 0x800) sb.AppendLine("Volume state is inconsistent.");
if((vh.attributes & 0x1000) == 0x1000) sb.AppendLine("CNIDs are reused.");
if((vh.attributes & 0x2000) == 0x2000) sb.AppendLine("Volume is journaled.");
if((vh.attributes & 0x8000) == 0x8000) sb.AppendLine("Volume is locked on software.");
if((vh.attributes & 0x80) == 0x80)
sb.AppendLine("Volume is locked on hardware.");
if((vh.attributes & 0x100) == 0x100)
sb.AppendLine("Volume is unmounted.");
if((vh.attributes & 0x200) == 0x200)
sb.AppendLine("There are bad blocks in the extents file.");
if((vh.attributes & 0x400) == 0x400)
sb.AppendLine("Volume does not require cache.");
if((vh.attributes & 0x800) == 0x800)
sb.AppendLine("Volume state is inconsistent.");
if((vh.attributes & 0x1000) == 0x1000)
sb.AppendLine("CNIDs are reused.");
if((vh.attributes & 0x2000) == 0x2000)
sb.AppendLine("Volume is journaled.");
if((vh.attributes & 0x8000) == 0x8000)
sb.AppendLine("Volume is locked on software.");
sb.AppendFormat("Implementation that last mounted the volume: \"{0}\".",
Encoding.ASCII.GetString(vh.lastMountedVersion)).AppendLine();
if((vh.attributes & 0x2000) == 0x2000)
sb.AppendFormat("Journal starts at allocation block {0}.", vh.journalInfoBlock).AppendLine();
sb.AppendFormat("Creation date: {0}", DateHandlers.MacToDateTime(vh.createDate)).AppendLine();
sb.AppendFormat("Last modification date: {0}", DateHandlers.MacToDateTime(vh.modifyDate)).AppendLine();
if(vh.backupDate > 0)
sb.AppendFormat("Last backup date: {0}", DateHandlers.MacToDateTime(vh.backupDate)).AppendLine();
else sb.AppendLine("Volume has never been backed up");
else
sb.AppendLine("Volume has never been backed up");
if(vh.backupDate > 0)
sb.AppendFormat("Last check date: {0}", DateHandlers.MacToDateTime(vh.checkedDate)).AppendLine();
else sb.AppendLine("Volume has never been checked up");
else
sb.AppendLine("Volume has never been checked up");
sb.AppendFormat("{0} files on volume.", vh.fileCount).AppendLine();
sb.AppendFormat("{0} folders on volume.", vh.folderCount).AppendLine();
sb.AppendFormat("{0} bytes per allocation block.", vh.blockSize).AppendLine();
@@ -208,10 +240,13 @@ namespace DiscImageChef.Filesystems
sb.AppendFormat("CNID of previously opened directory: {0}", vh.drFndrInfo2).AppendLine();
sb.AppendFormat("CNID of bootable Mac OS 8 or 9 directory: {0}", vh.drFndrInfo3).AppendLine();
sb.AppendFormat("CNID of bootable Mac OS X directory: {0}", vh.drFndrInfo5).AppendLine();
if(vh.drFndrInfo6 != 0 && vh.drFndrInfo7 != 0)
if(vh.drFndrInfo6 != 0 &&
vh.drFndrInfo7 != 0)
sb.AppendFormat("Mac OS X Volume ID: {0:X8}{1:X8}", vh.drFndrInfo6, vh.drFndrInfo7).AppendLine();
XmlFsType = new FileSystemType();
if(vh.backupDate > 0)
{
XmlFsType.BackupDate = DateHandlers.MacToDateTime(vh.backupDate);
@@ -221,6 +256,7 @@ namespace DiscImageChef.Filesystems
XmlFsType.Bootable |= vh.drFndrInfo0 != 0 || vh.drFndrInfo3 != 0 || vh.drFndrInfo5 != 0;
XmlFsType.Clusters = vh.totalBlocks;
XmlFsType.ClusterSize = vh.blockSize;
if(vh.createDate > 0)
{
XmlFsType.CreationDate = DateHandlers.MacToDateTime(vh.createDate);
@@ -232,16 +268,23 @@ namespace DiscImageChef.Filesystems
XmlFsType.FilesSpecified = true;
XmlFsType.FreeClusters = vh.freeBlocks;
XmlFsType.FreeClustersSpecified = true;
if(vh.modifyDate > 0)
{
XmlFsType.ModificationDate = DateHandlers.MacToDateTime(vh.modifyDate);
XmlFsType.ModificationDateSpecified = true;
}
if(vh.signature == 0x482B) XmlFsType.Type = "HFS+";
if(vh.signature == 0x4858) XmlFsType.Type = "HFSX";
if(vh.drFndrInfo6 != 0 && vh.drFndrInfo7 != 0)
if(vh.signature == 0x482B)
XmlFsType.Type = "HFS+";
if(vh.signature == 0x4858)
XmlFsType.Type = "HFSX";
if(vh.drFndrInfo6 != 0 &&
vh.drFndrInfo7 != 0)
XmlFsType.VolumeSerial = $"{vh.drFndrInfo6:X8}{vh.drFndrInfo7:X8}";
XmlFsType.SystemIdentifier = Encoding.ASCII.GetString(vh.lastMountedVersion);
}
else
@@ -253,11 +296,9 @@ namespace DiscImageChef.Filesystems
information = sb.ToString();
}
/// <summary>
/// HFS+ Volume Header, should be at offset 0x0400 bytes in volume with a size of 532 bytes
/// </summary>
/// <summary>HFS+ Volume Header, should be at offset 0x0400 bytes in volume with a size of 532 bytes</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct HfsPlusVolumeHeader
struct VolumeHeader
{
/// <summary>0x000, "H+" for HFS+, "HX" for HFSX</summary>
public ushort signature;
@@ -266,12 +307,8 @@ namespace DiscImageChef.Filesystems
/// <summary>0x004, Volume attributes</summary>
public readonly uint attributes;
/// <summary>
/// 0x008, Implementation that last mounted the volume.
/// Reserved by Apple:
/// "8.10" Mac OS 8.1 to 9.2.2
/// "10.0" Mac OS X
/// "HFSJ" Journaled implementation
/// "fsck" /sbin/fsck
/// 0x008, Implementation that last mounted the volume. Reserved by Apple: "8.10" Mac OS 8.1 to 9.2.2 "10.0" Mac
/// OS X "HFSJ" Journaled implementation "fsck" /sbin/fsck
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public readonly byte[] lastMountedVersion;
@@ -323,6 +360,7 @@ namespace DiscImageChef.Filesystems
public readonly uint drFndrInfo6;
/// <summary>0x06C, finderInfo[7], second part of Mac OS X volume ID</summary>
public readonly uint drFndrInfo7;
// HFSPlusForkData allocationFile;
/// <summary>0x070</summary>
public readonly ulong allocationFile_logicalSize;
@@ -362,6 +400,7 @@ namespace DiscImageChef.Filesystems
public readonly uint allocationFile_extents_startBlock7;
/// <summary>0x0BC</summary>
public readonly uint allocationFile_extents_blockCount7;
// HFSPlusForkData extentsFile;
/// <summary>0x0C0</summary>
public readonly ulong extentsFile_logicalSize;
@@ -401,6 +440,7 @@ namespace DiscImageChef.Filesystems
public readonly uint extentsFile_extents_startBlock7;
/// <summary>0x10C</summary>
public readonly uint extentsFile_extents_blockCount7;
// HFSPlusForkData catalogFile;
/// <summary>0x110</summary>
public readonly ulong catalogFile_logicalSize;
@@ -440,6 +480,7 @@ namespace DiscImageChef.Filesystems
public readonly uint catalogFile_extents_startBlock7;
/// <summary>0x15C</summary>
public readonly uint catalogFile_extents_blockCount7;
// HFSPlusForkData attributesFile;
/// <summary>0x160</summary>
public readonly ulong attributesFile_logicalSize;
@@ -479,6 +520,7 @@ namespace DiscImageChef.Filesystems
public readonly uint attributesFile_extents_startBlock7;
/// <summary>0x1AC</summary>
public readonly uint attributesFile_extents_blockCount7;
// HFSPlusForkData startupFile;
/// <summary>0x1B0</summary>
public readonly ulong startupFile_logicalSize;

View File

@@ -41,26 +41,24 @@ namespace DiscImageChef.Filesystems.AppleMFS
// Information from Inside Macintosh Volume II
public partial class AppleMFS : IReadOnlyFilesystem
{
bool mounted;
bool debug;
IMediaImage device;
ulong partitionStart;
Dictionary<uint, string> idToFilename;
Dictionary<uint, MFS_FileEntry> idToEntry;
Dictionary<string, uint> filenameToId;
MFS_MasterDirectoryBlock volMDB;
byte[] bootBlocks;
byte[] mdbBlocks;
byte[] directoryBlocks;
byte[] blockMapBytes;
uint[] blockMap;
int sectorsPerBlock;
byte[] bootTags;
byte[] mdbTags;
byte[] directoryTags;
byte[] bitmapTags;
bool mounted;
bool debug;
IMediaImage device;
ulong partitionStart;
Dictionary<uint, string> idToFilename;
Dictionary<uint, FileEntry> idToEntry;
Dictionary<string, uint> filenameToId;
MasterDirectoryBlock volMDB;
byte[] bootBlocks;
byte[] mdbBlocks;
byte[] directoryBlocks;
byte[] blockMapBytes;
uint[] blockMap;
int sectorsPerBlock;
byte[] bootTags;
byte[] mdbTags;
byte[] directoryTags;
byte[] bitmapTags;
public FileSystemType XmlFsType { get; private set; }
public string Name => "Apple Macintosh File System";
@@ -70,11 +68,16 @@ namespace DiscImageChef.Filesystems.AppleMFS
// TODO: Implement Finder namespace (requires decoding Desktop database)
public IEnumerable<(string name, Type type, string description)> SupportedOptions =>
new (string name, Type type, string description)[] { };
new (string name, Type type, string description)[]
{ };
public Dictionary<string, string> Namespaces => null;
static Dictionary<string, string> GetDefaultOptions() =>
new Dictionary<string, string> {{"debug", false.ToString()}};
static Dictionary<string, string> GetDefaultOptions() => new Dictionary<string, string>
{
{
"debug", false.ToString()
}
};
}
}

View File

@@ -73,19 +73,19 @@ namespace DiscImageChef.Filesystems.AppleMFS
bool FillDirectory()
{
idToFilename = new Dictionary<uint, string>();
idToEntry = new Dictionary<uint, MFS_FileEntry>();
idToEntry = new Dictionary<uint, FileEntry>();
filenameToId = new Dictionary<string, uint>();
int offset = 0;
while(offset + 51 < directoryBlocks.Length)
{
var entry = new MFS_FileEntry
var entry = new FileEntry
{
flFlags = (MFS_FileFlags)directoryBlocks[offset + 0]
flFlags = (FileFlags)directoryBlocks[offset + 0]
};
if(!entry.flFlags.HasFlag(MFS_FileFlags.Used))
if(!entry.flFlags.HasFlag(FileFlags.Used))
break;
entry.flTyp = directoryBlocks[offset + 1];
@@ -108,10 +108,10 @@ namespace DiscImageChef.Filesystems.AppleMFS
string lowerFilename = StringHandlers.
PascalToString(entry.flNam, Encoding).ToLowerInvariant().Replace('/', ':');
if(entry.flFlags.HasFlag(MFS_FileFlags.Used) &&
!idToFilename.ContainsKey(entry.flFlNum) &&
!idToEntry.ContainsKey(entry.flFlNum) &&
!filenameToId.ContainsKey(lowerFilename) &&
if(entry.flFlags.HasFlag(FileFlags.Used) &&
!idToFilename.ContainsKey(entry.flFlNum) &&
!idToEntry.ContainsKey(entry.flFlNum) &&
!filenameToId.ContainsKey(lowerFilename) &&
entry.flFlNum > 0)
{
idToEntry.Add(entry.flFlNum, entry);

View File

@@ -62,7 +62,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
if(!filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId))
return Errno.NoSuchFile;
if(!idToEntry.TryGetValue(fileId, out MFS_FileEntry entry))
if(!idToEntry.TryGetValue(fileId, out FileEntry entry))
return Errno.NoSuchFile;
if(fileBlock > entry.flPyLen / volMDB.drAlBlkSiz)
@@ -111,7 +111,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
if(!filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId))
return Errno.NoSuchFile;
if(!idToEntry.TryGetValue(fileId, out MFS_FileEntry entry))
if(!idToEntry.TryGetValue(fileId, out FileEntry entry))
return Errno.NoSuchFile;
if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsAlias))
@@ -132,7 +132,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsInvisible))
attributes |= FileAttributes.Hidden;
if(entry.flFlags.HasFlag(MFS_FileFlags.Locked))
if(entry.flFlags.HasFlag(FileFlags.Locked))
attributes |= FileAttributes.Immutable;
if(entry.flUsrWds.fdFlags.HasFlag(AppleCommon.FinderFlags.kIsOnDesk))
@@ -258,7 +258,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
if(!filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId))
return Errno.NoSuchFile;
if(!idToEntry.TryGetValue(fileId, out MFS_FileEntry entry))
if(!idToEntry.TryGetValue(fileId, out FileEntry entry))
return Errno.NoSuchFile;
Errno error = GetAttributes(path, out FileAttributes attr);
@@ -304,7 +304,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
if(!filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId))
return Errno.NoSuchFile;
if(!idToEntry.TryGetValue(fileId, out MFS_FileEntry entry))
if(!idToEntry.TryGetValue(fileId, out FileEntry entry))
return Errno.NoSuchFile;
uint nextBlock;

View File

@@ -63,7 +63,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
var sb = new StringBuilder();
var mdb = new MFS_MasterDirectoryBlock();
var mdb = new MasterDirectoryBlock();
byte[] pString = new byte[16];

View File

@@ -42,7 +42,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
public partial class AppleMFS
{
/// <summary>Master Directory Block, should be at offset 0x0400 bytes in volume</summary>
struct MFS_MasterDirectoryBlock
struct MasterDirectoryBlock
{
/// <summary>0x000, Signature, 0xD2D7</summary>
public ushort drSigWord;
@@ -77,15 +77,15 @@ namespace DiscImageChef.Filesystems.AppleMFS
}
[Flags]
enum MFS_FileFlags : byte
enum FileFlags : byte
{
Locked = 0x01, Used = 0x80
}
struct MFS_FileEntry
struct FileEntry
{
/// <summary>0x00, Entry flags</summary>
public MFS_FileFlags flFlags;
public FileFlags flFlags;
/// <summary>0x01, Version number</summary>
public byte flTyp;
/// <summary>0x02, FinderInfo</summary>

View File

@@ -57,7 +57,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
if(options.TryGetValue("debug", out string debugString))
bool.TryParse(debugString, out debug);
volMDB = new MFS_MasterDirectoryBlock();
volMDB = new MasterDirectoryBlock();
mdbBlocks = device.ReadSector(2 + partitionStart);
bootBlocks = device.ReadSector(0 + partitionStart);

View File

@@ -76,7 +76,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
if(!filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId))
return Errno.NoSuchFile;
if(!idToEntry.TryGetValue(fileId, out MFS_FileEntry entry))
if(!idToEntry.TryGetValue(fileId, out FileEntry entry))
return Errno.NoSuchFile;
if(entry.flRLgLen > 0)
@@ -162,7 +162,7 @@ namespace DiscImageChef.Filesystems.AppleMFS
if(!filenameToId.TryGetValue(path.ToLowerInvariant(), out uint fileId))
return Errno.NoSuchFile;
if(!idToEntry.TryGetValue(fileId, out MFS_FileEntry entry))
if(!idToEntry.TryGetValue(fileId, out FileEntry entry))
return Errno.NoSuchFile;
if(entry.flRLgLen > 0 &&