From 4d28330dcb504c78120ef897bbe1d2c6689f4d60 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 26 Apr 2019 01:29:29 +0100 Subject: [PATCH] Cache root directory for FAT12 and FAT16. --- DiscImageChef.Filesystems/FAT/Consts.cs | 28 +++++++++ DiscImageChef.Filesystems/FAT/FAT.cs | 23 +++---- DiscImageChef.Filesystems/FAT/Info.cs | 6 +- DiscImageChef.Filesystems/FAT/Super.cs | 80 +++++++++++++++++-------- 4 files changed, 97 insertions(+), 40 deletions(-) diff --git a/DiscImageChef.Filesystems/FAT/Consts.cs b/DiscImageChef.Filesystems/FAT/Consts.cs index 82efebd50..905f5d4d3 100644 --- a/DiscImageChef.Filesystems/FAT/Consts.cs +++ b/DiscImageChef.Filesystems/FAT/Consts.cs @@ -39,6 +39,34 @@ namespace DiscImageChef.Filesystems.FAT const uint FSINFO_SIGNATURE1 = 0x41615252; const uint FSINFO_SIGNATURE2 = 0x61417272; const uint FSINFO_SIGNATURE3 = 0xAA550000; + /// + /// Directory finishes + /// + const byte DIRENT_FINISHED = 0x00; + /// + /// Deleted directory entry + /// + const byte DIRENT_DELETED = 0xE5; + /// + /// Minimum allowed value in name/extension + /// + const byte DIRENT_MIN = 0x20; + /// + /// Value used instead of for first name character + /// + const byte DIRENT_E5 = 0x05; + /// + /// Entry points to self or parent directory + /// + const byte DIRENT_SUBDIR = 0x2E; + /// + /// FASTFAT.SYS indicator that extension is lowercase + /// + const byte FASTFAT_LOWERCASE_EXTENSION = 0x10; + /// + /// FASTFAT.SYS indicator that basename is lowercase + /// + const byte FASTFAT_LOWERCASE_BASENAME = 0x08; readonly (string hash, string name)[] knownBootHashes = { diff --git a/DiscImageChef.Filesystems/FAT/FAT.cs b/DiscImageChef.Filesystems/FAT/FAT.cs index 91ab9c6d3..ef921cdbf 100644 --- a/DiscImageChef.Filesystems/FAT/FAT.cs +++ b/DiscImageChef.Filesystems/FAT/FAT.cs @@ -42,17 +42,18 @@ namespace DiscImageChef.Filesystems.FAT // X68K uses cdate/adate from direntry for extending filename public partial class FAT : IReadOnlyFilesystem { - bool debug; - bool fat12; - bool fat16; - bool fat32; - ulong fatFirstSector; - ulong firstClusterSector; - bool mounted; - uint reservedSectors; - uint sectorsPerCluster; - uint sectorsPerFat; - bool useFirstFat; + bool debug; + bool fat12; + bool fat16; + bool fat32; + ulong fatFirstSector; + ulong firstClusterSector; + bool mounted; + uint reservedSectors; + Dictionary rootDirectoryCache; + uint sectorsPerCluster; + uint sectorsPerFat; + bool useFirstFat; public FileSystemType XmlFsType { get; private set; } diff --git a/DiscImageChef.Filesystems/FAT/Info.cs b/DiscImageChef.Filesystems/FAT/Info.cs index e21e34f79..605353984 100644 --- a/DiscImageChef.Filesystems/FAT/Info.cs +++ b/DiscImageChef.Filesystems/FAT/Info.cs @@ -775,10 +775,10 @@ namespace DiscImageChef.Filesystems.FAT for(int i = 0; i < rootDirectory.Length; i += 32) { // Not a correct entry - if(rootDirectory[i] < 0x20 && rootDirectory[i] != 0x05) continue; + if(rootDirectory[i] < DIRENT_MIN && rootDirectory[i] != DIRENT_E5) continue; // Deleted or subdirectory entry - if(rootDirectory[i] == 0x2E || rootDirectory[i] == 0xE5) continue; + if(rootDirectory[i] == DIRENT_SUBDIR || rootDirectory[i] == DIRENT_DELETED) continue; // Not a volume label if(rootDirectory[i + 0x0B] != 0x08 && rootDirectory[i + 0x0B] != 0x28) continue; @@ -791,7 +791,7 @@ namespace DiscImageChef.Filesystems.FAT Array.Copy(entry.extension, 0, fullname, 8, 3); string volname = Encoding.GetString(fullname).Trim(); if(!string.IsNullOrEmpty(volname)) - XmlFsType.VolumeName = (entry.caseinfo & 0x0C) > 0 ? volname.ToLower() : volname; + XmlFsType.VolumeName = (entry.caseinfo & 0x18) > 0 ? volname.ToLower() : volname; if(entry.ctime > 0 && entry.cdate > 0) { diff --git a/DiscImageChef.Filesystems/FAT/Super.cs b/DiscImageChef.Filesystems/FAT/Super.cs index 82a4aedfc..bb991d55e 100644 --- a/DiscImageChef.Filesystems/FAT/Super.cs +++ b/DiscImageChef.Filesystems/FAT/Super.cs @@ -32,6 +32,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Text; @@ -307,6 +308,8 @@ namespace DiscImageChef.Filesystems.FAT firstClusterSector += partition.Start; + rootDirectoryCache = new Dictionary(); + if(!fat32) if(firstClusterSector + partition.Start < partition.End && imagePlugin.Info.XmlMediaType != XmlMediaType.OpticalDisc) @@ -325,40 +328,65 @@ namespace DiscImageChef.Filesystems.FAT for(int i = 0; i < rootDirectory.Length; i += 32) { - // Not a correct entry - if(rootDirectory[i] < 0x20 && rootDirectory[i] != 0x05) continue; - - // Deleted or subdirectory entry - if(rootDirectory[i] == 0x2E || rootDirectory[i] == 0xE5) continue; - - // Not a volume label - if(rootDirectory[i + 0x0B] != 0x08 && rootDirectory[i + 0x0B] != 0x28) continue; - DirectoryEntry entry = Marshal.ByteArrayToStructureLittleEndian(rootDirectory, i, 32); - byte[] fullname = new byte[11]; - Array.Copy(entry.filename, 0, fullname, 0, 8); - Array.Copy(entry.extension, 0, fullname, 8, 3); - string volname = Encoding.GetString(fullname).Trim(); - if(!string.IsNullOrEmpty(volname)) - XmlFsType.VolumeName = (entry.caseinfo & 0x0C) > 0 ? volname.ToLower() : volname; + if(entry.filename[0] == DIRENT_FINISHED) break; - if(entry.ctime > 0 && entry.cdate > 0) + // Not a correct entry + if(entry.filename[0] < DIRENT_MIN && entry.filename[0] != DIRENT_E5) continue; + + // Deleted or subdirectory entry + if(entry.filename[0] == DIRENT_SUBDIR || entry.filename[0] == DIRENT_DELETED) continue; + + // TODO: LFN namespace + if(entry.attributes.HasFlag(FatAttributes.LFN)) continue; + + string filename; + + if(entry.attributes.HasFlag(FatAttributes.VolumeLabel)) { - XmlFsType.CreationDate = DateHandlers.DosToDateTime(entry.cdate, entry.ctime); - if(entry.ctime_ms > 0) - XmlFsType.CreationDate = XmlFsType.CreationDate.AddMilliseconds(entry.ctime_ms * 10); - XmlFsType.CreationDateSpecified = true; + byte[] fullname = new byte[11]; + Array.Copy(entry.filename, 0, fullname, 0, 8); + Array.Copy(entry.extension, 0, fullname, 8, 3); + string volname = Encoding.GetString(fullname).Trim(); + if(!string.IsNullOrEmpty(volname)) + XmlFsType.VolumeName = (entry.caseinfo & 0x18) > 0 ? volname.ToLower() : volname; + + if(entry.ctime > 0 && entry.cdate > 0) + { + XmlFsType.CreationDate = DateHandlers.DosToDateTime(entry.cdate, entry.ctime); + if(entry.ctime_ms > 0) + XmlFsType.CreationDate = + XmlFsType.CreationDate.AddMilliseconds(entry.ctime_ms * 10); + XmlFsType.CreationDateSpecified = true; + } + + if(entry.mtime > 0 && entry.mdate > 0) + { + XmlFsType.ModificationDate = + DateHandlers.DosToDateTime(entry.mdate, entry.mtime); + XmlFsType.ModificationDateSpecified = true; + } + + continue; } - if(entry.mtime > 0 && entry.mdate > 0) - { - XmlFsType.ModificationDate = DateHandlers.DosToDateTime(entry.mdate, entry.mtime); - XmlFsType.ModificationDateSpecified = true; - } + if(entry.filename[0] == DIRENT_E5) entry.filename[0] = DIRENT_DELETED; - break; + string name = Encoding.GetString(entry.filename).Trim(); + string extension = Encoding.GetString(entry.extension).Trim(); + + if((entry.caseinfo & FASTFAT_LOWERCASE_EXTENSION) > 0) + extension = extension.ToLower(CultureInfo.CurrentCulture); + + if((entry.caseinfo & FASTFAT_LOWERCASE_BASENAME) > 0) + name = name.ToLower(CultureInfo.CurrentCulture); + + if(extension != "") filename = name + "." + extension; + else filename = name; + + rootDirectoryCache.Add(filename, entry); } }