From 081b33026700f9fb69605a8b3f1e14315ca7e411 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Mon, 2 Oct 2017 14:24:19 +0100 Subject: [PATCH] Added support for DEC Rainbow's hardcoded BPB. --- DiscImageChef.Filesystems/FAT.cs | 117 ++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/DiscImageChef.Filesystems/FAT.cs b/DiscImageChef.Filesystems/FAT.cs index 865d5e7a..099c10d5 100644 --- a/DiscImageChef.Filesystems/FAT.cs +++ b/DiscImageChef.Filesystems/FAT.cs @@ -36,6 +36,7 @@ using System.Runtime.InteropServices; using System.Text; using DiscImageChef.CommonTypes; using DiscImageChef.Console; +using System.IO; namespace DiscImageChef.Filesystems { @@ -217,6 +218,47 @@ namespace DiscImageChef.Filesystems if(partition.Start != 0) return false; + // DEC Rainbow, lacks a BPB but has a very concrete structure... + if(imagePlugin.GetSectors() == 800 && imagePlugin.GetSectorSize() == 512) + { + // DEC Rainbow boots up with a Z80, first byte should be DI (disable interrupts) + byte z80_di = bpb_sector[0]; + // First FAT1 sector resides at LBA 0x14 + byte[] fat1_sector0 = imagePlugin.ReadSector(0x14); + // First FAT2 sector resides at LBA 0x1A + byte[] fat2_sector0 = imagePlugin.ReadSector(0x1A); + bool equal_fat_ids = fat1_sector0[0] == fat2_sector0[0] && fat1_sector0[1] == fat2_sector0[1]; + // Volume is software interleaved 2:1 + MemoryStream rootMs = new MemoryStream(); + foreach(ulong rootSector in new[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 }) + { + byte[] tmp = imagePlugin.ReadSector(rootSector); + rootMs.Write(tmp, 0, tmp.Length); + } + byte[] root_dir = rootMs.ToArray(); + rootMs = null; + bool valid_root_dir = true; + + // Iterate all root directory + for(int e = 0; e < 96 * 32; e += 32) + { + for(int c = 0; c < 11; c++) + { + if((root_dir[c + e] < 0x20 && root_dir[c + e] != 0x00 && root_dir[c + e] != 0x05) || root_dir[c + e] == 0xFF || root_dir[c + e] == 0x2E) + { + valid_root_dir = false; + break; + } + } + + if(!valid_root_dir) + break; + } + + if(z80_di == 0xF3 && equal_fat_ids && (fat1_sector0[0] & 0xF0) == 0xF0 && fat1_sector0[1] == 0xFF && valid_root_dir) + return true; + } + byte fat2 = fat_sector[1]; byte fat3 = fat_sector[2]; ushort fat_2nd_cluster = (ushort)(((fat2 << 8) + fat3) & 0xFFF); @@ -299,6 +341,7 @@ namespace DiscImageChef.Filesystems bool useLongFAT32 = false; bool andos_oem_correct = false; bool useApricotBPB = false; + bool useDecRainbowBPB = false; AtariParameterBlock atariBPB = new AtariParameterBlock(); MSXParameterBlock msxBPB = new MSXParameterBlock(); @@ -508,7 +551,66 @@ namespace DiscImageChef.Filesystems // This is needed because some OSes don't put volume label as first entry in the root directory uint sectors_for_root_directory = 0; - if(!useAtariBPB && !useMSXBPB && !useDOS2BPB && !useDOS3BPB && !useDOS32BPB && !useDOS33BPB && !useShortEBPB && !useEBPB && !useShortFAT32 && !useLongFAT32 && !useApricotBPB) + // DEC Rainbow, lacks a BPB but has a very concrete structure... + if(imagePlugin.GetSectors() == 800 && imagePlugin.GetSectorSize() == 512 && + !useAtariBPB && !useMSXBPB && !useDOS2BPB && !useDOS3BPB && !useDOS32BPB && !useDOS33BPB && !useShortEBPB && !useEBPB && !useShortFAT32 && !useLongFAT32 && !useApricotBPB) + { + // DEC Rainbow boots up with a Z80, first byte should be DI (disable interrupts) + byte z80_di = bpb_sector[0]; + // First FAT1 sector resides at LBA 0x14 + byte[] fat1_sector0 = imagePlugin.ReadSector(0x14); + // First FAT2 sector resides at LBA 0x1A + byte[] fat2_sector0 = imagePlugin.ReadSector(0x1A); + bool equal_fat_ids = fat1_sector0[0] == fat2_sector0[0] && fat1_sector0[1] == fat2_sector0[1]; + // Volume is software interleaved 2:1 + MemoryStream rootMs = new MemoryStream(); + foreach(ulong rootSector in new[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 }) + { + byte[] tmp = imagePlugin.ReadSector(rootSector); + rootMs.Write(tmp, 0, tmp.Length); + } + byte[] root_dir = rootMs.ToArray(); + rootMs = null; + bool valid_root_dir = true; + + // Iterate all root directory + for(int e = 0; e < 96 * 32; e += 32) + { + for(int c = 0; c < 11; c++) + { + if((root_dir[c + e] < 0x20 && root_dir[c + e] != 0x00 && root_dir[c + e] != 0x05) || root_dir[c + e] == 0xFF || root_dir[c + e] == 0x2E) + { + valid_root_dir = false; + break; + } + } + + if(!valid_root_dir) + break; + } + + if(z80_di == 0xF3 && equal_fat_ids && (fat1_sector0[0] & 0xF0) == 0xF0 && fat1_sector0[1] == 0xFF && valid_root_dir) + { + useDecRainbowBPB = true; + DicConsole.DebugWriteLine("FAT plugin", "Using DEC Rainbow hardcoded BPB."); + fakeBPB.bps = 512; + fakeBPB.spc = 1; + fakeBPB.rsectors = 20; + fakeBPB.fats_no = 2; + fakeBPB.root_ent = 96; + fakeBPB.sectors = 800; + fakeBPB.media = 0xFA; + fakeBPB.sptrk = 10; + fakeBPB.heads = 1; + fakeBPB.hsectors = 0; + fakeBPB.spfat = 3; + xmlFSType.Bootable = true; + fakeBPB.boot_code = bpb_sector; + isFAT12 = true; + } + } + + if(!useAtariBPB && !useMSXBPB && !useDOS2BPB && !useDOS3BPB && !useDOS32BPB && !useDOS33BPB && !useShortEBPB && !useEBPB && !useShortFAT32 && !useLongFAT32 && !useApricotBPB && !useDecRainbowBPB) { isFAT12 = true; fat_sector = imagePlugin.ReadSector(1 + partition.Start); @@ -1168,6 +1270,19 @@ namespace DiscImageChef.Filesystems if(root_directory_sector + partition.Start < partition.End && imagePlugin.ImageInfo.xmlMediaType != ImagePlugins.XmlMediaType.OpticalDisc) { byte[] root_directory = imagePlugin.ReadSectors(root_directory_sector + partition.Start, sectors_for_root_directory); + + if(useDecRainbowBPB) + { + MemoryStream rootMs = new MemoryStream(); + foreach(ulong rootSector in new[] { 0x17, 0x19, 0x1B, 0x1D, 0x1E, 0x20 }) + { + byte[] tmp = imagePlugin.ReadSector(rootSector); + rootMs.Write(tmp, 0, tmp.Length); + } + root_directory = rootMs.ToArray(); + rootMs = null; + } + for(int i = 0; i < root_directory.Length; i += 32) { // Not a correct entry