From f3d7054c7972e237fa70e2f68a19280814761be1 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Thu, 7 Mar 2019 11:57:54 -0600 Subject: [PATCH] Add an Attribute field to DirectoryEntry Makes the behavior more like FS --- src/LibHac.Nand/FatFileSystemDirectory.cs | 40 ++++++++++++--------- src/LibHac.Nand/FatFileSystemProvider.cs | 11 +++--- src/LibHac/IO/ConcatenationDirectory.cs | 17 +++++---- src/LibHac/IO/ConcatenationFileSystem.cs | 31 ++++++++-------- src/LibHac/IO/DirectoryEntry.cs | 21 ++++++++--- src/LibHac/IO/FileSystemExtensions.cs | 11 ++++++ src/LibHac/IO/IAttributeFileSystem.cs | 8 ++--- src/LibHac/IO/LocalDirectory.cs | 39 ++++++++++---------- src/LibHac/IO/LocalFileSystem.cs | 13 ++++--- src/LibHac/IO/PartitionFileSystemBuilder.cs | 1 - 10 files changed, 115 insertions(+), 77 deletions(-) diff --git a/src/LibHac.Nand/FatFileSystemDirectory.cs b/src/LibHac.Nand/FatFileSystemDirectory.cs index 4dda9ec9..7e5700c3 100644 --- a/src/LibHac.Nand/FatFileSystemDirectory.cs +++ b/src/LibHac.Nand/FatFileSystemDirectory.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; using DiscUtils; using LibHac.IO; + using DirectoryEntry = LibHac.IO.DirectoryEntry; using IFileSystem = LibHac.IO.IFileSystem; @@ -26,20 +29,19 @@ namespace LibHac.Nand public IEnumerable Read() { - if (Mode.HasFlag(OpenDirectoryMode.Directories)) + foreach (DiscFileSystemInfo entry in DirInfo.GetFileSystemInfos()) { - foreach (DiscDirectoryInfo dir in DirInfo.GetDirectories()) - { - yield return new DirectoryEntry(dir.Name, FullPath + '/' + dir.Name, DirectoryEntryType.Directory, 0); - } - } + bool isDir = (entry.Attributes & FileAttributes.Directory) != 0; - if (Mode.HasFlag(OpenDirectoryMode.Files)) - { - foreach (DiscFileInfo file in DirInfo.GetFiles()) + if (!CanReturnEntry(isDir, Mode)) continue; + + DirectoryEntryType type = isDir ? DirectoryEntryType.File : DirectoryEntryType.Directory; + long length = isDir ? 0 : ((DiscFileInfo)entry).Length; + + yield return new DirectoryEntry(entry.Name, FullPath + '/' + entry.Name, type, length) { - yield return new DirectoryEntry(file.Name, FullPath + '/' + file.Name, DirectoryEntryType.File, file.Length); - } + Attributes = entry.Attributes.ToNxAttributes() + }; } } @@ -47,17 +49,21 @@ namespace LibHac.Nand { int count = 0; - if (Mode.HasFlag(OpenDirectoryMode.Directories)) + foreach (DiscFileSystemInfo entry in DirInfo.GetFileSystemInfos()) { - count += DirInfo.GetDirectories().Length; - } + bool isDir = (entry.Attributes & FileAttributes.Directory) != 0; - if (Mode.HasFlag(OpenDirectoryMode.Files)) - { - count += DirInfo.GetFiles().Length; + if (CanReturnEntry(isDir, Mode)) count++; } return count; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool CanReturnEntry(bool isDir, OpenDirectoryMode mode) + { + return isDir && (mode & OpenDirectoryMode.Directories) != 0 || + !isDir && (mode & OpenDirectoryMode.Files) != 0; + } } } diff --git a/src/LibHac.Nand/FatFileSystemProvider.cs b/src/LibHac.Nand/FatFileSystemProvider.cs index e7539111..06f3ff78 100644 --- a/src/LibHac.Nand/FatFileSystemProvider.cs +++ b/src/LibHac.Nand/FatFileSystemProvider.cs @@ -68,18 +68,21 @@ namespace LibHac.Nand throw new FileNotFoundException(path); } - public FileAttributes GetFileAttributes(string path) + public NxFileAttributes GetFileAttributes(string path) { path = ToDiscUtilsPath(PathTools.Normalize(path)); - return Fs.GetAttributes(path); + return Fs.GetAttributes(path).ToNxAttributes(); } - public void SetFileAttributes(string path, FileAttributes attributes) + public void SetFileAttributes(string path, NxFileAttributes attributes) { path = ToDiscUtilsPath(PathTools.Normalize(path)); - Fs.SetAttributes(path, attributes); + FileAttributes attributesOld = File.GetAttributes(path); + FileAttributes attributesNew = attributesOld.ApplyNxAttributes(attributes); + + Fs.SetAttributes(path, attributesNew); } public long GetFileSize(string path) diff --git a/src/LibHac/IO/ConcatenationDirectory.cs b/src/LibHac/IO/ConcatenationDirectory.cs index 1c34f069..d9a40e12 100644 --- a/src/LibHac/IO/ConcatenationDirectory.cs +++ b/src/LibHac/IO/ConcatenationDirectory.cs @@ -23,19 +23,18 @@ namespace LibHac.IO { foreach (DirectoryEntry entry in ParentDirectory.Read()) { - bool isSplit = ParentFileSystem.IsSplitFile(entry.FullPath); + bool isSplit = ConcatenationFileSystem.HasConcatenationFileAttribute(entry.Attributes); if (!CanReturnEntry(entry, isSplit)) continue; - if (!isSplit) + if (isSplit) { - yield return entry; - } - else - { - long size = ParentFileSystem.GetConcatenationFileSize(entry.FullPath); - yield return new DirectoryEntry(entry.Name, entry.FullPath, DirectoryEntryType.File, size); + entry.Type = DirectoryEntryType.File; + entry.Size = ParentFileSystem.GetConcatenationFileSize(entry.FullPath); + entry.Attributes = NxFileAttributes.None; } + + yield return entry; } } @@ -45,7 +44,7 @@ namespace LibHac.IO foreach (DirectoryEntry entry in ParentDirectory.Read()) { - bool isSplit = ParentFileSystem.IsSplitFile(entry.FullPath); + bool isSplit = ConcatenationFileSystem.HasConcatenationFileAttribute(entry.Attributes); if (CanReturnEntry(entry, isSplit)) count++; } diff --git a/src/LibHac/IO/ConcatenationFileSystem.cs b/src/LibHac/IO/ConcatenationFileSystem.cs index a4fe26e5..e85a3edc 100644 --- a/src/LibHac/IO/ConcatenationFileSystem.cs +++ b/src/LibHac/IO/ConcatenationFileSystem.cs @@ -18,11 +18,14 @@ namespace LibHac.IO SplitFileSize = splitFileSize; } - internal bool IsSplitFile(string path) + internal bool IsConcatenationFile(string path) { - FileAttributes attributes = BaseFileSystem.GetFileAttributes(path); + return HasConcatenationFileAttribute(BaseFileSystem.GetFileAttributes(path)); + } - return (attributes & FileAttributes.Directory) != 0 && (attributes & FileAttributes.Archive) != 0; + internal static bool HasConcatenationFileAttribute(NxFileAttributes attributes) + { + return (attributes & NxFileAttributes.Directory) != 0 && (attributes & NxFileAttributes.Archive) != 0; } public void CreateDirectory(string path) @@ -51,10 +54,10 @@ namespace LibHac.IO // A concatenation file directory can't contain normal files string parentDir = PathTools.GetParentDirectory(path); - if (IsSplitFile(parentDir)) throw new IOException("Cannot create files inside of a concatenation file"); + if (IsConcatenationFile(parentDir)) throw new IOException("Cannot create files inside of a concatenation file"); BaseFileSystem.CreateDirectory(path); - FileAttributes attributes = BaseFileSystem.GetFileAttributes(path) | FileAttributes.Archive; + NxFileAttributes attributes = BaseFileSystem.GetFileAttributes(path) | NxFileAttributes.Archive; BaseFileSystem.SetFileAttributes(path, attributes); long remaining = size; @@ -74,7 +77,7 @@ namespace LibHac.IO { path = PathTools.Normalize(path); - if (IsSplitFile(path)) + if (IsConcatenationFile(path)) { throw new DirectoryNotFoundException(path); } @@ -86,7 +89,7 @@ namespace LibHac.IO { path = PathTools.Normalize(path); - if (!IsSplitFile(path)) + if (!IsConcatenationFile(path)) { BaseFileSystem.DeleteFile(path); } @@ -105,7 +108,7 @@ namespace LibHac.IO { path = PathTools.Normalize(path); - if (IsSplitFile(path)) + if (IsConcatenationFile(path)) { throw new DirectoryNotFoundException(path); } @@ -119,7 +122,7 @@ namespace LibHac.IO { path = PathTools.Normalize(path); - if (!IsSplitFile(path)) + if (!IsConcatenationFile(path)) { return BaseFileSystem.OpenFile(path, mode); } @@ -143,7 +146,7 @@ namespace LibHac.IO srcPath = PathTools.Normalize(srcPath); dstPath = PathTools.Normalize(dstPath); - if (IsSplitFile(srcPath)) + if (IsConcatenationFile(srcPath)) { throw new DirectoryNotFoundException(); } @@ -156,7 +159,7 @@ namespace LibHac.IO srcPath = PathTools.Normalize(srcPath); dstPath = PathTools.Normalize(dstPath); - if (IsSplitFile(srcPath)) + if (IsConcatenationFile(srcPath)) { BaseFileSystem.RenameDirectory(srcPath, dstPath); } @@ -170,21 +173,21 @@ namespace LibHac.IO { path = PathTools.Normalize(path); - return BaseFileSystem.DirectoryExists(path) && !IsSplitFile(path); + return BaseFileSystem.DirectoryExists(path) && !IsConcatenationFile(path); } public bool FileExists(string path) { path = PathTools.Normalize(path); - return BaseFileSystem.FileExists(path) || BaseFileSystem.DirectoryExists(path) && IsSplitFile(path); + return BaseFileSystem.FileExists(path) || BaseFileSystem.DirectoryExists(path) && IsConcatenationFile(path); } public DirectoryEntryType GetEntryType(string path) { path = PathTools.Normalize(path); - if (IsSplitFile(path)) return DirectoryEntryType.File; + if (IsConcatenationFile(path)) return DirectoryEntryType.File; return BaseFileSystem.GetEntryType(path); } diff --git a/src/LibHac/IO/DirectoryEntry.cs b/src/LibHac/IO/DirectoryEntry.cs index a04c48ed..e4814f49 100644 --- a/src/LibHac/IO/DirectoryEntry.cs +++ b/src/LibHac/IO/DirectoryEntry.cs @@ -1,11 +1,14 @@ -namespace LibHac.IO +using System; + +namespace LibHac.IO { public class DirectoryEntry { - public string Name { get; } - public string FullPath { get; } - public DirectoryEntryType Type { get; } - public long Size { get; } + public string Name { get; set; } + public string FullPath { get; set; } + public NxFileAttributes Attributes { get; set; } + public DirectoryEntryType Type { get; set; } + public long Size { get; set; } public DirectoryEntry(string name, string fullPath, DirectoryEntryType type, long size) { @@ -21,4 +24,12 @@ Directory, File } + + [Flags] + public enum NxFileAttributes + { + None = 0, + Directory = 1 << 0, + Archive = 1 << 1 + } } diff --git a/src/LibHac/IO/FileSystemExtensions.cs b/src/LibHac/IO/FileSystemExtensions.cs index 1fab500d..a81614b1 100644 --- a/src/LibHac/IO/FileSystemExtensions.cs +++ b/src/LibHac/IO/FileSystemExtensions.cs @@ -166,6 +166,17 @@ namespace LibHac.IO name.AsSpan(), ignoreCase); #endif } + + public static NxFileAttributes ToNxAttributes(this FileAttributes attributes) + { + return (NxFileAttributes)(((int)attributes >> 4) & 3); + } + + public static FileAttributes ApplyNxAttributes(this FileAttributes attributes, NxFileAttributes nxAttributes) + { + var nxAttributeBits = (FileAttributes)(((int)attributes & 3) << 4); + return attributes | nxAttributeBits; + } } [Flags] diff --git a/src/LibHac/IO/IAttributeFileSystem.cs b/src/LibHac/IO/IAttributeFileSystem.cs index 8fb79fa3..3c624549 100644 --- a/src/LibHac/IO/IAttributeFileSystem.cs +++ b/src/LibHac/IO/IAttributeFileSystem.cs @@ -1,11 +1,9 @@ -using System.IO; - -namespace LibHac.IO +namespace LibHac.IO { public interface IAttributeFileSystem : IFileSystem { - FileAttributes GetFileAttributes(string path); - void SetFileAttributes(string path, FileAttributes attributes); + NxFileAttributes GetFileAttributes(string path); + void SetFileAttributes(string path, NxFileAttributes attributes); long GetFileSize(string path); } } diff --git a/src/LibHac/IO/LocalDirectory.cs b/src/LibHac/IO/LocalDirectory.cs index b2057c74..4723bcfd 100644 --- a/src/LibHac/IO/LocalDirectory.cs +++ b/src/LibHac/IO/LocalDirectory.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.IO; -using System.Linq; +using System.Runtime.CompilerServices; namespace LibHac.IO { @@ -25,20 +25,19 @@ namespace LibHac.IO public IEnumerable Read() { - if (Mode.HasFlag(OpenDirectoryMode.Directories)) + foreach (FileSystemInfo entry in DirInfo.EnumerateFileSystemInfos()) { - foreach (DirectoryInfo dir in DirInfo.EnumerateDirectories()) - { - yield return new DirectoryEntry(dir.Name, FullPath + '/' + dir.Name, DirectoryEntryType.Directory, 0); - } - } + bool isDir = (entry.Attributes & FileAttributes.Directory) != 0; - if (Mode.HasFlag(OpenDirectoryMode.Files)) - { - foreach (FileInfo file in DirInfo.EnumerateFiles()) + if (!CanReturnEntry(isDir, Mode)) continue; + + DirectoryEntryType type = isDir ? DirectoryEntryType.Directory : DirectoryEntryType.File; + long length = isDir ? 0 : ((FileInfo)entry).Length; + + yield return new DirectoryEntry(entry.Name, FullPath + '/' + entry.Name, type, length) { - yield return new DirectoryEntry(file.Name, FullPath + '/' + file.Name, DirectoryEntryType.File, file.Length); - } + Attributes = entry.Attributes.ToNxAttributes() + }; } } @@ -46,17 +45,21 @@ namespace LibHac.IO { int count = 0; - if (Mode.HasFlag(OpenDirectoryMode.Directories)) + foreach (FileSystemInfo entry in DirInfo.EnumerateFileSystemInfos()) { - count += DirInfo.EnumerateDirectories().Count(); - } + bool isDir = (entry.Attributes & FileAttributes.Directory) != 0; - if (Mode.HasFlag(OpenDirectoryMode.Files)) - { - count += DirInfo.EnumerateFiles().Count(); + if (CanReturnEntry(isDir, Mode)) count++; } return count; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool CanReturnEntry(bool isDir, OpenDirectoryMode mode) + { + return isDir && (mode & OpenDirectoryMode.Directories) != 0 || + !isDir && (mode & OpenDirectoryMode.Files) != 0; + } } } diff --git a/src/LibHac/IO/LocalFileSystem.cs b/src/LibHac/IO/LocalFileSystem.cs index c665698e..84f0ca93 100644 --- a/src/LibHac/IO/LocalFileSystem.cs +++ b/src/LibHac/IO/LocalFileSystem.cs @@ -26,16 +26,21 @@ namespace LibHac.IO return Path.Combine(BasePath, path.TrimStart('/')); } - public FileAttributes GetFileAttributes(string path) + public NxFileAttributes GetFileAttributes(string path) { path = PathTools.Normalize(path); - return File.GetAttributes(ResolveLocalPath(path)); + return File.GetAttributes(ResolveLocalPath(path)).ToNxAttributes(); } - public void SetFileAttributes(string path, FileAttributes attributes) + public void SetFileAttributes(string path, NxFileAttributes attributes) { path = PathTools.Normalize(path); - File.SetAttributes(ResolveLocalPath(path), attributes); + string localPath = ResolveLocalPath(path); + + FileAttributes attributesOld = File.GetAttributes(localPath); + FileAttributes attributesNew = attributesOld.ApplyNxAttributes(attributes); + + File.SetAttributes(localPath, attributesNew); } public long GetFileSize(string path) diff --git a/src/LibHac/IO/PartitionFileSystemBuilder.cs b/src/LibHac/IO/PartitionFileSystemBuilder.cs index 4f96e2aa..cec52bc2 100644 --- a/src/LibHac/IO/PartitionFileSystemBuilder.cs +++ b/src/LibHac/IO/PartitionFileSystemBuilder.cs @@ -10,7 +10,6 @@ namespace LibHac.IO public class PartitionFileSystemBuilder { private const int HeaderSize = 0x10; - private const int MetaDataAlignment = 0x20; private List Entries { get; } = new List(); private long CurrentOffset { get; set; }