Implement ReadDir() in Xbox FAT plugin.

This commit is contained in:
2019-04-10 19:15:04 +01:00
parent c25d37b3c2
commit 7b8dd99354
3 changed files with 117 additions and 13 deletions

View File

@@ -32,7 +32,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DiscImageChef.CommonTypes.Structs;
using DiscImageChef.Helpers;
namespace DiscImageChef.Filesystems.FATX
{
@@ -43,7 +45,102 @@ namespace DiscImageChef.Filesystems.FATX
contents = null;
if(!mounted) return Errno.AccessDenied;
throw new NotImplementedException();
if(string.IsNullOrWhiteSpace(path) || path == "/")
{
contents = rootDirectory.Keys.ToList();
return Errno.NoError;
}
string cutPath = path.StartsWith("/") ? path.Substring(0).ToLower(cultureInfo) : path.ToLower(cultureInfo);
if(directoryCache.TryGetValue(cutPath, out Dictionary<string, DirectoryEntry> currentDirectory))
{
contents = currentDirectory.Keys.ToList();
return Errno.NoError;
}
string[] pieces = cutPath.Split('/');
KeyValuePair<string, DirectoryEntry> entry =
rootDirectory.FirstOrDefault(t => t.Key.ToLower(cultureInfo) == pieces[0]);
if(string.IsNullOrEmpty(entry.Key)) return Errno.NoSuchFile;
if(!entry.Value.attributes.HasFlag(Attributes.Directory)) return Errno.NotDirectory;
string currentPath = pieces[0];
currentDirectory = rootDirectory;
for(int p = 0; p < pieces.Length; p++)
{
entry = currentDirectory.FirstOrDefault(t => t.Key.ToLower(cultureInfo) == pieces[p]);
if(string.IsNullOrEmpty(entry.Key)) return Errno.NoSuchFile;
if(!entry.Value.attributes.HasFlag(Attributes.Directory)) return Errno.NotDirectory;
currentPath = p == 0 ? pieces[0] : $"{currentPath}/{pieces[p]}";
uint currentCluster = entry.Value.firstCluster;
if(directoryCache.TryGetValue(currentPath, out currentDirectory))
{
if(p == pieces.Length - 1) break;
entry = currentDirectory.FirstOrDefault(t => t.Key.ToLower(cultureInfo) == pieces[p]);
if(string.IsNullOrEmpty(entry.Key)) return Errno.NoSuchFile;
if(!entry.Value.attributes.HasFlag(Attributes.Directory)) return Errno.NotDirectory;
continue;
}
uint[] clusters = GetClusters(currentCluster);
if(clusters is null) return Errno.InvalidArgument;
byte[] directoryBuffer = new byte[bytesPerCluster * clusters.Length];
for(int i = 0; i < clusters.Length; i++)
{
byte[] buffer = imagePlugin.ReadSectors(firstClusterSector + (clusters[i] - 1) * sectorsPerCluster,
sectorsPerCluster);
Array.Copy(buffer, 0, directoryBuffer, i * bytesPerCluster, bytesPerCluster);
}
currentDirectory = new Dictionary<string, DirectoryEntry>();
int pos = 0;
while(pos < directoryBuffer.Length)
{
DirectoryEntry dirent = littleEndian
? Marshal
.ByteArrayToStructureLittleEndian<DirectoryEntry
>(directoryBuffer, pos, Marshal.SizeOf<DirectoryEntry>())
: Marshal.ByteArrayToStructureBigEndian<DirectoryEntry>(directoryBuffer,
pos,
Marshal
.SizeOf<
DirectoryEntry
>());
pos += Marshal.SizeOf<DirectoryEntry>();
if(dirent.filenameSize == UNUSED_DIRENTRY || dirent.filenameSize == FINISHED_DIRENTRY) break;
if(dirent.filenameSize == DELETED_DIRENTRY || dirent.filenameSize > MAX_FILENAME) continue;
string filename = Encoding.GetString(dirent.filename, 0, dirent.filenameSize);
currentDirectory.Add(filename, dirent);
}
directoryCache.Add(currentPath, currentDirectory);
}
contents = currentDirectory?.Keys.ToList();
return Errno.NoError;
}
}
}

View File

@@ -32,6 +32,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using DiscImageChef.CommonTypes;
using DiscImageChef.CommonTypes.Interfaces;
@@ -42,18 +43,20 @@ namespace DiscImageChef.Filesystems.FATX
{
public partial class XboxFatPlugin : IReadOnlyFilesystem
{
uint bytesPerCluster;
ushort[] fat16;
uint[] fat32;
ulong fatStartSector;
ulong firstClusterSector;
IMediaImage imagePlugin;
bool littleEndian;
bool mounted;
Partition partition;
Dictionary<string, DirectoryEntry> rootDirectory;
uint sectorsPerCluster;
FileSystemInfo stat;
uint bytesPerCluster;
CultureInfo cultureInfo;
Dictionary<string, Dictionary<string, DirectoryEntry>> directoryCache;
ushort[] fat16;
uint[] fat32;
ulong fatStartSector;
ulong firstClusterSector;
IMediaImage imagePlugin;
bool littleEndian;
bool mounted;
Partition partition;
Dictionary<string, DirectoryEntry> rootDirectory;
uint sectorsPerCluster;
FileSystemInfo stat;
Superblock superblock;
public FileSystemType XmlFsType { get; private set; }

View File

@@ -32,6 +32,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
using DiscImageChef.CommonTypes;
@@ -207,6 +208,9 @@ namespace DiscImageChef.Filesystems.FATX
rootDirectory.Add(filename, entry);
}
cultureInfo = new CultureInfo("en-US", false);
directoryCache = new Dictionary<string, Dictionary<string, DirectoryEntry>>();
return Errno.NoError;
}