diff --git a/DiscImageChef.Filesystems/FAT.cs b/DiscImageChef.Filesystems/FAT.cs index 45c71c0ac..b783272f2 100644 --- a/DiscImageChef.Filesystems/FAT.cs +++ b/DiscImageChef.Filesystems/FAT.cs @@ -148,6 +148,7 @@ namespace DiscImageChef.Filesystems ushort apricot_fat_sectors = BitConverter.ToUInt16(bpb_sector, 0x5B); bool apricot_correct_spc = apricot_spc == 1 || apricot_spc == 2 || apricot_spc == 4 || apricot_spc == 8 || apricot_spc == 16 || apricot_spc == 32 || apricot_spc == 64; int bits_in_apricot_bps = Helpers.CountBits.Count(apricot_bps); + byte apricot_partitions = bpb_sector[0x0C]; DicConsole.DebugWriteLine("FAT plugin", "apricot_bps = {0}", apricot_bps); DicConsole.DebugWriteLine("FAT plugin", "apricot_spc = {0}", apricot_spc); @@ -209,7 +210,7 @@ namespace DiscImageChef.Filesystems // Apricot BPB if(bits_in_apricot_bps == 1 && apricot_correct_spc && apricot_reserved_secs < (partition.End - partition.Start) && apricot_fats_no <= 2 && apricot_root_entries > 0 && - apricot_fat_sectors > 0 && apricot_sectors <= (partition.End - partition.Start) + 1) + apricot_fat_sectors > 0 && apricot_sectors <= (partition.End - partition.Start) + 1 && apricot_partitions == 0) return true; // All FAT12 without BPB can only be used on floppies, without partitions. @@ -307,7 +308,7 @@ namespace DiscImageChef.Filesystems BIOSParameterBlockEBPB EBPB = new BIOSParameterBlockEBPB(); FAT32ParameterBlockShort shortFat32BPB = new FAT32ParameterBlockShort(); FAT32ParameterBlock Fat32BPB = new FAT32ParameterBlock(); - ApricotParameterBlock ApricotBPB = new ApricotParameterBlock(); + ApricotLabel ApricotBPB = new ApricotLabel(); byte[] bpb_sector = imagePlugin.ReadSectors(partition.Start, 2); @@ -326,7 +327,7 @@ namespace DiscImageChef.Filesystems EBPB = (BIOSParameterBlockEBPB)Marshal.PtrToStructure(bpbPtr, typeof(BIOSParameterBlockEBPB)); shortFat32BPB = (FAT32ParameterBlockShort)Marshal.PtrToStructure(bpbPtr, typeof(FAT32ParameterBlockShort)); Fat32BPB = (FAT32ParameterBlock)Marshal.PtrToStructure(bpbPtr, typeof(FAT32ParameterBlock)); - ApricotBPB = (ApricotParameterBlock)Marshal.PtrToStructure(bpbPtr, typeof(ApricotParameterBlock)); + ApricotBPB = (ApricotLabel)Marshal.PtrToStructure(bpbPtr, typeof(ApricotLabel)); Marshal.FreeHGlobal(bpbPtr); @@ -340,7 +341,7 @@ namespace DiscImageChef.Filesystems int bits_in_bps_dos40 = Helpers.CountBits.Count(EBPB.bps); int bits_in_bps_fat32_short = Helpers.CountBits.Count(shortFat32BPB.bps); int bits_in_bps_fat32 = Helpers.CountBits.Count(Fat32BPB.bps); - int bits_in_bps_apricot = Helpers.CountBits.Count(ApricotBPB.bps); + int bits_in_bps_apricot = Helpers.CountBits.Count(ApricotBPB.mainBPB.bps); bool correct_spc_atari = atariBPB.spc == 1 || atariBPB.spc == 2 || atariBPB.spc == 4 || atariBPB.spc == 8 || atariBPB.spc == 16 || atariBPB.spc == 32 || atariBPB.spc == 64; bool correct_spc_msx = msxBPB.spc == 1 || msxBPB.spc == 2 || msxBPB.spc == 4 || msxBPB.spc == 8 || msxBPB.spc == 16 || msxBPB.spc == 32 || msxBPB.spc == 64; @@ -352,7 +353,7 @@ namespace DiscImageChef.Filesystems bool correct_spc_dos40 = EBPB.spc == 1 || EBPB.spc == 2 || EBPB.spc == 4 || EBPB.spc == 8 || EBPB.spc == 16 || EBPB.spc == 32 || EBPB.spc == 64; 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; - bool correct_spc_apricot = ApricotBPB.spc == 1 || ApricotBPB.spc == 2 || ApricotBPB.spc == 4 || ApricotBPB.spc == 8 || ApricotBPB.spc == 16 || ApricotBPB.spc == 32 || ApricotBPB.spc == 64; + bool correct_spc_apricot = ApricotBPB.mainBPB.spc == 1 || ApricotBPB.mainBPB.spc == 2 || ApricotBPB.mainBPB.spc == 4 || ApricotBPB.mainBPB.spc == 8 || ApricotBPB.mainBPB.spc == 16 || ApricotBPB.mainBPB.spc == 32 || ApricotBPB.mainBPB.spc == 64; // This is to support FAT partitions on hybrid ISO/USB images if(imagePlugin.ImageInfo.xmlMediaType == ImagePlugins.XmlMediaType.OpticalDisc) @@ -373,7 +374,7 @@ namespace DiscImageChef.Filesystems shortFat32BPB.huge_sectors /= 4; Fat32BPB.sectors /= 4; Fat32BPB.big_sectors /= 4; - ApricotBPB.sectors /= 4; + ApricotBPB.mainBPB.sectors /= 4; } andos_oem_correct = dos33BPB.oem_name[0] < 0x20 && dos33BPB.oem_name[1] >= 0x20 && dos33BPB.oem_name[2] >= 0x20 && dos33BPB.oem_name[3] >= 0x20 && @@ -394,7 +395,7 @@ namespace DiscImageChef.Filesystems DicConsole.DebugWriteLine("FAT plugin", "Using MSX BPB"); useMSXBPB = true; } - else if(bits_in_bps_apricot == 1 && correct_spc_apricot && ApricotBPB.fats_no <= 2 && ApricotBPB.root_ent > 0 && ApricotBPB.sectors <= (partition.End - partition.Start) + 1 && ApricotBPB.spfat > 0) + else if(bits_in_bps_apricot == 1 && correct_spc_apricot && ApricotBPB.mainBPB.fats_no <= 2 && ApricotBPB.mainBPB.root_ent > 0 && ApricotBPB.mainBPB.sectors <= (partition.End - partition.Start) + 1 && ApricotBPB.mainBPB.spfat > 0 && ApricotBPB.partitionCount == 0) { DicConsole.DebugWriteLine("FAT plugin", "Using Apricot BPB"); useApricotBPB = true; @@ -956,15 +957,20 @@ namespace DiscImageChef.Filesystems else if(useApricotBPB) { isFAT12 = true; - fakeBPB.bps = ApricotBPB.bps; - fakeBPB.spc = ApricotBPB.spc; - fakeBPB.rsectors = ApricotBPB.rsectors; - fakeBPB.fats_no = ApricotBPB.fats_no; - fakeBPB.root_ent = ApricotBPB.root_ent; - fakeBPB.sectors = ApricotBPB.sectors; - fakeBPB.media = ApricotBPB.media; - fakeBPB.spfat = ApricotBPB.spfat; - fakeBPB.boot_code = ApricotBPB.boot_code; + fakeBPB.bps = ApricotBPB.mainBPB.bps; + fakeBPB.spc = ApricotBPB.mainBPB.spc; + fakeBPB.rsectors = ApricotBPB.mainBPB.rsectors; + fakeBPB.fats_no = ApricotBPB.mainBPB.fats_no; + fakeBPB.root_ent = ApricotBPB.mainBPB.root_ent; + fakeBPB.sectors = ApricotBPB.mainBPB.sectors; + fakeBPB.media = ApricotBPB.mainBPB.media; + fakeBPB.spfat = ApricotBPB.mainBPB.spfat; + fakeBPB.sptrk = ApricotBPB.spt; + xmlFSType.Bootable = ApricotBPB.bootType > 0; + + if(ApricotBPB.bootLocation > 0 && ApricotBPB.bootLocation + ApricotBPB.bootSize < imagePlugin.GetSectors()) + fakeBPB.boot_code = imagePlugin.ReadSectors(ApricotBPB.bootLocation, + (uint)(ApricotBPB.sectorSize * ApricotBPB.bootSize) / imagePlugin.GetSectorSize()); } if(!isFAT32) @@ -1727,13 +1733,220 @@ namespace DiscImageChef.Filesystems public ushort boot_signature; } - /// Apricot BIOS Parameter Block. + /// Apricot Label. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ApricotLabel + { + /// Version of format which created disk + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] version; + /// Operating system. + public byte operatingSystem; + /// Software write protection. + [MarshalAs(UnmanagedType.U1)] + public bool writeProtected; + /// Copy protected. + [MarshalAs(UnmanagedType.U1)] + public bool copyProtected; + /// Boot type. + public byte bootType; + /// Partitions. + public byte partitionCount; + /// Is hard disk?. + [MarshalAs(UnmanagedType.U1)] + public bool winchester; + /// Sector size. + public ushort sectorSize; + /// Sectors per track. + public ushort spt; + /// Tracks per side. + public uint cylinders; + /// Sides. + public byte heads; + /// Interleave factor. + public byte interleave; + /// Skew factor. + public ushort skew; + /// Sector where boot code starts. + public uint bootLocation; + /// Size in sectors of boot code. + public ushort bootSize; + /// Address at which to load boot code. + public uint bootAddress; + /// Offset where to jump to boot. + public ushort bootOffset; + /// Segment where to jump to boot. + public ushort bootSegment; + /// First data sector. + public uint firstDataBlock; + /// Generation. + public ushort generation; + /// Copy count. + public ushort copyCount; + /// Maximum number of copies. + public ushort maxCopies; + /// Serial number. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] serialNumber; + /// Part number. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] partNumber; + /// Copyright. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] + public byte[] copyright; + /// BPB for whole disk. + public ApricotParameterBlock mainBPB; + /// Name of FONT file. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] fontName; + /// Name of KEYBOARD file. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] keyboardName; + /// Minor BIOS version. + public byte biosMinorVersion; + /// Major BIOS version. + public byte biosMajorVersion; + /// Diagnostics enabled?. + [MarshalAs(UnmanagedType.U1)] + public bool diagnosticsFlag; + /// Printer device. + public byte prnDevice; + /// Bell volume. + public byte bellVolume; + /// Cache enabled?. + [MarshalAs(UnmanagedType.U1)] + public bool enableCache; + /// Graphics enabled?. + [MarshalAs(UnmanagedType.U1)] + public bool enableGraphics; + /// Length in sectors of DOS. + public byte dosLength; + /// Length in sectors of FONT file. + public byte fontLength; + /// Length in sectors of KEYBOARD file. + public byte keyboardLength; + /// Starting sector of DOS. + public ushort dosStart; + /// Starting sector of FONT file. + public ushort fontStart; + /// Starting sector of KEYBOARD file. + public ushort keyboardStart; + /// Keyboard click volume. + public byte keyboardVolume; + /// Auto-repeat enabled?. + [MarshalAs(UnmanagedType.U1)] + public bool autorepeat; + /// Auto-repeat lead-in. + public byte autorepeatLeadIn; + /// Auto-repeat interval. + public byte autorepeatInterval; + /// Microscreen mode. + public byte microscreenMode; + /// Spare area for keyboard values expansion. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] spareKeyboard; + /// Screen line mode. + public byte lineMode; + /// Screen line width. + public byte lineWidth; + /// Screen disabled?. + [MarshalAs(UnmanagedType.U1)] + public bool imageOff; + /// Spare area for screen values expansion. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] + public byte[] spareScreen; + /// TX baud rate. + public byte txBaudRate; + /// RX baud rate. + public byte rxBaudRate; + /// TX bits. + public byte txBits; + /// RX bits. + public byte rxBits; + /// Stop bits. + public byte stopBits; + /// Parity enabled?. + [MarshalAs(UnmanagedType.U1)] + public bool parityCheck; + /// Parity type. + public byte parityType; + /// Xon/Xoff enabled on TX. + [MarshalAs(UnmanagedType.U1)] + public bool txXonXoff; + /// Xon/Xoff enabled on RX. + [MarshalAs(UnmanagedType.U1)] + public bool rxXonXoff; + /// Xon character. + public byte xonCharacter; + /// Xoff character. + public byte xoffCharacter; + /// Xon/Xoff buffer on RX. + public ushort rxXonXoffBuffer; + /// DTR/DSR enabled?. + [MarshalAs(UnmanagedType.U1)] + public bool dtrDsr; + /// CTS/RTS enabled?. + [MarshalAs(UnmanagedType.U1)] + public bool ctsRts; + /// NULLs after CR. + public byte nullsAfterCr; + /// NULLs after 0xFF. + public byte nullsAfterFF; + /// Send LF after CR in serial port. + [MarshalAs(UnmanagedType.U1)] + public bool lfAfterCRSerial; + /// BIOS error report in serial port. + [MarshalAs(UnmanagedType.U1)] + public bool biosErrorReportSerial; + /// Spare area for serial port values expansion. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] + public byte[] spareSerial; + /// Send LF after CR in parallel port. + [MarshalAs(UnmanagedType.U1)] + public bool lfAfterCrParallel; + /// Select line supported?. + [MarshalAs(UnmanagedType.U1)] + public bool selectLine; + /// Paper empty supported?. + [MarshalAs(UnmanagedType.U1)] + public bool paperEmpty; + /// Fault line supported?. + [MarshalAs(UnmanagedType.U1)] + public bool faultLine; + /// BIOS error report in parallel port. + [MarshalAs(UnmanagedType.U1)] + public bool biosErrorReportParallel; + /// Spare area for parallel port values expansion. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] spareParallel; + /// Spare area for Winchester values expansion. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] + public byte[] spareWinchester; + /// Parking enabled?. + [MarshalAs(UnmanagedType.U1)] + public bool parkingEnabled; + /// Format protection?. + [MarshalAs(UnmanagedType.U1)] + public bool formatProtection; + /// Spare area for RAM disk values expansion. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] spareRamDisk; + /// List of bad blocks. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public ushort[] badBlocks; + /// Array of partition BPBs. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public ApricotParameterBlock[] partitions; + /// Spare area. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 63)] + public byte[] spare; + /// CP/M double side indicator?. + public bool cpmDoubleSided; + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct ApricotParameterBlock { - /// Boot specific information - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 80)] - public byte[] boot_code; /// Bytes per sector public ushort bps; /// Sectors per cluster @@ -1752,11 +1965,8 @@ namespace DiscImageChef.Filesystems public ushort spfat; /// Disk type public byte diskType; - /// Reserved - public ushort reserved; - /// Unknown. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 416)] - public byte[] unknown; + /// Volume starting sector + public ushort startSector; } public const uint fsinfo_signature1 = 0x41615252; diff --git a/DiscImageChef.Partitions/Apricot.cs b/DiscImageChef.Partitions/Apricot.cs new file mode 100644 index 000000000..ef0255a51 --- /dev/null +++ b/DiscImageChef.Partitions/Apricot.cs @@ -0,0 +1,41 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : Apricot.cs +// Author(s) : Natalia Portillo +// +// Component : Component +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2017 Natalia Portillo +// ****************************************************************************/ +using System; +namespace DiscImageChef.Partitions +{ + public class Apricot + { + public Apricot() + { + } + } +}