From fcc0211fb64171e8c4d19bd6140bde9e8323018d Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Thu, 3 Jun 2021 23:34:17 +0100 Subject: [PATCH] Fix identifying between FAT12 and FAT16, checking entire FAT validity. Fixes #576 --- Aaru.Filesystems/FAT/Info.cs | 75 ++++++++++++++++++++++++++++++++++- Aaru.Filesystems/FAT/Super.cs | 67 +++++++++++++++++++++++++++---- 2 files changed, 133 insertions(+), 9 deletions(-) diff --git a/Aaru.Filesystems/FAT/Info.cs b/Aaru.Filesystems/FAT/Info.cs index 53fb784fa..f647368b1 100644 --- a/Aaru.Filesystems/FAT/Info.cs +++ b/Aaru.Filesystems/FAT/Info.cs @@ -34,6 +34,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using Aaru.Checksums; using Aaru.CommonTypes; @@ -42,6 +43,7 @@ using Aaru.CommonTypes.Interfaces; using Aaru.Console; using Aaru.Helpers; using Schemas; +using Marshal = Aaru.Helpers.Marshal; namespace Aaru.Filesystems { @@ -690,8 +692,79 @@ namespace Aaru.Filesystems else clusters = humanBpb.clusters == 0 ? humanBpb.big_clusters : humanBpb.clusters; + // This will walk all the FAT entries and check if they're valid FAT12 or FAT16 entries. + // If the whole table is valid in both senses, it considers the type entry in the BPB. + // BeOS is known to set the type as FAT16 but treat it as FAT12. + if(!isFat12 && + !isFat16) + { if(clusters < 4089) - isFat12 = true; + { + ushort[] fat12 = new ushort[clusters]; + + _reservedSectors = fakeBpb.rsectors; + sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize; + _fatFirstSector = partition.Start + (_reservedSectors * sectorsPerRealSector); + + byte[] fatBytes = imagePlugin.ReadSectors(_fatFirstSector, fakeBpb.spfat); + + int pos = 0; + + for(int i = 0; i + 3 < fatBytes.Length && pos < fat12.Length; i += 3) + { + fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]); + + if(pos >= fat12.Length) + break; + + fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4)); + } + + bool fat12Valid = fat12[0] >= FAT12_RESERVED && fat12[1] >= FAT12_RESERVED; + + foreach(ushort entry in fat12) + { + if(entry >= FAT12_RESERVED || + entry <= clusters) + continue; + + fat12Valid = false; + + break; + } + + ushort[] fat16 = MemoryMarshal.Cast(fatBytes).ToArray(); + + bool fat16Valid = fat16[0] >= FAT16_RESERVED && fat16[1] >= 0x3FF0; + + foreach(ushort entry in fat16) + { + if(entry >= FAT16_RESERVED || + entry <= clusters) + continue; + + fat16Valid = false; + + break; + } + + isFat12 = fat12Valid; + isFat16 = fat16Valid; + + // Check BPB type + if(isFat12 == isFat16) + { + isFat12 = fakeBpb.fs_type != null && + Encoding.ASCII.GetString(fakeBpb.fs_type) == "FAT12 "; + + isFat16 = fakeBpb.fs_type != null && + Encoding.ASCII.GetString(fakeBpb.fs_type) == "FAT16 "; + } + + if(!isFat12 && + !isFat16) + isFat12 = true; + } else isFat16 = true; } diff --git a/Aaru.Filesystems/FAT/Super.cs b/Aaru.Filesystems/FAT/Super.cs index 52accd1ed..013299385 100644 --- a/Aaru.Filesystems/FAT/Super.cs +++ b/Aaru.Filesystems/FAT/Super.cs @@ -313,15 +313,66 @@ namespace Aaru.Filesystems if(!_fat12 && !_fat16) { - ulong clusters; - - 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; - if(clusters < 4089) - _fat12 = true; + { + ushort[] fat12 = new ushort[clusters]; + + _reservedSectors = fakeBpb.rsectors; + sectorsPerRealSector = fakeBpb.bps / imagePlugin.Info.SectorSize; + _fatFirstSector = partition.Start + (_reservedSectors * sectorsPerRealSector); + + byte[] fatBytes = imagePlugin.ReadSectors(_fatFirstSector, fakeBpb.spfat); + + int pos = 0; + + for(int i = 0; i + 3 < fatBytes.Length && pos < fat12.Length; i += 3) + { + fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF) << 8) + fatBytes[i + 0]); + + if(pos >= fat12.Length) + break; + + fat12[pos++] = (ushort)(((fatBytes[i + 1] & 0xF0) >> 4) + (fatBytes[i + 2] << 4)); + } + + bool fat12Valid = fat12[0] >= FAT12_RESERVED && fat12[1] >= FAT12_RESERVED; + + foreach(ushort entry in fat12) + { + if(entry >= FAT12_RESERVED || + entry <= clusters) + continue; + + fat12Valid = false; + + break; + } + + ushort[] fat16 = MemoryMarshal.Cast(fatBytes).ToArray(); + + bool fat16Valid = fat16[0] >= FAT16_RESERVED && fat16[1] >= 0x3FF0; + + foreach(ushort entry in fat16) + { + if(entry >= FAT16_RESERVED || + entry <= clusters) + continue; + + fat16Valid = false; + + break; + } + + _fat12 = fat12Valid; + _fat16 = fat16Valid; + + // Check BPB type + if(_fat12 == _fat16) + { + _fat12 = Encoding.ASCII.GetString(fakeBpb.fs_type) == "FAT12 "; + _fat16 = Encoding.ASCII.GetString(fakeBpb.fs_type) == "FAT16 "; + } + } else _fat16 = true; }