From 3e4dcd94662ddebf035a6c7b692bc196a1bd482e Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 11 Jan 2019 15:26:27 -0600 Subject: [PATCH] Add an IFileSystem provider for DiscUtils --- src/LibHac.Nand/FatFileSystemDirectory.cs | 63 ++++++++++++++ src/LibHac.Nand/FatFileSystemProvider.cs | 92 ++++++++++++++++++++ src/LibHac.Nand/Nand.cs | 16 ++-- src/LibHac/IO/FileSystemExtensions.cs | 2 +- src/LibHac/IO/LocalDirectory.cs | 4 +- src/NandReader/Program.cs | 15 ++-- src/NandReaderGui/ViewModel/NandViewModel.cs | 10 +-- 7 files changed, 179 insertions(+), 23 deletions(-) create mode 100644 src/LibHac.Nand/FatFileSystemDirectory.cs create mode 100644 src/LibHac.Nand/FatFileSystemProvider.cs diff --git a/src/LibHac.Nand/FatFileSystemDirectory.cs b/src/LibHac.Nand/FatFileSystemDirectory.cs new file mode 100644 index 00000000..4dda9ec9 --- /dev/null +++ b/src/LibHac.Nand/FatFileSystemDirectory.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using DiscUtils; +using LibHac.IO; +using DirectoryEntry = LibHac.IO.DirectoryEntry; +using IFileSystem = LibHac.IO.IFileSystem; + +namespace LibHac.Nand +{ + public class FatFileSystemDirectory : IDirectory + { + public IFileSystem ParentFileSystem { get; } + public string FullPath { get; } + public OpenDirectoryMode Mode { get; } + private DiscDirectoryInfo DirInfo { get; } + + public FatFileSystemDirectory(FatFileSystemProvider fs, string path, OpenDirectoryMode mode) + { + ParentFileSystem = fs; + FullPath = path; + Mode = mode; + + path = FatFileSystemProvider.ToDiscUtilsPath(PathTools.Normalize(path)); + + DirInfo = fs.Fs.GetDirectoryInfo(path); + } + + public IEnumerable Read() + { + if (Mode.HasFlag(OpenDirectoryMode.Directories)) + { + foreach (DiscDirectoryInfo dir in DirInfo.GetDirectories()) + { + yield return new DirectoryEntry(dir.Name, FullPath + '/' + dir.Name, DirectoryEntryType.Directory, 0); + } + } + + if (Mode.HasFlag(OpenDirectoryMode.Files)) + { + foreach (DiscFileInfo file in DirInfo.GetFiles()) + { + yield return new DirectoryEntry(file.Name, FullPath + '/' + file.Name, DirectoryEntryType.File, file.Length); + } + } + } + + public int GetEntryCount() + { + int count = 0; + + if (Mode.HasFlag(OpenDirectoryMode.Directories)) + { + count += DirInfo.GetDirectories().Length; + } + + if (Mode.HasFlag(OpenDirectoryMode.Files)) + { + count += DirInfo.GetFiles().Length; + } + + return count; + } + } +} diff --git a/src/LibHac.Nand/FatFileSystemProvider.cs b/src/LibHac.Nand/FatFileSystemProvider.cs new file mode 100644 index 00000000..3d771417 --- /dev/null +++ b/src/LibHac.Nand/FatFileSystemProvider.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; +using DiscUtils.Fat; +using LibHac.IO; + +namespace LibHac.Nand +{ + public class FatFileSystemProvider : IAttributeFileSystem + { + public FatFileSystem Fs { get; } + + public FatFileSystemProvider(FatFileSystem fileSystem) + { + Fs = fileSystem; + } + + public void DeleteDirectory(string path) + { + path = ToDiscUtilsPath(PathTools.Normalize(path)); + Fs.DeleteDirectory(path); + } + + public void DeleteFile(string path) + { + path = ToDiscUtilsPath(PathTools.Normalize(path)); + Fs.DeleteFile(path); + } + + public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + { + path = PathTools.Normalize(path); + + return new FatFileSystemDirectory(this, path, mode); + } + + public IFile OpenFile(string path, OpenMode mode) + { + path = ToDiscUtilsPath(PathTools.Normalize(path)); + + Stream stream = Fs.OpenFile(path, FileMode.Open, GetFileAccess(mode)); + return stream.AsIFile(mode); + } + + public bool DirectoryExists(string path) + { + path = ToDiscUtilsPath(PathTools.Normalize(path)); + + if (path == @"\\") return true; + + return Fs.DirectoryExists(path); + } + + public bool FileExists(string path) + { + path = ToDiscUtilsPath(PathTools.Normalize(path)); + + return Fs.FileExists(path); + } + + public FileAttributes GetFileAttributes(string path) + { + path = ToDiscUtilsPath(PathTools.Normalize(path)); + + return Fs.GetAttributes(path); + } + + public long GetFileSize(string path) + { + path = ToDiscUtilsPath(PathTools.Normalize(path)); + + return Fs.GetFileInfo(path).Length; + } + + public void Commit() { } + + public void CreateDirectory(string path) => throw new NotSupportedException(); + public void CreateFile(string path, long size) => throw new NotSupportedException(); + public void RenameDirectory(string srcPath, string dstPath) => throw new NotSupportedException(); + public void RenameFile(string srcPath, string dstPath) => throw new NotSupportedException(); + + private static FileAccess GetFileAccess(OpenMode mode) + { + // FileAccess and OpenMode have the same flags + return (FileAccess)(mode & OpenMode.ReadWrite); + } + + internal static string ToDiscUtilsPath(string path) + { + return path.Replace("/", @"\\"); + } + } +} diff --git a/src/LibHac.Nand/Nand.cs b/src/LibHac.Nand/Nand.cs index d35d8085..f83483ea 100644 --- a/src/LibHac.Nand/Nand.cs +++ b/src/LibHac.Nand/Nand.cs @@ -37,40 +37,40 @@ namespace LibHac.Nand return decStorage.AsStream(); } - public NandPartition OpenProdInfoF() + public FatFileSystemProvider OpenProdInfoF() { IStorage encStorage = ProdInfoF.Open().AsStorage(); var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[0], 0x4000, true), 0x4000, 4, true); decStorage.SetReadOnly(); var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None); - return new NandPartition(fat); + return new FatFileSystemProvider(fat); } - public NandPartition OpenSafePartition() + public FatFileSystemProvider OpenSafePartition() { IStorage encStorage = Safe.Open().AsStorage(); var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[1], 0x4000, true), 0x4000, 4, true); decStorage.SetReadOnly(); var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None); - return new NandPartition(fat); + return new FatFileSystemProvider(fat); } - public NandPartition OpenSystemPartition() + public FatFileSystemProvider OpenSystemPartition() { IStorage encStorage = System.Open().AsStorage(); var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[2], 0x4000, true), 0x4000, 4, true); decStorage.SetReadOnly(); var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None); - return new NandPartition(fat); + return new FatFileSystemProvider(fat); } - public NandPartition OpenUserPartition() + public FatFileSystemProvider OpenUserPartition() { IStorage encStorage = User.Open().AsStorage(); var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[3], 0x4000, true), 0x4000, 4, true); decStorage.SetReadOnly(); var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None); - return new NandPartition(fat); + return new FatFileSystemProvider(fat); } } } diff --git a/src/LibHac/IO/FileSystemExtensions.cs b/src/LibHac/IO/FileSystemExtensions.cs index 65beb76b..e44396fa 100644 --- a/src/LibHac/IO/FileSystemExtensions.cs +++ b/src/LibHac/IO/FileSystemExtensions.cs @@ -61,7 +61,7 @@ namespace LibHac.IO public static IEnumerable EnumerateEntries(this IFileSystem fileSystem) { - return fileSystem.OpenDirectory("/", OpenDirectoryMode.All).EnumerateEntries(); + return fileSystem.OpenDirectory("/", OpenDirectoryMode.All).EnumerateEntries("*", SearchOptions.RecurseSubdirectories); } public static IEnumerable EnumerateEntries(this IDirectory directory) diff --git a/src/LibHac/IO/LocalDirectory.cs b/src/LibHac/IO/LocalDirectory.cs index 231e070f..b2057c74 100644 --- a/src/LibHac/IO/LocalDirectory.cs +++ b/src/LibHac/IO/LocalDirectory.cs @@ -48,12 +48,12 @@ namespace LibHac.IO if (Mode.HasFlag(OpenDirectoryMode.Directories)) { - count += Directory.EnumerateDirectories(LocalPath).Count(); + count += DirInfo.EnumerateDirectories().Count(); } if (Mode.HasFlag(OpenDirectoryMode.Files)) { - count += Directory.EnumerateFiles(LocalPath).Count(); + count += DirInfo.EnumerateFiles().Count(); } return count; diff --git a/src/NandReader/Program.cs b/src/NandReader/Program.cs index 3bdcb7e3..581ce48a 100644 --- a/src/NandReader/Program.cs +++ b/src/NandReader/Program.cs @@ -49,8 +49,9 @@ namespace NandReader { Keyset keyset = OpenKeyset(); var nand = new Nand(stream, keyset); - NandPartition user = nand.OpenSystemPartition(); - var sdfs = new SwitchFs(keyset, user); + FatFileSystemProvider user = nand.OpenSystemPartition(); + // todo + //var sdfs = new SwitchFs(keyset, user); } } @@ -87,13 +88,13 @@ namespace NandReader private static Ticket[] GetTickets(Keyset keyset, Nand nand, IProgressReport logger = null) { var tickets = new List(); - NandPartition system = nand.OpenSystemPartition(); + FatFileSystemProvider system = nand.OpenSystemPartition(); - Stream saveE1File = system.OpenFile("save\\80000000000000E1", FileMode.Open, FileAccess.Read); - tickets.AddRange(ReadTickets(keyset, saveE1File)); + IFile saveE1File = system.OpenFile("/save/80000000000000E1", OpenMode.Read); + tickets.AddRange(ReadTickets(keyset, saveE1File.AsStream())); - Stream saveE2 = system.OpenFile("save\\80000000000000E2", FileMode.Open, FileAccess.Read); - tickets.AddRange(ReadTickets(keyset, saveE2)); + IFile saveE2 = system.OpenFile("/save/80000000000000E2", OpenMode.Read); + tickets.AddRange(ReadTickets(keyset, saveE2.AsStream())); logger?.LogMessage($"Found {tickets.Count} tickets"); diff --git a/src/NandReaderGui/ViewModel/NandViewModel.cs b/src/NandReaderGui/ViewModel/NandViewModel.cs index 1bf7dfb2..422a0bc1 100644 --- a/src/NandReaderGui/ViewModel/NandViewModel.cs +++ b/src/NandReaderGui/ViewModel/NandViewModel.cs @@ -71,13 +71,13 @@ namespace NandReaderGui.ViewModel private static Ticket[] GetTickets(Keyset keyset, Nand nand, IProgressReport logger = null) { var tickets = new List(); - NandPartition system = nand.OpenSystemPartition(); + FatFileSystemProvider system = nand.OpenSystemPartition(); - Stream saveE1File = system.OpenFile("save\\80000000000000E1", FileMode.Open, FileAccess.Read); - tickets.AddRange(ReadTickets(keyset, saveE1File)); + IFile saveE1File = system.OpenFile("/save/80000000000000E1", OpenMode.Read); + tickets.AddRange(ReadTickets(keyset, saveE1File.AsStream())); - Stream saveE2 = system.OpenFile("save\\80000000000000E2", FileMode.Open, FileAccess.Read); - tickets.AddRange(ReadTickets(keyset, saveE2)); + IFile saveE2 = system.OpenFile("/save/80000000000000E2", OpenMode.Read); + tickets.AddRange(ReadTickets(keyset, saveE2.AsStream())); logger?.LogMessage($"Found {tickets.Count} tickets");