Add an Attribute field to DirectoryEntry

Makes the behavior more like FS
This commit is contained in:
Alex Barney 2019-03-07 11:57:54 -06:00
parent bc986a4d0b
commit f3d7054c79
10 changed files with 115 additions and 77 deletions

View file

@ -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<DirectoryEntry> 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;
}
}
}

View file

@ -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)

View file

@ -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++;
}

View file

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

View file

@ -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
}
}

View file

@ -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]

View file

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

View file

@ -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<DirectoryEntry> 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;
}
}
}

View file

@ -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)

View file

@ -10,7 +10,6 @@ namespace LibHac.IO
public class PartitionFileSystemBuilder
{
private const int HeaderSize = 0x10;
private const int MetaDataAlignment = 0x20;
private List<Entry> Entries { get; } = new List<Entry>();
private long CurrentOffset { get; set; }