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);
}
}