2017-07-19 16:31:08 +01:00
// /***************************************************************************
2016-07-28 18:13:49 +01:00
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : FAT.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Microsoft FAT filesystem plugin.
//
// --[ Description ] ----------------------------------------------------------
//
// Identifies the Microsoft FAT filesystem and shows information.
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
2017-12-19 03:50:57 +00:00
// Copyright © 2011-2018 Natalia Portillo
2016-07-28 18:13:49 +01:00
// ****************************************************************************/
2014-04-17 19:58:14 +00:00
2011-03-03 18:34:33 +00:00
using System ;
2016-07-21 17:16:08 +01:00
using System.Collections.Generic ;
2017-12-19 19:33:46 +00:00
using System.IO ;
2017-12-21 07:08:26 +00:00
using System.Linq ;
2017-07-10 21:39:12 +01:00
using System.Runtime.InteropServices ;
2017-07-19 16:31:08 +01:00
using System.Text ;
2017-12-21 14:30:38 +00:00
using DiscImageChef.Checksums ;
2017-07-19 16:31:08 +01:00
using DiscImageChef.CommonTypes ;
using DiscImageChef.Console ;
2017-12-21 14:30:38 +00:00
using DiscImageChef.DiscImages ;
using DiscImageChef.Helpers ;
using Schemas ;
2015-10-18 22:04:03 +01:00
2016-07-21 16:15:39 +01:00
namespace DiscImageChef.Filesystems
2011-03-03 18:34:33 +00:00
{
2017-07-19 16:31:08 +01:00
// TODO: Differentiate between Atari and X68k FAT, as this one uses a standard BPB.
2017-08-14 22:06:58 +01:00
// X68K uses cdate/adate from direntry for extending filename
2017-07-01 03:26:08 +01:00
public class FAT : Filesystem
2014-04-14 02:29:13 +00:00
{
2015-10-05 20:04:05 +01:00
public FAT ( )
2011-03-03 18:34:33 +00:00
{
2014-04-14 02:29:13 +00:00
Name = "Microsoft File Allocation Table" ;
2017-12-22 08:43:22 +00:00
PluginUuid = new Guid ( "33513B2C-0D26-0D2D-32C3-79D8611158E0" ) ;
2017-06-06 21:23:20 +01:00
CurrentEncoding = Encoding . GetEncoding ( "IBM437" ) ;
2011-03-03 18:34:33 +00:00
}
2012-08-05 03:02:55 +00:00
2017-10-12 23:54:02 +01:00
public FAT ( Encoding encoding )
{
Name = "Microsoft File Allocation Table" ;
2017-12-22 08:43:22 +00:00
PluginUuid = new Guid ( "33513B2C-0D26-0D2D-32C3-79D8611158E0" ) ;
CurrentEncoding = encoding ? ? Encoding . GetEncoding ( "IBM437" ) ;
2017-10-12 23:54:02 +01:00
}
2017-12-21 14:30:38 +00:00
public FAT ( ImagePlugin imagePlugin , Partition partition , Encoding encoding )
2016-07-27 13:32:45 +01:00
{
Name = "Microsoft File Allocation Table" ;
2017-12-22 08:43:22 +00:00
PluginUuid = new Guid ( "33513B2C-0D26-0D2D-32C3-79D8611158E0" ) ;
CurrentEncoding = encoding ? ? Encoding . GetEncoding ( "IBM437" ) ;
2016-07-27 13:32:45 +01:00
}
2017-12-21 14:30:38 +00:00
public override bool Identify ( ImagePlugin imagePlugin , Partition partition )
2014-04-14 02:29:13 +00:00
{
2017-12-20 17:26:28 +00:00
if ( 2 + partition . Start > = partition . End ) return false ;
2014-07-09 19:49:14 +01:00
2017-07-10 21:39:12 +01:00
ushort bps ;
byte spc ;
2017-12-22 08:43:22 +00:00
byte numberOfFats ;
ushort reservedSecs ;
ushort rootEntries ;
2017-07-10 21:39:12 +01:00
ushort sectors ;
2017-12-22 08:43:22 +00:00
byte mediaDescriptor ;
ushort fatSectors ;
uint bigSectors ;
byte bpbSignature ;
byte fat32Signature ;
ulong hugeSectors ;
byte [ ] fat32Id = new byte [ 8 ] ;
byte [ ] msxId = new byte [ 6 ] ;
byte fatId ;
byte [ ] dosOem = new byte [ 8 ] ;
byte [ ] atariOem = new byte [ 6 ] ;
2017-07-10 21:39:12 +01:00
ushort bootable = 0 ;
2014-04-14 02:29:13 +00:00
2017-12-22 08:43:22 +00:00
byte [ ] bpbSector = imagePlugin . ReadSector ( 0 + partition . Start ) ;
byte [ ] fatSector = imagePlugin . ReadSector ( 1 + partition . Start ) ;
Array . Copy ( bpbSector , 0x02 , atariOem , 0 , 6 ) ;
Array . Copy ( bpbSector , 0x03 , dosOem , 0 , 8 ) ;
bps = BitConverter . ToUInt16 ( bpbSector , 0x00B ) ;
spc = bpbSector [ 0x00D ] ;
reservedSecs = BitConverter . ToUInt16 ( bpbSector , 0x00E ) ;
numberOfFats = bpbSector [ 0x010 ] ;
rootEntries = BitConverter . ToUInt16 ( bpbSector , 0x011 ) ;
sectors = BitConverter . ToUInt16 ( bpbSector , 0x013 ) ;
mediaDescriptor = bpbSector [ 0x015 ] ;
fatSectors = BitConverter . ToUInt16 ( bpbSector , 0x016 ) ;
Array . Copy ( bpbSector , 0x052 , msxId , 0 , 6 ) ;
bigSectors = BitConverter . ToUInt32 ( bpbSector , 0x020 ) ;
bpbSignature = bpbSector [ 0x026 ] ;
fat32Signature = bpbSector [ 0x042 ] ;
Array . Copy ( bpbSector , 0x052 , fat32Id , 0 , 8 ) ;
hugeSectors = BitConverter . ToUInt64 ( bpbSector , 0x052 ) ;
fatId = fatSector [ 0 ] ;
int bitsInBps = CountBits . Count ( bps ) ;
if ( imagePlugin . ImageInfo . SectorSize > = 512 ) bootable = BitConverter . ToUInt16 ( bpbSector , 0x1FE ) ;
bool correctSpc = spc = = 1 | | spc = = 2 | | spc = = 4 | | spc = = 8 | | spc = = 16 | | spc = = 32 | | spc = = 64 ;
string msxString = Encoding . ASCII . GetString ( msxId ) ;
string fat32String = Encoding . ASCII . GetString ( fat32Id ) ;
bool atariOemCorrect = atariOem [ 0 ] > = 0x20 & & atariOem [ 1 ] > = 0x20 & & atariOem [ 2 ] > = 0x20 & &
atariOem [ 3 ] > = 0x20 & & atariOem [ 4 ] > = 0x20 & & atariOem [ 5 ] > = 0x20 ;
bool dosOemCorrect = dosOem [ 0 ] > = 0x20 & & dosOem [ 1 ] > = 0x20 & & dosOem [ 2 ] > = 0x20 & &
dosOem [ 3 ] > = 0x20 & & dosOem [ 4 ] > = 0x20 & & dosOem [ 5 ] > = 0x20 & &
dosOem [ 6 ] > = 0x20 & & dosOem [ 7 ] > = 0x20 ;
string atariString = Encoding . ASCII . GetString ( atariOem ) ;
string oemString = Encoding . ASCII . GetString ( dosOem ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "atari_oem_correct = {0}" , atariOemCorrect ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "dos_oem_correct = {0}" , dosOemCorrect ) ;
2017-07-10 21:39:12 +01:00
DicConsole . DebugWriteLine ( "FAT plugin" , "bps = {0}" , bps ) ;
2017-12-22 08:43:22 +00:00
DicConsole . DebugWriteLine ( "FAT plugin" , "bits in bps = {0}" , bitsInBps ) ;
2017-07-10 21:39:12 +01:00
DicConsole . DebugWriteLine ( "FAT plugin" , "spc = {0}" , spc ) ;
2017-12-22 08:43:22 +00:00
DicConsole . DebugWriteLine ( "FAT plugin" , "correct_spc = {0}" , correctSpc ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "reserved_secs = {0}" , reservedSecs ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "fats_no = {0}" , numberOfFats ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "root_entries = {0}" , rootEntries ) ;
2017-07-10 21:39:12 +01:00
DicConsole . DebugWriteLine ( "FAT plugin" , "sectors = {0}" , sectors ) ;
2017-12-22 08:43:22 +00:00
DicConsole . DebugWriteLine ( "FAT plugin" , "media_descriptor = 0x{0:X2}" , mediaDescriptor ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "fat_sectors = {0}" , fatSectors ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "msx_id = \"{0}\"" , msxString ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "big_sectors = {0}" , bigSectors ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "bpb_signature = 0x{0:X2}" , bpbSignature ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "fat32_signature = 0x{0:X2}" , fat32Signature ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "fat32_id = \"{0}\"" , fat32String ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "huge_sectors = {0}" , hugeSectors ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "fat_id = 0x{0:X2}" , fatId ) ;
ushort apricotBps = BitConverter . ToUInt16 ( bpbSector , 0x50 ) ;
byte apricotSpc = bpbSector [ 0x52 ] ;
ushort apricotReservedSecs = BitConverter . ToUInt16 ( bpbSector , 0x53 ) ;
byte apricotFatsNo = bpbSector [ 0x55 ] ;
ushort apricotRootEntries = BitConverter . ToUInt16 ( bpbSector , 0x56 ) ;
ushort apricotSectors = BitConverter . ToUInt16 ( bpbSector , 0x58 ) ;
byte apricotMediaDescriptor = bpbSector [ 0x5A ] ;
ushort apricotFatSectors = BitConverter . ToUInt16 ( bpbSector , 0x5B ) ;
bool apricotCorrectSpc = apricotSpc = = 1 | | apricotSpc = = 2 | | apricotSpc = = 4 | | apricotSpc = = 8 | |
apricotSpc = = 16 | | apricotSpc = = 32 | | apricotSpc = = 64 ;
int bitsInApricotBps = CountBits . Count ( apricotBps ) ;
byte apricotPartitions = bpbSector [ 0x0C ] ;
DicConsole . DebugWriteLine ( "FAT plugin" , "apricot_bps = {0}" , apricotBps ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "apricot_spc = {0}" , apricotSpc ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "apricot_correct_spc = {0}" , apricotCorrectSpc ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "apricot_reserved_secs = {0}" , apricotReservedSecs ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "apricot_fats_no = {0}" , apricotFatsNo ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "apricot_root_entries = {0}" , apricotRootEntries ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "apricot_sectors = {0}" , apricotSectors ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "apricot_media_descriptor = 0x{0:X2}" , apricotMediaDescriptor ) ;
DicConsole . DebugWriteLine ( "FAT plugin" , "apricot_fat_sectors = {0}" , apricotFatSectors ) ;
2017-09-22 23:57:53 +01:00
2017-07-25 00:27:46 +01:00
// This is to support FAT partitions on hybrid ISO/USB images
2017-12-21 14:30:38 +00:00
if ( imagePlugin . ImageInfo . XmlMediaType = = XmlMediaType . OpticalDisc )
2017-07-25 00:27:46 +01:00
{
sectors / = 4 ;
2017-12-22 08:43:22 +00:00
bigSectors / = 4 ;
hugeSectors / = 4 ;
2017-07-25 00:27:46 +01:00
}
2017-12-22 08:43:22 +00:00
switch ( oemString ) {
2017-12-21 04:43:29 +00:00
// exFAT
case "EXFAT " : return false ;
// NTFS
2017-12-22 08:43:22 +00:00
case "NTFS " when bootable = = 0xAA55 & & numberOfFats = = 0 & & fatSectors = = 0 : return false ;
2017-12-21 04:43:29 +00:00
// QNX4
case "FQNX4FS " : return false ;
}
2017-07-10 21:39:12 +01:00
// HPFS
2017-07-23 19:58:11 +01:00
if ( 16 + partition . Start < = partition . End )
{
2017-12-22 08:43:22 +00:00
uint hpfsMagic1 , hpfsMagic2 ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
byte [ ] hpfsSbSector =
2017-12-19 20:33:03 +00:00
imagePlugin . ReadSector ( 16 + partition . Start ) ; // Seek to superblock, on logical sector 16
2017-12-22 08:43:22 +00:00
hpfsMagic1 = BitConverter . ToUInt32 ( hpfsSbSector , 0x000 ) ;
hpfsMagic2 = BitConverter . ToUInt32 ( hpfsSbSector , 0x004 ) ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( hpfsMagic1 = = 0xF995E849 & & hpfsMagic2 = = 0xFA53E9C5 ) return false ;
2017-07-23 19:58:11 +01:00
}
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
switch ( bitsInBps ) {
2017-12-21 04:43:29 +00:00
// FAT32 for sure
2017-12-22 08:43:22 +00:00
case 1 when correctSpc & & numberOfFats < = 2 & & sectors = = 0 & & fatSectors = = 0 & & fat32Signature = = 0x29 & & fat32String = = "FAT32 " : return true ;
2017-12-21 04:43:29 +00:00
// short FAT32
2017-12-22 08:43:22 +00:00
case 1 when correctSpc & & numberOfFats < = 2 & & sectors = = 0 & & fatSectors = = 0 & & fat32Signature = = 0x28 :
return bigSectors = = 0
? hugeSectors < = partition . End - partition . Start + 1
: bigSectors < = partition . End - partition . Start + 1 ;
2017-12-21 04:43:29 +00:00
// MSX-DOS FAT12
2017-12-22 08:43:22 +00:00
case 1 when correctSpc & & numberOfFats < = 2 & & rootEntries > 0 & & sectors < = partition . End - partition . Start + 1 & & fatSectors > 0 & & msxString = = "VOL_ID" : return true ;
2017-12-21 04:43:29 +00:00
// EBPB
2017-12-22 08:43:22 +00:00
case 1 when correctSpc & & numberOfFats < = 2 & & rootEntries > 0 & & fatSectors > 0 & & ( bpbSignature = = 0x28 | | bpbSignature = = 0x29 ) :
2017-12-21 04:43:29 +00:00
return sectors = = 0
2017-12-22 08:43:22 +00:00
? bigSectors < = partition . End - partition . Start + 1
2017-12-21 04:43:29 +00:00
: sectors < = partition . End - partition . Start + 1 ;
// BPB
2017-12-22 08:43:22 +00:00
case 1 when correctSpc & & reservedSecs < partition . End - partition . Start & & numberOfFats < = 2 & & rootEntries > 0 & & fatSectors > 0 :
2017-12-21 04:43:29 +00:00
return sectors = = 0
2017-12-22 08:43:22 +00:00
? bigSectors < = partition . End - partition . Start + 1
2017-12-21 04:43:29 +00:00
: sectors < = partition . End - partition . Start + 1 ;
}
2017-07-10 21:39:12 +01:00
2017-09-22 23:57:53 +01:00
// Apricot BPB
2017-12-22 08:43:22 +00:00
if ( bitsInApricotBps = = 1 & & apricotCorrectSpc & &
apricotReservedSecs < partition . End - partition . Start & & apricotFatsNo < = 2 & &
apricotRootEntries > 0 & & apricotFatSectors > 0 & &
apricotSectors < = partition . End - partition . Start + 1 & & apricotPartitions = = 0 ) return true ;
2017-09-22 23:57:53 +01:00
2017-07-10 21:39:12 +01:00
// All FAT12 without BPB can only be used on floppies, without partitions.
2017-12-19 20:33:03 +00:00
if ( partition . Start ! = 0 ) return false ;
2017-07-10 21:39:12 +01:00
2017-10-02 14:24:19 +01:00
// 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)
2017-12-22 08:43:22 +00:00
byte z80Di = bpbSector [ 0 ] ;
2017-10-02 14:24:19 +01:00
// First FAT1 sector resides at LBA 0x14
2017-12-22 08:43:22 +00:00
byte [ ] fat1Sector0 = imagePlugin . ReadSector ( 0x14 ) ;
2017-10-02 14:24:19 +01:00
// First FAT2 sector resides at LBA 0x1A
2017-12-22 08:43:22 +00:00
byte [ ] fat2Sector0 = imagePlugin . ReadSector ( 0x1A ) ;
bool equalFatIds = fat1Sector0 [ 0 ] = = fat2Sector0 [ 0 ] & & fat1Sector0 [ 1 ] = = fat2Sector0 [ 1 ] ;
2017-10-02 14:24:19 +01:00
// Volume is software interleaved 2:1
MemoryStream rootMs = new MemoryStream ( ) ;
2017-12-21 07:08:26 +00:00
foreach ( byte [ ] tmp in from ulong rootSector in new [ ] { 0x17 , 0x19 , 0x1B , 0x1D , 0x1E , 0x20 } select imagePlugin . ReadSector ( rootSector ) )
{ rootMs . Write ( tmp , 0 , tmp . Length ) ; }
2017-12-19 20:33:03 +00:00
2017-12-22 08:43:22 +00:00
byte [ ] rootDir = rootMs . ToArray ( ) ;
bool validRootDir = true ;
2017-10-02 14:24:19 +01:00
// Iterate all root directory
for ( int e = 0 ; e < 96 * 32 ; e + = 32 )
{
for ( int c = 0 ; c < 11 ; c + + )
2017-12-22 08:43:22 +00:00
if ( rootDir [ c + e ] < 0x20 & & rootDir [ c + e ] ! = 0x00 & & rootDir [ c + e ] ! = 0x05 | |
rootDir [ c + e ] = = 0xFF | | rootDir [ c + e ] = = 0x2E )
2017-10-02 14:24:19 +01:00
{
2017-12-22 08:43:22 +00:00
validRootDir = false ;
2017-10-02 14:24:19 +01:00
break ;
}
2017-12-22 08:43:22 +00:00
if ( ! validRootDir ) break ;
2017-10-02 14:24:19 +01:00
}
2017-12-22 08:43:22 +00:00
if ( z80Di = = 0xF3 & & equalFatIds & & ( fat1Sector0 [ 0 ] & 0xF0 ) = = 0xF0 & & fat1Sector0 [ 1 ] = = 0xFF & &
validRootDir ) return true ;
2017-10-02 14:24:19 +01:00
}
2017-12-22 08:43:22 +00:00
byte fat2 = fatSector [ 1 ] ;
byte fat3 = fatSector [ 2 ] ;
ushort fat2ndCluster = ( ushort ) ( ( ( fat2 < < 8 ) + fat3 ) & 0xFFF ) ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
DicConsole . DebugWriteLine ( "FAT plugin" , "1st fat cluster 1 = {0:X3}" , fat2ndCluster ) ;
if ( fat2ndCluster < 0xFF0 ) return false ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
ulong fat2SectorNo = 0 ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
switch ( fatId )
2014-04-14 02:29:13 +00:00
{
2017-07-10 21:39:12 +01:00
case 0xE5 :
2017-12-20 17:15:26 +00:00
if ( imagePlugin . ImageInfo . Sectors = = 2002 & & imagePlugin . ImageInfo . SectorSize = = 128 )
2017-12-22 08:43:22 +00:00
fat2SectorNo = 2 ;
2017-07-10 21:39:12 +01:00
break ;
case 0xFD :
2017-12-20 17:15:26 +00:00
if ( imagePlugin . ImageInfo . Sectors = = 4004 & & imagePlugin . ImageInfo . SectorSize = = 128 )
2017-12-22 08:43:22 +00:00
fat2SectorNo = 7 ;
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 2002 & & imagePlugin . ImageInfo . SectorSize = = 128 )
2017-12-22 08:43:22 +00:00
fat2SectorNo = 7 ;
2017-07-10 21:39:12 +01:00
break ;
case 0xFE :
2017-12-20 17:15:26 +00:00
if ( imagePlugin . ImageInfo . Sectors = = 320 & & imagePlugin . ImageInfo . SectorSize = = 512 )
2017-12-22 08:43:22 +00:00
fat2SectorNo = 2 ;
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 2002 & & imagePlugin . ImageInfo . SectorSize = = 128 )
2017-12-22 08:43:22 +00:00
fat2SectorNo = 7 ;
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 1232 & & imagePlugin . ImageInfo . SectorSize = = 1024 )
2017-12-22 08:43:22 +00:00
fat2SectorNo = 3 ;
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 616 & & imagePlugin . ImageInfo . SectorSize = = 1024 )
2017-12-22 08:43:22 +00:00
fat2SectorNo = 2 ;
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 720 & & imagePlugin . ImageInfo . SectorSize = = 128 )
2017-12-22 08:43:22 +00:00
fat2SectorNo = 5 ;
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 640 & & imagePlugin . ImageInfo . SectorSize = = 512 )
2017-12-22 08:43:22 +00:00
fat2SectorNo = 2 ;
2017-07-10 21:39:12 +01:00
break ;
case 0xFF :
2017-12-20 17:15:26 +00:00
if ( imagePlugin . ImageInfo . Sectors = = 640 & & imagePlugin . ImageInfo . SectorSize = = 512 )
2017-12-22 08:43:22 +00:00
fat2SectorNo = 2 ;
2017-07-10 21:39:12 +01:00
break ;
default :
2017-12-22 08:43:22 +00:00
if ( fatId < 0xE8 ) return false ;
2017-12-19 20:33:03 +00:00
2017-12-22 08:43:22 +00:00
fat2SectorNo = 2 ;
2017-07-10 21:39:12 +01:00
break ;
}
2017-12-22 08:43:22 +00:00
if ( fat2SectorNo > partition . End ) return false ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
DicConsole . DebugWriteLine ( "FAT plugin" , "2nd fat starts at = {0}" , fat2SectorNo ) ;
2014-06-07 17:21:40 +01:00
2017-12-22 08:43:22 +00:00
byte [ ] fat2Sector = imagePlugin . ReadSector ( fat2SectorNo ) ;
2012-08-05 21:10:54 +00:00
2017-12-22 08:43:22 +00:00
fat2 = fat2Sector [ 1 ] ;
fat3 = fat2Sector [ 2 ] ;
fat2ndCluster = ( ushort ) ( ( ( fat2 < < 8 ) + fat3 ) & 0xFFF ) ;
if ( fat2ndCluster < 0xFF0 ) return false ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
return fatId = = fat2Sector [ 0 ] ;
2017-07-10 21:39:12 +01:00
}
2017-12-21 14:30:38 +00:00
public override void GetInformation ( ImagePlugin imagePlugin , Partition partition ,
2017-12-19 20:33:03 +00:00
out string information )
2017-07-10 21:39:12 +01:00
{
information = "" ;
StringBuilder sb = new StringBuilder ( ) ;
2017-12-22 08:43:22 +00:00
XmlFsType = new FileSystemType ( ) ;
bool useAtariBpb = false ;
bool useMsxBpb = false ;
bool useDos2Bpb = false ;
bool useDos3Bpb = false ;
bool useDos32Bpb = false ;
bool useDos33Bpb = false ;
bool userShortExtendedBpb = false ;
bool useExtendedBpb = false ;
bool useShortFat32 = false ;
bool useLongFat32 = false ;
bool andosOemCorrect = false ;
bool useApricotBpb = false ;
bool useDecRainbowBpb = false ;
AtariParameterBlock atariBpb = new AtariParameterBlock ( ) ;
MsxParameterBlock msxBpb = new MsxParameterBlock ( ) ;
BiosParameterBlock2 dos2Bpb = new BiosParameterBlock2 ( ) ;
BiosParameterBlock30 dos30Bpb = new BiosParameterBlock30 ( ) ;
BiosParameterBlock32 dos32Bpb = new BiosParameterBlock32 ( ) ;
BiosParameterBlock33 dos33Bpb = new BiosParameterBlock33 ( ) ;
BiosParameterBlockShortEbpb shortEbpb = new BiosParameterBlockShortEbpb ( ) ;
BiosParameterBlockEbpb ebpb = new BiosParameterBlockEbpb ( ) ;
Fat32ParameterBlockShort shortFat32Bpb = new Fat32ParameterBlockShort ( ) ;
Fat32ParameterBlock fat32Bpb = new Fat32ParameterBlock ( ) ;
ApricotLabel apricotBpb = new ApricotLabel ( ) ;
byte [ ] bpbSector = imagePlugin . ReadSectors ( partition . Start , 2 ) ;
2016-04-19 02:11:47 +01:00
2017-12-20 17:15:26 +00:00
if ( imagePlugin . ImageInfo . SectorSize > = 256 )
2017-07-10 21:39:12 +01:00
{
IntPtr bpbPtr = Marshal . AllocHGlobal ( 512 ) ;
2017-12-22 08:43:22 +00:00
Marshal . Copy ( bpbSector , 0 , bpbPtr , 512 ) ;
atariBpb = ( AtariParameterBlock ) Marshal . PtrToStructure ( bpbPtr , typeof ( AtariParameterBlock ) ) ;
msxBpb = ( MsxParameterBlock ) Marshal . PtrToStructure ( bpbPtr , typeof ( MsxParameterBlock ) ) ;
dos2Bpb = ( BiosParameterBlock2 ) Marshal . PtrToStructure ( bpbPtr , typeof ( BiosParameterBlock2 ) ) ;
dos30Bpb = ( BiosParameterBlock30 ) Marshal . PtrToStructure ( bpbPtr , typeof ( BiosParameterBlock30 ) ) ;
dos32Bpb = ( BiosParameterBlock32 ) Marshal . PtrToStructure ( bpbPtr , typeof ( BiosParameterBlock32 ) ) ;
dos33Bpb = ( BiosParameterBlock33 ) Marshal . PtrToStructure ( bpbPtr , typeof ( BiosParameterBlock33 ) ) ;
shortEbpb =
( BiosParameterBlockShortEbpb ) Marshal . PtrToStructure ( bpbPtr , typeof ( BiosParameterBlockShortEbpb ) ) ;
ebpb = ( BiosParameterBlockEbpb ) Marshal . PtrToStructure ( bpbPtr , typeof ( BiosParameterBlockEbpb ) ) ;
shortFat32Bpb =
( Fat32ParameterBlockShort ) Marshal . PtrToStructure ( bpbPtr , typeof ( Fat32ParameterBlockShort ) ) ;
fat32Bpb = ( Fat32ParameterBlock ) Marshal . PtrToStructure ( bpbPtr , typeof ( Fat32ParameterBlock ) ) ;
apricotBpb = ( ApricotLabel ) Marshal . PtrToStructure ( bpbPtr , typeof ( ApricotLabel ) ) ;
2017-07-10 21:39:12 +01:00
Marshal . FreeHGlobal ( bpbPtr ) ;
2017-12-22 08:43:22 +00:00
int bitsInBpsAtari = CountBits . Count ( atariBpb . bps ) ;
int bitsInBpsMsx = CountBits . Count ( msxBpb . bps ) ;
int bitsInBpsDos20 = CountBits . Count ( dos2Bpb . bps ) ;
int bitsInBpsDos30 = CountBits . Count ( dos30Bpb . bps ) ;
int bitsInBpsDos32 = CountBits . Count ( dos32Bpb . bps ) ;
int bitsInBpsDos33 = CountBits . Count ( dos33Bpb . bps ) ;
int bitsInBpsDos34 = CountBits . Count ( shortEbpb . bps ) ;
int bitsInBpsDos40 = CountBits . Count ( ebpb . bps ) ;
int bitsInBpsFat32Short = CountBits . Count ( shortFat32Bpb . bps ) ;
int bitsInBpsFat32 = CountBits . Count ( fat32Bpb . bps ) ;
int bitsInBpsApricot = CountBits . Count ( apricotBpb . mainBPB . bps ) ;
bool correctSpcAtari = atariBpb . spc = = 1 | | atariBpb . spc = = 2 | | atariBpb . spc = = 4 | |
atariBpb . spc = = 8 | | atariBpb . spc = = 16 | | atariBpb . spc = = 32 | |
atariBpb . spc = = 64 ;
bool correctSpcMsx = msxBpb . spc = = 1 | | msxBpb . spc = = 2 | | msxBpb . spc = = 4 | | msxBpb . spc = = 8 | |
msxBpb . spc = = 16 | | msxBpb . spc = = 32 | | msxBpb . spc = = 64 ;
bool correctSpcDos20 = dos2Bpb . spc = = 1 | | dos2Bpb . spc = = 2 | | dos2Bpb . spc = = 4 | | dos2Bpb . spc = = 8 | |
dos2Bpb . spc = = 16 | | dos2Bpb . spc = = 32 | | dos2Bpb . spc = = 64 ;
bool correctSpcDos30 = dos30Bpb . spc = = 1 | | dos30Bpb . spc = = 2 | | dos30Bpb . spc = = 4 | |
dos30Bpb . spc = = 8 | | dos30Bpb . spc = = 16 | | dos30Bpb . spc = = 32 | |
dos30Bpb . spc = = 64 ;
bool correctSpcDos32 = dos32Bpb . spc = = 1 | | dos32Bpb . spc = = 2 | | dos32Bpb . spc = = 4 | |
dos32Bpb . spc = = 8 | | dos32Bpb . spc = = 16 | | dos32Bpb . spc = = 32 | |
dos32Bpb . spc = = 64 ;
bool correctSpcDos33 = dos33Bpb . spc = = 1 | | dos33Bpb . spc = = 2 | | dos33Bpb . spc = = 4 | |
dos33Bpb . spc = = 8 | | dos33Bpb . spc = = 16 | | dos33Bpb . spc = = 32 | |
dos33Bpb . spc = = 64 ;
bool correctSpcDos34 = shortEbpb . spc = = 1 | | shortEbpb . spc = = 2 | | shortEbpb . spc = = 4 | |
shortEbpb . spc = = 8 | | shortEbpb . spc = = 16 | | shortEbpb . spc = = 32 | |
shortEbpb . spc = = 64 ;
bool correctSpcDos40 = ebpb . spc = = 1 | | ebpb . spc = = 2 | | ebpb . spc = = 4 | | ebpb . spc = = 8 | |
ebpb . spc = = 16 | | ebpb . spc = = 32 | | ebpb . spc = = 64 ;
bool correctSpcFat32Short = shortFat32Bpb . spc = = 1 | | shortFat32Bpb . spc = = 2 | |
shortFat32Bpb . spc = = 4 | | shortFat32Bpb . spc = = 8 | |
shortFat32Bpb . spc = = 16 | | shortFat32Bpb . spc = = 32 | |
shortFat32Bpb . spc = = 64 ;
bool correctSpcFat32 = fat32Bpb . spc = = 1 | | fat32Bpb . spc = = 2 | | fat32Bpb . spc = = 4 | |
fat32Bpb . spc = = 8 | | fat32Bpb . spc = = 16 | | fat32Bpb . spc = = 32 | |
fat32Bpb . spc = = 64 ;
bool correctSpcApricot = 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 ;
2017-07-10 21:39:12 +01:00
2017-07-25 00:27:46 +01:00
// This is to support FAT partitions on hybrid ISO/USB images
2017-12-21 14:30:38 +00:00
if ( imagePlugin . ImageInfo . XmlMediaType = = XmlMediaType . OpticalDisc )
2017-07-25 00:27:46 +01:00
{
2017-12-22 08:43:22 +00:00
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 ;
apricotBpb . mainBPB . sectors / = 4 ;
2017-07-25 00:27:46 +01:00
}
2017-12-22 08:43:22 +00:00
andosOemCorrect = dos33Bpb . oem_name [ 0 ] < 0x20 & & dos33Bpb . oem_name [ 1 ] > = 0x20 & &
dos33Bpb . oem_name [ 2 ] > = 0x20 & & dos33Bpb . oem_name [ 3 ] > = 0x20 & &
dos33Bpb . oem_name [ 4 ] > = 0x20 & & dos33Bpb . oem_name [ 5 ] > = 0x20 & &
dos33Bpb . oem_name [ 6 ] > = 0x20 & & dos33Bpb . oem_name [ 7 ] > = 0x20 ;
2017-08-25 03:28:55 +01:00
2017-12-22 08:43:22 +00:00
if ( bitsInBpsFat32 = = 1 & & correctSpcFat32 & & fat32Bpb . fats_no < = 2 & & fat32Bpb . sectors = = 0 & &
fat32Bpb . spfat = = 0 & & fat32Bpb . signature = = 0x29 & &
Encoding . ASCII . GetString ( fat32Bpb . fs_type ) = = "FAT32 " )
2014-06-07 17:21:40 +01:00
{
2017-07-10 21:39:12 +01:00
DicConsole . DebugWriteLine ( "FAT plugin" , "Using FAT32 BPB" ) ;
2017-12-22 08:43:22 +00:00
useLongFat32 = true ;
2014-06-07 17:21:40 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( bitsInBpsFat32Short = = 1 & & correctSpcFat32Short & & shortFat32Bpb . fats_no < = 2 & &
shortFat32Bpb . sectors = = 0 & & shortFat32Bpb . spfat = = 0 & & shortFat32Bpb . signature = = 0x28 )
2014-06-07 17:21:40 +01:00
{
2017-07-10 21:39:12 +01:00
DicConsole . DebugWriteLine ( "FAT plugin" , "Using short FAT32 BPB" ) ;
2017-12-22 08:43:22 +00:00
useShortFat32 = shortFat32Bpb . big_sectors = = 0
? shortFat32Bpb . huge_sectors < = partition . End - partition . Start + 1
: shortFat32Bpb . big_sectors < = partition . End - partition . Start + 1 ;
2014-06-07 17:21:40 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( bitsInBpsMsx = = 1 & & correctSpcMsx & & msxBpb . fats_no < = 2 & & msxBpb . root_ent > 0 & &
msxBpb . sectors < = partition . End - partition . Start + 1 & & msxBpb . spfat > 0 & &
Encoding . ASCII . GetString ( msxBpb . vol_id ) = = "VOL_ID" )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using MSX BPB" ) ;
2017-12-22 08:43:22 +00:00
useMsxBpb = true ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( bitsInBpsApricot = = 1 & & correctSpcApricot & & 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 )
2017-09-22 23:57:53 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using Apricot BPB" ) ;
2017-12-22 08:43:22 +00:00
useApricotBpb = true ;
2017-09-22 23:57:53 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( bitsInBpsDos40 = = 1 & & correctSpcDos40 & & ebpb . fats_no < = 2 & & ebpb . root_ent > 0 & &
ebpb . spfat > 0 & & ( ebpb . signature = = 0x28 | | ebpb . signature = = 0x29 | | andosOemCorrect ) )
2014-06-07 17:21:40 +01:00
{
2017-12-22 08:43:22 +00:00
if ( ebpb . sectors = = 0 )
2014-06-07 17:21:40 +01:00
{
2017-12-22 08:43:22 +00:00
if ( ebpb . big_sectors < = partition . End - partition . Start + 1 )
if ( ebpb . signature = = 0x29 | | andosOemCorrect )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using DOS 4.0 BPB" ) ;
2017-12-22 08:43:22 +00:00
useExtendedBpb = true ;
2017-07-10 21:39:12 +01:00
}
else
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using DOS 3.4 BPB" ) ;
2017-12-22 08:43:22 +00:00
userShortExtendedBpb = true ;
2017-07-10 21:39:12 +01:00
}
}
2017-12-22 08:43:22 +00:00
else if ( ebpb . sectors < = partition . End - partition . Start + 1 )
if ( ebpb . signature = = 0x29 | | andosOemCorrect )
2014-06-07 17:21:40 +01:00
{
2017-07-10 21:39:12 +01:00
DicConsole . DebugWriteLine ( "FAT plugin" , "Using DOS 4.0 BPB" ) ;
2017-12-22 08:43:22 +00:00
useExtendedBpb = true ;
2017-07-10 21:39:12 +01:00
}
else
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using DOS 3.4 BPB" ) ;
2017-12-22 08:43:22 +00:00
userShortExtendedBpb = true ;
2014-06-07 17:21:40 +01:00
}
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( bitsInBpsDos33 = = 1 & & correctSpcDos33 & &
dos33Bpb . rsectors < partition . End - partition . Start & & dos33Bpb . fats_no < = 2 & &
dos33Bpb . root_ent > 0 & & dos33Bpb . spfat > 0 )
if ( dos33Bpb . sectors = = 0 & & dos33Bpb . hsectors < = partition . Start & & dos33Bpb . big_sectors > 0 & &
dos33Bpb . big_sectors < = partition . End - partition . Start + 1 )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using DOS 3.3 BPB" ) ;
2017-12-22 08:43:22 +00:00
useDos33Bpb = true ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( dos33Bpb . big_sectors = = 0 & & dos33Bpb . hsectors < = partition . Start & & dos33Bpb . sectors > 0 & &
dos33Bpb . sectors < = partition . End - partition . Start + 1 )
if ( atariBpb . jump [ 0 ] = = 0x60 | | atariBpb . jump [ 0 ] = = 0xE9 & & atariBpb . jump [ 1 ] = = 0x00 & &
Encoding . ASCII . GetString ( dos33Bpb . oem_name ) ! = "NEXT " )
2014-06-07 17:21:40 +01:00
{
2017-07-10 21:39:12 +01:00
DicConsole . DebugWriteLine ( "FAT plugin" , "Using Atari BPB" ) ;
2017-12-22 08:43:22 +00:00
useAtariBpb = true ;
2014-06-07 17:21:40 +01:00
}
2017-07-10 21:39:12 +01:00
else
2014-06-07 17:21:40 +01:00
{
2017-07-10 21:39:12 +01:00
DicConsole . DebugWriteLine ( "FAT plugin" , "Using DOS 3.3 BPB" ) ;
2017-12-22 08:43:22 +00:00
useDos33Bpb = true ;
2017-07-10 21:39:12 +01:00
}
else
{
2017-12-22 08:43:22 +00:00
if ( dos32Bpb . hsectors < = partition . Start & &
dos32Bpb . hsectors + dos32Bpb . sectors = = dos32Bpb . total_sectors )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using DOS 3.2 BPB" ) ;
2017-12-22 08:43:22 +00:00
useDos32Bpb = true ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( dos30Bpb . sptrk > 0 & & dos30Bpb . sptrk < 64 & & dos30Bpb . heads > 0 & & dos30Bpb . heads < 256 )
if ( atariBpb . jump [ 0 ] = = 0x60 | | atariBpb . jump [ 0 ] = = 0xE9 & & atariBpb . jump [ 1 ] = = 0x00 & &
Encoding . ASCII . GetString ( dos33Bpb . oem_name ) ! = "NEXT " )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using Atari BPB" ) ;
2017-12-22 08:43:22 +00:00
useAtariBpb = true ;
2017-07-10 21:39:12 +01:00
}
else
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using DOS 3.0 BPB" ) ;
2017-12-22 08:43:22 +00:00
useDos3Bpb = true ;
2017-07-10 21:39:12 +01:00
}
else
{
2017-12-22 08:43:22 +00:00
if ( atariBpb . jump [ 0 ] = = 0x60 | | atariBpb . jump [ 0 ] = = 0xE9 & & atariBpb . jump [ 1 ] = = 0x00 & &
Encoding . ASCII . GetString ( dos33Bpb . oem_name ) ! = "NEXT " )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using Atari BPB" ) ;
2017-12-22 08:43:22 +00:00
useAtariBpb = true ;
2017-07-10 21:39:12 +01:00
}
else
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using DOS 2.0 BPB" ) ;
2017-12-22 08:43:22 +00:00
useDos2Bpb = true ;
2017-07-10 21:39:12 +01:00
}
2014-06-07 17:21:40 +01:00
}
}
2014-04-14 02:29:13 +00:00
}
2011-03-03 18:34:33 +00:00
2017-12-22 08:43:22 +00:00
BiosParameterBlockEbpb fakeBpb = new BiosParameterBlockEbpb ( ) ;
bool isFat12 = false ;
bool isFat16 = false ;
bool isFat32 = false ;
ulong rootDirectorySector = 0 ;
2017-07-10 21:39:12 +01:00
string extraInfo = null ;
string bootChk = null ;
2017-12-21 14:30:38 +00:00
Sha1Context sha1Ctx = new Sha1Context ( ) ;
2017-07-10 21:39:12 +01:00
sha1Ctx . Init ( ) ;
2014-04-14 02:29:13 +00:00
2017-07-10 21:39:12 +01:00
// This is needed because for FAT16, GEMDOS increases bytes per sector count instead of using big_sectors field.
2017-12-22 08:43:22 +00:00
uint sectorsPerRealSector ;
2017-07-15 01:37:28 +01:00
// This is needed because some OSes don't put volume label as first entry in the root directory
2017-12-22 08:43:22 +00:00
uint sectorsForRootDirectory = 0 ;
2016-04-19 02:11:47 +01:00
2017-10-02 14:24:19 +01:00
// DEC Rainbow, lacks a BPB but has a very concrete structure...
2017-12-22 08:43:22 +00:00
if ( imagePlugin . GetSectors ( ) = = 800 & & imagePlugin . GetSectorSize ( ) = = 512 & & ! useAtariBpb & & ! useMsxBpb & &
! useDos2Bpb & & ! useDos3Bpb & & ! useDos32Bpb & & ! useDos33Bpb & & ! userShortExtendedBpb & & ! useExtendedBpb & &
! useShortFat32 & & ! useLongFat32 & & ! useApricotBpb )
2017-10-02 14:24:19 +01:00
{
// DEC Rainbow boots up with a Z80, first byte should be DI (disable interrupts)
2017-12-22 08:43:22 +00:00
byte z80Di = bpbSector [ 0 ] ;
2017-10-02 14:24:19 +01:00
// First FAT1 sector resides at LBA 0x14
2017-12-22 08:43:22 +00:00
byte [ ] fat1Sector0 = imagePlugin . ReadSector ( 0x14 ) ;
2017-10-02 14:24:19 +01:00
// First FAT2 sector resides at LBA 0x1A
2017-12-22 08:43:22 +00:00
byte [ ] fat2Sector0 = imagePlugin . ReadSector ( 0x1A ) ;
bool equalFatIds = fat1Sector0 [ 0 ] = = fat2Sector0 [ 0 ] & & fat1Sector0 [ 1 ] = = fat2Sector0 [ 1 ] ;
2017-10-02 14:24:19 +01:00
// Volume is software interleaved 2:1
MemoryStream rootMs = new MemoryStream ( ) ;
2017-12-21 07:08:26 +00:00
foreach ( byte [ ] tmp in from ulong rootSector in new [ ] { 0x17 , 0x19 , 0x1B , 0x1D , 0x1E , 0x20 } select imagePlugin . ReadSector ( rootSector ) )
{ rootMs . Write ( tmp , 0 , tmp . Length ) ; }
2017-12-19 20:33:03 +00:00
2017-12-22 08:43:22 +00:00
byte [ ] rootDir = rootMs . ToArray ( ) ;
bool validRootDir = true ;
2017-10-02 14:24:19 +01:00
// Iterate all root directory
for ( int e = 0 ; e < 96 * 32 ; e + = 32 )
{
for ( int c = 0 ; c < 11 ; c + + )
2017-12-22 08:43:22 +00:00
if ( rootDir [ c + e ] < 0x20 & & rootDir [ c + e ] ! = 0x00 & & rootDir [ c + e ] ! = 0x05 | |
rootDir [ c + e ] = = 0xFF | | rootDir [ c + e ] = = 0x2E )
2017-10-02 14:24:19 +01:00
{
2017-12-22 08:43:22 +00:00
validRootDir = false ;
2017-10-02 14:24:19 +01:00
break ;
}
2017-12-22 08:43:22 +00:00
if ( ! validRootDir ) break ;
2017-10-02 14:24:19 +01:00
}
2017-12-22 08:43:22 +00:00
if ( z80Di = = 0xF3 & & equalFatIds & & ( fat1Sector0 [ 0 ] & 0xF0 ) = = 0xF0 & & fat1Sector0 [ 1 ] = = 0xFF & &
validRootDir )
2017-10-02 14:24:19 +01:00
{
2017-12-22 08:43:22 +00:00
useDecRainbowBpb = true ;
2017-10-02 14:24:19 +01:00
DicConsole . DebugWriteLine ( "FAT plugin" , "Using DEC Rainbow hardcoded BPB." ) ;
2017-12-22 08:43:22 +00:00
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 = bpbSector ;
isFat12 = true ;
2017-10-02 14:24:19 +01:00
}
}
2017-12-22 08:43:22 +00:00
if ( ! useAtariBpb & & ! useMsxBpb & & ! useDos2Bpb & & ! useDos3Bpb & & ! useDos32Bpb & & ! useDos33Bpb & &
! userShortExtendedBpb & & ! useExtendedBpb & & ! useShortFat32 & & ! useLongFat32 & & ! useApricotBpb & & ! useDecRainbowBpb )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
isFat12 = true ;
byte [ ] fatSector = imagePlugin . ReadSector ( 1 + partition . Start ) ;
switch ( fatSector [ 0 ] )
2017-07-10 21:39:12 +01:00
{
case 0xE5 :
2017-12-20 17:15:26 +00:00
if ( imagePlugin . ImageInfo . Sectors = = 2002 & & imagePlugin . ImageInfo . SectorSize = = 128 )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using hardcoded BPB." ) ;
2017-12-22 08:43:22 +00:00
fakeBpb . bps = 128 ;
fakeBpb . spc = 4 ;
fakeBpb . rsectors = 1 ;
fakeBpb . fats_no = 2 ;
fakeBpb . root_ent = 64 ;
fakeBpb . sectors = 2002 ;
fakeBpb . media = 0xE5 ;
fakeBpb . sptrk = 26 ;
fakeBpb . heads = 1 ;
fakeBpb . hsectors = 0 ;
fakeBpb . spfat = 1 ;
2017-07-10 21:39:12 +01:00
}
break ;
case 0xFD :
2017-12-20 17:15:26 +00:00
if ( imagePlugin . ImageInfo . Sectors = = 4004 & & imagePlugin . ImageInfo . SectorSize = = 128 )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using hardcoded BPB." ) ;
2017-12-22 08:43:22 +00:00
fakeBpb . bps = 128 ;
fakeBpb . spc = 4 ;
fakeBpb . rsectors = 4 ;
fakeBpb . fats_no = 2 ;
fakeBpb . root_ent = 68 ;
fakeBpb . sectors = 4004 ;
fakeBpb . media = 0xFD ;
fakeBpb . sptrk = 26 ;
fakeBpb . heads = 2 ;
fakeBpb . hsectors = 0 ;
fakeBpb . spfat = 6 ;
2017-07-10 21:39:12 +01:00
}
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 2002 & & imagePlugin . ImageInfo . SectorSize = = 128 )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using hardcoded BPB." ) ;
2017-12-22 08:43:22 +00:00
fakeBpb . bps = 128 ;
fakeBpb . spc = 4 ;
fakeBpb . rsectors = 4 ;
fakeBpb . fats_no = 2 ;
fakeBpb . root_ent = 68 ;
fakeBpb . sectors = 2002 ;
fakeBpb . media = 0xFD ;
fakeBpb . sptrk = 26 ;
fakeBpb . heads = 1 ;
fakeBpb . hsectors = 0 ;
fakeBpb . spfat = 6 ;
2017-07-10 21:39:12 +01:00
}
break ;
case 0xFE :
2017-12-20 17:15:26 +00:00
if ( imagePlugin . ImageInfo . Sectors = = 320 & & imagePlugin . ImageInfo . SectorSize = = 512 )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using hardcoded BPB for 5.25\" SSDD." ) ;
2017-12-22 08:43:22 +00:00
fakeBpb . bps = 512 ;
fakeBpb . spc = 1 ;
fakeBpb . rsectors = 1 ;
fakeBpb . fats_no = 2 ;
fakeBpb . root_ent = 64 ;
fakeBpb . sectors = 320 ;
fakeBpb . media = 0xFE ;
fakeBpb . sptrk = 8 ;
fakeBpb . heads = 1 ;
fakeBpb . hsectors = 0 ;
fakeBpb . spfat = 1 ;
2017-07-10 21:39:12 +01:00
}
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 2002 & & imagePlugin . ImageInfo . SectorSize = = 128 )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using hardcoded BPB." ) ;
2017-12-22 08:43:22 +00:00
fakeBpb . bps = 128 ;
fakeBpb . spc = 4 ;
fakeBpb . rsectors = 1 ;
fakeBpb . fats_no = 2 ;
fakeBpb . root_ent = 68 ;
fakeBpb . sectors = 2002 ;
fakeBpb . media = 0xFE ;
fakeBpb . sptrk = 26 ;
fakeBpb . heads = 1 ;
fakeBpb . hsectors = 0 ;
fakeBpb . spfat = 6 ;
2017-07-10 21:39:12 +01:00
}
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 1232 & & imagePlugin . ImageInfo . SectorSize = = 1024 )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using hardcoded BPB." ) ;
2017-12-22 08:43:22 +00:00
fakeBpb . bps = 1024 ;
fakeBpb . spc = 1 ;
fakeBpb . rsectors = 1 ;
fakeBpb . fats_no = 2 ;
fakeBpb . root_ent = 192 ;
fakeBpb . sectors = 1232 ;
fakeBpb . media = 0xFE ;
fakeBpb . sptrk = 8 ;
fakeBpb . heads = 2 ;
fakeBpb . hsectors = 0 ;
fakeBpb . spfat = 2 ;
2017-07-10 21:39:12 +01:00
}
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 616 & & imagePlugin . ImageInfo . SectorSize = = 1024 )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using hardcoded BPB." ) ;
2017-12-22 08:43:22 +00:00
fakeBpb . bps = 1024 ;
fakeBpb . spc = 1 ;
fakeBpb . rsectors = 1 ;
fakeBpb . fats_no = 2 ;
fakeBpb . root_ent = 6192 ;
fakeBpb . sectors = 616 ;
fakeBpb . media = 0xFE ;
fakeBpb . sptrk = 8 ;
fakeBpb . heads = 2 ;
fakeBpb . hsectors = 0 ;
2017-07-10 21:39:12 +01:00
}
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 720 & & imagePlugin . ImageInfo . SectorSize = = 128 )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using hardcoded BPB." ) ;
2017-12-22 08:43:22 +00:00
fakeBpb . bps = 128 ;
fakeBpb . spc = 2 ;
fakeBpb . rsectors = 54 ;
fakeBpb . fats_no = 2 ;
fakeBpb . root_ent = 64 ;
fakeBpb . sectors = 720 ;
fakeBpb . media = 0xFE ;
fakeBpb . sptrk = 18 ;
fakeBpb . heads = 1 ;
fakeBpb . hsectors = 0 ;
fakeBpb . spfat = 4 ;
2017-07-10 21:39:12 +01:00
}
2017-12-20 17:15:26 +00:00
else if ( imagePlugin . ImageInfo . Sectors = = 640 & & imagePlugin . ImageInfo . SectorSize = = 512 )
2017-09-27 12:36:02 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using hardcoded BPB for 5.25\" DSDD." ) ;
2017-12-22 08:43:22 +00:00
fakeBpb . bps = 512 ;
fakeBpb . spc = 2 ;
fakeBpb . rsectors = 1 ;
fakeBpb . fats_no = 2 ;
fakeBpb . root_ent = 112 ;
fakeBpb . sectors = 640 ;
fakeBpb . media = 0xFF ;
fakeBpb . sptrk = 8 ;
fakeBpb . heads = 2 ;
fakeBpb . hsectors = 0 ;
fakeBpb . spfat = 1 ;
2017-09-27 12:36:02 +01:00
}
2017-07-10 21:39:12 +01:00
break ;
case 0xFF :
2017-12-20 17:15:26 +00:00
if ( imagePlugin . ImageInfo . Sectors = = 640 & & imagePlugin . ImageInfo . SectorSize = = 512 )
2017-07-10 21:39:12 +01:00
{
DicConsole . DebugWriteLine ( "FAT plugin" , "Using hardcoded BPB for 5.25\" DSDD." ) ;
2017-12-22 08:43:22 +00:00
fakeBpb . bps = 512 ;
fakeBpb . spc = 2 ;
fakeBpb . rsectors = 1 ;
fakeBpb . fats_no = 2 ;
fakeBpb . root_ent = 112 ;
fakeBpb . sectors = 640 ;
fakeBpb . media = 0xFF ;
fakeBpb . sptrk = 8 ;
fakeBpb . heads = 2 ;
fakeBpb . hsectors = 0 ;
fakeBpb . spfat = 1 ;
2017-07-10 21:39:12 +01:00
}
break ;
}
2012-08-05 03:02:55 +00:00
2017-07-10 21:39:12 +01:00
// This assumes a bootable sector will jump somewhere or disable interrupts in x86 code
2017-12-22 08:43:22 +00:00
XmlFsType . Bootable | = bpbSector [ 0 ] = = 0xFA | | bpbSector [ 0 ] = = 0xEB & & bpbSector [ 1 ] < = 0x7F ;
fakeBpb . boot_code = bpbSector ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( useShortFat32 | | useLongFat32 )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
isFat32 = true ;
2012-08-05 03:02:55 +00:00
2017-07-25 00:27:46 +01:00
// This is to support FAT partitions on hybrid ISO/USB images
2017-12-21 14:30:38 +00:00
if ( imagePlugin . ImageInfo . XmlMediaType = = XmlMediaType . OpticalDisc )
2017-07-25 00:27:46 +01:00
{
2017-12-22 08:43:22 +00:00
fat32Bpb . bps * = 4 ;
fat32Bpb . spc / = 4 ;
fat32Bpb . big_spfat / = 4 ;
fat32Bpb . hsectors / = 4 ;
fat32Bpb . sptrk / = 4 ;
2017-07-25 00:27:46 +01:00
}
2017-12-22 08:43:22 +00:00
if ( fat32Bpb . version ! = 0 )
2017-07-10 21:39:12 +01:00
{
sb . AppendLine ( "FAT+" ) ;
2017-12-22 08:43:22 +00:00
XmlFsType . Type = "FAT+" ;
2017-07-10 21:39:12 +01:00
}
else
{
sb . AppendLine ( "Microsoft FAT32" ) ;
2017-12-22 08:43:22 +00:00
XmlFsType . Type = "FAT32" ;
2017-07-10 21:39:12 +01:00
}
2014-06-07 17:21:40 +01:00
2017-12-22 08:43:22 +00:00
if ( fat32Bpb . oem_name ! = null )
if ( fat32Bpb . oem_name [ 5 ] = = 0x49 & & fat32Bpb . oem_name [ 6 ] = = 0x48 & & fat32Bpb . oem_name [ 7 ] = = 0x43 )
2017-07-10 21:39:12 +01:00
sb . AppendLine ( "Volume has been modified by Windows 9x/Me Volume Tracker." ) ;
2017-12-22 08:43:22 +00:00
else XmlFsType . SystemIdentifier = StringHandlers . CToString ( fat32Bpb . oem_name ) ;
if ( ! string . IsNullOrEmpty ( XmlFsType . SystemIdentifier ) )
sb . AppendFormat ( "OEM Name: {0}" , XmlFsType . SystemIdentifier . Trim ( ) ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} bytes per sector." , fat32Bpb . bps ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} sectors per cluster." , fat32Bpb . spc ) . AppendLine ( ) ;
XmlFsType . ClusterSize = fat32Bpb . bps * fat32Bpb . spc ;
sb . AppendFormat ( "{0} sectors reserved between BPB and FAT." , fat32Bpb . rsectors ) . AppendLine ( ) ;
if ( fat32Bpb . big_sectors = = 0 & & fat32Bpb . signature = = 0x28 )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} sectors on volume ({1} bytes)." , shortFat32Bpb . huge_sectors ,
shortFat32Bpb . huge_sectors * shortFat32Bpb . bps ) . AppendLine ( ) ;
XmlFsType . Clusters = ( long ) ( shortFat32Bpb . huge_sectors / shortFat32Bpb . spc ) ;
2017-07-10 21:39:12 +01:00
}
else
{
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} sectors on volume ({1} bytes)." , fat32Bpb . big_sectors ,
fat32Bpb . big_sectors * fat32Bpb . bps ) . AppendLine ( ) ;
XmlFsType . Clusters = fat32Bpb . big_sectors / fat32Bpb . spc ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} clusters on volume." , XmlFsType . Clusters ) . AppendLine ( ) ;
sb . AppendFormat ( "Media descriptor: 0x{0:X2}" , fat32Bpb . media ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} sectors per FAT." , fat32Bpb . big_spfat ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} sectors per track." , fat32Bpb . sptrk ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} heads." , fat32Bpb . heads ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} hidden sectors before BPB." , fat32Bpb . hsectors ) . AppendLine ( ) ;
sb . AppendFormat ( "Cluster of root directory: {0}" , fat32Bpb . root_cluster ) . AppendLine ( ) ;
sb . AppendFormat ( "Sector of FSINFO structure: {0}" , fat32Bpb . fsinfo_sector ) . AppendLine ( ) ;
sb . AppendFormat ( "Sector of backup FAT32 parameter block: {0}" , fat32Bpb . backup_sector ) . AppendLine ( ) ;
sb . AppendFormat ( "Drive number: 0x{0:X2}" , fat32Bpb . drive_no ) . AppendLine ( ) ;
sb . AppendFormat ( "Volume Serial Number: 0x{0:X8}" , fat32Bpb . serial_no ) . AppendLine ( ) ;
XmlFsType . VolumeSerial = $"{fat32Bpb.serial_no:X8}" ;
if ( ( fat32Bpb . flags & 0xF8 ) = = 0x00 )
2014-06-07 17:21:40 +01:00
{
2017-12-22 08:43:22 +00:00
if ( ( fat32Bpb . flags & 0x01 ) = = 0x01 )
2016-09-13 12:58:19 +01:00
{
2017-07-10 21:39:12 +01:00
sb . AppendLine ( "Volume should be checked on next mount." ) ;
2017-12-22 08:43:22 +00:00
XmlFsType . Dirty = true ;
2016-09-13 12:58:19 +01:00
}
2017-12-22 08:43:22 +00:00
if ( ( fat32Bpb . flags & 0x02 ) = = 0x02 ) sb . AppendLine ( "Disk surface should be on next mount." ) ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
if ( ( fat32Bpb . mirror_flags & 0x80 ) = = 0x80 )
sb . AppendFormat ( "FATs are out of sync. FAT #{0} is in use." , fat32Bpb . mirror_flags & 0xF )
2017-12-19 20:33:03 +00:00
. AppendLine ( ) ;
else sb . AppendLine ( "All copies of FAT are the same." ) ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( ( fat32Bpb . mirror_flags & 0x6F20 ) = = 0x6F20 ) sb . AppendLine ( "DR-DOS will boot this FAT32 using CHS." ) ;
else if ( ( fat32Bpb . mirror_flags & 0x4F20 ) = = 0x4F20 )
2017-07-10 21:39:12 +01:00
sb . AppendLine ( "DR-DOS will boot this FAT32 using LBA." ) ;
2017-12-22 08:43:22 +00:00
if ( fat32Bpb . signature = = 0x29 )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
XmlFsType . VolumeName = Encoding . ASCII . GetString ( fat32Bpb . volume_label ) ;
sb . AppendFormat ( "Filesystem type: {0}" , Encoding . ASCII . GetString ( fat32Bpb . fs_type ) ) . AppendLine ( ) ;
bootChk = sha1Ctx . Data ( fat32Bpb . boot_code , out _ ) ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else bootChk = sha1Ctx . Data ( shortFat32Bpb . boot_code , out _ ) ;
2017-07-10 21:39:12 +01:00
// Check that jumps to a correct boot code position and has boot signature set.
// This will mean that the volume will boot, even if just to say "this is not bootable change disk"......
2017-12-22 08:43:22 +00:00
XmlFsType . Bootable | = fat32Bpb . jump [ 0 ] = = 0xEB & & fat32Bpb . jump [ 1 ] > 0x58 & & fat32Bpb . jump [ 1 ] < 0x80 & &
fat32Bpb . boot_signature = = 0xAA55 ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
sectorsPerRealSector = fat32Bpb . bps / imagePlugin . ImageInfo . SectorSize ;
2017-07-10 21:39:12 +01:00
// First root directory sector
2017-12-22 08:43:22 +00:00
rootDirectorySector =
( ulong ) ( ( fat32Bpb . root_cluster - 2 ) * fat32Bpb . spc + fat32Bpb . big_spfat * fat32Bpb . fats_no +
fat32Bpb . rsectors ) * sectorsPerRealSector ;
sectorsForRootDirectory = 1 ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( fat32Bpb . fsinfo_sector + partition . Start < = partition . End )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
byte [ ] fsinfoSector = imagePlugin . ReadSector ( fat32Bpb . fsinfo_sector + partition . Start ) ;
IntPtr fsinfoPtr = Marshal . AllocHGlobal ( 512 ) ;
Marshal . Copy ( fsinfoSector , 0 , fsinfoPtr , 512 ) ;
FsInfoSector fsInfo = ( FsInfoSector ) Marshal . PtrToStructure ( fsinfoPtr , typeof ( FsInfoSector ) ) ;
Marshal . FreeHGlobal ( fsinfoPtr ) ;
if ( fsInfo . signature1 = = FSINFO_SIGNATURE1 & & fsInfo . signature2 = = FSINFO_SIGNATURE2 & &
fsInfo . signature3 = = FSINFO_SIGNATURE3 )
2016-09-13 12:58:19 +01:00
{
2017-12-22 08:43:22 +00:00
if ( fsInfo . free_clusters < 0xFFFFFFFF )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} free clusters" , fsInfo . free_clusters ) . AppendLine ( ) ;
XmlFsType . FreeClusters = fsInfo . free_clusters ;
XmlFsType . FreeClustersSpecified = true ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
if ( fsInfo . last_cluster > 2 & & fsInfo . last_cluster < 0xFFFFFFFF )
sb . AppendFormat ( "Last allocated cluster {0}" , fsInfo . last_cluster ) . AppendLine ( ) ;
2016-09-13 12:58:19 +01:00
}
2014-06-07 17:21:40 +01:00
}
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( useExtendedBpb ) fakeBpb = ebpb ;
else if ( userShortExtendedBpb )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
fakeBpb . jump = shortEbpb . jump ;
fakeBpb . oem_name = shortEbpb . oem_name ;
fakeBpb . bps = shortEbpb . bps ;
fakeBpb . spc = shortEbpb . spc ;
fakeBpb . rsectors = shortEbpb . rsectors ;
fakeBpb . fats_no = shortEbpb . fats_no ;
fakeBpb . root_ent = shortEbpb . root_ent ;
fakeBpb . sectors = shortEbpb . sectors ;
fakeBpb . media = shortEbpb . media ;
fakeBpb . spfat = shortEbpb . spfat ;
fakeBpb . sptrk = shortEbpb . sptrk ;
fakeBpb . heads = shortEbpb . heads ;
fakeBpb . hsectors = shortEbpb . hsectors ;
fakeBpb . big_sectors = shortEbpb . big_sectors ;
fakeBpb . drive_no = shortEbpb . drive_no ;
fakeBpb . flags = shortEbpb . flags ;
fakeBpb . signature = shortEbpb . signature ;
fakeBpb . serial_no = shortEbpb . serial_no ;
fakeBpb . boot_code = shortEbpb . boot_code ;
fakeBpb . boot_signature = shortEbpb . boot_signature ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( useDos33Bpb )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
fakeBpb . jump = dos33Bpb . jump ;
fakeBpb . oem_name = dos33Bpb . oem_name ;
fakeBpb . bps = dos33Bpb . bps ;
fakeBpb . spc = dos33Bpb . spc ;
fakeBpb . rsectors = dos33Bpb . rsectors ;
fakeBpb . fats_no = dos33Bpb . fats_no ;
fakeBpb . root_ent = dos33Bpb . root_ent ;
fakeBpb . sectors = dos33Bpb . sectors ;
fakeBpb . media = dos33Bpb . media ;
fakeBpb . spfat = dos33Bpb . spfat ;
fakeBpb . sptrk = dos33Bpb . sptrk ;
fakeBpb . heads = dos33Bpb . heads ;
fakeBpb . hsectors = dos33Bpb . hsectors ;
fakeBpb . big_sectors = dos33Bpb . big_sectors ;
fakeBpb . boot_code = dos33Bpb . boot_code ;
fakeBpb . boot_signature = dos33Bpb . boot_signature ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( useDos32Bpb )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
fakeBpb . jump = dos32Bpb . jump ;
fakeBpb . oem_name = dos32Bpb . oem_name ;
fakeBpb . bps = dos32Bpb . bps ;
fakeBpb . spc = dos32Bpb . spc ;
fakeBpb . rsectors = dos32Bpb . rsectors ;
fakeBpb . fats_no = dos32Bpb . fats_no ;
fakeBpb . root_ent = dos32Bpb . root_ent ;
fakeBpb . sectors = dos32Bpb . sectors ;
fakeBpb . media = dos32Bpb . media ;
fakeBpb . spfat = dos32Bpb . spfat ;
fakeBpb . sptrk = dos32Bpb . sptrk ;
fakeBpb . heads = dos32Bpb . heads ;
fakeBpb . hsectors = dos32Bpb . hsectors ;
fakeBpb . boot_code = dos32Bpb . boot_code ;
fakeBpb . boot_signature = dos32Bpb . boot_signature ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( useDos3Bpb )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
fakeBpb . jump = dos30Bpb . jump ;
fakeBpb . oem_name = dos30Bpb . oem_name ;
fakeBpb . bps = dos30Bpb . bps ;
fakeBpb . spc = dos30Bpb . spc ;
fakeBpb . rsectors = dos30Bpb . rsectors ;
fakeBpb . fats_no = dos30Bpb . fats_no ;
fakeBpb . root_ent = dos30Bpb . root_ent ;
fakeBpb . sectors = dos30Bpb . sectors ;
fakeBpb . media = dos30Bpb . media ;
fakeBpb . spfat = dos30Bpb . spfat ;
fakeBpb . sptrk = dos30Bpb . sptrk ;
fakeBpb . heads = dos30Bpb . heads ;
fakeBpb . hsectors = dos30Bpb . hsectors ;
fakeBpb . boot_code = dos30Bpb . boot_code ;
fakeBpb . boot_signature = dos30Bpb . boot_signature ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( useDos2Bpb )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
fakeBpb . jump = dos2Bpb . jump ;
fakeBpb . oem_name = dos2Bpb . oem_name ;
fakeBpb . bps = dos2Bpb . bps ;
fakeBpb . spc = dos2Bpb . spc ;
fakeBpb . rsectors = dos2Bpb . rsectors ;
fakeBpb . fats_no = dos2Bpb . fats_no ;
fakeBpb . root_ent = dos2Bpb . root_ent ;
fakeBpb . sectors = dos2Bpb . sectors ;
fakeBpb . media = dos2Bpb . media ;
fakeBpb . spfat = dos2Bpb . spfat ;
fakeBpb . boot_code = dos2Bpb . boot_code ;
fakeBpb . boot_signature = dos2Bpb . boot_signature ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( useMsxBpb )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
isFat12 = true ;
fakeBpb . jump = msxBpb . jump ;
fakeBpb . oem_name = msxBpb . oem_name ;
fakeBpb . bps = msxBpb . bps ;
fakeBpb . spc = msxBpb . spc ;
fakeBpb . rsectors = msxBpb . rsectors ;
fakeBpb . fats_no = msxBpb . fats_no ;
fakeBpb . root_ent = msxBpb . root_ent ;
fakeBpb . sectors = msxBpb . sectors ;
fakeBpb . media = msxBpb . media ;
fakeBpb . spfat = msxBpb . spfat ;
fakeBpb . sptrk = msxBpb . sptrk ;
fakeBpb . heads = msxBpb . heads ;
fakeBpb . hsectors = msxBpb . hsectors ;
fakeBpb . boot_code = msxBpb . boot_code ;
fakeBpb . boot_signature = msxBpb . boot_signature ;
fakeBpb . serial_no = msxBpb . serial_no ;
2017-07-10 21:39:12 +01:00
// TODO: Is there any way to check this?
2017-12-22 08:43:22 +00:00
XmlFsType . Bootable = true ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( useAtariBpb )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
fakeBpb . jump = atariBpb . jump ;
fakeBpb . oem_name = atariBpb . oem_name ;
fakeBpb . bps = atariBpb . bps ;
fakeBpb . spc = atariBpb . spc ;
fakeBpb . rsectors = atariBpb . rsectors ;
fakeBpb . fats_no = atariBpb . fats_no ;
fakeBpb . root_ent = atariBpb . root_ent ;
fakeBpb . sectors = atariBpb . sectors ;
fakeBpb . media = atariBpb . media ;
fakeBpb . spfat = atariBpb . spfat ;
fakeBpb . sptrk = atariBpb . sptrk ;
fakeBpb . heads = atariBpb . heads ;
fakeBpb . boot_code = atariBpb . boot_code ;
2017-07-10 21:39:12 +01:00
ushort sum = 0 ;
BigEndianBitConverter . IsLittleEndian = BitConverter . IsLittleEndian ;
2017-12-22 08:43:22 +00:00
for ( int i = 0 ; i < bpbSector . Length ; i + = 2 ) sum + = BigEndianBitConverter . ToUInt16 ( bpbSector , i ) ;
2017-07-10 21:39:12 +01:00
// TODO: Check this
if ( sum = = 0x1234 )
2014-06-07 17:21:40 +01:00
{
2017-12-22 08:43:22 +00:00
XmlFsType . Bootable = true ;
2017-07-10 21:39:12 +01:00
StringBuilder atariSb = new StringBuilder ( ) ;
2017-12-19 20:33:03 +00:00
atariSb . AppendFormat ( "cmdload will be loaded with value {0:X4}h" ,
2017-12-22 08:43:22 +00:00
BigEndianBitConverter . ToUInt16 ( bpbSector , 0x01E ) ) . AppendLine ( ) ;
atariSb . AppendFormat ( "Boot program will be loaded at address {0:X4}h" , atariBpb . ldaaddr )
2017-12-19 20:33:03 +00:00
. AppendLine ( ) ;
2017-12-22 08:43:22 +00:00
atariSb . AppendFormat ( "FAT and directory will be cached at address {0:X4}h" , atariBpb . fatbuf )
2017-12-19 20:33:03 +00:00
. AppendLine ( ) ;
2017-12-22 08:43:22 +00:00
if ( atariBpb . ldmode = = 0 )
2015-12-05 17:10:27 +00:00
{
2017-07-10 21:39:12 +01:00
byte [ ] tmp = new byte [ 8 ] ;
2017-12-22 08:43:22 +00:00
Array . Copy ( atariBpb . fname , 0 , tmp , 0 , 8 ) ;
2017-07-10 21:39:12 +01:00
string fname = Encoding . ASCII . GetString ( tmp ) . Trim ( ) ;
tmp = new byte [ 3 ] ;
2017-12-22 08:43:22 +00:00
Array . Copy ( atariBpb . fname , 8 , tmp , 0 , 3 ) ;
2017-07-10 21:39:12 +01:00
string extension = Encoding . ASCII . GetString ( tmp ) . Trim ( ) ;
string filename ;
2017-12-19 20:33:03 +00:00
if ( string . IsNullOrEmpty ( extension ) ) filename = fname ;
else filename = fname + "." + extension ;
2017-07-10 21:39:12 +01:00
atariSb . AppendFormat ( "Boot program resides in file \"{0}\"" , filename ) . AppendLine ( ) ;
2015-12-05 17:10:27 +00:00
}
2017-07-10 21:39:12 +01:00
else
2017-12-19 20:33:03 +00:00
atariSb . AppendFormat ( "Boot program starts in sector {0} and is {1} sectors long ({2} bytes)" ,
2017-12-22 08:43:22 +00:00
atariBpb . ssect , atariBpb . sectcnt , atariBpb . sectcnt * atariBpb . bps )
2017-12-19 20:33:03 +00:00
. AppendLine ( ) ;
2017-07-10 21:39:12 +01:00
extraInfo = atariSb . ToString ( ) ;
}
}
2017-12-22 08:43:22 +00:00
else if ( useApricotBpb )
2017-09-22 23:57:53 +01:00
{
2017-12-22 08:43:22 +00:00
isFat12 = true ;
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 ) /
2017-12-19 20:33:03 +00:00
imagePlugin . GetSectorSize ( ) ) ;
2017-09-22 23:57:53 +01:00
}
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( ! isFat32 )
2017-07-10 21:39:12 +01:00
{
2017-07-25 00:27:46 +01:00
// This is to support FAT partitions on hybrid ISO/USB images
2017-12-21 14:30:38 +00:00
if ( imagePlugin . ImageInfo . XmlMediaType = = XmlMediaType . OpticalDisc )
2017-07-25 00:27:46 +01:00
{
2017-12-22 08:43:22 +00:00
fakeBpb . bps * = 4 ;
fakeBpb . spc / = 4 ;
fakeBpb . spfat / = 4 ;
fakeBpb . hsectors / = 4 ;
fakeBpb . sptrk / = 4 ;
fakeBpb . rsectors / = 4 ;
if ( fakeBpb . spc = = 0 ) fakeBpb . spc = 1 ;
2017-07-25 00:27:46 +01:00
}
2017-07-10 21:39:12 +01:00
// 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,
// so let's hope implementations use common sense?
2017-12-22 08:43:22 +00:00
if ( ! isFat12 & & ! isFat16 )
2017-07-10 21:39:12 +01:00
{
ulong clusters ;
2017-08-07 16:12:36 +01:00
2017-12-22 08:43:22 +00:00
if ( fakeBpb . sectors = = 0 )
clusters = fakeBpb . spc = = 0 ? fakeBpb . big_sectors : fakeBpb . big_sectors / fakeBpb . spc ;
else clusters = fakeBpb . spc = = 0 ? fakeBpb . sectors : ( ulong ) fakeBpb . sectors / fakeBpb . spc ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( clusters < 4089 ) isFat12 = true ;
else isFat16 = true ;
2014-06-07 17:21:40 +01:00
}
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( isFat12 )
2014-06-07 17:21:40 +01:00
{
2017-12-22 08:43:22 +00:00
if ( useAtariBpb ) sb . AppendLine ( "Atari FAT12" ) ;
else if ( useApricotBpb ) sb . AppendLine ( "Apricot FAT12" ) ;
2017-12-19 20:33:03 +00:00
else sb . AppendLine ( "Microsoft FAT12" ) ;
2017-12-22 08:43:22 +00:00
XmlFsType . Type = "FAT12" ;
2014-06-07 17:21:40 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( isFat16 )
2014-04-14 02:29:13 +00:00
{
2017-12-22 08:43:22 +00:00
sb . AppendLine ( useAtariBpb ? "Atari FAT16" : "Microsoft FAT16" ) ;
XmlFsType . Type = "FAT16" ;
2014-04-14 02:29:13 +00:00
}
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( useAtariBpb )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
if ( atariBpb . serial_no [ 0 ] = = 0x49 & & atariBpb . serial_no [ 1 ] = = 0x48 & & atariBpb . serial_no [ 2 ] = = 0x43 )
2017-07-10 21:39:12 +01:00
sb . AppendLine ( "Volume has been modified by Windows 9x/Me Volume Tracker." ) ;
else
2017-12-22 08:43:22 +00:00
XmlFsType . VolumeSerial =
$"{atariBpb.serial_no[0]:X2}{atariBpb.serial_no[1]:X2}{atariBpb.serial_no[2]:X2}" ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
XmlFsType . SystemIdentifier = StringHandlers . CToString ( atariBpb . oem_name ) ;
if ( string . IsNullOrEmpty ( XmlFsType . SystemIdentifier ) ) XmlFsType . SystemIdentifier = null ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
else if ( fakeBpb . oem_name ! = null )
2014-04-14 02:29:13 +00:00
{
2017-12-22 08:43:22 +00:00
if ( fakeBpb . oem_name [ 5 ] = = 0x49 & & fakeBpb . oem_name [ 6 ] = = 0x48 & & fakeBpb . oem_name [ 7 ] = = 0x43 )
2017-07-10 21:39:12 +01:00
sb . AppendLine ( "Volume has been modified by Windows 9x/Me Volume Tracker." ) ;
else
{
// Later versions of Windows create a DOS 3 BPB without OEM name on 8 sectors/track floppies
// OEM ID should be ASCII, otherwise ignore it
2017-12-22 08:43:22 +00:00
if ( fakeBpb . oem_name [ 0 ] > = 0x20 & & fakeBpb . oem_name [ 0 ] < = 0x7F & & fakeBpb . oem_name [ 1 ] > = 0x20 & &
fakeBpb . oem_name [ 1 ] < = 0x7F & & fakeBpb . oem_name [ 2 ] > = 0x20 & & fakeBpb . oem_name [ 2 ] < = 0x7F & &
fakeBpb . oem_name [ 3 ] > = 0x20 & & fakeBpb . oem_name [ 3 ] < = 0x7F & & fakeBpb . oem_name [ 4 ] > = 0x20 & &
fakeBpb . oem_name [ 4 ] < = 0x7F & & fakeBpb . oem_name [ 5 ] > = 0x20 & & fakeBpb . oem_name [ 5 ] < = 0x7F & &
fakeBpb . oem_name [ 6 ] > = 0x20 & & fakeBpb . oem_name [ 6 ] < = 0x7F & & fakeBpb . oem_name [ 7 ] > = 0x20 & &
fakeBpb . oem_name [ 7 ] < = 0x7F )
XmlFsType . SystemIdentifier = StringHandlers . CToString ( fakeBpb . oem_name ) ;
else if ( fakeBpb . oem_name [ 0 ] < 0x20 & & fakeBpb . oem_name [ 1 ] > = 0x20 & &
fakeBpb . oem_name [ 1 ] < = 0x7F & & fakeBpb . oem_name [ 2 ] > = 0x20 & &
fakeBpb . oem_name [ 2 ] < = 0x7F & & fakeBpb . oem_name [ 3 ] > = 0x20 & &
fakeBpb . oem_name [ 3 ] < = 0x7F & & fakeBpb . oem_name [ 4 ] > = 0x20 & &
fakeBpb . oem_name [ 4 ] < = 0x7F & & fakeBpb . oem_name [ 5 ] > = 0x20 & &
fakeBpb . oem_name [ 5 ] < = 0x7F & & fakeBpb . oem_name [ 6 ] > = 0x20 & &
fakeBpb . oem_name [ 6 ] < = 0x7F & & fakeBpb . oem_name [ 7 ] > = 0x20 & &
fakeBpb . oem_name [ 7 ] < = 0x7F )
XmlFsType . SystemIdentifier =
StringHandlers . CToString ( fakeBpb . oem_name , CurrentEncoding , start : 1 ) ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
if ( fakeBpb . signature = = 0x28 | | fakeBpb . signature = = 0x29 )
XmlFsType . VolumeSerial = $"{fakeBpb.serial_no:X8}" ;
2014-06-07 17:21:40 +01:00
}
2016-04-19 02:11:47 +01:00
2017-12-22 08:43:22 +00:00
if ( XmlFsType . SystemIdentifier ! = null )
sb . AppendFormat ( "OEM Name: {0}" , XmlFsType . SystemIdentifier . Trim ( ) ) . AppendLine ( ) ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} bytes per sector." , fakeBpb . bps ) . AppendLine ( ) ;
if ( fakeBpb . sectors = = 0 )
2015-12-05 17:10:27 +00:00
{
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} sectors on volume ({1} bytes)." , fakeBpb . big_sectors ,
fakeBpb . big_sectors * fakeBpb . bps ) . AppendLine ( ) ;
XmlFsType . Clusters = fakeBpb . spc = = 0 ? fakeBpb . big_sectors : fakeBpb . big_sectors / fakeBpb . spc ;
2015-12-05 17:10:27 +00:00
}
2014-06-07 17:21:40 +01:00
else
2015-12-05 17:10:27 +00:00
{
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} sectors on volume ({1} bytes)." , fakeBpb . sectors ,
fakeBpb . sectors * fakeBpb . bps ) . AppendLine ( ) ;
XmlFsType . Clusters = fakeBpb . spc = = 0 ? fakeBpb . sectors : fakeBpb . sectors / fakeBpb . spc ;
2015-12-05 17:10:27 +00:00
}
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} sectors per cluster." , fakeBpb . spc ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} clusters on volume." , XmlFsType . Clusters ) . AppendLine ( ) ;
XmlFsType . ClusterSize = fakeBpb . bps * fakeBpb . spc ;
sb . AppendFormat ( "{0} sectors reserved between BPB and FAT." , fakeBpb . rsectors ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} FATs." , fakeBpb . fats_no ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} entries on root directory." , fakeBpb . root_ent ) . AppendLine ( ) ;
2016-04-19 02:11:47 +01:00
2017-12-22 08:43:22 +00:00
if ( fakeBpb . media > 0 ) sb . AppendFormat ( "Media descriptor: 0x{0:X2}" , fakeBpb . media ) . AppendLine ( ) ;
2017-12-19 20:33:03 +00:00
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} sectors per FAT." , fakeBpb . spfat ) . AppendLine ( ) ;
2016-04-19 02:11:47 +01:00
2017-12-22 08:43:22 +00:00
if ( fakeBpb . sptrk > 0 & & fakeBpb . sptrk < 64 & & fakeBpb . heads > 0 & & fakeBpb . heads < 256 )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "{0} sectors per track." , fakeBpb . sptrk ) . AppendLine ( ) ;
sb . AppendFormat ( "{0} heads." , fakeBpb . heads ) . AppendLine ( ) ;
2014-04-14 02:29:13 +00:00
}
2017-12-22 08:43:22 +00:00
if ( fakeBpb . hsectors < = partition . Start )
sb . AppendFormat ( "{0} hidden sectors before BPB." , fakeBpb . hsectors ) . AppendLine ( ) ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( fakeBpb . signature = = 0x28 | | fakeBpb . signature = = 0x29 | | andosOemCorrect )
2014-06-07 17:21:40 +01:00
{
2017-12-22 08:43:22 +00:00
sb . AppendFormat ( "Drive number: 0x{0:X2}" , fakeBpb . drive_no ) . AppendLine ( ) ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( XmlFsType . VolumeSerial ! = null )
sb . AppendFormat ( "Volume Serial Number: {0}" , XmlFsType . VolumeSerial ) . AppendLine ( ) ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( ( fakeBpb . flags & 0xF8 ) = = 0x00 )
2014-06-07 17:21:40 +01:00
{
2017-12-22 08:43:22 +00:00
if ( ( fakeBpb . flags & 0x01 ) = = 0x01 )
2014-06-07 17:21:40 +01:00
{
2016-04-19 02:11:47 +01:00
sb . AppendLine ( "Volume should be checked on next mount." ) ;
2017-12-22 08:43:22 +00:00
XmlFsType . Dirty = true ;
2014-06-07 17:21:40 +01:00
}
2017-12-22 08:43:22 +00:00
if ( ( fakeBpb . flags & 0x02 ) = = 0x02 ) sb . AppendLine ( "Disk surface should be on next mount." ) ;
2017-07-10 21:39:12 +01:00
}
2017-12-22 08:43:22 +00:00
if ( fakeBpb . signature = = 0x29 | | andosOemCorrect )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
XmlFsType . VolumeName = Encoding . ASCII . GetString ( fakeBpb . volume_label ) ;
sb . AppendFormat ( "Filesystem type: {0}" , Encoding . ASCII . GetString ( fakeBpb . fs_type ) ) . AppendLine ( ) ;
2017-07-10 21:39:12 +01:00
}
}
2017-12-22 08:43:22 +00:00
else if ( useAtariBpb & & XmlFsType . VolumeSerial ! = null )
sb . AppendFormat ( "Volume Serial Number: {0}" , XmlFsType . VolumeSerial ) . AppendLine ( ) ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
bootChk = sha1Ctx . Data ( fakeBpb . boot_code , out _ ) ;
2017-07-10 21:39:12 +01:00
// Check that jumps to a correct boot code position and has boot signature set.
// This will mean that the volume will boot, even if just to say "this is not bootable change disk"......
2017-12-22 08:43:22 +00:00
if ( XmlFsType . Bootable = = false & & fakeBpb . jump ! = null )
XmlFsType . Bootable | = fakeBpb . jump [ 0 ] = = 0xEB & & fakeBpb . jump [ 1 ] > 0x58 & &
fakeBpb . jump [ 1 ] < 0x80 & & fakeBpb . boot_signature = = 0xAA55 ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
sectorsPerRealSector = fakeBpb . bps / imagePlugin . ImageInfo . SectorSize ;
2017-07-10 21:39:12 +01:00
// First root directory sector
2017-12-22 08:43:22 +00:00
rootDirectorySector =
( ulong ) ( fakeBpb . spfat * fakeBpb . fats_no + fakeBpb . rsectors ) * sectorsPerRealSector ;
sectorsForRootDirectory = ( uint ) ( fakeBpb . root_ent * 32 / imagePlugin . ImageInfo . SectorSize ) ;
2017-07-10 21:39:12 +01:00
}
2017-12-19 20:33:03 +00:00
if ( extraInfo ! = null ) sb . Append ( extraInfo ) ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( rootDirectorySector + partition . Start < partition . End & &
2017-12-21 14:30:38 +00:00
imagePlugin . ImageInfo . XmlMediaType ! = XmlMediaType . OpticalDisc )
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
byte [ ] rootDirectory =
imagePlugin . ReadSectors ( rootDirectorySector + partition . Start , sectorsForRootDirectory ) ;
2017-10-02 14:24:19 +01:00
2017-12-22 08:43:22 +00:00
if ( useDecRainbowBpb )
2017-10-02 14:24:19 +01:00
{
MemoryStream rootMs = new MemoryStream ( ) ;
2017-12-21 07:08:26 +00:00
foreach ( byte [ ] tmp in from ulong rootSector in new [ ] { 0x17 , 0x19 , 0x1B , 0x1D , 0x1E , 0x20 } select imagePlugin . ReadSector ( rootSector ) )
{ rootMs . Write ( tmp , 0 , tmp . Length ) ; }
2017-12-19 20:33:03 +00:00
2017-12-22 08:43:22 +00:00
rootDirectory = rootMs . ToArray ( ) ;
2017-10-02 14:24:19 +01:00
}
2017-12-22 08:43:22 +00:00
for ( int i = 0 ; i < rootDirectory . Length ; i + = 32 )
2017-07-10 21:39:12 +01:00
{
// Not a correct entry
2017-12-22 08:43:22 +00:00
if ( rootDirectory [ i ] < 0x20 & & rootDirectory [ i ] ! = 0x05 ) continue ;
2017-07-10 21:39:12 +01:00
// Deleted or subdirectory entry
2017-12-22 08:43:22 +00:00
if ( rootDirectory [ i ] = = 0x2E | | rootDirectory [ i ] = = 0xE5 ) continue ;
2017-07-10 21:39:12 +01:00
// Not a volume label
2017-12-22 08:43:22 +00:00
if ( rootDirectory [ i + 0x0B ] ! = 0x08 & & rootDirectory [ i + 0x0B ] ! = 0x28 ) continue ;
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
IntPtr entryPtr = Marshal . AllocHGlobal ( 32 ) ;
Marshal . Copy ( rootDirectory , i , entryPtr , 32 ) ;
DirectoryEntry entry = ( DirectoryEntry ) Marshal . PtrToStructure ( entryPtr , typeof ( DirectoryEntry ) ) ;
Marshal . FreeHGlobal ( entryPtr ) ;
2017-07-10 21:39:12 +01:00
byte [ ] fullname = new byte [ 11 ] ;
Array . Copy ( entry . filename , 0 , fullname , 0 , 8 ) ;
Array . Copy ( entry . extension , 0 , fullname , 8 , 3 ) ;
string volname = CurrentEncoding . GetString ( fullname ) . Trim ( ) ;
if ( ! string . IsNullOrEmpty ( volname ) )
2017-12-22 08:43:22 +00:00
XmlFsType . VolumeName = ( entry . caseinfo & 0x0C ) > 0 ? volname . ToLower ( ) : volname ;
2017-07-10 21:39:12 +01:00
if ( entry . ctime > 0 & & entry . cdate > 0 )
{
2017-12-23 03:59:48 +00:00
XmlFsType . CreationDate = DateHandlers . DosToDateTime ( entry . cdate , entry . ctime ) ;
2017-12-22 08:43:22 +00:00
if ( entry . ctime_ms > 0 ) XmlFsType . CreationDate = XmlFsType . CreationDate . AddMilliseconds ( entry . ctime_ms * 10 ) ;
XmlFsType . CreationDateSpecified = true ;
sb . AppendFormat ( "Volume created on {0}" , XmlFsType . CreationDate ) . AppendLine ( ) ;
2017-07-10 21:39:12 +01:00
}
2016-04-19 02:11:47 +01:00
2017-07-10 21:39:12 +01:00
if ( entry . mtime > 0 & & entry . mdate > 0 )
{
2017-12-23 03:59:48 +00:00
XmlFsType . ModificationDate = DateHandlers . DosToDateTime ( entry . mdate , entry . mtime ) ;
2017-12-22 08:43:22 +00:00
XmlFsType . ModificationDateSpecified = true ;
sb . AppendFormat ( "Volume last modified on {0}" , XmlFsType . ModificationDate ) . AppendLine ( ) ;
2014-06-07 17:21:40 +01:00
}
2017-07-10 21:39:12 +01:00
if ( entry . adate > 0 )
2017-12-23 03:59:48 +00:00
sb . AppendFormat ( "Volume last accessed on {0:d}" , DateHandlers . DosToDateTime ( entry . adate , 0 ) )
2017-12-19 20:33:03 +00:00
. AppendLine ( ) ;
2017-08-25 03:28:55 +01:00
break ;
2014-06-07 17:21:40 +01:00
}
}
2017-07-10 21:39:12 +01:00
2017-12-22 08:43:22 +00:00
if ( ! string . IsNullOrEmpty ( XmlFsType . VolumeName ) )
sb . AppendFormat ( "Volume label: {0}" , XmlFsType . VolumeName ) . AppendLine ( ) ;
if ( XmlFsType . Bootable )
2014-06-07 17:21:40 +01:00
{
2017-07-10 21:39:12 +01:00
sb . AppendLine ( "Volume is bootable" ) ;
sb . AppendFormat ( "Boot code's SHA1: {0}" , bootChk ) . AppendLine ( ) ;
2014-04-14 02:29:13 +00:00
}
2016-04-19 02:11:47 +01:00
2014-04-14 02:29:13 +00:00
information = sb . ToString ( ) ;
}
2016-04-19 02:11:47 +01:00
2017-07-10 21:39:12 +01:00
/// <summary>
/// BIOS Parameter Block as used by Atari ST GEMDOS on FAT12 volumes.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-20 02:08:37 +00:00
struct AtariParameterBlock
2014-04-14 02:29:13 +00:00
{
2017-07-10 21:39:12 +01:00
/// <summary>68000 BRA.S jump or x86 loop</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte [ ] jump ;
2017-07-10 21:39:12 +01:00
/// <summary>OEM Name, 6 bytes, space-padded, "Loader" for Atari ST boot loader</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public byte [ ] oem_name ;
2017-12-21 16:45:16 +00:00
/// <summary>Volume serial number</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] serial_no ;
2017-07-10 21:39:12 +01:00
/// <summary>Bytes per sector</summary>
2016-07-28 22:25:26 +01:00
public ushort bps ;
2017-07-10 21:39:12 +01:00
/// <summary>Sectors per cluster</summary>
2014-04-14 02:29:13 +00:00
public byte spc ;
2017-07-10 21:39:12 +01:00
/// <summary>Reserved sectors between BPB and FAT (inclusive)</summary>
2016-07-28 22:25:26 +01:00
public ushort rsectors ;
2017-07-10 21:39:12 +01:00
/// <summary>Number of FATs</summary>
2014-04-14 02:29:13 +00:00
public byte fats_no ;
2017-07-10 21:39:12 +01:00
/// <summary>Number of entries on root directory</summary>
2016-07-28 22:25:26 +01:00
public ushort root_ent ;
2017-07-10 21:39:12 +01:00
/// <summary>Sectors in volume</summary>
2016-07-28 22:25:26 +01:00
public ushort sectors ;
2017-07-10 21:39:12 +01:00
/// <summary>Media descriptor, unused by GEMDOS</summary>
2014-04-14 02:29:13 +00:00
public byte media ;
2017-07-10 21:39:12 +01:00
/// <summary>Sectors per FAT</summary>
2016-07-28 22:25:26 +01:00
public ushort spfat ;
2017-07-10 21:39:12 +01:00
/// <summary>Sectors per track</summary>
2016-07-28 22:25:26 +01:00
public ushort sptrk ;
2017-07-10 21:39:12 +01:00
/// <summary>Heads</summary>
2016-07-28 22:25:26 +01:00
public ushort heads ;
2017-07-10 21:39:12 +01:00
/// <summary>Hidden sectors before BPB, unused by GEMDOS</summary>
public ushort hsectors ;
/// <summary>Word to be loaded in the cmdload system variable. Big-endian.</summary>
public ushort execflag ;
/// <summary>Word indicating load mode. If zero, file named <see cref="fname"/> is located and loaded. It not, sectors specified in <see cref="ssect"/> and <see cref="sectcnt"/> are loaded. Big endian.</summary>
public ushort ldmode ;
/// <summary>Starting sector of boot code.</summary>
public ushort ssect ;
/// <summary>Count of sectors of boot code.</summary>
public ushort sectcnt ;
/// <summary>Address where boot code should be loaded.</summary>
public ushort ldaaddr ;
2017-07-23 19:58:11 +01:00
/// <summary>Padding.</summary>
public ushort padding ;
2017-07-10 21:39:12 +01:00
/// <summary>Address where FAT and root directory sectors must be loaded.</summary>
public ushort fatbuf ;
2017-07-23 19:58:11 +01:00
/// <summary>Unknown.</summary>
public ushort unknown ;
2017-07-10 21:39:12 +01:00
/// <summary>Filename to be loaded for booting.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte [ ] fname ;
2017-07-10 21:39:12 +01:00
/// <summary>Reserved</summary>
public ushort reserved ;
/// <summary>Boot code.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 455)] public byte [ ] boot_code ;
2017-07-10 21:39:12 +01:00
/// <summary>Big endian word to make big endian sum of all sector words be equal to 0x1234 if disk is bootable.</summary>
public ushort checksum ;
2014-04-14 02:29:13 +00:00
}
2014-06-07 17:21:40 +01:00
/// <summary>
2017-07-10 21:39:12 +01:00
/// BIOS Parameter Block as used by MSX-DOS 2.
2014-06-07 17:21:40 +01:00
/// </summary>
2017-07-10 21:39:12 +01:00
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-22 08:43:22 +00:00
struct MsxParameterBlock
2014-04-14 02:29:13 +00:00
{
2017-07-10 21:39:12 +01:00
/// <summary>x86 loop</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] jump ;
2017-07-10 21:39:12 +01:00
/// <summary>OEM Name, 8 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] oem_name ;
2017-07-10 21:39:12 +01:00
/// <summary>Bytes per sector</summary>
public ushort bps ;
/// <summary>Sectors per cluster</summary>
public byte spc ;
/// <summary>Reserved sectors between BPB and FAT (inclusive)</summary>
public ushort rsectors ;
/// <summary>Number of FATs</summary>
public byte fats_no ;
/// <summary>Number of entries on root directory</summary>
public ushort root_ent ;
/// <summary>Sectors in volume</summary>
public ushort sectors ;
/// <summary>Media descriptor</summary>
public byte media ;
/// <summary>Sectors per FAT</summary>
public ushort spfat ;
/// <summary>Sectors per track</summary>
public ushort sptrk ;
/// <summary>Heads</summary>
public ushort heads ;
/// <summary>Hidden sectors before BPB</summary>
2016-07-28 22:25:26 +01:00
public ushort hsectors ;
2017-07-10 21:39:12 +01:00
/// <summary>Jump for MSX-DOS 1 boot code</summary>
public ushort msxdos_jmp ;
/// <summary>Set to "VOL_ID" by MSX-DOS 2</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte [ ] vol_id ;
2017-07-10 21:39:12 +01:00
/// <summary>Bigger than 0 if there are deleted files (MSX-DOS 2)</summary>
public byte undelete_flag ;
2017-12-21 16:45:16 +00:00
/// <summary>Volume serial number (MSX-DOS 2)</summary>
2017-07-10 21:39:12 +01:00
public uint serial_no ;
2017-12-21 16:45:16 +00:00
/// <summary>Reserved (MSX-DOS 2)</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public byte [ ] reserved ;
2017-07-10 21:39:12 +01:00
/// <summary>Jump for MSX-DOS 2 boot code (MSX-DOS 2)</summary>
public ushort msxdos2_jmp ;
/// <summary>Boot code.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 460)] public byte [ ] boot_code ;
2017-07-10 21:39:12 +01:00
/// <summary>Always 0x55 0xAA.</summary>
public ushort boot_signature ;
}
/// <summary>DOS 2.0 BIOS Parameter Block.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-22 08:43:22 +00:00
struct BiosParameterBlock2
2017-07-10 21:39:12 +01:00
{
/// <summary>x86 jump</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] jump ;
2017-07-10 21:39:12 +01:00
/// <summary>OEM Name, 8 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] oem_name ;
2017-07-10 21:39:12 +01:00
/// <summary>Bytes per sector</summary>
public ushort bps ;
/// <summary>Sectors per cluster</summary>
public byte spc ;
/// <summary>Reserved sectors between BPB and FAT</summary>
public ushort rsectors ;
/// <summary>Number of FATs</summary>
public byte fats_no ;
/// <summary>Number of entries on root directory</summary>
public ushort root_ent ;
/// <summary>Sectors in volume</summary>
public ushort sectors ;
/// <summary>Media descriptor</summary>
public byte media ;
/// <summary>Sectors per FAT</summary>
public ushort spfat ;
/// <summary>Boot code.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 486)] public byte [ ] boot_code ;
2017-07-10 21:39:12 +01:00
/// <summary>0x55 0xAA if bootable.</summary>
public ushort boot_signature ;
2014-04-14 02:29:13 +00:00
}
2013-12-14 20:35:03 +00:00
2017-07-10 21:39:12 +01:00
/// <summary>DOS 3.0 BIOS Parameter Block.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-22 08:43:22 +00:00
struct BiosParameterBlock30
2014-04-14 02:29:13 +00:00
{
2017-07-10 21:39:12 +01:00
/// <summary>x86 jump</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] jump ;
2017-07-10 21:39:12 +01:00
/// <summary>OEM Name, 8 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] oem_name ;
2017-07-10 21:39:12 +01:00
/// <summary>Bytes per sector</summary>
public ushort bps ;
/// <summary>Sectors per cluster</summary>
public byte spc ;
/// <summary>Reserved sectors between BPB and FAT</summary>
public ushort rsectors ;
/// <summary>Number of FATs</summary>
public byte fats_no ;
/// <summary>Number of entries on root directory</summary>
public ushort root_ent ;
/// <summary>Sectors in volume</summary>
public ushort sectors ;
/// <summary>Media descriptor</summary>
public byte media ;
/// <summary>Sectors per FAT</summary>
public ushort spfat ;
/// <summary>Sectors per track</summary>
public ushort sptrk ;
/// <summary>Heads</summary>
public ushort heads ;
/// <summary>Hidden sectors before BPB</summary>
public ushort hsectors ;
/// <summary>Boot code.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 480)] public byte [ ] boot_code ;
2017-07-10 21:39:12 +01:00
/// <summary>Always 0x55 0xAA.</summary>
public ushort boot_signature ;
}
/// <summary>DOS 3.2 BIOS Parameter Block.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-22 08:43:22 +00:00
struct BiosParameterBlock32
2017-07-10 21:39:12 +01:00
{
/// <summary>x86 jump</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] jump ;
2017-07-10 21:39:12 +01:00
/// <summary>OEM Name, 8 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] oem_name ;
2017-07-10 21:39:12 +01:00
/// <summary>Bytes per sector</summary>
public ushort bps ;
/// <summary>Sectors per cluster</summary>
public byte spc ;
/// <summary>Reserved sectors between BPB and FAT</summary>
public ushort rsectors ;
/// <summary>Number of FATs</summary>
public byte fats_no ;
/// <summary>Number of entries on root directory</summary>
public ushort root_ent ;
/// <summary>Sectors in volume</summary>
public ushort sectors ;
/// <summary>Media descriptor</summary>
public byte media ;
/// <summary>Sectors per FAT</summary>
public ushort spfat ;
/// <summary>Sectors per track</summary>
public ushort sptrk ;
/// <summary>Heads</summary>
public ushort heads ;
/// <summary>Hidden sectors before BPB</summary>
public ushort hsectors ;
/// <summary>Total sectors including hidden ones</summary>
public ushort total_sectors ;
/// <summary>Boot code.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 478)] public byte [ ] boot_code ;
2017-07-10 21:39:12 +01:00
/// <summary>Always 0x55 0xAA.</summary>
public ushort boot_signature ;
}
/// <summary>DOS 3.31 BIOS Parameter Block.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-22 08:43:22 +00:00
struct BiosParameterBlock33
2017-07-10 21:39:12 +01:00
{
/// <summary>x86 jump</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] jump ;
2017-07-10 21:39:12 +01:00
/// <summary>OEM Name, 8 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] oem_name ;
2017-07-10 21:39:12 +01:00
/// <summary>Bytes per sector</summary>
public ushort bps ;
/// <summary>Sectors per cluster</summary>
public byte spc ;
/// <summary>Reserved sectors between BPB and FAT</summary>
public ushort rsectors ;
/// <summary>Number of FATs</summary>
public byte fats_no ;
/// <summary>Number of entries on root directory</summary>
public ushort root_ent ;
/// <summary>Sectors in volume</summary>
public ushort sectors ;
/// <summary>Media descriptor</summary>
public byte media ;
/// <summary>Sectors per FAT</summary>
public ushort spfat ;
/// <summary>Sectors per track</summary>
public ushort sptrk ;
/// <summary>Heads</summary>
public ushort heads ;
/// <summary>Hidden sectors before BPB</summary>
public uint hsectors ;
/// <summary>Sectors in volume if > 65535</summary>
public uint big_sectors ;
/// <summary>Boot code.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 474)] public byte [ ] boot_code ;
2017-07-10 21:39:12 +01:00
/// <summary>Always 0x55 0xAA.</summary>
public ushort boot_signature ;
}
/// <summary>DOS 3.4 BIOS Parameter Block.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-22 08:43:22 +00:00
struct BiosParameterBlockShortEbpb
2017-07-10 21:39:12 +01:00
{
/// <summary>x86 jump</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] jump ;
2017-07-10 21:39:12 +01:00
/// <summary>OEM Name, 8 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] oem_name ;
2017-07-10 21:39:12 +01:00
/// <summary>Bytes per sector</summary>
public ushort bps ;
/// <summary>Sectors per cluster</summary>
public byte spc ;
/// <summary>Reserved sectors between BPB and FAT</summary>
public ushort rsectors ;
/// <summary>Number of FATs</summary>
public byte fats_no ;
/// <summary>Number of entries on root directory</summary>
public ushort root_ent ;
/// <summary>Sectors in volume</summary>
public ushort sectors ;
/// <summary>Media descriptor</summary>
public byte media ;
/// <summary>Sectors per FAT</summary>
public ushort spfat ;
/// <summary>Sectors per track</summary>
public ushort sptrk ;
/// <summary>Heads</summary>
public ushort heads ;
/// <summary>Hidden sectors before BPB</summary>
public uint hsectors ;
/// <summary>Sectors in volume if > 65535</summary>
public uint big_sectors ;
2017-12-21 16:45:16 +00:00
/// <summary>Drive number</summary>
2017-07-10 21:39:12 +01:00
public byte drive_no ;
2017-12-21 16:45:16 +00:00
/// <summary>Volume flags</summary>
2017-07-10 21:39:12 +01:00
public byte flags ;
2017-12-21 16:45:16 +00:00
/// <summary>EPB signature, 0x28</summary>
2017-07-10 21:39:12 +01:00
public byte signature ;
2017-12-21 16:45:16 +00:00
/// <summary>Volume serial number</summary>
2017-07-10 21:39:12 +01:00
public uint serial_no ;
/// <summary>Boot code.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 467)] public byte [ ] boot_code ;
2017-07-10 21:39:12 +01:00
/// <summary>Always 0x55 0xAA.</summary>
public ushort boot_signature ;
}
/// <summary>DOS 4.0 or higher BIOS Parameter Block.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-22 08:43:22 +00:00
struct BiosParameterBlockEbpb
2017-07-10 21:39:12 +01:00
{
/// <summary>x86 jump</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] jump ;
2017-07-10 21:39:12 +01:00
/// <summary>OEM Name, 8 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] oem_name ;
2017-07-10 21:39:12 +01:00
/// <summary>Bytes per sector</summary>
public ushort bps ;
/// <summary>Sectors per cluster</summary>
public byte spc ;
/// <summary>Reserved sectors between BPB and FAT</summary>
public ushort rsectors ;
/// <summary>Number of FATs</summary>
public byte fats_no ;
/// <summary>Number of entries on root directory</summary>
public ushort root_ent ;
/// <summary>Sectors in volume</summary>
public ushort sectors ;
/// <summary>Media descriptor</summary>
public byte media ;
/// <summary>Sectors per FAT</summary>
public ushort spfat ;
/// <summary>Sectors per track</summary>
public ushort sptrk ;
/// <summary>Heads</summary>
public ushort heads ;
/// <summary>Hidden sectors before BPB</summary>
public uint hsectors ;
/// <summary>Sectors in volume if > 65535</summary>
public uint big_sectors ;
2017-12-21 16:45:16 +00:00
/// <summary>Drive number</summary>
2017-07-10 21:39:12 +01:00
public byte drive_no ;
2017-12-21 16:45:16 +00:00
/// <summary>Volume flags</summary>
2017-07-10 21:39:12 +01:00
public byte flags ;
2017-12-21 16:45:16 +00:00
/// <summary>EPB signature, 0x29</summary>
2017-07-10 21:39:12 +01:00
public byte signature ;
2017-12-21 16:45:16 +00:00
/// <summary>Volume serial number</summary>
2017-07-10 21:39:12 +01:00
public uint serial_no ;
2017-12-21 16:45:16 +00:00
/// <summary>Volume label, 11 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte [ ] volume_label ;
2017-12-21 16:45:16 +00:00
/// <summary>Filesystem type, 8 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] fs_type ;
2017-07-10 21:39:12 +01:00
/// <summary>Boot code.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 448)] public byte [ ] boot_code ;
2017-07-10 21:39:12 +01:00
/// <summary>Always 0x55 0xAA.</summary>
public ushort boot_signature ;
}
/// <summary>FAT32 Parameter Block</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-22 08:43:22 +00:00
struct Fat32ParameterBlockShort
2017-07-10 21:39:12 +01:00
{
/// <summary>x86 jump</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] jump ;
2017-07-10 21:39:12 +01:00
/// <summary>OEM Name, 8 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] oem_name ;
2017-07-10 21:39:12 +01:00
/// <summary>Bytes per sector</summary>
public ushort bps ;
/// <summary>Sectors per cluster</summary>
public byte spc ;
/// <summary>Reserved sectors between BPB and FAT</summary>
public ushort rsectors ;
/// <summary>Number of FATs</summary>
public byte fats_no ;
/// <summary>Number of entries on root directory, set to 0</summary>
public ushort root_ent ;
/// <summary>Sectors in volume, set to 0</summary>
public ushort sectors ;
/// <summary>Media descriptor</summary>
public byte media ;
/// <summary>Sectors per FAT, set to 0</summary>
public ushort spfat ;
/// <summary>Sectors per track</summary>
public ushort sptrk ;
/// <summary>Heads</summary>
public ushort heads ;
/// <summary>Hidden sectors before BPB</summary>
public uint hsectors ;
/// <summary>Sectors in volume</summary>
public uint big_sectors ;
/// <summary>Sectors per FAT</summary>
public uint big_spfat ;
/// <summary>FAT flags</summary>
public ushort mirror_flags ;
/// <summary>FAT32 version</summary>
public ushort version ;
/// <summary>Cluster of root directory</summary>
public uint root_cluster ;
/// <summary>Sector of FSINFO structure</summary>
public ushort fsinfo_sector ;
/// <summary>Sector of FAT32PB backup</summary>
public ushort backup_sector ;
/// <summary>Reserved</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte [ ] reserved ;
2017-07-10 21:39:12 +01:00
/// <summary>Drive number</summary>
2014-04-14 02:29:13 +00:00
public byte drive_no ;
2017-07-10 21:39:12 +01:00
/// <summary>Volume flags</summary>
public byte flags ;
/// <summary>Signature, should be 0x28</summary>
2014-04-14 02:29:13 +00:00
public byte signature ;
2017-07-10 21:39:12 +01:00
/// <summary>Volume serial number</summary>
2016-07-28 22:25:26 +01:00
public uint serial_no ;
2017-07-10 21:39:12 +01:00
/// <summary>Volume label, 11 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte [ ] reserved2 ;
2017-07-10 21:39:12 +01:00
/// <summary>Sectors in volume if <see cref="big_sectors"/> equals 0</summary>
public ulong huge_sectors ;
/// <summary>Boot code.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 420)] public byte [ ] boot_code ;
2017-07-10 21:39:12 +01:00
/// <summary>Always 0x55 0xAA.</summary>
public ushort boot_signature ;
2014-04-14 02:29:13 +00:00
}
2014-06-07 17:21:40 +01:00
/// <summary>FAT32 Parameter Block</summary>
2017-07-10 21:39:12 +01:00
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-22 08:43:22 +00:00
struct Fat32ParameterBlock
2014-04-14 02:29:13 +00:00
{
2017-07-10 21:39:12 +01:00
/// <summary>x86 jump</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] jump ;
2017-07-10 21:39:12 +01:00
/// <summary>OEM Name, 8 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] oem_name ;
2017-07-10 21:39:12 +01:00
/// <summary>Bytes per sector</summary>
public ushort bps ;
/// <summary>Sectors per cluster</summary>
public byte spc ;
/// <summary>Reserved sectors between BPB and FAT</summary>
public ushort rsectors ;
/// <summary>Number of FATs</summary>
public byte fats_no ;
/// <summary>Number of entries on root directory, set to 0</summary>
public ushort root_ent ;
/// <summary>Sectors in volume, set to 0</summary>
public ushort sectors ;
/// <summary>Media descriptor</summary>
public byte media ;
/// <summary>Sectors per FAT, set to 0</summary>
public ushort spfat ;
/// <summary>Sectors per track</summary>
public ushort sptrk ;
/// <summary>Heads</summary>
public ushort heads ;
/// <summary>Hidden sectors before BPB</summary>
public uint hsectors ;
/// <summary>Sectors in volume</summary>
public uint big_sectors ;
/// <summary>Sectors per FAT</summary>
public uint big_spfat ;
/// <summary>FAT flags</summary>
public ushort mirror_flags ;
/// <summary>FAT32 version</summary>
2016-07-28 22:25:26 +01:00
public ushort version ;
2017-07-10 21:39:12 +01:00
/// <summary>Cluster of root directory</summary>
2016-07-28 22:25:26 +01:00
public uint root_cluster ;
2017-07-10 21:39:12 +01:00
/// <summary>Sector of FSINFO structure</summary>
2016-07-28 22:25:26 +01:00
public ushort fsinfo_sector ;
2017-07-10 21:39:12 +01:00
/// <summary>Sector of FAT32PB backup</summary>
2016-07-28 22:25:26 +01:00
public ushort backup_sector ;
2017-07-10 21:39:12 +01:00
/// <summary>Reserved</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte [ ] reserved ;
2017-07-10 21:39:12 +01:00
/// <summary>Drive number</summary>
2014-04-14 02:29:13 +00:00
public byte drive_no ;
2017-07-10 21:39:12 +01:00
/// <summary>Volume flags</summary>
public byte flags ;
/// <summary>Signature, should be 0x29</summary>
2014-04-14 02:29:13 +00:00
public byte signature ;
2017-07-10 21:39:12 +01:00
/// <summary>Volume serial number</summary>
2016-07-28 22:25:26 +01:00
public uint serial_no ;
2017-07-10 21:39:12 +01:00
/// <summary>Volume label, 11 bytes, space-padded</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte [ ] volume_label ;
2017-07-10 21:39:12 +01:00
/// <summary>Filesystem type, 8 bytes, space-padded, must be "FAT32 "</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] fs_type ;
2017-07-10 21:39:12 +01:00
/// <summary>Boot code.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 419)] public byte [ ] boot_code ;
2017-07-10 21:39:12 +01:00
/// <summary>Always 0x55 0xAA.</summary>
public ushort boot_signature ;
}
2017-09-24 19:15:22 +01:00
/// <summary>Apricot Label.</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-20 02:08:37 +00:00
struct ApricotLabel
2017-09-24 19:15:22 +01:00
{
/// <summary>Version of format which created disk</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] version ;
2017-09-24 19:15:22 +01:00
/// <summary>Operating system.</summary>
public byte operatingSystem ;
/// <summary>Software write protection.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool writeProtected ;
2017-09-24 19:15:22 +01:00
/// <summary>Copy protected.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool copyProtected ;
2017-09-24 19:15:22 +01:00
/// <summary>Boot type.</summary>
public byte bootType ;
/// <summary>Partitions.</summary>
public byte partitionCount ;
/// <summary>Is hard disk?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool winchester ;
2017-09-24 19:15:22 +01:00
/// <summary>Sector size.</summary>
public ushort sectorSize ;
/// <summary>Sectors per track.</summary>
public ushort spt ;
/// <summary>Tracks per side.</summary>
public uint cylinders ;
/// <summary>Sides.</summary>
public byte heads ;
/// <summary>Interleave factor.</summary>
public byte interleave ;
/// <summary>Skew factor.</summary>
public ushort skew ;
/// <summary>Sector where boot code starts.</summary>
public uint bootLocation ;
/// <summary>Size in sectors of boot code.</summary>
public ushort bootSize ;
/// <summary>Address at which to load boot code.</summary>
public uint bootAddress ;
/// <summary>Offset where to jump to boot.</summary>
public ushort bootOffset ;
/// <summary>Segment where to jump to boot.</summary>
public ushort bootSegment ;
/// <summary>First data sector.</summary>
public uint firstDataBlock ;
/// <summary>Generation.</summary>
public ushort generation ;
/// <summary>Copy count.</summary>
public ushort copyCount ;
/// <summary>Maximum number of copies.</summary>
public ushort maxCopies ;
/// <summary>Serial number.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] serialNumber ;
2017-09-24 19:15:22 +01:00
/// <summary>Part number.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] partNumber ;
2017-09-24 19:15:22 +01:00
/// <summary>Copyright.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte [ ] copyright ;
2017-09-24 19:15:22 +01:00
/// <summary>BPB for whole disk.</summary>
public ApricotParameterBlock mainBPB ;
/// <summary>Name of FONT file.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte [ ] fontName ;
2017-09-24 19:15:22 +01:00
/// <summary>Name of KEYBOARD file.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte [ ] keyboardName ;
2017-09-24 19:15:22 +01:00
/// <summary>Minor BIOS version.</summary>
public byte biosMinorVersion ;
/// <summary>Major BIOS version.</summary>
public byte biosMajorVersion ;
/// <summary>Diagnostics enabled?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool diagnosticsFlag ;
2017-09-24 19:15:22 +01:00
/// <summary>Printer device.</summary>
public byte prnDevice ;
/// <summary>Bell volume.</summary>
public byte bellVolume ;
/// <summary>Cache enabled?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool enableCache ;
2017-09-24 19:15:22 +01:00
/// <summary>Graphics enabled?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool enableGraphics ;
2017-09-24 19:15:22 +01:00
/// <summary>Length in sectors of DOS.</summary>
public byte dosLength ;
/// <summary>Length in sectors of FONT file.</summary>
public byte fontLength ;
/// <summary>Length in sectors of KEYBOARD file.</summary>
public byte keyboardLength ;
/// <summary>Starting sector of DOS.</summary>
public ushort dosStart ;
/// <summary>Starting sector of FONT file.</summary>
public ushort fontStart ;
/// <summary>Starting sector of KEYBOARD file.</summary>
public ushort keyboardStart ;
/// <summary>Keyboard click volume.</summary>
public byte keyboardVolume ;
/// <summary>Auto-repeat enabled?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool autorepeat ;
2017-09-24 19:15:22 +01:00
/// <summary>Auto-repeat lead-in.</summary>
public byte autorepeatLeadIn ;
/// <summary>Auto-repeat interval.</summary>
public byte autorepeatInterval ;
/// <summary>Microscreen mode.</summary>
public byte microscreenMode ;
/// <summary>Spare area for keyboard values expansion.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte [ ] spareKeyboard ;
2017-09-24 19:15:22 +01:00
/// <summary>Screen line mode.</summary>
public byte lineMode ;
/// <summary>Screen line width.</summary>
public byte lineWidth ;
/// <summary>Screen disabled?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool imageOff ;
2017-09-24 19:15:22 +01:00
/// <summary>Spare area for screen values expansion.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] public byte [ ] spareScreen ;
2017-09-24 19:15:22 +01:00
/// <summary>TX baud rate.</summary>
public byte txBaudRate ;
/// <summary>RX baud rate.</summary>
public byte rxBaudRate ;
/// <summary>TX bits.</summary>
public byte txBits ;
/// <summary>RX bits.</summary>
public byte rxBits ;
/// <summary>Stop bits.</summary>
public byte stopBits ;
/// <summary>Parity enabled?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool parityCheck ;
2017-09-24 19:15:22 +01:00
/// <summary>Parity type.</summary>
public byte parityType ;
/// <summary>Xon/Xoff enabled on TX.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool txXonXoff ;
2017-09-24 19:15:22 +01:00
/// <summary>Xon/Xoff enabled on RX.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool rxXonXoff ;
2017-09-24 19:15:22 +01:00
/// <summary>Xon character.</summary>
public byte xonCharacter ;
/// <summary>Xoff character.</summary>
public byte xoffCharacter ;
/// <summary>Xon/Xoff buffer on RX.</summary>
public ushort rxXonXoffBuffer ;
/// <summary>DTR/DSR enabled?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool dtrDsr ;
2017-09-24 19:15:22 +01:00
/// <summary>CTS/RTS enabled?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool ctsRts ;
2017-09-24 19:15:22 +01:00
/// <summary>NULLs after CR.</summary>
public byte nullsAfterCr ;
/// <summary>NULLs after 0xFF.</summary>
public byte nullsAfterFF ;
/// <summary>Send LF after CR in serial port.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool lfAfterCRSerial ;
2017-09-24 19:15:22 +01:00
/// <summary>BIOS error report in serial port.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool biosErrorReportSerial ;
2017-09-24 19:15:22 +01:00
/// <summary>Spare area for serial port values expansion.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)] public byte [ ] spareSerial ;
2017-09-24 19:15:22 +01:00
/// <summary>Send LF after CR in parallel port.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool lfAfterCrParallel ;
2017-09-24 19:15:22 +01:00
/// <summary>Select line supported?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool selectLine ;
2017-09-24 19:15:22 +01:00
/// <summary>Paper empty supported?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool paperEmpty ;
2017-09-24 19:15:22 +01:00
/// <summary>Fault line supported?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool faultLine ;
2017-09-24 19:15:22 +01:00
/// <summary>BIOS error report in parallel port.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool biosErrorReportParallel ;
2017-09-24 19:15:22 +01:00
/// <summary>Spare area for parallel port values expansion.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] public byte [ ] spareParallel ;
2017-09-24 19:15:22 +01:00
/// <summary>Spare area for Winchester values expansion.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] public byte [ ] spareWinchester ;
2017-09-24 19:15:22 +01:00
/// <summary>Parking enabled?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool parkingEnabled ;
2017-09-24 19:15:22 +01:00
/// <summary>Format protection?.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.U1)] public bool formatProtection ;
2017-09-24 19:15:22 +01:00
/// <summary>Spare area for RAM disk values expansion.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public byte [ ] spareRamDisk ;
2017-09-24 19:15:22 +01:00
/// <summary>List of bad blocks.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public ushort [ ] badBlocks ;
2017-09-24 19:15:22 +01:00
/// <summary>Array of partition BPBs.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public ApricotParameterBlock [ ] partitions ;
2017-09-24 19:15:22 +01:00
/// <summary>Spare area.</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 63)] public byte [ ] spare ;
2017-09-24 19:15:22 +01:00
/// <summary>CP/M double side indicator?.</summary>
public bool cpmDoubleSided ;
}
2017-09-22 23:57:53 +01:00
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-20 02:08:37 +00:00
struct ApricotParameterBlock
2017-09-22 23:57:53 +01:00
{
/// <summary>Bytes per sector</summary>
public ushort bps ;
/// <summary>Sectors per cluster</summary>
public byte spc ;
/// <summary>Reserved sectors between BPB and FAT</summary>
public ushort rsectors ;
/// <summary>Number of FATs</summary>
public byte fats_no ;
/// <summary>Number of entries on root directory</summary>
public ushort root_ent ;
/// <summary>Sectors in volume</summary>
public ushort sectors ;
/// <summary>Media descriptor</summary>
public byte media ;
/// <summary>Sectors per FAT</summary>
public ushort spfat ;
/// <summary>Disk type</summary>
public byte diskType ;
2017-09-24 19:15:22 +01:00
/// <summary>Volume starting sector</summary>
public ushort startSector ;
2017-09-22 23:57:53 +01:00
}
2017-12-22 08:43:22 +00:00
const uint FSINFO_SIGNATURE1 = 0x41615252 ;
const uint FSINFO_SIGNATURE2 = 0x61417272 ;
const uint FSINFO_SIGNATURE3 = 0xAA550000 ;
2017-07-10 21:39:12 +01:00
/// <summary>FAT32 FS Information Sector</summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-22 08:43:22 +00:00
struct FsInfoSector
2017-07-10 21:39:12 +01:00
{
2017-12-22 08:43:22 +00:00
/// <summary>Signature must be <see cref="FAT.FSINFO_SIGNATURE1"/></summary>
2017-07-10 21:39:12 +01:00
public uint signature1 ;
/// <summary>Reserved</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 480)] public byte [ ] reserved1 ;
2017-12-22 08:43:22 +00:00
/// <summary>Signature must be <see cref="FAT.FSINFO_SIGNATURE2"/></summary>
2017-07-10 21:39:12 +01:00
public uint signature2 ;
/// <summary>Free clusters</summary>
public uint free_clusters ;
/// <summary> cated cluster</summary>
public uint last_cluster ;
/// <summary>Reserved</summary>
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte [ ] reserved2 ;
2017-12-22 08:43:22 +00:00
/// <summary>Signature must be <see cref="FAT.FSINFO_SIGNATURE3"/></summary>
2017-07-10 21:39:12 +01:00
public uint signature3 ;
}
[Flags]
2017-12-20 02:08:37 +00:00
enum FatAttributes : byte
2017-07-10 21:39:12 +01:00
{
ReadOnly = 0x01 ,
Hidden = 0x02 ,
System = 0x04 ,
VolumeLabel = 0x08 ,
Subdirectory = 0x10 ,
Archive = 0x20 ,
Device = 0x40 ,
Reserved = 0x80 ,
LFN = 0x0F
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
2017-12-20 02:08:37 +00:00
struct DirectoryEntry
2017-07-10 21:39:12 +01:00
{
2017-12-19 20:33:03 +00:00
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte [ ] filename ;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte [ ] extension ;
2017-07-10 21:39:12 +01:00
public FatAttributes attributes ;
public byte caseinfo ;
public byte ctime_ms ;
public ushort ctime ;
public ushort cdate ;
public ushort adate ;
public ushort ea_handle ;
public ushort mtime ;
public ushort mdate ;
public ushort start_cluster ;
public uint size ;
2014-04-14 02:29:13 +00:00
}
2016-07-21 17:16:08 +01:00
public override Errno Mount ( )
{
return Errno . NotImplemented ;
}
2016-07-22 00:43:22 +01:00
public override Errno Mount ( bool debug )
{
return Errno . NotImplemented ;
}
2016-07-21 17:16:08 +01:00
public override Errno Unmount ( )
{
return Errno . NotImplemented ;
}
public override Errno MapBlock ( string path , long fileBlock , ref long deviceBlock )
{
return Errno . NotImplemented ;
}
public override Errno GetAttributes ( string path , ref FileAttributes attributes )
{
return Errno . NotImplemented ;
}
public override Errno ListXAttr ( string path , ref List < string > xattrs )
{
return Errno . NotImplemented ;
}
public override Errno GetXattr ( string path , string xattr , ref byte [ ] buf )
{
return Errno . NotImplemented ;
}
public override Errno Read ( string path , long offset , long size , ref byte [ ] buf )
{
return Errno . NotImplemented ;
}
public override Errno ReadDir ( string path , ref List < string > contents )
{
return Errno . NotImplemented ;
}
public override Errno StatFs ( ref FileSystemInfo stat )
{
return Errno . NotImplemented ;
}
public override Errno Stat ( string path , ref FileEntryInfo stat )
{
return Errno . NotImplemented ;
}
public override Errno ReadLink ( string path , ref string dest )
{
return Errno . NotImplemented ;
}
2014-04-14 02:29:13 +00:00
}
2014-04-14 01:14:20 +00:00
}