diff --git a/DiscImageChef.Filesystems/HPFS.cs b/DiscImageChef.Filesystems/HPFS.cs
index 834aead27..236562c17 100644
--- a/DiscImageChef.Filesystems/HPFS.cs
+++ b/DiscImageChef.Filesystems/HPFS.cs
@@ -33,6 +33,8 @@
using System;
using System.Text;
using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using DiscImageChef.Checksums;
namespace DiscImageChef.Filesystems
{
@@ -90,71 +92,22 @@ namespace DiscImageChef.Filesystems
byte[] hpfs_sb_sector = imagePlugin.ReadSector(16 + partitionStart); // Seek to superblock, on logical sector 16
byte[] hpfs_sp_sector = imagePlugin.ReadSector(17 + partitionStart); // Seek to spareblock, on logical sector 17
- hpfs_bpb.jmp1 = hpfs_bpb_sector[0x000];
- hpfs_bpb.jmp2 = BitConverter.ToUInt16(hpfs_bpb_sector, 0x001);
- Array.Copy(hpfs_bpb_sector, 0x003, oem_name, 0, 8);
- hpfs_bpb.OEMName = StringHandlers.CToString(oem_name);
- hpfs_bpb.bps = BitConverter.ToUInt16(hpfs_bpb_sector, 0x00B);
- hpfs_bpb.spc = hpfs_bpb_sector[0x00D];
- hpfs_bpb.rsectors = BitConverter.ToUInt16(hpfs_bpb_sector, 0x00E);
- hpfs_bpb.fats_no = hpfs_bpb_sector[0x010];
- hpfs_bpb.root_ent = BitConverter.ToUInt16(hpfs_bpb_sector, 0x011);
- hpfs_bpb.sectors = BitConverter.ToUInt16(hpfs_bpb_sector, 0x013);
- hpfs_bpb.media = hpfs_bpb_sector[0x015];
- hpfs_bpb.spfat = BitConverter.ToUInt16(hpfs_bpb_sector, 0x016);
- hpfs_bpb.sptrk = BitConverter.ToUInt16(hpfs_bpb_sector, 0x018);
- hpfs_bpb.heads = BitConverter.ToUInt16(hpfs_bpb_sector, 0x01A);
- hpfs_bpb.hsectors = BitConverter.ToUInt32(hpfs_bpb_sector, 0x01C);
- hpfs_bpb.big_sectors = BitConverter.ToUInt32(hpfs_bpb_sector, 0x024);
- hpfs_bpb.drive_no = hpfs_bpb_sector[0x028];
- hpfs_bpb.nt_flags = hpfs_bpb_sector[0x029];
- hpfs_bpb.signature = hpfs_bpb_sector[0x02A];
- hpfs_bpb.serial_no = BitConverter.ToUInt32(hpfs_bpb_sector, 0x02B);
- Array.Copy(hpfs_bpb_sector, 0x02F, volume_name, 0, 11);
- hpfs_bpb.volume_label = StringHandlers.CToString(volume_name, CurrentEncoding);
- Array.Copy(hpfs_bpb_sector, 0x03A, oem_name, 0, 8);
- hpfs_bpb.fs_type = StringHandlers.CToString(oem_name, CurrentEncoding);
+ IntPtr bpbPtr = Marshal.AllocHGlobal(512);
+ Marshal.Copy(hpfs_bpb_sector, 0, bpbPtr, 512);
+ hpfs_bpb = (HPFS_BIOSParameterBlock)Marshal.PtrToStructure(bpbPtr, typeof(HPFS_BIOSParameterBlock));
+ Marshal.FreeHGlobal(bpbPtr);
- hpfs_sb.magic1 = BitConverter.ToUInt32(hpfs_sb_sector, 0x000);
- hpfs_sb.magic2 = BitConverter.ToUInt32(hpfs_sb_sector, 0x004);
- hpfs_sb.version = hpfs_sb_sector[0x008];
- hpfs_sb.func_version = hpfs_sb_sector[0x009];
- hpfs_sb.dummy = BitConverter.ToUInt16(hpfs_sb_sector, 0x00A);
- hpfs_sb.root_fnode = BitConverter.ToUInt32(hpfs_sb_sector, 0x00C);
- hpfs_sb.sectors = BitConverter.ToUInt32(hpfs_sb_sector, 0x010);
- hpfs_sb.badblocks = BitConverter.ToUInt32(hpfs_sb_sector, 0x014);
- hpfs_sb.bitmap_lsn = BitConverter.ToUInt32(hpfs_sb_sector, 0x018);
- hpfs_sb.zero1 = BitConverter.ToUInt32(hpfs_sb_sector, 0x01C);
- hpfs_sb.badblock_lsn = BitConverter.ToUInt32(hpfs_sb_sector, 0x020);
- hpfs_sb.zero2 = BitConverter.ToUInt32(hpfs_sb_sector, 0x024);
- hpfs_sb.last_chkdsk = BitConverter.ToInt32(hpfs_sb_sector, 0x028);
- hpfs_sb.last_optim = BitConverter.ToInt32(hpfs_sb_sector, 0x02C);
- hpfs_sb.dband_sectors = BitConverter.ToUInt32(hpfs_sb_sector, 0x030);
- hpfs_sb.dband_start = BitConverter.ToUInt32(hpfs_sb_sector, 0x034);
- hpfs_sb.dband_last = BitConverter.ToUInt32(hpfs_sb_sector, 0x038);
- hpfs_sb.dband_bitmap = BitConverter.ToUInt32(hpfs_sb_sector, 0x03C);
- hpfs_sb.zero3 = BitConverter.ToUInt64(hpfs_sb_sector, 0x040);
- hpfs_sb.zero4 = BitConverter.ToUInt64(hpfs_sb_sector, 0x048);
- hpfs_sb.zero5 = BitConverter.ToUInt64(hpfs_sb_sector, 0x04C);
- hpfs_sb.zero6 = BitConverter.ToUInt64(hpfs_sb_sector, 0x050);
- hpfs_sb.acl_start = BitConverter.ToUInt32(hpfs_sb_sector, 0x058);
+ IntPtr sbPtr = Marshal.AllocHGlobal(512);
+ Marshal.Copy(hpfs_sb_sector, 0, sbPtr, 512);
+ hpfs_sb = (HPFS_SuperBlock)Marshal.PtrToStructure(sbPtr, typeof(HPFS_SuperBlock));
+ Marshal.FreeHGlobal(sbPtr);
- hpfs_sp.magic1 = BitConverter.ToUInt32(hpfs_sp_sector, 0x000);
- hpfs_sp.magic2 = BitConverter.ToUInt32(hpfs_sp_sector, 0x004);
- hpfs_sp.flags1 = hpfs_sp_sector[0x008];
- hpfs_sp.flags2 = hpfs_sp_sector[0x009];
- hpfs_sp.dummy = BitConverter.ToUInt16(hpfs_sp_sector, 0x00A);
- hpfs_sp.hotfix_start = BitConverter.ToUInt32(hpfs_sp_sector, 0x00C);
- hpfs_sp.hotfix_used = BitConverter.ToUInt32(hpfs_sp_sector, 0x010);
- hpfs_sp.hotfix_entries = BitConverter.ToUInt32(hpfs_sp_sector, 0x014);
- hpfs_sp.spare_dnodes_free = BitConverter.ToUInt32(hpfs_sp_sector, 0x018);
- hpfs_sp.spare_dnodes = BitConverter.ToUInt32(hpfs_sp_sector, 0x01C);
- hpfs_sp.codepage_lsn = BitConverter.ToUInt32(hpfs_sp_sector, 0x020);
- hpfs_sp.codepages = BitConverter.ToUInt32(hpfs_sp_sector, 0x024);
- hpfs_sp.sb_crc32 = BitConverter.ToUInt32(hpfs_sp_sector, 0x028);
- hpfs_sp.sp_crc32 = BitConverter.ToUInt32(hpfs_sp_sector, 0x02C);
+ IntPtr spPtr = Marshal.AllocHGlobal(512);
+ Marshal.Copy(hpfs_sp_sector, 0, spPtr, 512);
+ hpfs_sp = (HPFS_SpareBlock)Marshal.PtrToStructure(spPtr, typeof(HPFS_SpareBlock));
+ Marshal.FreeHGlobal(spPtr);
- if(hpfs_bpb.fs_type != "HPFS " ||
+ if(StringHandlers.CToString(hpfs_bpb.fs_type) != "HPFS " ||
hpfs_sb.magic1 != 0xF995E849 || hpfs_sb.magic2 != 0xFA53E9C5 ||
hpfs_sp.magic1 != 0xF9911849 || hpfs_sp.magic2 != 0xFA5229C5)
{
@@ -166,9 +119,9 @@ namespace DiscImageChef.Filesystems
sb.AppendFormat("Spareblock magic2: 0x{0:X8} (Should be 0xFA5229C5)", hpfs_sp.magic2).AppendLine();
}
- sb.AppendFormat("OEM name: {0}", hpfs_bpb.OEMName).AppendLine();
+ sb.AppendFormat("OEM name: {0}", StringHandlers.CToString(hpfs_bpb.oem_name)).AppendLine();
sb.AppendFormat("{0} bytes per sector", hpfs_bpb.bps).AppendLine();
- sb.AppendFormat("{0} sectors per cluster", hpfs_bpb.spc).AppendLine();
+ // sb.AppendFormat("{0} sectors per cluster", hpfs_bpb.spc).AppendLine();
// sb.AppendFormat("{0} reserved sectors", hpfs_bpb.rsectors).AppendLine();
// sb.AppendFormat("{0} FATs", hpfs_bpb.fats_no).AppendLine();
// sb.AppendFormat("{0} entries on root directory", hpfs_bpb.root_ent).AppendLine();
@@ -178,12 +131,13 @@ namespace DiscImageChef.Filesystems
// sb.AppendFormat("{0} sectors per track", hpfs_bpb.sptrk).AppendLine();
// sb.AppendFormat("{0} heads", hpfs_bpb.heads).AppendLine();
sb.AppendFormat("{0} sectors hidden before BPB", hpfs_bpb.hsectors).AppendLine();
- sb.AppendFormat("{0} sectors on volume ({1} bytes)", hpfs_bpb.big_sectors, hpfs_bpb.big_sectors * hpfs_bpb.bps).AppendLine();
+ sb.AppendFormat("{0} sectors on volume ({1} bytes)", hpfs_sb.sectors, hpfs_sb.sectors * hpfs_bpb.bps).AppendLine();
+ // sb.AppendFormat("{0} sectors on volume ({1} bytes)", hpfs_bpb.big_sectors, hpfs_bpb.big_sectors * hpfs_bpb.bps).AppendLine();
sb.AppendFormat("BIOS Drive Number: 0x{0:X2}", hpfs_bpb.drive_no).AppendLine();
- // sb.AppendFormat("NT Flags: 0x{0:X2}", hpfs_bpb.nt_flags).AppendLine();
+ sb.AppendFormat("NT Flags: 0x{0:X2}", hpfs_bpb.nt_flags).AppendLine();
sb.AppendFormat("Signature: 0x{0:X2}", hpfs_bpb.signature).AppendLine();
sb.AppendFormat("Serial number: 0x{0:X8}", hpfs_bpb.serial_no).AppendLine();
- sb.AppendFormat("Volume label: {0}", hpfs_bpb.volume_label).AppendLine();
+ sb.AppendFormat("Volume label: {0}", StringHandlers.CToString(hpfs_bpb.volume_label, CurrentEncoding)).AppendLine();
// sb.AppendFormat("Filesystem type: \"{0}\"", hpfs_bpb.fs_type).AppendLine();
DateTime last_chk = DateHandlers.UNIXToDateTime(hpfs_sb.last_chkdsk);
@@ -192,11 +146,13 @@ namespace DiscImageChef.Filesystems
sb.AppendFormat("HPFS version: {0}", hpfs_sb.version).AppendLine();
sb.AppendFormat("Functional version: {0}", hpfs_sb.func_version).AppendLine();
sb.AppendFormat("Sector of root directory FNode: {0}", hpfs_sb.root_fnode).AppendLine();
- // sb.AppendFormat("{0} sectors on volume", hpfs_sb.sectors).AppendLine();
sb.AppendFormat("{0} sectors are marked bad", hpfs_sb.badblocks).AppendLine();
sb.AppendFormat("Sector of free space bitmaps: {0}", hpfs_sb.bitmap_lsn).AppendLine();
sb.AppendFormat("Sector of bad blocks list: {0}", hpfs_sb.badblock_lsn).AppendLine();
- sb.AppendFormat("Date of last integrity check: {0}", last_chk).AppendLine();
+ if(hpfs_sb.last_chkdsk > 0)
+ sb.AppendFormat("Date of last integrity check: {0}", last_chk).AppendLine();
+ else
+ sb.AppendLine("Filesystem integrity has never been checked");
if(hpfs_sb.last_optim > 0)
sb.AppendFormat("Date of last optimization {0}", last_optim).AppendLine();
else
@@ -254,13 +210,25 @@ namespace DiscImageChef.Filesystems
sb.AppendLine("Unknown flag 0x80 on flags2 is active");
xmlFSType = new Schemas.FileSystemType();
+
+ // Theoretically everything from BPB to SB is boot code, should I hash everything or only the sector loaded by BIOS itself?
+ if(hpfs_bpb.jump[0] == 0xEB && hpfs_bpb.jump[1] > 0x3C && hpfs_bpb.jump[1] < 0x80 && hpfs_bpb.signature2 == 0xAA55)
+ {
+ xmlFSType.Bootable = true;
+ SHA1Context sha1Ctx = new SHA1Context();
+ sha1Ctx.Init();
+ string bootChk = sha1Ctx.Data(hpfs_bpb.boot_code, out byte[] sha1_out);
+ sb.AppendLine("Volume is bootable");
+ sb.AppendFormat("Boot code's SHA1: {0}", bootChk).AppendLine();
+ }
+
xmlFSType.Dirty |= (hpfs_sp.flags1 & 0x01) == 0x01;
- xmlFSType.Clusters = hpfs_bpb.big_sectors / hpfs_bpb.spc;
- xmlFSType.ClusterSize = hpfs_bpb.bps * hpfs_bpb.spc;
+ xmlFSType.Clusters = hpfs_sb.sectors;
+ xmlFSType.ClusterSize = hpfs_bpb.bps;
xmlFSType.Type = "HPFS";
- xmlFSType.VolumeName = hpfs_bpb.volume_label;
+ xmlFSType.VolumeName = StringHandlers.CToString(hpfs_bpb.volume_label, CurrentEncoding);
xmlFSType.VolumeSerial = string.Format("{0:X8}", hpfs_bpb.serial_no);
- xmlFSType.SystemIdentifier = hpfs_bpb.OEMName;
+ xmlFSType.SystemIdentifier = StringHandlers.CToString(hpfs_bpb.oem_name);
information = sb.ToString();
}
@@ -268,14 +236,15 @@ namespace DiscImageChef.Filesystems
///
/// BIOS Parameter Block, at sector 0
///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
struct HPFS_BIOSParameterBlock
{
/// 0x000, Jump to boot code
- public byte jmp1;
- /// 0x001, ...;
- public ushort jmp2;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public byte[] jump;
/// 0x003, OEM Name, 8 bytes, space-padded
- public string OEMName;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
+ public byte[] oem_name;
/// 0x00B, Bytes per sector
public ushort bps;
/// 0x00D, Sectors per cluster
@@ -309,14 +278,22 @@ namespace DiscImageChef.Filesystems
/// 0x02B, Volume serial number
public uint serial_no;
/// 0x02F, Volume label, 11 bytes, space-padded
- public string volume_label;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
+ public byte[] volume_label;
/// 0x03A, Filesystem type, 8 bytes, space-padded ("HPFS ")
- public string fs_type;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
+ public byte[] fs_type;
+ /// Boot code.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 448)]
+ public byte[] boot_code;
+ /// 0x1FE, 0xAA55
+ public ushort signature2;
}
///
/// HPFS superblock at sector 16
///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
struct HPFS_SuperBlock
{
/// 0x000, 0xF995E849
@@ -370,6 +347,7 @@ namespace DiscImageChef.Filesystems
///
/// HPFS spareblock at sector 17
///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
struct HPFS_SpareBlock
{
/// 0x000, 0xF9911849