mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Cache root directory for FAT12 and FAT16.
This commit is contained in:
@@ -39,6 +39,34 @@ namespace DiscImageChef.Filesystems.FAT
|
|||||||
const uint FSINFO_SIGNATURE1 = 0x41615252;
|
const uint FSINFO_SIGNATURE1 = 0x41615252;
|
||||||
const uint FSINFO_SIGNATURE2 = 0x61417272;
|
const uint FSINFO_SIGNATURE2 = 0x61417272;
|
||||||
const uint FSINFO_SIGNATURE3 = 0xAA550000;
|
const uint FSINFO_SIGNATURE3 = 0xAA550000;
|
||||||
|
/// <summary>
|
||||||
|
/// Directory finishes
|
||||||
|
/// </summary>
|
||||||
|
const byte DIRENT_FINISHED = 0x00;
|
||||||
|
/// <summary>
|
||||||
|
/// Deleted directory entry
|
||||||
|
/// </summary>
|
||||||
|
const byte DIRENT_DELETED = 0xE5;
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum allowed value in name/extension
|
||||||
|
/// </summary>
|
||||||
|
const byte DIRENT_MIN = 0x20;
|
||||||
|
/// <summary>
|
||||||
|
/// Value used instead of <see cref="DIRENT_FINISHED" /> for first name character
|
||||||
|
/// </summary>
|
||||||
|
const byte DIRENT_E5 = 0x05;
|
||||||
|
/// <summary>
|
||||||
|
/// Entry points to self or parent directory
|
||||||
|
/// </summary>
|
||||||
|
const byte DIRENT_SUBDIR = 0x2E;
|
||||||
|
/// <summary>
|
||||||
|
/// FASTFAT.SYS indicator that extension is lowercase
|
||||||
|
/// </summary>
|
||||||
|
const byte FASTFAT_LOWERCASE_EXTENSION = 0x10;
|
||||||
|
/// <summary>
|
||||||
|
/// FASTFAT.SYS indicator that basename is lowercase
|
||||||
|
/// </summary>
|
||||||
|
const byte FASTFAT_LOWERCASE_BASENAME = 0x08;
|
||||||
|
|
||||||
readonly (string hash, string name)[] knownBootHashes =
|
readonly (string hash, string name)[] knownBootHashes =
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,17 +42,18 @@ namespace DiscImageChef.Filesystems.FAT
|
|||||||
// X68K uses cdate/adate from direntry for extending filename
|
// X68K uses cdate/adate from direntry for extending filename
|
||||||
public partial class FAT : IReadOnlyFilesystem
|
public partial class FAT : IReadOnlyFilesystem
|
||||||
{
|
{
|
||||||
bool debug;
|
bool debug;
|
||||||
bool fat12;
|
bool fat12;
|
||||||
bool fat16;
|
bool fat16;
|
||||||
bool fat32;
|
bool fat32;
|
||||||
ulong fatFirstSector;
|
ulong fatFirstSector;
|
||||||
ulong firstClusterSector;
|
ulong firstClusterSector;
|
||||||
bool mounted;
|
bool mounted;
|
||||||
uint reservedSectors;
|
uint reservedSectors;
|
||||||
uint sectorsPerCluster;
|
Dictionary<string, DirectoryEntry> rootDirectoryCache;
|
||||||
uint sectorsPerFat;
|
uint sectorsPerCluster;
|
||||||
bool useFirstFat;
|
uint sectorsPerFat;
|
||||||
|
bool useFirstFat;
|
||||||
|
|
||||||
public FileSystemType XmlFsType { get; private set; }
|
public FileSystemType XmlFsType { get; private set; }
|
||||||
|
|
||||||
|
|||||||
@@ -775,10 +775,10 @@ namespace DiscImageChef.Filesystems.FAT
|
|||||||
for(int i = 0; i < rootDirectory.Length; i += 32)
|
for(int i = 0; i < rootDirectory.Length; i += 32)
|
||||||
{
|
{
|
||||||
// Not a correct entry
|
// 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
|
// 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
|
// Not a volume label
|
||||||
if(rootDirectory[i + 0x0B] != 0x08 && rootDirectory[i + 0x0B] != 0x28) continue;
|
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);
|
Array.Copy(entry.extension, 0, fullname, 8, 3);
|
||||||
string volname = Encoding.GetString(fullname).Trim();
|
string volname = Encoding.GetString(fullname).Trim();
|
||||||
if(!string.IsNullOrEmpty(volname))
|
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)
|
if(entry.ctime > 0 && entry.cdate > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -307,6 +308,8 @@ namespace DiscImageChef.Filesystems.FAT
|
|||||||
|
|
||||||
firstClusterSector += partition.Start;
|
firstClusterSector += partition.Start;
|
||||||
|
|
||||||
|
rootDirectoryCache = new Dictionary<string, DirectoryEntry>();
|
||||||
|
|
||||||
if(!fat32)
|
if(!fat32)
|
||||||
if(firstClusterSector + partition.Start < partition.End &&
|
if(firstClusterSector + partition.Start < partition.End &&
|
||||||
imagePlugin.Info.XmlMediaType != XmlMediaType.OpticalDisc)
|
imagePlugin.Info.XmlMediaType != XmlMediaType.OpticalDisc)
|
||||||
@@ -325,40 +328,65 @@ namespace DiscImageChef.Filesystems.FAT
|
|||||||
|
|
||||||
for(int i = 0; i < rootDirectory.Length; i += 32)
|
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 =
|
DirectoryEntry entry =
|
||||||
Marshal.ByteArrayToStructureLittleEndian<DirectoryEntry>(rootDirectory, i, 32);
|
Marshal.ByteArrayToStructureLittleEndian<DirectoryEntry>(rootDirectory, i, 32);
|
||||||
|
|
||||||
byte[] fullname = new byte[11];
|
if(entry.filename[0] == DIRENT_FINISHED) break;
|
||||||
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.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);
|
byte[] fullname = new byte[11];
|
||||||
if(entry.ctime_ms > 0)
|
Array.Copy(entry.filename, 0, fullname, 0, 8);
|
||||||
XmlFsType.CreationDate = XmlFsType.CreationDate.AddMilliseconds(entry.ctime_ms * 10);
|
Array.Copy(entry.extension, 0, fullname, 8, 3);
|
||||||
XmlFsType.CreationDateSpecified = true;
|
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)
|
if(entry.filename[0] == DIRENT_E5) entry.filename[0] = DIRENT_DELETED;
|
||||||
{
|
|
||||||
XmlFsType.ModificationDate = DateHandlers.DosToDateTime(entry.mdate, entry.mtime);
|
|
||||||
XmlFsType.ModificationDateSpecified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user