From 9a5d52caab92ff0cbdf8a6a8ab816959940a984b Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Tue, 25 Jul 2017 00:27:46 +0100 Subject: [PATCH] Added support for hybrid ISO/USB images with GPT and FAT partitions. --- DiscImageChef.Filesystems/FAT.cs | 50 ++++++++++++++++++++++++++++ DiscImageChef.Partitions/GPT.cs | 57 ++++++++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 7 deletions(-) diff --git a/DiscImageChef.Filesystems/FAT.cs b/DiscImageChef.Filesystems/FAT.cs index 3018763c..4f7f1efa 100644 --- a/DiscImageChef.Filesystems/FAT.cs +++ b/DiscImageChef.Filesystems/FAT.cs @@ -135,6 +135,14 @@ namespace DiscImageChef.Filesystems DicConsole.DebugWriteLine("FAT plugin", "huge_sectors = {0}", huge_sectors); DicConsole.DebugWriteLine("FAT plugin", "fat_id = 0x{0:X2}", fat_id); + // This is to support FAT partitions on hybrid ISO/USB images + if(imagePlugin.ImageInfo.xmlMediaType == ImagePlugins.XmlMediaType.OpticalDisc) + { + sectors /= 4; + big_sectors /= 4; + huge_sectors /= 4; + } + // exFAT if(oem_string == "EXFAT ") return false; @@ -308,6 +316,27 @@ namespace DiscImageChef.Filesystems bool correct_spc_fat32_short = shortFat32BPB.spc == 1 || shortFat32BPB.spc == 2 || shortFat32BPB.spc == 4 || shortFat32BPB.spc == 8 || shortFat32BPB.spc == 16 || shortFat32BPB.spc == 32 || shortFat32BPB.spc == 64; bool correct_spc_fat32 = Fat32BPB.spc == 1 || Fat32BPB.spc == 2 || Fat32BPB.spc == 4 || Fat32BPB.spc == 8 || Fat32BPB.spc == 16 || Fat32BPB.spc == 32 || Fat32BPB.spc == 64; + // This is to support FAT partitions on hybrid ISO/USB images + if(imagePlugin.ImageInfo.xmlMediaType == ImagePlugins.XmlMediaType.OpticalDisc) + { + atariBPB.sectors /= 4; + msxBPB.sectors /= 4; + dos2BPB.sectors /= 4; + dos30BPB.sectors /= 4; + dos32BPB.sectors /= 4; + dos33BPB.sectors /= 4; + dos33BPB.big_sectors /= 4; + shortEBPB.sectors /= 4; + shortEBPB.big_sectors /= 4; + EBPB.sectors /= 4; + EBPB.big_sectors /= 4; + shortFat32BPB.sectors /= 4; + shortFat32BPB.big_sectors /= 4; + shortFat32BPB.huge_sectors /= 4; + Fat32BPB.sectors /= 4; + Fat32BPB.big_sectors /= 4; + } + if(bits_in_bps_fat32 == 1 && correct_spc_fat32 && Fat32BPB.fats_no <= 2 && Fat32BPB.sectors == 0 && Fat32BPB.spfat == 0 && Fat32BPB.signature == 0x29 && Encoding.ASCII.GetString(Fat32BPB.fs_type) == "FAT32 ") { DicConsole.DebugWriteLine("FAT plugin", "Using FAT32 BPB"); @@ -587,6 +616,16 @@ namespace DiscImageChef.Filesystems { isFAT32 = true; + // This is to support FAT partitions on hybrid ISO/USB images + if(imagePlugin.ImageInfo.xmlMediaType == ImagePlugins.XmlMediaType.OpticalDisc) + { + Fat32BPB.bps *= 4; + Fat32BPB.spc /= 4; + Fat32BPB.big_spfat /= 4; + Fat32BPB.hsectors /= 4; + Fat32BPB.sptrk /= 4; + } + if(Fat32BPB.version != 0) { sb.AppendLine("FAT+"); @@ -870,6 +909,17 @@ namespace DiscImageChef.Filesystems if(!isFAT32) { + // This is to support FAT partitions on hybrid ISO/USB images + if(imagePlugin.ImageInfo.xmlMediaType == ImagePlugins.XmlMediaType.OpticalDisc) + { + fakeBPB.bps *= 4; + fakeBPB.spc /= 4; + fakeBPB.spfat /= 4; + fakeBPB.hsectors /= 4; + fakeBPB.sptrk /= 4; + fakeBPB.rsectors /= 4; + } + // This assumes no sane implementation will violate cluster size rules // However nothing prevents this to happen // If first file on disk uses only one cluster there is absolutely no way to differentiate between FAT12 and FAT16, diff --git a/DiscImageChef.Partitions/GPT.cs b/DiscImageChef.Partitions/GPT.cs index 97f9ccee..4d0deaf5 100644 --- a/DiscImageChef.Partitions/GPT.cs +++ b/DiscImageChef.Partitions/GPT.cs @@ -55,6 +55,33 @@ namespace DiscImageChef.PartPlugins byte[] hdrBytes = imagePlugin.ReadSector(1 + sectorOffset); GptHeader hdr; + ulong signature = BitConverter.ToUInt64(hdrBytes, 0); + bool misaligned = false; + + DicConsole.DebugWriteLine("GPT Plugin", "hdr.signature = 0x{0:X16}", signature); + + if(signature != GptMagic) + { + if(imagePlugin.ImageInfo.xmlMediaType == ImagePlugins.XmlMediaType.OpticalDisc) + { + hdrBytes = imagePlugin.ReadSector(sectorOffset); + signature = BitConverter.ToUInt64(hdrBytes, 512); + DicConsole.DebugWriteLine("GPT Plugin", "hdr.signature @ 0x200 = 0x{0:X16}", signature); + if(signature == GptMagic) + { + DicConsole.DebugWriteLine("GPT Plugin", "Found unaligned signature", signature); + byte[] real = new byte[512]; + Array.Copy(hdrBytes, 512, real, 0, 512); + hdrBytes = real; + misaligned = true; + } + else + return false; + } + else + return false; + } + try { GCHandle handle = GCHandle.Alloc(hdrBytes, GCHandleType.Pinned); @@ -66,7 +93,6 @@ namespace DiscImageChef.PartPlugins return false; } - DicConsole.DebugWriteLine("GPT Plugin", "hdr.signature = 0x{0:X16}", hdr.signature); DicConsole.DebugWriteLine("GPT Plugin", "hdr.revision = 0x{0:X8}", hdr.revision); DicConsole.DebugWriteLine("GPT Plugin", "hdr.headerSize = {0}", hdr.headerSize); DicConsole.DebugWriteLine("GPT Plugin", "hdr.headerCrc = 0x{0:X8}", hdr.headerCrc); @@ -87,9 +113,26 @@ namespace DiscImageChef.PartPlugins if(hdr.myLBA != 1) return false; + uint divisor, modulo, sectorSize; + + if(misaligned) + { + divisor = 4; + modulo = (uint)(hdr.entryLBA % divisor); + sectorSize = 512; + } + else + { + divisor = 1; + modulo = 0; + sectorSize = imagePlugin.GetSectorSize(); + } + uint totalEntriesSectors = (hdr.entries * hdr.entriesSize) / imagePlugin.GetSectorSize(); - byte[] entriesBytes = imagePlugin.ReadSectors(hdr.entryLBA, totalEntriesSectors); + byte[] temp = imagePlugin.ReadSectors(hdr.entryLBA / divisor, totalEntriesSectors + modulo); + byte[] entriesBytes = new byte[temp.Length - (modulo * 512)]; + Array.Copy(temp, modulo * 512, entriesBytes, 0, entriesBytes.Length); List entries = new List(); for(int i = 0; i < hdr.entries; i++) @@ -126,18 +169,18 @@ namespace DiscImageChef.PartPlugins DicConsole.DebugWriteLine("GPT Plugin", "entry.attributes = 0x{0:X16}", entry.attributes); DicConsole.DebugWriteLine("GPT Plugin", "entry.name = {0}", entry.name); - if(entry.startLBA > imagePlugin.GetSectors() || entry.endLBA > imagePlugin.GetSectors()) + if((entry.startLBA / divisor) > imagePlugin.GetSectors() || (entry.endLBA / divisor) > imagePlugin.GetSectors()) return false; CommonTypes.Partition part = new CommonTypes.Partition { Description = string.Format("ID: {0}", entry.partitionId), - Size = (entry.endLBA - entry.startLBA + 1) * imagePlugin.GetSectorSize(), + Size = (entry.endLBA - entry.startLBA + 1) * sectorSize, Name = entry.name, - Length = (entry.endLBA - entry.startLBA + 1), + Length = (entry.endLBA - entry.startLBA + 1) / divisor, Sequence = pseq++, - Offset = entry.startLBA * imagePlugin.GetSectorSize(), - Start = entry.startLBA, + Offset = entry.startLBA * sectorSize, + Start = entry.startLBA / divisor, Type = GetGuidTypeName(entry.partitionType), Scheme = Name };