diff --git a/build/CodeGen/results.csv b/build/CodeGen/results.csv index 39f37d15..6eab7333 100644 --- a/build/CodeGen/results.csv +++ b/build/CodeGen/results.csv @@ -152,7 +152,7 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary 2,6061,,InvalidOffset, 2,6062,,InvalidSize, -2,6063,,NullArgument, +2,6063,,NullptrArgument, 2,6065,,InvalidMountName, 2,6066,,ExtensionSizeTooLarge, 2,6067,,ExtensionSizeInvalid, diff --git a/src/LibHac/Common/U8Span.cs b/src/LibHac/Common/U8Span.cs index 3dedc2ef..b14f32cd 100644 --- a/src/LibHac/Common/U8Span.cs +++ b/src/LibHac/Common/U8Span.cs @@ -62,9 +62,9 @@ namespace LibHac.Common return new U8Span(_buffer.Slice(start, length)); } - public static implicit operator ReadOnlySpan(U8Span value) => value.Value; + public static implicit operator ReadOnlySpan(in U8Span value) => value.Value; - public static explicit operator string(U8Span value) => value.ToString(); + public static explicit operator string(in U8Span value) => value.ToString(); public static explicit operator U8Span(string value) => new U8Span(value); public override string ToString() diff --git a/src/LibHac/Common/U8String.cs b/src/LibHac/Common/U8String.cs index e995298e..c41083bb 100644 --- a/src/LibHac/Common/U8String.cs +++ b/src/LibHac/Common/U8String.cs @@ -46,6 +46,18 @@ namespace LibHac.Common return StringUtils.Utf8ZToString(_buffer); } - public bool IsEmpty() => _buffer == null || _buffer.Length == 0; + /// + /// Checks if the has no buffer. + /// + /// if the string has no buffer. + /// Otherwise, . + public bool IsNull() => _buffer == null; + + /// + /// Checks if the has no buffer or begins with a null terminator. + /// + /// if the string has no buffer or begins with a null terminator. + /// Otherwise, . + public bool IsEmpty() => _buffer == null || _buffer.Length < 1 || _buffer[0] == 0; } } diff --git a/src/LibHac/Fs/Accessors/DirectoryAccessor.cs b/src/LibHac/Fs/Accessors/DirectoryAccessor.cs index 75cf7b25..582e0aa6 100644 --- a/src/LibHac/Fs/Accessors/DirectoryAccessor.cs +++ b/src/LibHac/Fs/Accessors/DirectoryAccessor.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using LibHac.FsSystem; namespace LibHac.Fs.Accessors { @@ -10,22 +8,10 @@ namespace LibHac.Fs.Accessors public FileSystemAccessor Parent { get; } - private IFileSystem ParentFs { get; } - private string Path { get; } - - public DirectoryAccessor(IDirectory baseDirectory, FileSystemAccessor parent, IFileSystem parentFs, string path) + public DirectoryAccessor(IDirectory baseDirectory, FileSystemAccessor parent) { Directory = baseDirectory; Parent = parent; - ParentFs = parentFs; - Path = path; - } - - public IEnumerable Read() - { - CheckIfDisposed(); - - return ParentFs.EnumerateEntries(Path, "*", SearchOptions.Default); } public Result Read(out long entriesRead, Span entryBuffer) diff --git a/src/LibHac/Fs/Accessors/FileSystemAccessor.cs b/src/LibHac/Fs/Accessors/FileSystemAccessor.cs index 22bc24f4..2178d29b 100644 --- a/src/LibHac/Fs/Accessors/FileSystemAccessor.cs +++ b/src/LibHac/Fs/Accessors/FileSystemAccessor.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using LibHac.FsSystem; +using LibHac.Common; namespace LibHac.Fs.Accessors { @@ -28,44 +28,44 @@ namespace LibHac.Fs.Accessors MountNameGenerator = nameGenerator; } - public Result CreateDirectory(string path) + public Result CreateDirectory(U8Span path) { return FileSystem.CreateDirectory(path); } - public Result CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(U8Span path, long size, CreateFileOptions options) { return FileSystem.CreateFile(path, size, options); } - public Result DeleteDirectory(string path) + public Result DeleteDirectory(U8Span path) { return FileSystem.DeleteDirectory(path); } - public Result DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(U8Span path) { return FileSystem.DeleteDirectoryRecursively(path); } - public Result CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(U8Span path) { return FileSystem.CleanDirectoryRecursively(path); } - public Result DeleteFile(string path) + public Result DeleteFile(U8Span path) { return FileSystem.DeleteFile(path); } - public Result OpenDirectory(out DirectoryAccessor directory, string path, OpenDirectoryMode mode) + public Result OpenDirectory(out DirectoryAccessor directory, U8Span path, OpenDirectoryMode mode) { directory = default; Result rc = FileSystem.OpenDirectory(out IDirectory rawDirectory, path, mode); if (rc.IsFailure()) return rc; - var accessor = new DirectoryAccessor(rawDirectory, this, FileSystem, path); + var accessor = new DirectoryAccessor(rawDirectory, this); lock (_locker) { @@ -76,7 +76,7 @@ namespace LibHac.Fs.Accessors return Result.Success; } - public Result OpenFile(out FileAccessor file, string path, OpenMode mode) + public Result OpenFile(out FileAccessor file, U8Span path, OpenMode mode) { file = default; @@ -94,42 +94,32 @@ namespace LibHac.Fs.Accessors return Result.Success; } - public Result RenameDirectory(string oldPath, string newPath) + public Result RenameDirectory(U8Span oldPath, U8Span newPath) { return FileSystem.RenameDirectory(oldPath, newPath); } - public Result RenameFile(string oldPath, string newPath) + public Result RenameFile(U8Span oldPath, U8Span newPath) { return FileSystem.RenameFile(oldPath, newPath); } - public bool DirectoryExists(string path) - { - return FileSystem.DirectoryExists(path); - } - - public bool FileExists(string path) - { - return FileSystem.FileExists(path); - } - - public Result GetEntryType(out DirectoryEntryType type, string path) + public Result GetEntryType(out DirectoryEntryType type, U8Span path) { return FileSystem.GetEntryType(out type, path); } - public Result GetFreeSpaceSize(out long freeSpace, string path) + public Result GetFreeSpaceSize(out long freeSpace, U8Span path) { return FileSystem.GetFreeSpaceSize(out freeSpace, path); } - public Result GetTotalSpaceSize(out long totalSpace, string path) + public Result GetTotalSpaceSize(out long totalSpace, U8Span path) { return FileSystem.GetTotalSpaceSize(out totalSpace, path); } - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path) { return FileSystem.GetFileTimeStampRaw(out timeStamp, path); } @@ -144,7 +134,7 @@ namespace LibHac.Fs.Accessors return FileSystem.Commit(); } - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, U8Span path, QueryId queryId) { return FileSystem.QueryEntry(outBuffer, inBuffer, queryId, path); } diff --git a/src/LibHac/Fs/AttributeFileSystemBase.cs b/src/LibHac/Fs/AttributeFileSystemBase.cs index de0997c1..2da813c0 100644 --- a/src/LibHac/Fs/AttributeFileSystemBase.cs +++ b/src/LibHac/Fs/AttributeFileSystemBase.cs @@ -1,20 +1,22 @@ -namespace LibHac.Fs +using LibHac.Common; + +namespace LibHac.Fs { public abstract class AttributeFileSystemBase : FileSystemBase, IAttributeFileSystem { - protected abstract Result CreateDirectoryImpl(string path, NxFileAttributes archiveAttribute); - protected abstract Result GetFileAttributesImpl(string path, out NxFileAttributes attributes); - protected abstract Result SetFileAttributesImpl(string path, NxFileAttributes attributes); - protected abstract Result GetFileSizeImpl(out long fileSize, string path); + protected abstract Result CreateDirectoryImpl(U8Span path, NxFileAttributes archiveAttribute); + protected abstract Result GetFileAttributesImpl(out NxFileAttributes attributes, U8Span path); + protected abstract Result SetFileAttributesImpl(U8Span path, NxFileAttributes attributes); + protected abstract Result GetFileSizeImpl(out long fileSize, U8Span path); - public Result CreateDirectory(string path, NxFileAttributes archiveAttribute) + public Result CreateDirectory(U8Span path, NxFileAttributes archiveAttribute) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return CreateDirectoryImpl(path, archiveAttribute); } - public Result GetFileAttributes(out NxFileAttributes attributes, string path) + public Result GetFileAttributes(out NxFileAttributes attributes, U8Span path) { if (IsDisposed) { @@ -22,17 +24,17 @@ return ResultFs.PreconditionViolation.Log(); } - return GetFileAttributesImpl(path, out attributes); + return GetFileAttributesImpl(out attributes, path); } - public Result SetFileAttributes(string path, NxFileAttributes attributes) + public Result SetFileAttributes(U8Span path, NxFileAttributes attributes) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return SetFileAttributesImpl(path, attributes); } - public Result GetFileSize(out long fileSize, string path) + public Result GetFileSize(out long fileSize, U8Span path) { if (IsDisposed) { diff --git a/src/LibHac/Fs/CommonMountNames.cs b/src/LibHac/Fs/CommonMountNames.cs index c4f044cf..a3cdc16e 100644 --- a/src/LibHac/Fs/CommonMountNames.cs +++ b/src/LibHac/Fs/CommonMountNames.cs @@ -4,16 +4,16 @@ namespace LibHac.Fs { internal static class CommonMountNames { - public static readonly U8String GameCardMountName = new U8String("@Gc"); - public static readonly U8String SystemContentMountName = new U8String("@SystemContent"); - public static readonly U8String UserContentMountName = new U8String("@UserContent"); - public static readonly U8String SdCardContentMountName = new U8String("@SdCardContent"); - public static readonly U8String CalibrationPartitionMountName = new U8String("@CalibFile"); - public static readonly U8String SafePartitionMountName = new U8String("@Safe"); - public static readonly U8String UserPartitionMountName = new U8String("@User"); - public static readonly U8String SystemPartitionMountName = new U8String("@System"); - public static readonly U8String SdCardMountName = new U8String("@Sdcard"); - public static readonly U8String HostMountName = new U8String("@Host"); + public static readonly U8String GameCardFileSystemMountName = new U8String("@Gc"); + public static readonly U8String ContentStorageSystemMountName = new U8String("@SystemContent"); + public static readonly U8String ContentStorageUserMountName = new U8String("@UserContent"); + public static readonly U8String ContentStorageSdCardMountName = new U8String("@SdCardContent"); + public static readonly U8String BisCalibrationFilePartitionMountName = new U8String("@CalibFile"); + public static readonly U8String BisSafeModePartitionMountName = new U8String("@Safe"); + public static readonly U8String BisUserPartitionMountName = new U8String("@User"); + public static readonly U8String BisSystemPartitionMountName = new U8String("@System"); + public static readonly U8String SdCardFileSystemMountName = new U8String("@Sdcard"); + public static readonly U8String HostRootFileSystemMountName = new U8String("@Host"); public static readonly U8String RegisteredUpdatePartitionMountName = new U8String("@RegUpdate"); } } diff --git a/src/LibHac/Fs/FileStorageBasedFileSystem.cs b/src/LibHac/Fs/FileStorageBasedFileSystem.cs index a76888a7..cc27d1bb 100644 --- a/src/LibHac/Fs/FileStorageBasedFileSystem.cs +++ b/src/LibHac/Fs/FileStorageBasedFileSystem.cs @@ -30,7 +30,7 @@ namespace LibHac.Fs private Result Initialize(IFileSystem baseFileSystem, U8Span path, OpenMode mode) { - Result rc = baseFileSystem.OpenFile(out IFile file, path.ToString(), mode); + Result rc = baseFileSystem.OpenFile(out IFile file, path, mode); if (rc.IsFailure()) return rc; SetFile(file); diff --git a/src/LibHac/Fs/FileSystemBase.cs b/src/LibHac/Fs/FileSystemBase.cs index 4c6ab0ff..5303b688 100644 --- a/src/LibHac/Fs/FileSystemBase.cs +++ b/src/LibHac/Fs/FileSystemBase.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using LibHac.Common; namespace LibHac.Fs { @@ -9,85 +10,86 @@ namespace LibHac.Fs private int _disposedState; protected bool IsDisposed => _disposedState != 0; - protected abstract Result CreateDirectoryImpl(string path); - protected abstract Result CreateFileImpl(string path, long size, CreateFileOptions options); - protected abstract Result DeleteDirectoryImpl(string path); - protected abstract Result DeleteDirectoryRecursivelyImpl(string path); - protected abstract Result CleanDirectoryRecursivelyImpl(string path); - protected abstract Result DeleteFileImpl(string path); - protected abstract Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode); - protected abstract Result OpenFileImpl(out IFile file, string path, OpenMode mode); - protected abstract Result RenameDirectoryImpl(string oldPath, string newPath); - protected abstract Result RenameFileImpl(string oldPath, string newPath); - protected abstract Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path); + protected abstract Result CreateDirectoryImpl(U8Span path); + protected abstract Result CreateFileImpl(U8Span path, long size, CreateFileOptions options); + protected abstract Result DeleteDirectoryImpl(U8Span path); + protected abstract Result DeleteDirectoryRecursivelyImpl(U8Span path); + protected abstract Result CleanDirectoryRecursivelyImpl(U8Span path); + protected abstract Result DeleteFileImpl(U8Span path); + protected abstract Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode); + protected abstract Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode); + protected abstract Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath); + protected abstract Result RenameFileImpl(U8Span oldPath, U8Span newPath); + protected abstract Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path); protected abstract Result CommitImpl(); - protected virtual Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + protected virtual Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path) { freeSpace = default; return ResultFs.NotImplemented.Log(); } - protected virtual Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + protected virtual Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path) { totalSpace = default; return ResultFs.NotImplemented.Log(); } - protected virtual Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) + protected virtual Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path) { timeStamp = default; return ResultFs.NotImplemented.Log(); } - protected virtual Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + protected virtual Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, + U8Span path) { return ResultFs.NotImplemented.Log(); } - public Result CreateDirectory(string path) + public Result CreateDirectory(U8Span path) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return CreateDirectoryImpl(path); } - public Result CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(U8Span path, long size, CreateFileOptions options) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return CreateFileImpl(path, size, options); } - public Result DeleteDirectory(string path) + public Result DeleteDirectory(U8Span path) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return DeleteDirectoryImpl(path); } - public Result DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(U8Span path) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return DeleteDirectoryRecursivelyImpl(path); } - public Result CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(U8Span path) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return CleanDirectoryRecursivelyImpl(path); } - public Result DeleteFile(string path) + public Result DeleteFile(U8Span path) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return DeleteFileImpl(path); } - public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { if (IsDisposed) { @@ -95,10 +97,10 @@ namespace LibHac.Fs return ResultFs.PreconditionViolation.Log(); } - if (path == null) + if (path.IsNull()) { directory = default; - return ResultFs.NullArgument.Log(); + return ResultFs.NullptrArgument.Log(); } if ((mode & ~OpenDirectoryMode.All) != 0 || (mode & OpenDirectoryMode.All) == 0) @@ -110,7 +112,7 @@ namespace LibHac.Fs return OpenDirectoryImpl(out directory, path, mode); } - public Result OpenFile(out IFile file, string path, OpenMode mode) + public Result OpenFile(out IFile file, U8Span path, OpenMode mode) { if (IsDisposed) { @@ -118,10 +120,10 @@ namespace LibHac.Fs return ResultFs.PreconditionViolation.Log(); } - if (path == null) + if (path.IsNull()) { file = default; - return ResultFs.NullArgument.Log(); + return ResultFs.NullptrArgument.Log(); } if ((mode & ~OpenMode.All) != 0 || (mode & OpenMode.ReadWrite) == 0) @@ -133,21 +135,21 @@ namespace LibHac.Fs return OpenFileImpl(out file, path, mode); } - public Result RenameDirectory(string oldPath, string newPath) + public Result RenameDirectory(U8Span oldPath, U8Span newPath) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return RenameDirectoryImpl(oldPath, newPath); } - public Result RenameFile(string oldPath, string newPath) + public Result RenameFile(U8Span oldPath, U8Span newPath) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); return RenameFileImpl(oldPath, newPath); } - public Result GetEntryType(out DirectoryEntryType entryType, string path) + public Result GetEntryType(out DirectoryEntryType entryType, U8Span path) { if (IsDisposed) { @@ -158,7 +160,7 @@ namespace LibHac.Fs return GetEntryTypeImpl(out entryType, path); } - public Result GetFreeSpaceSize(out long freeSpace, string path) + public Result GetFreeSpaceSize(out long freeSpace, U8Span path) { if (IsDisposed) { @@ -169,7 +171,7 @@ namespace LibHac.Fs return GetFreeSpaceSizeImpl(out freeSpace, path); } - public Result GetTotalSpaceSize(out long totalSpace, string path) + public Result GetTotalSpaceSize(out long totalSpace, U8Span path) { if (IsDisposed) { @@ -180,7 +182,7 @@ namespace LibHac.Fs return GetTotalSpaceSizeImpl(out totalSpace, path); } - public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path) { if (IsDisposed) { @@ -198,7 +200,7 @@ namespace LibHac.Fs return CommitImpl(); } - public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, U8Span path) { if (IsDisposed) return ResultFs.PreconditionViolation.Log(); diff --git a/src/LibHac/Fs/FileSystemClient.AccessLog.cs b/src/LibHac/Fs/FileSystemClient.AccessLog.cs index f42231f0..bc1b988f 100644 --- a/src/LibHac/Fs/FileSystemClient.AccessLog.cs +++ b/src/LibHac/Fs/FileSystemClient.AccessLog.cs @@ -105,9 +105,9 @@ namespace LibHac.Fs return IsEnabledAccessLog(AccessLogTarget.All); } - internal bool IsEnabledFileSystemAccessorAccessLog(string mountName) + internal bool IsEnabledFileSystemAccessorAccessLog(U8Span mountName) { - if (MountTable.Find(mountName, out FileSystemAccessor accessor).IsFailure()) + if (MountTable.Find(mountName.ToString(), out FileSystemAccessor accessor).IsFailure()) { return true; } diff --git a/src/LibHac/Fs/FileSystemClient.FileSystem.cs b/src/LibHac/Fs/FileSystemClient.FileSystem.cs index 7ed7e6a9..73e40b0b 100644 --- a/src/LibHac/Fs/FileSystemClient.FileSystem.cs +++ b/src/LibHac/Fs/FileSystemClient.FileSystem.cs @@ -1,147 +1,148 @@ using System; +using LibHac.Common; using LibHac.Fs.Accessors; namespace LibHac.Fs { public partial class FileSystemClient { - public Result CreateDirectory(string path) + public Result CreateDirectory(U8Span path) { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.CreateDirectory(subPath.ToString()); + rc = fileSystem.CreateDirectory(subPath); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\""); } else { - rc = fileSystem.CreateDirectory(subPath.ToString()); + rc = fileSystem.CreateDirectory(subPath); } return rc; } - public Result CreateFile(string path, long size) + public Result CreateFile(U8Span path, long size) { return CreateFile(path, size, CreateFileOptions.None); } - public Result CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(U8Span path, long size, CreateFileOptions options) { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.CreateFile(subPath.ToString(), size, options); + rc = fileSystem.CreateFile(subPath, size, options); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\", size: {size}"); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\", size: {size}"); } else { - rc = fileSystem.CreateFile(subPath.ToString(), size, options); + rc = fileSystem.CreateFile(subPath, size, options); } return rc; } - public Result DeleteDirectory(string path) + public Result DeleteDirectory(U8Span path) { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.DeleteDirectory(subPath.ToString()); + rc = fileSystem.DeleteDirectory(subPath); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\""); } else { - rc = fileSystem.DeleteDirectory(subPath.ToString()); + rc = fileSystem.DeleteDirectory(subPath); } return rc; } - public Result DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(U8Span path) { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); + rc = fileSystem.DeleteDirectoryRecursively(subPath); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\""); } else { - rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); + rc = fileSystem.DeleteDirectoryRecursively(subPath); } return rc; } - public Result CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(U8Span path) { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); + rc = fileSystem.CleanDirectoryRecursively(subPath); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\""); } else { - rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); + rc = fileSystem.CleanDirectoryRecursively(subPath); } return rc; } - public Result DeleteFile(string path) + public Result DeleteFile(U8Span path) { - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.DeleteFile(subPath.ToString()); + rc = fileSystem.DeleteFile(subPath); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\""); } else { - rc = fileSystem.DeleteFile(subPath.ToString()); + rc = fileSystem.DeleteFile(subPath); } return rc; } - public Result RenameDirectory(string oldPath, string newPath) + public Result RenameDirectory(U8Span oldPath, U8Span newPath) { - Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath); + Result rc = FindFileSystem(out FileSystemAccessor oldFileSystem, out U8Span oldSubPath, oldPath); if (rc.IsFailure()) return rc; - rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath); + rc = FindFileSystem(out FileSystemAccessor newFileSystem, out U8Span newSubPath, newPath); if (rc.IsFailure()) return rc; if (oldFileSystem != newFileSystem) @@ -152,25 +153,25 @@ namespace LibHac.Fs if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameDirectory(oldSubPath, newSubPath); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath.ToString()}\", new_path: \"{newPath.ToString()}\""); } else { - rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameDirectory(oldSubPath, newSubPath); } return rc; } - public Result RenameFile(string oldPath, string newPath) + public Result RenameFile(U8Span oldPath, U8Span newPath) { - Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath); + Result rc = FindFileSystem(out FileSystemAccessor oldFileSystem, out U8Span oldSubPath, oldPath); if (rc.IsFailure()) return rc; - rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath); + rc = FindFileSystem(out FileSystemAccessor newFileSystem, out U8Span newSubPath, newPath); if (rc.IsFailure()) return rc; if (oldFileSystem != newFileSystem) @@ -181,125 +182,125 @@ namespace LibHac.Fs if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameFile(oldSubPath, newSubPath); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{oldPath.ToString()}\", new_path: \"{newPath.ToString()}\""); } else { - rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameFile(oldSubPath, newSubPath); } return rc; } - public Result GetEntryType(out DirectoryEntryType type, string path) + public Result GetEntryType(out DirectoryEntryType type, U8Span path) { type = default; - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.GetEntryType(out type, subPath.ToString()); + rc = fileSystem.GetEntryType(out type, subPath); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", path: \"{path}\""); + OutputAccessLog(rc, startTime, endTime, $", path: \"{path.ToString()}\""); } else { - rc = fileSystem.GetEntryType(out type, subPath.ToString()); + rc = fileSystem.GetEntryType(out type, subPath); } return rc; } - public Result OpenFile(out FileHandle handle, string path, OpenMode mode) + public Result OpenFile(out FileHandle handle, U8Span path, OpenMode mode) { handle = default; - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode); + rc = fileSystem.OpenFile(out FileAccessor file, subPath, mode); handle = new FileHandle(file); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}"); + OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path.ToString()}\", open_mode: {mode}"); } else { - rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode); + rc = fileSystem.OpenFile(out FileAccessor file, subPath, mode); handle = new FileHandle(file); } return rc; } - public Result OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) + public Result OpenDirectory(out DirectoryHandle handle, U8Span path, OpenDirectoryMode mode) { handle = default; - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode); + rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath, mode); handle = new DirectoryHandle(dir); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path}\", open_mode: {mode}"); + OutputAccessLog(rc, startTime, endTime, handle, $", path: \"{path.ToString()}\", open_mode: {mode}"); } else { - rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode); + rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath, mode); handle = new DirectoryHandle(dir); } return rc; } - public Result GetFreeSpaceSize(out long freeSpace, string path) + public Result GetFreeSpaceSize(out long freeSpace, U8Span path) { freeSpace = default; - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; - return fileSystem.GetFreeSpaceSize(out freeSpace, subPath.ToString()); + return fileSystem.GetFreeSpaceSize(out freeSpace, subPath); } - public Result GetTotalSpaceSize(out long totalSpace, string path) + public Result GetTotalSpaceSize(out long totalSpace, U8Span path) { totalSpace = default; - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; - return fileSystem.GetTotalSpaceSize(out totalSpace, subPath.ToString()); + return fileSystem.GetTotalSpaceSize(out totalSpace, subPath); } - public Result GetFileTimeStamp(out FileTimeStampRaw timeStamp, string path) + public Result GetFileTimeStamp(out FileTimeStampRaw timeStamp, U8Span path) { timeStamp = default; - Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + Result rc = FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, path); if (rc.IsFailure()) return rc; - return fileSystem.GetFileTimeStampRaw(out timeStamp, subPath.ToString()); + return fileSystem.GetFileTimeStampRaw(out timeStamp, subPath); } - public Result Commit(string mountName) + public Result Commit(U8Span mountName) { - Result rc = MountTable.Find(mountName, out FileSystemAccessor fileSystem); + Result rc = MountTable.Find(mountName.ToString(), out FileSystemAccessor fileSystem); if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) @@ -308,7 +309,7 @@ namespace LibHac.Fs rc = fileSystem.Commit(); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName}\""); + OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\""); } else { diff --git a/src/LibHac/Fs/FileSystemClient.cs b/src/LibHac/Fs/FileSystemClient.cs index a80bd712..bb7e0c71 100644 --- a/src/LibHac/Fs/FileSystemClient.cs +++ b/src/LibHac/Fs/FileSystemClient.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics; +using System.Runtime.InteropServices; using LibHac.Common; using LibHac.Fs.Accessors; using LibHac.FsService; @@ -76,45 +78,65 @@ namespace LibHac.Fs return Result.Success; } - public void Unmount(string mountName) + public void Unmount(U8Span mountName) { Result rc; + string mountNameStr = mountName.ToString(); if (IsEnabledAccessLog() && IsEnabledFileSystemAccessorAccessLog(mountName)) { TimeSpan startTime = Time.GetCurrent(); - rc = MountTable.Unmount(mountName); + rc = MountTable.Unmount(mountNameStr); TimeSpan endTime = Time.GetCurrent(); - OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName}\""); + OutputAccessLog(rc, startTime, endTime, $", name: \"{mountNameStr}\""); } else { - rc = MountTable.Unmount(mountName); + rc = MountTable.Unmount(mountNameStr); } rc.ThrowIfFailure(); } - internal Result FindFileSystem(ReadOnlySpan path, out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) + internal Result FindFileSystem(out FileSystemAccessor fileSystem, out U8Span subPath, U8Span path) { fileSystem = default; + subPath = default; - Result rc = GetMountName(path, out ReadOnlySpan mountName, out subPath); + if (path.IsNull()) + return ResultFs.NullptrArgument.Log(); + + int hostMountNameLen = StringUtils.GetLength(CommonMountNames.HostRootFileSystemMountName); + if (StringUtils.Compare(path, CommonMountNames.HostRootFileSystemMountName, hostMountNameLen) == 0) + { + return ResultFs.NotMounted.Log(); + } + + Result rc = GetMountNameAndSubPath(out MountName mountName, out subPath, path); if (rc.IsFailure()) return rc; - rc = MountTable.Find(mountName.ToString(), out fileSystem); + rc = MountTable.Find(StringUtils.Utf8ZToString(mountName.Name), out fileSystem); if (rc.IsFailure()) return rc; return Result.Success; } - internal static Result GetMountName(ReadOnlySpan path, out ReadOnlySpan mountName, out ReadOnlySpan subPath) + internal static Result GetMountNameAndSubPath(out MountName mountName, out U8Span subPath, U8Span path) { int mountLen = 0; int maxMountLen = Math.Min(path.Length, PathTools.MountNameLengthMax); + if (PathUtility.IsWindowsDrive(path) || PathUtility.IsUnc(path)) + { + StringUtils.Copy(mountName.Name, CommonMountNames.HostRootFileSystemMountName); + mountName.Name[PathTools.MountNameLengthMax] = StringTraits.NullTerminator; + + subPath = path; + return Result.Success; + } + for (int i = 0; i <= maxMountLen; i++) { if (path[i] == PathTools.MountSeparator) @@ -124,7 +146,7 @@ namespace LibHac.Fs } } - if (mountLen == 0) + if (mountLen == 0 || mountLen > maxMountLen) { mountName = default; subPath = default; @@ -132,18 +154,30 @@ namespace LibHac.Fs return ResultFs.InvalidMountName.Log(); } - mountName = path.Slice(0, mountLen); + U8Span subPathTemp = path.Slice(mountLen + 1); - if (mountLen + 1 < path.Length) - { - subPath = path.Slice(mountLen + 1); - } - else + if (subPathTemp.Length == 0 || !PathTool.IsAnySeparator(subPathTemp[0])) { + mountName = default; subPath = default; + + return ResultFs.InvalidPathFormat.Log(); } + path.Value.Slice(0, mountLen).CopyTo(mountName.Name); + mountName.Name[mountLen] = StringTraits.NullTerminator; + subPath = subPathTemp; + return Result.Success; } } + + [StructLayout(LayoutKind.Sequential, Size = 16)] + [DebuggerDisplay("{ToString()}")] + internal struct MountName + { + public Span Name => SpanHelpers.AsByteSpan(ref this); + + public override string ToString() => new U8Span(Name).ToString(); + } } diff --git a/src/LibHac/Fs/FileSystemClientUtils.cs b/src/LibHac/Fs/FileSystemClientUtils.cs index 3a26c0df..b104af69 100644 --- a/src/LibHac/Fs/FileSystemClientUtils.cs +++ b/src/LibHac/Fs/FileSystemClientUtils.cs @@ -12,7 +12,7 @@ namespace LibHac.Fs public static Result CopyDirectory(this FileSystemClient fs, string sourcePath, string destPath, CreateFileOptions options = CreateFileOptions.None, IProgressReport logger = null) { - Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All); + Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath.ToU8Span(), OpenDirectoryMode.All); if (rc.IsFailure()) return rc; using (sourceHandle) @@ -46,12 +46,12 @@ namespace LibHac.Fs public static Result CopyFile(this FileSystemClient fs, string sourcePath, string destPath, IProgressReport logger = null) { - Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read); + Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath.ToU8Span(), OpenMode.Read); if (rc.IsFailure()) return rc; using (sourceHandle) { - rc = fs.OpenFile(out FileHandle destHandle, destPath, OpenMode.Write | OpenMode.AllowAppend); + rc = fs.OpenFile(out FileHandle destHandle, destPath.ToU8Span(), OpenMode.Write | OpenMode.AllowAppend); if (rc.IsFailure()) return rc; using (destHandle) @@ -111,7 +111,7 @@ namespace LibHac.Fs bool ignoreCase = searchOptions.HasFlag(SearchOptions.CaseInsensitive); bool recurse = searchOptions.HasFlag(SearchOptions.RecurseSubdirectories); - fs.OpenDirectory(out DirectoryHandle sourceHandle, path, OpenDirectoryMode.All).ThrowIfFailure(); + fs.OpenDirectory(out DirectoryHandle sourceHandle, path.ToU8Span(), OpenDirectoryMode.All).ThrowIfFailure(); using (sourceHandle) { @@ -144,14 +144,14 @@ namespace LibHac.Fs public static bool DirectoryExists(this FileSystemClient fs, string path) { - Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + Result rc = fs.GetEntryType(out DirectoryEntryType type, path.ToU8Span()); return (rc.IsSuccess() && type == DirectoryEntryType.Directory); } public static bool FileExists(this FileSystemClient fs, string path) { - Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + Result rc = fs.GetEntryType(out DirectoryEntryType type, path.ToU8Span()); return (rc.IsSuccess() && type == DirectoryEntryType.File); } @@ -189,25 +189,30 @@ namespace LibHac.Fs { string subPath = path.Substring(0, i); - fs.CreateDirectory(subPath); + fs.CreateDirectory(subPath.ToU8Span()); } } - fs.CreateDirectory(path); + fs.CreateDirectory(path.ToU8Span()); } - public static void CreateOrOverwriteFile(this FileSystemClient fs, string path, long size) + public static Result CreateOrOverwriteFile(this FileSystemClient fs, string path, long size) { - fs.CreateOrOverwriteFile(path, size, CreateFileOptions.None); + return fs.CreateOrOverwriteFile(path, size, CreateFileOptions.None); } - public static void CreateOrOverwriteFile(this FileSystemClient fs, string path, long size, CreateFileOptions options) + public static Result CreateOrOverwriteFile(this FileSystemClient fs, string path, long size, CreateFileOptions options) { path = PathTools.Normalize(path); + var u8Path = path.ToU8Span(); - if (fs.FileExists(path)) fs.DeleteFile(path); + if (fs.FileExists(path)) + { + Result rc = fs.DeleteFile(u8Path); + if (rc.IsFailure()) return rc; + } - fs.CreateFile(path, size, CreateFileOptions.None); + return fs.CreateFile(u8Path, size, CreateFileOptions.None); } internal static bool IsEnabledFileSystemAccessorAccessLog(this FileSystemClient fs, string mountName) diff --git a/src/LibHac/Fs/IAttributeFileSystem.cs b/src/LibHac/Fs/IAttributeFileSystem.cs index cc37a807..39cdf430 100644 --- a/src/LibHac/Fs/IAttributeFileSystem.cs +++ b/src/LibHac/Fs/IAttributeFileSystem.cs @@ -1,10 +1,12 @@ -namespace LibHac.Fs +using LibHac.Common; + +namespace LibHac.Fs { public interface IAttributeFileSystem : IFileSystem { - Result CreateDirectory(string path, NxFileAttributes archiveAttribute); - Result GetFileAttributes(out NxFileAttributes attributes, string path); - Result SetFileAttributes(string path, NxFileAttributes attributes); - Result GetFileSize(out long fileSize, string path); + Result CreateDirectory(U8Span path, NxFileAttributes archiveAttribute); + Result GetFileAttributes(out NxFileAttributes attributes, U8Span path); + Result SetFileAttributes(U8Span path, NxFileAttributes attributes); + Result GetFileSize(out long fileSize, U8Span path); } } diff --git a/src/LibHac/Fs/IFileSystem.cs b/src/LibHac/Fs/IFileSystem.cs index 5ec86524..7192378e 100644 --- a/src/LibHac/Fs/IFileSystem.cs +++ b/src/LibHac/Fs/IFileSystem.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Common; using LibHac.FsSystem; namespace LibHac.Fs @@ -23,7 +24,7 @@ namespace LibHac.Fs /// Specified path already exists as either a file or directory: /// Insufficient free space to create the file: /// - Result CreateFile(string path, long size, CreateFileOptions options); + Result CreateFile(U8Span path, long size, CreateFileOptions options); /// /// Deletes the specified file. @@ -35,7 +36,7 @@ namespace LibHac.Fs /// /// The specified path does not exist or is a directory: /// - Result DeleteFile(string path); + Result DeleteFile(U8Span path); /// /// Creates all directories and subdirectories in the specified path unless they already exist. @@ -49,7 +50,7 @@ namespace LibHac.Fs /// Specified path already exists as either a file or directory: /// Insufficient free space to create the directory: /// - Result CreateDirectory(string path); + Result CreateDirectory(U8Span path); /// /// Deletes the specified directory. @@ -62,7 +63,7 @@ namespace LibHac.Fs /// The specified path does not exist or is a file: /// The specified directory is not empty: /// - Result DeleteDirectory(string path); + Result DeleteDirectory(U8Span path); /// /// Deletes the specified directory and any subdirectories and files in the directory. @@ -74,7 +75,7 @@ namespace LibHac.Fs /// /// The specified path does not exist or is a file: /// - Result DeleteDirectoryRecursively(string path); + Result DeleteDirectoryRecursively(U8Span path); /// /// Deletes any subdirectories and files in the specified directory. @@ -86,7 +87,7 @@ namespace LibHac.Fs /// /// The specified path does not exist or is a file: /// - Result CleanDirectoryRecursively(string path); + Result CleanDirectoryRecursively(U8Span path); /// /// Renames or moves a file to a new location. @@ -102,7 +103,7 @@ namespace LibHac.Fs /// 's parent directory does not exist: /// already exists as either a file or directory: /// - Result RenameFile(string oldPath, string newPath); + Result RenameFile(U8Span oldPath, U8Span newPath); /// /// Renames or moves a directory to a new location. @@ -119,7 +120,7 @@ namespace LibHac.Fs /// already exists as either a file or directory: /// Either or is a subpath of the other: /// - Result RenameDirectory(string oldPath, string newPath); + Result RenameDirectory(U8Span oldPath, U8Span newPath); /// /// Determines whether the specified path is a file or directory, or does not exist. @@ -127,7 +128,7 @@ namespace LibHac.Fs /// If the operation returns successfully, the of the file. /// The full path to check. /// The of the requested operation. - Result GetEntryType(out DirectoryEntryType entryType, string path); + Result GetEntryType(out DirectoryEntryType entryType, U8Span path); /// /// Gets the amount of available free space on a drive, in bytes. @@ -135,7 +136,7 @@ namespace LibHac.Fs /// If the operation returns successfully, the amount of free space available on the drive, in bytes. /// The path of the drive to query. Unused in almost all cases. /// The of the requested operation. - Result GetFreeSpaceSize(out long freeSpace, string path); + Result GetFreeSpaceSize(out long freeSpace, U8Span path); /// /// Gets the total size of storage space on a drive, in bytes. @@ -143,7 +144,7 @@ namespace LibHac.Fs /// If the operation returns successfully, the total size of the drive, in bytes. /// The path of the drive to query. Unused in almost all cases. /// The of the requested operation. - Result GetTotalSpaceSize(out long totalSpace, string path); + Result GetTotalSpaceSize(out long totalSpace, U8Span path); /// /// Opens an instance for the specified path. @@ -158,7 +159,7 @@ namespace LibHac.Fs /// /// The specified path does not exist or is a directory: /// - Result OpenFile(out IFile file, string path, OpenMode mode); + Result OpenFile(out IFile file, U8Span path, OpenMode mode); /// /// Creates an instance for enumerating the specified directory. @@ -173,7 +174,7 @@ namespace LibHac.Fs /// /// The specified path does not exist or is a file: /// - Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode); + Result OpenDirectory(out IDirectory directory, U8Span path, OpenDirectoryMode mode); /// /// Commits any changes to a transactional file system. @@ -194,7 +195,7 @@ namespace LibHac.Fs /// /// The specified path does not exist: /// - Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path); + Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path); /// /// Performs a query on the specified file. @@ -208,7 +209,7 @@ namespace LibHac.Fs /// The type of query to perform. /// The full path of the file to query. /// The of the requested operation. - Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path); + Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, U8Span path); } /// diff --git a/src/LibHac/Fs/InMemoryFileSystem.cs b/src/LibHac/Fs/InMemoryFileSystem.cs index a3c3c4b7..0b793424 100644 --- a/src/LibHac/Fs/InMemoryFileSystem.cs +++ b/src/LibHac/Fs/InMemoryFileSystem.cs @@ -18,59 +18,55 @@ namespace LibHac.Fs FsTable = new FileTable(); } - protected override Result CreateDirectoryImpl(string path) + protected override Result CreateDirectoryImpl(U8Span path) { return FsTable.AddDirectory(new U8Span(path)); } - protected override Result CreateDirectoryImpl(string path, NxFileAttributes archiveAttribute) + protected override Result CreateDirectoryImpl(U8Span path, NxFileAttributes archiveAttribute) { - var u8Path = new U8Span(path); - - Result rc = FsTable.AddDirectory(u8Path); + Result rc = FsTable.AddDirectory(path); if (rc.IsFailure()) return rc; - rc = FsTable.GetDirectory(u8Path, out DirectoryNode dir); + rc = FsTable.GetDirectory(path, out DirectoryNode dir); if (rc.IsFailure()) return rc; dir.Attributes = archiveAttribute; return Result.Success; } - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) { - var u8Path = new U8Span(path); - - Result rc = FsTable.AddFile(u8Path); + Result rc = FsTable.AddFile(path); if (rc.IsFailure()) return rc; - rc = FsTable.GetFile(u8Path, out FileNode file); + rc = FsTable.GetFile(path, out FileNode file); if (rc.IsFailure()) return rc; return file.File.SetSize(size); } - protected override Result DeleteDirectoryImpl(string path) + protected override Result DeleteDirectoryImpl(U8Span path) { return FsTable.DeleteDirectory(new U8Span(path), false); } - protected override Result DeleteDirectoryRecursivelyImpl(string path) + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) { return FsTable.DeleteDirectory(new U8Span(path), true); } - protected override Result CleanDirectoryRecursivelyImpl(string path) + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) { return FsTable.CleanDirectory(new U8Span(path)); } - protected override Result DeleteFileImpl(string path) + protected override Result DeleteFileImpl(U8Span path) { return FsTable.DeleteFile(new U8Span(path)); } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { directory = default; @@ -81,12 +77,11 @@ namespace LibHac.Fs return Result.Success; } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; - var u8Path = new U8Span(path); - Result rc = FsTable.GetFile(u8Path, out FileNode fileNode); + Result rc = FsTable.GetFile(path, out FileNode fileNode); if (rc.IsFailure()) return rc; file = new MemoryFile(mode, fileNode.File); @@ -94,27 +89,25 @@ namespace LibHac.Fs return Result.Success; } - protected override Result RenameDirectoryImpl(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) { return FsTable.RenameDirectory(new U8Span(oldPath), new U8Span(newPath)); } - protected override Result RenameFileImpl(string oldPath, string newPath) + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) { return FsTable.RenameFile(new U8Span(oldPath), new U8Span(newPath)); } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { - var u8Path = new U8Span(path); - - if (FsTable.GetFile(u8Path, out _).IsSuccess()) + if (FsTable.GetFile(path, out _).IsSuccess()) { entryType = DirectoryEntryType.File; return Result.Success; } - if (FsTable.GetDirectory(u8Path, out _).IsSuccess()) + if (FsTable.GetDirectory(path, out _).IsSuccess()) { entryType = DirectoryEntryType.Directory; return Result.Success; @@ -129,17 +122,15 @@ namespace LibHac.Fs return Result.Success; } - protected override Result GetFileAttributesImpl(string path, out NxFileAttributes attributes) + protected override Result GetFileAttributesImpl(out NxFileAttributes attributes, U8Span path) { - var u8Path = new U8Span(path); - - if (FsTable.GetFile(u8Path, out FileNode file).IsSuccess()) + if (FsTable.GetFile(path, out FileNode file).IsSuccess()) { attributes = file.Attributes; return Result.Success; } - if (FsTable.GetDirectory(u8Path, out DirectoryNode dir).IsSuccess()) + if (FsTable.GetDirectory(path, out DirectoryNode dir).IsSuccess()) { attributes = dir.Attributes; return Result.Success; @@ -149,17 +140,15 @@ namespace LibHac.Fs return ResultFs.PathNotFound.Log(); } - protected override Result SetFileAttributesImpl(string path, NxFileAttributes attributes) + protected override Result SetFileAttributesImpl(U8Span path, NxFileAttributes attributes) { - var u8Path = new U8Span(path); - - if (FsTable.GetFile(u8Path, out FileNode file).IsSuccess()) + if (FsTable.GetFile(path, out FileNode file).IsSuccess()) { file.Attributes = attributes; return Result.Success; } - if (FsTable.GetDirectory(u8Path, out DirectoryNode dir).IsSuccess()) + if (FsTable.GetDirectory(path, out DirectoryNode dir).IsSuccess()) { dir.Attributes = attributes; return Result.Success; @@ -168,11 +157,9 @@ namespace LibHac.Fs return ResultFs.PathNotFound.Log(); } - protected override Result GetFileSizeImpl(out long fileSize, string path) + protected override Result GetFileSizeImpl(out long fileSize, U8Span path) { - var u8Path = new U8Span(path); - - if (FsTable.GetFile(u8Path, out FileNode file).IsSuccess()) + if (FsTable.GetFile(path, out FileNode file).IsSuccess()) { return file.File.GetSize(out fileSize); } @@ -646,7 +633,12 @@ namespace LibHac.Fs while (parser.MoveNext()) { - if (!TryFindChildDirectory(new U8Span(parser.GetCurrent()), current, out DirectoryNode child)) + var currentDir = new U8Span(parser.GetCurrent()); + + // End if we've hit a trailing separator + if (currentDir.IsEmpty() && parser.IsFinished()) break; + + if (!TryFindChildDirectory(currentDir, current, out DirectoryNode child)) { directory = default; return ResultFs.PathNotFound.Log(); diff --git a/src/LibHac/Fs/MountHelpers.cs b/src/LibHac/Fs/MountHelpers.cs index 33ecb09e..a7d49654 100644 --- a/src/LibHac/Fs/MountHelpers.cs +++ b/src/LibHac/Fs/MountHelpers.cs @@ -6,7 +6,7 @@ namespace LibHac.Fs { public static Result CheckMountName(U8Span name) { - if (name.IsNull()) return ResultFs.NullArgument.Log(); + if (name.IsNull()) return ResultFs.NullptrArgument.Log(); if (name.Length > 0 && name[0] == '@') return ResultFs.InvalidMountName.Log(); if (!CheckMountNameImpl(name)) return ResultFs.InvalidMountName.Log(); @@ -16,7 +16,7 @@ namespace LibHac.Fs public static Result CheckMountNameAcceptingReservedMountName(U8Span name) { - if (name.IsNull()) return ResultFs.NullArgument.Log(); + if (name.IsNull()) return ResultFs.NullptrArgument.Log(); if (!CheckMountNameImpl(name)) return ResultFs.InvalidMountName.Log(); diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index 871f9512..2b7e7a45 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -301,7 +301,7 @@ namespace LibHac.Fs /// Error code: 2002-6062; Inner value: 0x2f5c02 public static Result.Base InvalidSize => new Result.Base(ModuleFs, 6062); /// Error code: 2002-6063; Inner value: 0x2f5e02 - public static Result.Base NullArgument => new Result.Base(ModuleFs, 6063); + public static Result.Base NullptrArgument => new Result.Base(ModuleFs, 6063); /// Error code: 2002-6065; Inner value: 0x2f6202 public static Result.Base InvalidMountName => new Result.Base(ModuleFs, 6065); /// Error code: 2002-6066; Inner value: 0x2f6402 diff --git a/src/LibHac/Fs/Shim/ContentStorage.cs b/src/LibHac/Fs/Shim/ContentStorage.cs index 8c1c169c..3efa8c21 100644 --- a/src/LibHac/Fs/Shim/ContentStorage.cs +++ b/src/LibHac/Fs/Shim/ContentStorage.cs @@ -31,11 +31,11 @@ namespace LibHac.Fs.Shim switch (storageId) { case ContentStorageId.System: - return CommonMountNames.SystemContentMountName; + return CommonMountNames.ContentStorageSystemMountName; case ContentStorageId.User: - return CommonMountNames.UserContentMountName; + return CommonMountNames.ContentStorageUserMountName; case ContentStorageId.SdCard: - return CommonMountNames.SdCardContentMountName; + return CommonMountNames.ContentStorageSdCardMountName; default: throw new ArgumentOutOfRangeException(nameof(storageId), storageId, null); } diff --git a/src/LibHac/Fs/Shim/GameCard.cs b/src/LibHac/Fs/Shim/GameCard.cs index e1e3b0f4..0535a188 100644 --- a/src/LibHac/Fs/Shim/GameCard.cs +++ b/src/LibHac/Fs/Shim/GameCard.cs @@ -70,7 +70,7 @@ namespace LibHac.Fs.Shim { char letter = GetGameCardMountNameSuffix(PartitionId); - string mountName = $"{CommonMountNames.GameCardMountName}{letter}{Handle.Value:x8}"; + string mountName = $"{CommonMountNames.GameCardFileSystemMountName}{letter}{Handle.Value:x8}"; new U8Span(mountName).Value.CopyTo(nameBuffer); return Result.Success; diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs index f4eabedf..2cf17e25 100644 --- a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreator.cs @@ -23,7 +23,7 @@ namespace LibHac.FsService.Creators fileSystem = default; if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument.Log(); - if (rootPath == null) return ResultFs.NullArgument.Log(); + if (rootPath == null) return ResultFs.NullptrArgument.Log(); if (Config.TryGetFileSystem(out fileSystem, partitionId)) { diff --git a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs index f5c7200f..90b75a58 100644 --- a/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs +++ b/src/LibHac/FsService/Creators/EmulatedBisFileSystemCreatorConfig.cs @@ -14,7 +14,7 @@ namespace LibHac.FsService.Creators public Result SetFileSystem(IFileSystem fileSystem, BisPartitionId partitionId) { - if (fileSystem == null) return ResultFs.NullArgument.Log(); + if (fileSystem == null) return ResultFs.NullptrArgument.Log(); if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument.Log(); PartitionFileSystems[GetArrayIndex(partitionId)] = fileSystem; @@ -24,7 +24,7 @@ namespace LibHac.FsService.Creators public Result SetPath(string path, BisPartitionId partitionId) { - if (path == null) return ResultFs.NullArgument.Log(); + if (path == null) return ResultFs.NullptrArgument.Log(); if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument.Log(); PartitionPaths[GetArrayIndex(partitionId)] = path; diff --git a/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs index 3bae3cb7..e8c60add 100644 --- a/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ISubDirectoryFileSystemCreator.cs @@ -1,9 +1,10 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsService.Creators { public interface ISubDirectoryFileSystemCreator { - Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, string path); + Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, U8Span path); } } \ No newline at end of file diff --git a/src/LibHac/FsService/Creators/SaveDataFileSystemCreator.cs b/src/LibHac/FsService/Creators/SaveDataFileSystemCreator.cs index 9e9ac1c1..997954d3 100644 --- a/src/LibHac/FsService/Creators/SaveDataFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/SaveDataFileSystemCreator.cs @@ -27,7 +27,7 @@ namespace LibHac.FsService.Creators fileSystem = default; extraDataAccessor = default; - string saveDataPath = $"/{saveDataId:x16}"; + var saveDataPath = $"/{saveDataId:x16}".ToU8String(); Result rc = sourceFileSystem.GetEntryType(out DirectoryEntryType entryType, saveDataPath); if (rc.IsFailure()) @@ -40,7 +40,7 @@ namespace LibHac.FsService.Creators case DirectoryEntryType.Directory: if (!allowDirectorySaveData) return ResultFs.InvalidSaveDataEntryType.Log(); - rc = SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem subDirFs, sourceFileSystem, saveDataPath.ToU8String()); + rc = SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem subDirFs, sourceFileSystem, saveDataPath); if (rc.IsFailure()) return rc; bool isPersistentSaveData = type != SaveDataType.Temporary; diff --git a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs index d0d52853..90e835f7 100644 --- a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs @@ -6,7 +6,7 @@ namespace LibHac.FsService.Creators { public class SubDirectoryFileSystemCreator : ISubDirectoryFileSystemCreator { - public Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, string path) + public Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, U8Span path) { subDirFileSystem = default; diff --git a/src/LibHac/FsService/FileSystemProxy.cs b/src/LibHac/FsService/FileSystemProxy.cs index 044baf3d..8bd7223c 100644 --- a/src/LibHac/FsService/FileSystemProxy.cs +++ b/src/LibHac/FsService/FileSystemProxy.cs @@ -1113,7 +1113,7 @@ namespace LibHac.FsService string.Empty, false); if (rc.IsFailure()) return rc; - rc = saveDirFs.CleanDirectoryRecursively("/"); + rc = saveDirFs.CleanDirectoryRecursively("/".ToU8Span()); if (rc.IsFailure()) return rc; SaveDataIndexerReader reader = default; diff --git a/src/LibHac/FsService/FileSystemProxyCore.cs b/src/LibHac/FsService/FileSystemProxyCore.cs index 1b5798c2..5badf4d6 100644 --- a/src/LibHac/FsService/FileSystemProxyCore.cs +++ b/src/LibHac/FsService/FileSystemProxyCore.cs @@ -65,7 +65,7 @@ namespace LibHac.FsService { fileSystem = default; - string contentDirPath = default; + U8String contentDirPath = default; IFileSystem baseFileSystem = default; bool isEncrypted = false; Result rc; @@ -74,15 +74,15 @@ namespace LibHac.FsService { case ContentStorageId.System: rc = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.System); - contentDirPath = $"/{ContentDirectoryName}"; + contentDirPath = $"/{ContentDirectoryName}".ToU8String(); break; case ContentStorageId.User: rc = OpenBisFileSystem(out baseFileSystem, string.Empty, BisPartitionId.User); - contentDirPath = $"/{ContentDirectoryName}"; + contentDirPath = $"/{ContentDirectoryName}".ToU8String(); break; case ContentStorageId.SdCard: rc = OpenSdCardFileSystem(out baseFileSystem); - contentDirPath = $"/{NintendoDirectoryName}/{ContentDirectoryName}"; + contentDirPath = $"/{NintendoDirectoryName}/{ContentDirectoryName}".ToU8String(); isEncrypted = true; break; default: @@ -92,7 +92,7 @@ namespace LibHac.FsService if (rc.IsFailure()) return rc; - baseFileSystem.EnsureDirectoryExists(contentDirPath); + baseFileSystem.EnsureDirectoryExists(contentDirPath.ToString()); rc = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFileSystem, baseFileSystem, contentDirPath); @@ -199,7 +199,7 @@ namespace LibHac.FsService string saveDataPath = $"/{saveDataId:x16}"; - rc = fileSystem.GetEntryType(out _, saveDataPath); + rc = fileSystem.GetEntryType(out _, saveDataPath.ToU8Span()); if (rc.IsFailure()) { @@ -337,7 +337,7 @@ namespace LibHac.FsService string metaFilePath = $"/{(int)type:x8}.meta"; - return metaDirFs.OpenFile(out file, metaFilePath, OpenMode.ReadWrite); + return metaDirFs.OpenFile(out file, metaFilePath.ToU8Span(), OpenMode.ReadWrite); } public Result DeleteSaveDataMetaFiles(ulong saveDataId, SaveDataSpaceId spaceId) @@ -348,7 +348,7 @@ namespace LibHac.FsService { if (rc.IsFailure()) return rc; - rc = metaDirFs.DeleteDirectoryRecursively($"/{saveDataId:x16}"); + rc = metaDirFs.DeleteDirectoryRecursively($"/{saveDataId:x16}".ToU8Span()); if (rc.IsFailure() && !ResultFs.PathNotFound.Includes(rc)) return rc; @@ -369,7 +369,7 @@ namespace LibHac.FsService if (size < 0) return ResultFs.OutOfRange.Log(); - return metaDirFs.CreateFile(metaFilePath, size, CreateFileOptions.None); + return metaDirFs.CreateFile(metaFilePath.ToU8Span(), size, CreateFileOptions.None); } public Result CreateSaveDataFileSystem(ulong saveDataId, ref SaveDataAttribute attribute, @@ -391,7 +391,7 @@ namespace LibHac.FsService { if (rc.IsFailure()) return rc; - string saveDataPath = GetSaveDataIdPath(saveDataId); + var saveDataPath = GetSaveDataIdPath(saveDataId).ToU8Span(); rc = fileSystem.GetEntryType(out DirectoryEntryType entryType, saveDataPath); if (rc.IsFailure()) return rc; diff --git a/src/LibHac/FsService/SaveDataIndexer.cs b/src/LibHac/FsService/SaveDataIndexer.cs index c1fa4383..42ac4f8b 100644 --- a/src/LibHac/FsService/SaveDataIndexer.cs +++ b/src/LibHac/FsService/SaveDataIndexer.cs @@ -18,7 +18,7 @@ namespace LibHac.FsService private const long LastIdFileSize = 8; private FileSystemClient FsClient { get; } - private string MountName { get; } + private U8String MountName { get; } private ulong SaveDataId { get; } private SaveDataSpaceId SpaceId { get; } private KeyValueDatabase KvDatabase { get; set; } @@ -29,10 +29,10 @@ namespace LibHac.FsService private int Version { get; set; } private List OpenedReaders { get; } = new List(); - public SaveDataIndexer(FileSystemClient fsClient, string mountName, SaveDataSpaceId spaceId, ulong saveDataId) + public SaveDataIndexer(FileSystemClient fsClient, U8Span mountName, SaveDataSpaceId spaceId, ulong saveDataId) { FsClient = fsClient; - MountName = mountName; + MountName = mountName.ToU8String(); SaveDataId = saveDataId; SpaceId = spaceId; Version = 1; @@ -77,7 +77,7 @@ namespace LibHac.FsService string idFilePath = $"{MountName}:/{LastIdFileName}"; - rc = FsClient.OpenFile(out FileHandle handle, idFilePath, OpenMode.Write); + rc = FsClient.OpenFile(out FileHandle handle, idFilePath.ToU8Span(), OpenMode.Write); if (rc.IsFailure()) return rc; bool fileAlreadyClosed = false; @@ -423,7 +423,7 @@ namespace LibHac.FsService string dbDirectory = $"{MountName}:/"; - rc = FsClient.GetEntryType(out DirectoryEntryType entryType, dbDirectory); + rc = FsClient.GetEntryType(out DirectoryEntryType entryType, dbDirectory.ToU8Span()); if (rc.IsFailure()) return rc; if (entryType == DirectoryEntryType.File) @@ -431,7 +431,7 @@ namespace LibHac.FsService string dbArchiveFile = $"{dbDirectory}imkvdb.arc"; - KvDatabase = new KeyValueDatabase(FsClient, dbArchiveFile); + KvDatabase = new KeyValueDatabase(FsClient, dbArchiveFile.ToU8Span()); IsInitialized = true; return Result.Success; @@ -466,7 +466,7 @@ namespace LibHac.FsService if (rc.IsFailure()) return rc; bool createdNewFile = false; - string idFilePath = $"{MountName}:/{LastIdFileName}"; + var idFilePath = $"{MountName}:/{LastIdFileName}".ToU8String(); rc = FsClient.OpenFile(out FileHandle handle, idFilePath, OpenMode.Read); @@ -572,10 +572,10 @@ namespace LibHac.FsService private ref struct Mounter { private FileSystemClient FsClient { get; set; } - private string MountName { get; set; } + private U8String MountName { get; set; } private bool IsMounted { get; set; } - public Result Initialize(FileSystemClient fsClient, string mountName, SaveDataSpaceId spaceId, + public Result Initialize(FileSystemClient fsClient, U8String mountName, SaveDataSpaceId spaceId, ulong saveDataId) { FsClient = fsClient; @@ -583,7 +583,7 @@ namespace LibHac.FsService FsClient.DisableAutoSaveDataCreation(); - Result rc = FsClient.MountSystemSaveData(MountName.ToU8Span(), spaceId, saveDataId); + Result rc = FsClient.MountSystemSaveData(MountName, spaceId, saveDataId); if (rc.IsFailure()) { @@ -592,7 +592,7 @@ namespace LibHac.FsService rc = FsClient.CreateSystemSaveData(spaceId, saveDataId, TitleId.Zero, 0xC0000, 0xC0000, 0); if (rc.IsFailure()) return rc; - rc = FsClient.MountSystemSaveData(MountName.ToU8Span(), spaceId, saveDataId); + rc = FsClient.MountSystemSaveData(MountName, spaceId, saveDataId); if (rc.IsFailure()) return rc; } else @@ -608,7 +608,7 @@ namespace LibHac.FsService rc = FsClient.CreateSystemSaveData(spaceId, saveDataId, TitleId.Zero, 0xC0000, 0xC0000, 0); if (rc.IsFailure()) return rc; - rc = FsClient.MountSystemSaveData(MountName.ToU8Span(), spaceId, saveDataId); + rc = FsClient.MountSystemSaveData(MountName, spaceId, saveDataId); if (rc.IsFailure()) return rc; } } diff --git a/src/LibHac/FsService/SaveDataIndexerManager.cs b/src/LibHac/FsService/SaveDataIndexerManager.cs index 1e6a18c2..ee6722da 100644 --- a/src/LibHac/FsService/SaveDataIndexerManager.cs +++ b/src/LibHac/FsService/SaveDataIndexerManager.cs @@ -1,4 +1,5 @@ using System.Threading; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsService @@ -30,7 +31,7 @@ namespace LibHac.FsService if (!_bisIndexer.IsInitialized) { - _bisIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDb", SaveDataSpaceId.System, SaveDataId); + _bisIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDb".ToU8Span(), SaveDataSpaceId.System, SaveDataId); } reader = new SaveDataIndexerReader(_bisIndexer.Indexer, _bisIndexer.Locker); @@ -44,7 +45,7 @@ namespace LibHac.FsService if (!_sdCardIndexer.IsInitialized) { - _sdCardIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbSd", SaveDataSpaceId.SdSystem, SaveDataId); + _sdCardIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbSd".ToU8Span(), SaveDataSpaceId.SdSystem, SaveDataId); } reader = new SaveDataIndexerReader(_sdCardIndexer.Indexer, _sdCardIndexer.Locker); @@ -66,7 +67,7 @@ namespace LibHac.FsService if (!_safeIndexer.IsInitialized) { - _safeIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbPr", SaveDataSpaceId.ProperSystem, SaveDataId); + _safeIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbPr".ToU8Span(), SaveDataSpaceId.ProperSystem, SaveDataId); } reader = new SaveDataIndexerReader(_safeIndexer.Indexer, _safeIndexer.Locker); @@ -77,7 +78,7 @@ namespace LibHac.FsService if (!_properSystemIndexer.IsInitialized) { - _properSystemIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbSf", SaveDataSpaceId.SafeMode, SaveDataId); + _properSystemIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbSf".ToU8Span(), SaveDataSpaceId.SafeMode, SaveDataId); } reader = new SaveDataIndexerReader(_properSystemIndexer.Indexer, _properSystemIndexer.Locker); diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs index 4d2a24c9..b1208cf1 100644 --- a/src/LibHac/FsService/Util.cs +++ b/src/LibHac/FsService/Util.cs @@ -13,9 +13,9 @@ namespace LibHac.FsService if (!createPathIfMissing) { - if (path == null) return ResultFs.NullArgument.Log(); + if (path == null) return ResultFs.NullptrArgument.Log(); - Result rc = baseFileSystem.GetEntryType(out DirectoryEntryType entryType, path); + Result rc = baseFileSystem.GetEntryType(out DirectoryEntryType entryType, path.ToU8Span()); if (rc.IsFailure() || entryType != DirectoryEntryType.Directory) { @@ -32,9 +32,9 @@ namespace LibHac.FsService { subFileSystem = default; - if (path == null) return ResultFs.NullArgument.Log(); + if (path == null) return ResultFs.NullptrArgument.Log(); - Result rc = baseFileSystem.OpenDirectory(out IDirectory _, path, OpenDirectoryMode.Directory); + Result rc = baseFileSystem.OpenDirectory(out IDirectory _, path.ToU8Span(), OpenDirectoryMode.Directory); if (rc.IsFailure()) return rc; rc = SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem fs, baseFileSystem, path.ToU8String()); diff --git a/src/LibHac/FsSystem/AesXtsDirectory.cs b/src/LibHac/FsSystem/AesXtsDirectory.cs index c262ae6d..8345a24e 100644 --- a/src/LibHac/FsSystem/AesXtsDirectory.cs +++ b/src/LibHac/FsSystem/AesXtsDirectory.cs @@ -6,13 +6,13 @@ namespace LibHac.FsSystem { public class AesXtsDirectory : IDirectory { - private string Path { get; } + private U8String Path { get; } private OpenDirectoryMode Mode { get; } private IFileSystem BaseFileSystem { get; } private IDirectory BaseDirectory { get; } - public AesXtsDirectory(IFileSystem baseFs, IDirectory baseDir, string path, OpenDirectoryMode mode) + public AesXtsDirectory(IFileSystem baseFs, IDirectory baseDir, U8String path, OpenDirectoryMode mode) { BaseFileSystem = baseFs; BaseDirectory = baseDir; @@ -38,7 +38,7 @@ namespace LibHac.FsSystem else { string entryName = Util.GetUtf8StringNullTerminated(entry.Name); - entry.Size = GetAesXtsFileSize(PathTools.Combine(Path, entryName)); + entry.Size = GetAesXtsFileSize(PathTools.Combine(Path.ToString(), entryName).ToU8Span()); } } } @@ -56,7 +56,7 @@ namespace LibHac.FsSystem /// /// /// - private long GetAesXtsFileSize(string path) + private long GetAesXtsFileSize(U8Span path) { const long magicOffset = 0x20; const long fileSizeOffset = 0x48; diff --git a/src/LibHac/FsSystem/AesXtsFile.cs b/src/LibHac/FsSystem/AesXtsFile.cs index 8a31f23b..72a0ca35 100644 --- a/src/LibHac/FsSystem/AesXtsFile.cs +++ b/src/LibHac/FsSystem/AesXtsFile.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsSystem @@ -6,7 +7,7 @@ namespace LibHac.FsSystem public class AesXtsFile : FileBase { private IFile BaseFile { get; } - private string Path { get; } + private U8String Path { get; } private byte[] KekSeed { get; } private byte[] VerificationKey { get; } private int BlockSize { get; } @@ -17,7 +18,7 @@ namespace LibHac.FsSystem internal const int HeaderLength = 0x4000; - public AesXtsFile(OpenMode mode, IFile baseFile, string path, ReadOnlySpan kekSeed, ReadOnlySpan verificationKey, int blockSize) + public AesXtsFile(OpenMode mode, IFile baseFile, U8String path, ReadOnlySpan kekSeed, ReadOnlySpan verificationKey, int blockSize) { Mode = mode; BaseFile = baseFile; @@ -30,7 +31,7 @@ namespace LibHac.FsSystem baseFile.GetSize(out long fileSize).ThrowIfFailure(); - if (!Header.TryDecryptHeader(Path, KekSeed, VerificationKey)) + if (!Header.TryDecryptHeader(Path.ToString(), KekSeed, VerificationKey)) { ThrowHelper.ThrowResult(ResultFs.AesXtsFileHeaderInvalidKeys.Value, "NAX0 key derivation failed."); } diff --git a/src/LibHac/FsSystem/AesXtsFileSystem.cs b/src/LibHac/FsSystem/AesXtsFileSystem.cs index d2bc1cab..2e6abcf0 100644 --- a/src/LibHac/FsSystem/AesXtsFileSystem.cs +++ b/src/LibHac/FsSystem/AesXtsFileSystem.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsSystem @@ -28,12 +29,12 @@ namespace LibHac.FsSystem BlockSize = blockSize; } - protected override Result CreateDirectoryImpl(string path) + protected override Result CreateDirectoryImpl(U8Span path) { return BaseFileSystem.CreateDirectory(path); } - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) { return CreateFile(path, size, options, new byte[0x20]); } @@ -46,14 +47,14 @@ namespace LibHac.FsSystem /// Flags to control how the file is created. /// Should usually be /// The 256-bit key containing a 128-bit data key followed by a 128-bit tweak key. - public Result CreateFile(string path, long size, CreateFileOptions options, byte[] key) + public Result CreateFile(U8Span path, long size, CreateFileOptions options, byte[] key) { long containerSize = AesXtsFile.HeaderLength + Util.AlignUp(size, 0x10); Result rc = BaseFileSystem.CreateFile(path, containerSize, options); if (rc.IsFailure()) return rc; - var header = new AesXtsFileHeader(key, size, path, KekSource, ValidationKey); + var header = new AesXtsFileHeader(key, size, path.ToString(), KekSource, ValidationKey); rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write); if (rc.IsFailure()) return rc; @@ -67,57 +68,52 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result DeleteDirectoryImpl(string path) + protected override Result DeleteDirectoryImpl(U8Span path) { return BaseFileSystem.DeleteDirectory(path); } - protected override Result DeleteDirectoryRecursivelyImpl(string path) + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) { return BaseFileSystem.DeleteDirectoryRecursively(path); } - protected override Result CleanDirectoryRecursivelyImpl(string path) + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) { return BaseFileSystem.CleanDirectoryRecursively(path); } - protected override Result DeleteFileImpl(string path) + protected override Result DeleteFileImpl(U8Span path) { return BaseFileSystem.DeleteFile(path); } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { directory = default; - path = PathTools.Normalize(path); Result rc = BaseFileSystem.OpenDirectory(out IDirectory baseDir, path, mode); if (rc.IsFailure()) return rc; - directory = new AesXtsDirectory(BaseFileSystem, baseDir, path, mode); + directory = new AesXtsDirectory(BaseFileSystem, baseDir, path.ToU8String(), mode); return Result.Success; } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; - path = PathTools.Normalize(path); Result rc = BaseFileSystem.OpenFile(out IFile baseFile, path, mode | OpenMode.Read); if (rc.IsFailure()) return rc; - var xtsFile = new AesXtsFile(mode, baseFile, path, KekSource, ValidationKey, BlockSize); + var xtsFile = new AesXtsFile(mode, baseFile, path.ToU8String(), KekSource, ValidationKey, BlockSize); file = xtsFile; return Result.Success; } - protected override Result RenameDirectoryImpl(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) { - oldPath = PathTools.Normalize(oldPath); - newPath = PathTools.Normalize(newPath); - // todo: Return proper result codes // Official code procedure: @@ -133,11 +129,11 @@ namespace LibHac.FsSystem try { - RenameDirectoryImpl(oldPath, newPath, false); + RenameDirectoryImpl(oldPath.ToString(), newPath.ToString(), false); } catch (Exception) { - RenameDirectoryImpl(oldPath, newPath, true); + RenameDirectoryImpl(oldPath.ToString(), newPath.ToString(), true); BaseFileSystem.RenameDirectory(oldPath, newPath); throw; @@ -176,26 +172,23 @@ namespace LibHac.FsSystem } } - protected override Result RenameFileImpl(string oldPath, string newPath) + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) { - oldPath = PathTools.Normalize(oldPath); - newPath = PathTools.Normalize(newPath); - // todo: Return proper result codes - AesXtsFileHeader header = ReadXtsHeader(oldPath, oldPath); + AesXtsFileHeader header = ReadXtsHeader(oldPath.ToString(), oldPath.ToString()); Result rc = BaseFileSystem.RenameFile(oldPath, newPath); if (rc.IsFailure()) return rc; try { - WriteXtsHeader(header, newPath, newPath); + WriteXtsHeader(header, newPath.ToString(), newPath.ToString()); } catch (Exception) { BaseFileSystem.RenameFile(newPath, oldPath); - WriteXtsHeader(header, oldPath, oldPath); + WriteXtsHeader(header, oldPath.ToString(), oldPath.ToString()); throw; } @@ -203,22 +196,22 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { return BaseFileSystem.GetEntryType(out entryType, path); } - protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path) { return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, path); } - protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path) { return BaseFileSystem.GetFreeSpaceSize(out freeSpace, path); } - protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path) { return BaseFileSystem.GetTotalSpaceSize(out totalSpace, path); } @@ -228,7 +221,8 @@ namespace LibHac.FsSystem return BaseFileSystem.Commit(); } - protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, + U8Span path) { return BaseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, path); } @@ -250,7 +244,7 @@ namespace LibHac.FsSystem header = null; - Result rc = BaseFileSystem.OpenFile(out IFile file, filePath, OpenMode.Read); + Result rc = BaseFileSystem.OpenFile(out IFile file, filePath.ToU8Span(), OpenMode.Read); if (rc.IsFailure()) return false; using (file) @@ -268,7 +262,7 @@ namespace LibHac.FsSystem header.EncryptHeader(keyPath, KekSource, ValidationKey); - BaseFileSystem.OpenFile(out IFile file, filePath, OpenMode.ReadWrite); + BaseFileSystem.OpenFile(out IFile file, filePath.ToU8Span(), OpenMode.ReadWrite); using (file) { diff --git a/src/LibHac/FsSystem/ConcatenationDirectory.cs b/src/LibHac/FsSystem/ConcatenationDirectory.cs index f22e72df..22d00340 100644 --- a/src/LibHac/FsSystem/ConcatenationDirectory.cs +++ b/src/LibHac/FsSystem/ConcatenationDirectory.cs @@ -7,20 +7,35 @@ namespace LibHac.FsSystem { public class ConcatenationDirectory : IDirectory { - private string Path { get; } private OpenDirectoryMode Mode { get; } - - private ConcatenationFileSystem ParentFileSystem { get; } - private IFileSystem BaseFileSystem { get; } private IDirectory ParentDirectory { get; } + private IFileSystem BaseFileSystem { get; } + private ConcatenationFileSystem ParentFileSystem { get; } - public ConcatenationDirectory(ConcatenationFileSystem fs, IFileSystem baseFs, IDirectory parentDirectory, OpenDirectoryMode mode, string path) + private FsPath _path; + + public ConcatenationDirectory(ConcatenationFileSystem fs, IFileSystem baseFs, IDirectory parentDirectory, OpenDirectoryMode mode, U8Span path) { ParentFileSystem = fs; BaseFileSystem = baseFs; ParentDirectory = parentDirectory; Mode = mode; - Path = path; + + StringUtils.Copy(_path.Str, path); + _path.Str[PathTools.MaxPathLength] = StringTraits.NullTerminator; + + // Ensure the path ends with a separator + int pathLength = StringUtils.GetLength(path, PathTools.MaxPathLength + 1); + + if (pathLength != 0 && _path.Str[pathLength - 1] == StringTraits.DirectorySeparator) + return; + + if (pathLength >= PathTools.MaxPathLength) + throw new HorizonResultException(ResultFs.TooLongPath.Value, "abort"); + + _path.Str[pathLength] = StringTraits.DirectorySeparator; + _path.Str[pathLength + 1] = StringTraits.NullTerminator; + _path.Str[PathTools.MaxPathLength] = StringTraits.NullTerminator; } public Result Read(out long entriesRead, Span entryBuffer) @@ -48,9 +63,12 @@ namespace LibHac.FsSystem if (!Mode.HasFlag(OpenDirectoryMode.NoFileSize)) { string entryName = Util.GetUtf8StringNullTerminated(entry.Name); - string entryFullPath = PathTools.Combine(Path, entryName); + string entryFullPath = PathTools.Combine(_path.ToString(), entryName); - entry.Size = ParentFileSystem.GetConcatenationFileSize(entryFullPath); + rc = ParentFileSystem.GetConcatenationFileSize(out long fileSize, entryFullPath.ToU8Span()); + if (rc.IsFailure()) return rc; + + entry.Size = fileSize; } } @@ -68,7 +86,7 @@ namespace LibHac.FsSystem entryCount = 0; long count = 0; - Result rc = BaseFileSystem.OpenDirectory(out IDirectory _, Path, + Result rc = BaseFileSystem.OpenDirectory(out IDirectory _, _path, OpenDirectoryMode.All | OpenDirectoryMode.NoFileSize); if (rc.IsFailure()) return rc; @@ -104,7 +122,7 @@ namespace LibHac.FsSystem else { string name = Util.GetUtf8StringNullTerminated(entry.Name); - string fullPath = PathTools.Combine(Path, name); + var fullPath = PathTools.Combine(_path.ToString(), name).ToU8Span(); return ParentFileSystem.IsConcatenationFile(fullPath); } diff --git a/src/LibHac/FsSystem/ConcatenationFile.cs b/src/LibHac/FsSystem/ConcatenationFile.cs index 9165a36e..c2eecf62 100644 --- a/src/LibHac/FsSystem/ConcatenationFile.cs +++ b/src/LibHac/FsSystem/ConcatenationFile.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsSystem @@ -9,15 +10,15 @@ namespace LibHac.FsSystem public class ConcatenationFile : FileBase { private IFileSystem BaseFileSystem { get; } - private string FilePath { get; } + private U8String FilePath { get; } private List Sources { get; } private long SubFileSize { get; } private OpenMode Mode { get; } - internal ConcatenationFile(IFileSystem baseFileSystem, string path, IEnumerable sources, long subFileSize, OpenMode mode) + internal ConcatenationFile(IFileSystem baseFileSystem, U8Span path, IEnumerable sources, long subFileSize, OpenMode mode) { BaseFileSystem = baseFileSystem; - FilePath = path; + FilePath = path.ToU8String(); Sources = sources.ToList(); SubFileSize = subFileSize; Mode = mode; @@ -78,7 +79,8 @@ namespace LibHac.FsSystem long outPos = offset; int remaining = source.Length; - GetSize(out long fileSize).ThrowIfFailure(); + rc = GetSize(out long fileSize); + if (rc.IsFailure()) return rc; while (remaining > 0) { @@ -151,7 +153,12 @@ namespace LibHac.FsSystem for (int i = currentSubFileCount; i < newSubFileCount; i++) { - string newSubFilePath = ConcatenationFileSystem.GetSubFilePath(FilePath, i); + FsPath newSubFilePath; + unsafe { _ = &newSubFilePath; } // workaround for CS0165 + + rc = ConcatenationFileSystem.GetSubFilePath(newSubFilePath.Str, FilePath, i); + if (rc.IsFailure()) return rc; + newSubFileSize = QuerySubFileSize(i, size, SubFileSize); rc = BaseFileSystem.CreateFile(newSubFilePath, newSubFileSize, CreateFileOptions.None); @@ -170,7 +177,11 @@ namespace LibHac.FsSystem Sources[i].Dispose(); Sources.RemoveAt(i); - string subFilePath = ConcatenationFileSystem.GetSubFilePath(FilePath, i); + FsPath subFilePath; + unsafe { _ = &subFilePath; } // workaround for CS0165 + + rc = ConcatenationFileSystem.GetSubFilePath(subFilePath.Str, FilePath, i); + if (rc.IsFailure()) return rc; rc = BaseFileSystem.DeleteFile(subFilePath); if (rc.IsFailure()) return rc; diff --git a/src/LibHac/FsSystem/ConcatenationFileSystem.cs b/src/LibHac/FsSystem/ConcatenationFileSystem.cs index 9c543681..a572a2ec 100644 --- a/src/LibHac/FsSystem/ConcatenationFileSystem.cs +++ b/src/LibHac/FsSystem/ConcatenationFileSystem.cs @@ -1,6 +1,9 @@ using System; +using System.Buffers; +using System.Buffers.Text; using System.Collections.Generic; using System.Runtime.InteropServices; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsSystem @@ -47,7 +50,7 @@ namespace LibHac.FsSystem // .NET Core on platforms other than Windows doesn't support getting the // archive flag in FAT file systems. Try to work around that for now for reading, // but writing still won't work properly on those platforms - internal bool IsConcatenationFile(string path) + internal bool IsConcatenationFile(U8Span path) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -62,14 +65,14 @@ namespace LibHac.FsSystem } } - private bool IsConcatenationFileHeuristic(string path) + private bool IsConcatenationFileHeuristic(U8Span path) { // Check if the path is a directory Result getTypeResult = BaseFileSystem.GetEntryType(out DirectoryEntryType pathType, path); if (getTypeResult.IsFailure() || pathType != DirectoryEntryType.Directory) return false; // Check if the directory contains at least one subfile - getTypeResult = BaseFileSystem.GetEntryType(out DirectoryEntryType subFileType, PathTools.Combine(path, "00")); + getTypeResult = BaseFileSystem.GetEntryType(out DirectoryEntryType subFileType, PathTools.Combine(path.ToString(), "00").ToU8Span()); if (getTypeResult.IsFailure() || subFileType != DirectoryEntryType.File) return false; // Make sure the directory contains no subdirectories @@ -88,15 +91,14 @@ namespace LibHac.FsSystem return (attributes & NxFileAttributes.Directory) != 0 && (attributes & NxFileAttributes.Archive) != 0; } - private Result SetConcatenationFileAttribute(string path) + private Result SetConcatenationFileAttribute(U8Span path) { return BaseFileSystem.SetFileAttributes(path, NxFileAttributes.Archive); } - protected override Result CreateDirectoryImpl(string path) + protected override Result CreateDirectoryImpl(U8Span path) { - path = PathTools.Normalize(path); - string parent = PathTools.GetParentDirectory(path); + var parent = new U8Span(PathTools.GetParentDirectory(path)); if (IsConcatenationFile(parent)) { @@ -107,10 +109,8 @@ namespace LibHac.FsSystem return BaseFileSystem.CreateDirectory(path); } - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) { - path = PathTools.Normalize(path); - CreateFileOptions newOptions = options & ~CreateFileOptions.CreateConcatenationFile; if (!options.HasFlag(CreateFileOptions.CreateConcatenationFile)) @@ -119,9 +119,9 @@ namespace LibHac.FsSystem } // A concatenation file directory can't contain normal files - string parentDir = PathTools.GetParentDirectory(path); + ReadOnlySpan parentDir = PathTools.GetParentDirectory(path); - if (IsConcatenationFile(parentDir)) + if (IsConcatenationFile(new U8Span(parentDir))) { // Cannot create a file inside of a concatenation file return ResultFs.PathNotFound.Log(); @@ -135,7 +135,12 @@ namespace LibHac.FsSystem for (int i = 0; remaining > 0; i++) { long fileSize = Math.Min(SubFileSize, remaining); - string fileName = GetSubFilePath(path, i); + + FsPath fileName; + unsafe { _ = &fileName; } // workaround for CS0165 + + rc = GetSubFilePath(fileName.Str, path, i); + if (rc.IsFailure()) return rc; Result createSubFileResult = BaseFileSystem.CreateFile(fileName, fileSize, CreateFileOptions.None); @@ -151,10 +156,8 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result DeleteDirectoryImpl(string path) + protected override Result DeleteDirectoryImpl(U8Span path) { - path = PathTools.Normalize(path); - if (IsConcatenationFile(path)) { return ResultFs.PathNotFound.Log(); @@ -163,48 +166,48 @@ namespace LibHac.FsSystem return BaseFileSystem.DeleteDirectory(path); } - protected override Result DeleteDirectoryRecursivelyImpl(string path) + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) { - path = PathTools.Normalize(path); - if (IsConcatenationFile(path)) return ResultFs.PathNotFound.Log(); return BaseFileSystem.DeleteDirectoryRecursively(path); } - protected override Result CleanDirectoryRecursivelyImpl(string path) + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) { - path = PathTools.Normalize(path); - if (IsConcatenationFile(path)) return ResultFs.PathNotFound.Log(); return BaseFileSystem.CleanDirectoryRecursively(path); } - protected override Result DeleteFileImpl(string path) + protected override Result DeleteFileImpl(U8Span path) { - path = PathTools.Normalize(path); - if (!IsConcatenationFile(path)) { return BaseFileSystem.DeleteFile(path); } - int count = GetSubFileCount(path); + Result rc = GetSubFileCount(out int count, path); + if (rc.IsFailure()) return rc; for (int i = 0; i < count; i++) { - Result rc = BaseFileSystem.DeleteFile(GetSubFilePath(path, i)); + FsPath subFilePath; + unsafe { _ = &subFilePath; } // workaround for CS0165 + + rc = GetSubFilePath(subFilePath.Str, path, i); + if (rc.IsFailure()) return rc; + + rc = BaseFileSystem.DeleteFile(subFilePath); if (rc.IsFailure()) return rc; } return BaseFileSystem.DeleteDirectory(path); } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { directory = default; - path = PathTools.Normalize(path); if (IsConcatenationFile(path)) { @@ -218,25 +221,29 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; - path = PathTools.Normalize(path); if (!IsConcatenationFile(path)) { return BaseFileSystem.OpenFile(out file, path, mode); } - int fileCount = GetSubFileCount(path); + Result rc = GetSubFileCount(out int fileCount, path); + if (rc.IsFailure()) return rc; - var files = new List(); + var files = new List(fileCount); for (int i = 0; i < fileCount; i++) { - string filePath = GetSubFilePath(path, i); + FsPath subFilePath; + unsafe { _ = &subFilePath; } // workaround for CS0165 - Result rc = BaseFileSystem.OpenFile(out IFile subFile, filePath, mode); + rc = GetSubFilePath(subFilePath.Str, path, i); + if (rc.IsFailure()) return rc; + + rc = BaseFileSystem.OpenFile(out IFile subFile, subFilePath, mode); if (rc.IsFailure()) return rc; files.Add(subFile); @@ -246,11 +253,8 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result RenameDirectoryImpl(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) { - oldPath = PathTools.Normalize(oldPath); - newPath = PathTools.Normalize(newPath); - if (IsConcatenationFile(oldPath)) { return ResultFs.PathNotFound.Log(); @@ -259,11 +263,8 @@ namespace LibHac.FsSystem return BaseFileSystem.RenameDirectory(oldPath, newPath); } - protected override Result RenameFileImpl(string oldPath, string newPath) + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) { - oldPath = PathTools.Normalize(oldPath); - newPath = PathTools.Normalize(newPath); - if (IsConcatenationFile(oldPath)) { return BaseFileSystem.RenameDirectory(oldPath, newPath); @@ -274,10 +275,8 @@ namespace LibHac.FsSystem } } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { - path = PathTools.Normalize(path); - if (IsConcatenationFile(path)) { entryType = DirectoryEntryType.File; @@ -287,17 +286,17 @@ namespace LibHac.FsSystem return BaseFileSystem.GetEntryType(out entryType, path); } - protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path) { return BaseFileSystem.GetFreeSpaceSize(out freeSpace, path); } - protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path) { return BaseFileSystem.GetTotalSpaceSize(out totalSpace, path); } - protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path) { return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, path); } @@ -307,42 +306,101 @@ namespace LibHac.FsSystem return BaseFileSystem.Commit(); } - protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, + U8Span path) { if (queryId != QueryId.MakeConcatFile) return ResultFs.UnsupportedOperationInConcatFsQueryEntry.Log(); return SetConcatenationFileAttribute(path); } - private int GetSubFileCount(string dirPath) + private Result GetSubFileCount(out int fileCount, U8Span dirPath) { - int count = 0; + fileCount = default; - while (BaseFileSystem.FileExists(GetSubFilePath(dirPath, count))) + FsPath buffer; + unsafe { _ = &buffer; } // workaround for CS0165 + + int pathLen = StringUtils.Copy(buffer.Str, dirPath); + + // Make sure we have at least 3 bytes for the sub file name + if (pathLen + 3 > PathTools.MaxPathLength) + return ResultFs.TooLongPath.Log(); + + buffer.Str[pathLen] = StringTraits.DirectorySeparator; + Span subFileName = buffer.Str.Slice(pathLen + 1); + + Result rc; + int count; + + for (count = 0; ; count++) { - count++; + Utf8Formatter.TryFormat(count, subFileName, out _, new StandardFormat('D', 2)); + + rc = BaseFileSystem.GetEntryType(out _, buffer); + if (rc.IsFailure()) break; } - return count; - } - - internal static string GetSubFilePath(string dirPath, int index) - { - return $"{dirPath}/{index:D2}"; - } - - internal long GetConcatenationFileSize(string path) - { - int fileCount = GetSubFileCount(path); - long size = 0; - - for (int i = 0; i < fileCount; i++) + if (!ResultFs.PathNotFound.Includes(rc)) { - BaseFileSystem.GetFileSize(out long fileSize, GetSubFilePath(path, i)).ThrowIfFailure(); - size += fileSize; + return rc; } - return size; + fileCount = count; + return Result.Success; + } + + internal static Result GetSubFilePath(Span subFilePathBuffer, ReadOnlySpan basePath, int index) + { + int basePathLen = StringUtils.Copy(subFilePathBuffer, basePath); + + // Make sure we have at least 3 bytes for the sub file name + if (basePathLen + 3 > PathTools.MaxPathLength) + return ResultFs.TooLongPath.Log(); + + subFilePathBuffer[basePathLen] = StringTraits.DirectorySeparator; + + Utf8Formatter.TryFormat(index, subFilePathBuffer.Slice(basePathLen + 1), out _, new StandardFormat('D', 2)); + + return Result.Success; + } + + internal Result GetConcatenationFileSize(out long size, ReadOnlySpan path) + { + size = default; + + FsPath buffer; + unsafe { _ = &buffer; } // workaround for CS0165 + + int pathLen = StringUtils.Copy(buffer.Str, path); + + // Make sure we have at least 3 bytes for the sub file name + if (pathLen + 3 > PathTools.MaxPathLength) + return ResultFs.TooLongPath.Log(); + + buffer.Str[pathLen] = StringTraits.DirectorySeparator; + Span subFileName = buffer.Str.Slice(pathLen + 1); + + Result rc; + long totalSize = 0; + + for (int i = 0; ; i++) + { + Utf8Formatter.TryFormat(i, subFileName, out _, new StandardFormat('D', 2)); + + rc = BaseFileSystem.GetFileSize(out long fileSize, buffer); + if (rc.IsFailure()) break; + + totalSize += fileSize; + } + + if (!ResultFs.PathNotFound.Includes(rc)) + { + return rc; + } + + size = totalSize; + return Result.Success; } } } diff --git a/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs index 4eea8b81..e775bc81 100644 --- a/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/DirectorySaveDataFileSystem.cs @@ -1,12 +1,18 @@ -using LibHac.Fs; +using System; +using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem { public class DirectorySaveDataFileSystem : FileSystemBase { - private const string CommittedDir = "/0/"; - private const string WorkingDir = "/1/"; - private const string SyncDir = "/_/"; + private ReadOnlySpan CommittedDirectoryBytes => new[] { (byte)'/', (byte)'0', (byte)'/' }; + private ReadOnlySpan WorkingDirectoryBytes => new[] { (byte)'/', (byte)'1', (byte)'/' }; + private ReadOnlySpan SynchronizingDirectoryBytes => new[] { (byte)'/', (byte)'_', (byte)'/' }; + + private U8Span CommittedDirectoryPath => new U8Span(CommittedDirectoryBytes); + private U8Span WorkingDirectoryPath => new U8Span(WorkingDirectoryBytes); + private U8Span SynchronizingDirectoryPath => new U8Span(SynchronizingDirectoryBytes); private IFileSystem BaseFs { get; } private object Locker { get; } = new object(); @@ -44,18 +50,18 @@ namespace LibHac.FsSystem IsUserSaveData = isUserSaveData; // Ensure the working directory exists - Result rc = BaseFs.GetEntryType(out _, WorkingDir); + Result rc = BaseFs.GetEntryType(out _, WorkingDirectoryPath); if (rc.IsFailure()) { if (!ResultFs.PathNotFound.Includes(rc)) return rc; - rc = BaseFs.CreateDirectory(WorkingDir); + rc = BaseFs.CreateDirectory(WorkingDirectoryPath); if (rc.IsFailure()) return rc; if (!IsPersistentSaveData) return Result.Success; - rc = BaseFs.CreateDirectory(CommittedDir); + rc = BaseFs.CreateDirectory(CommittedDirectoryPath); // Nintendo returns on all failures, but we'll keep going if committed already exists // to avoid confusing people manually creating savedata in emulators @@ -65,11 +71,11 @@ namespace LibHac.FsSystem // Only the working directory is needed for temporary savedata if (!IsPersistentSaveData) return Result.Success; - rc = BaseFs.GetEntryType(out _, CommittedDir); + rc = BaseFs.GetEntryType(out _, CommittedDirectoryPath); if (rc.IsSuccess()) { - return SynchronizeDirectory(WorkingDir, CommittedDir); + return SynchronizeDirectory(WorkingDirectoryPath, CommittedDirectoryPath); } if (!ResultFs.PathNotFound.Includes(rc)) return rc; @@ -77,15 +83,19 @@ namespace LibHac.FsSystem // If a previous commit failed, the committed dir may be missing. // Finish that commit by copying the working dir to the committed dir - rc = SynchronizeDirectory(SyncDir, WorkingDir); + rc = SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath); if (rc.IsFailure()) return rc; - return BaseFs.RenameDirectory(SyncDir, CommittedDir); + return BaseFs.RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath); } - protected override Result CreateDirectoryImpl(string path) + protected override Result CreateDirectoryImpl(U8Span path) { - string fullPath = GetFullPath(PathTools.Normalize(path)); + FsPath fullPath; + unsafe { _ = &fullPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullPath.Str, path); + if (rc.IsFailure()) return rc; lock (Locker) { @@ -93,9 +103,13 @@ namespace LibHac.FsSystem } } - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) { - string fullPath = GetFullPath(PathTools.Normalize(path)); + FsPath fullPath; + unsafe { _ = &fullPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullPath.Str, path); + if (rc.IsFailure()) return rc; lock (Locker) { @@ -103,9 +117,13 @@ namespace LibHac.FsSystem } } - protected override Result DeleteDirectoryImpl(string path) + protected override Result DeleteDirectoryImpl(U8Span path) { - string fullPath = GetFullPath(PathTools.Normalize(path)); + FsPath fullPath; + unsafe { _ = &fullPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullPath.Str, path); + if (rc.IsFailure()) return rc; lock (Locker) { @@ -113,9 +131,13 @@ namespace LibHac.FsSystem } } - protected override Result DeleteDirectoryRecursivelyImpl(string path) + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) { - string fullPath = GetFullPath(PathTools.Normalize(path)); + FsPath fullPath; + unsafe { _ = &fullPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullPath.Str, path); + if (rc.IsFailure()) return rc; lock (Locker) { @@ -123,9 +145,13 @@ namespace LibHac.FsSystem } } - protected override Result CleanDirectoryRecursivelyImpl(string path) + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) { - string fullPath = GetFullPath(PathTools.Normalize(path)); + FsPath fullPath; + unsafe { _ = &fullPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullPath.Str, path); + if (rc.IsFailure()) return rc; lock (Locker) { @@ -133,9 +159,13 @@ namespace LibHac.FsSystem } } - protected override Result DeleteFileImpl(string path) + protected override Result DeleteFileImpl(U8Span path) { - string fullPath = GetFullPath(PathTools.Normalize(path)); + FsPath fullPath; + unsafe { _ = &fullPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullPath.Str, path); + if (rc.IsFailure()) return rc; lock (Locker) { @@ -143,9 +173,17 @@ namespace LibHac.FsSystem } } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { - string fullPath = GetFullPath(PathTools.Normalize(path)); + FsPath fullPath; + unsafe { _ = &fullPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullPath.Str, path); + if (rc.IsFailure()) + { + directory = default; + return rc; + } lock (Locker) { @@ -153,14 +191,19 @@ namespace LibHac.FsSystem } } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; - string fullPath = GetFullPath(PathTools.Normalize(path)); + + FsPath fullPath; + unsafe { _ = &fullPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullPath.Str, path); + if (rc.IsFailure()) return rc; lock (Locker) { - Result rc = BaseFs.OpenFile(out IFile baseFile, fullPath, mode); + rc = BaseFs.OpenFile(out IFile baseFile, fullPath, mode); if (rc.IsFailure()) return rc; file = new DirectorySaveDataFile(this, baseFile, mode); @@ -174,31 +217,55 @@ namespace LibHac.FsSystem } } - protected override Result RenameDirectoryImpl(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) { - string fullOldPath = GetFullPath(PathTools.Normalize(oldPath)); - string fullNewPath = GetFullPath(PathTools.Normalize(newPath)); + FsPath fullCurrentPath; + FsPath fullNewPath; + unsafe { _ = &fullCurrentPath; } // workaround for CS0165 + unsafe { _ = &fullNewPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullCurrentPath.Str, oldPath); + if (rc.IsFailure()) return rc; + + rc = ResolveFullPath(fullNewPath.Str, newPath); + if (rc.IsFailure()) return rc; lock (Locker) { - return BaseFs.RenameDirectory(fullOldPath, fullNewPath); + return BaseFs.RenameDirectory(fullCurrentPath, fullNewPath); } } - protected override Result RenameFileImpl(string oldPath, string newPath) + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) { - string fullOldPath = GetFullPath(PathTools.Normalize(oldPath)); - string fullNewPath = GetFullPath(PathTools.Normalize(newPath)); + FsPath fullCurrentPath; + FsPath fullNewPath; + unsafe { _ = &fullCurrentPath; } // workaround for CS0165 + unsafe { _ = &fullNewPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullCurrentPath.Str, oldPath); + if (rc.IsFailure()) return rc; + + rc = ResolveFullPath(fullNewPath.Str, newPath); + if (rc.IsFailure()) return rc; lock (Locker) { - return BaseFs.RenameFile(fullOldPath, fullNewPath); + return BaseFs.RenameFile(fullCurrentPath, fullNewPath); } } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { - string fullPath = GetFullPath(PathTools.Normalize(path)); + FsPath fullPath; + unsafe { _ = &fullPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullPath.Str, path); + if (rc.IsFailure()) + { + entryType = default; + return rc; + } lock (Locker) { @@ -219,25 +286,31 @@ namespace LibHac.FsSystem } // Get rid of the previous commit by renaming the folder - Result rc = BaseFs.RenameDirectory(CommittedDir, SyncDir); + Result rc = BaseFs.RenameDirectory(CommittedDirectoryPath, SynchronizingDirectoryPath); if (rc.IsFailure()) return rc; // If something goes wrong beyond this point, the commit will be // completed the next time the savedata is opened - rc = SynchronizeDirectory(SyncDir, WorkingDir); + rc = SynchronizeDirectory(SynchronizingDirectoryPath, WorkingDirectoryPath); if (rc.IsFailure()) return rc; - return BaseFs.RenameDirectory(SyncDir, CommittedDir); + return BaseFs.RenameDirectory(SynchronizingDirectoryPath, CommittedDirectoryPath); } } - private string GetFullPath(string path) + private Result ResolveFullPath(Span outPath, U8Span relativePath) { - return PathTools.Normalize(PathTools.Combine(WorkingDir, path)); + if (StringUtils.GetLength(relativePath, PathTools.MaxPathLength + 1) > PathTools.MaxPathLength) + return ResultFs.TooLongPath.Log(); + + StringUtils.Copy(outPath, WorkingDirectoryBytes); + outPath[^1] = StringTraits.NullTerminator; + + return PathTool.Normalize(outPath.Slice(2), out _, relativePath, false, false); } - private Result SynchronizeDirectory(string dest, string src) + private Result SynchronizeDirectory(U8Span dest, U8Span src) { Result rc = BaseFs.DeleteDirectoryRecursively(dest); if (rc.IsFailure() && !ResultFs.PathNotFound.Includes(rc)) return rc; @@ -245,7 +318,7 @@ namespace LibHac.FsSystem rc = BaseFs.CreateDirectory(dest); if (rc.IsFailure()) return rc; - return BaseFs.CopyDirectory(BaseFs, src, dest); + return BaseFs.CopyDirectory(BaseFs, src.ToString(), dest.ToString()); } internal void NotifyCloseWritableFile() diff --git a/src/LibHac/FsSystem/DirectoryUtils.cs b/src/LibHac/FsSystem/DirectoryUtils.cs index f28e5896..3e98bfe8 100644 --- a/src/LibHac/FsSystem/DirectoryUtils.cs +++ b/src/LibHac/FsSystem/DirectoryUtils.cs @@ -11,9 +11,7 @@ namespace LibHac.FsSystem public static Result IterateDirectoryRecursivelyInternal(IFileSystem fs, Span workPath, ref DirectoryEntry entry, Blah onEnterDir, Blah onExitDir, Blah onFile) { - string currentPath = Util.GetUtf8StringNullTerminated(workPath); - - Result rc = fs.OpenDirectory(out IDirectory _, currentPath, OpenDirectoryMode.All); + Result rc = fs.OpenDirectory(out IDirectory _, new U8Span(workPath), OpenDirectoryMode.All); if (rc.IsFailure()) return rc; onFile(workPath, ref entry); @@ -40,7 +38,7 @@ namespace LibHac.FsSystem try { - Result rc = sourceFs.OpenFile(out srcFile, StringUtils.Utf8ZToString(sourcePath), OpenMode.Read); + Result rc = sourceFs.OpenFile(out srcFile, new U8Span(sourcePath), OpenMode.Read); if (rc.IsFailure()) return rc; FsPath dstPath = default; @@ -52,12 +50,10 @@ namespace LibHac.FsSystem throw new ArgumentException(); } - string dstPathStr = StringUtils.Utf8ZToString(dstPath.Str); - - rc = destFs.CreateFile(dstPathStr, dirEntry.Size, CreateFileOptions.None); + rc = destFs.CreateFile(dstPath, dirEntry.Size, CreateFileOptions.None); if (rc.IsFailure()) return rc; - rc = destFs.OpenFile(out dstFile, dstPathStr, OpenMode.Write); + rc = destFs.OpenFile(out dstFile, dstPath, OpenMode.Write); if (rc.IsFailure()) return rc; long fileSize = dirEntry.Size; diff --git a/src/LibHac/FsSystem/FileSystemExtensions.cs b/src/LibHac/FsSystem/FileSystemExtensions.cs index 5b0471a5..858cf318 100644 --- a/src/LibHac/FsSystem/FileSystemExtensions.cs +++ b/src/LibHac/FsSystem/FileSystemExtensions.cs @@ -31,12 +31,12 @@ namespace LibHac.FsSystem { destFs.CreateOrOverwriteFile(subDstPath, entry.Size, options); - rc = sourceFs.OpenFile(out IFile srcFile, subSrcPath, OpenMode.Read); + rc = sourceFs.OpenFile(out IFile srcFile, subSrcPath.ToU8Span(), OpenMode.Read); if (rc.IsFailure()) return rc; using (srcFile) { - rc = destFs.OpenFile(out IFile dstFile, subDstPath, OpenMode.Write | OpenMode.AllowAppend); + rc = destFs.OpenFile(out IFile dstFile, subDstPath.ToU8Span(), OpenMode.Write | OpenMode.AllowAppend); if (rc.IsFailure()) return rc; using (dstFile) @@ -80,7 +80,7 @@ namespace LibHac.FsSystem IFileSystem fs = fileSystem; - fileSystem.OpenDirectory(out IDirectory directory, path, OpenDirectoryMode.All).ThrowIfFailure(); + fileSystem.OpenDirectory(out IDirectory directory, path.ToU8Span(), OpenDirectoryMode.All).ThrowIfFailure(); while (true) { @@ -199,7 +199,7 @@ namespace LibHac.FsSystem public static void SetConcatenationFileAttribute(this IFileSystem fs, string path) { - fs.QueryEntry(Span.Empty, Span.Empty, QueryId.MakeConcatFile, path); + fs.QueryEntry(Span.Empty, Span.Empty, QueryId.MakeConcatFile, path.ToU8Span()); } public static void CleanDirectoryRecursivelyGeneric(IFileSystem fileSystem, string path) @@ -213,11 +213,11 @@ namespace LibHac.FsSystem if (entry.Type == DirectoryEntryType.Directory) { CleanDirectoryRecursivelyGeneric(fileSystem, subPath); - fs.DeleteDirectory(subPath); + fs.DeleteDirectory(subPath.ToU8Span()); } else if (entry.Type == DirectoryEntryType.File) { - fs.DeleteFile(subPath); + fs.DeleteFile(subPath.ToU8Span()); } } } @@ -234,14 +234,14 @@ namespace LibHac.FsSystem public static bool DirectoryExists(this IFileSystem fs, string path) { - Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + Result rc = fs.GetEntryType(out DirectoryEntryType type, path.ToU8Span()); return (rc.IsSuccess() && type == DirectoryEntryType.Directory); } public static bool FileExists(this IFileSystem fs, string path) { - Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + Result rc = fs.GetEntryType(out DirectoryEntryType type, path.ToU8Span()); return (rc.IsSuccess() && type == DirectoryEntryType.File); } @@ -277,12 +277,12 @@ namespace LibHac.FsSystem { string subPath = path.Substring(0, i); - Result rc = fs.CreateDirectory(subPath); + Result rc = fs.CreateDirectory(subPath.ToU8Span()); if (rc.IsFailure()) return rc; } } - return fs.CreateDirectory(path); + return fs.CreateDirectory(path.ToU8Span()); } public static void CreateOrOverwriteFile(this IFileSystem fs, string path, long size) @@ -294,9 +294,9 @@ namespace LibHac.FsSystem { path = PathTools.Normalize(path); - if (fs.FileExists(path)) fs.DeleteFile(path); + if (fs.FileExists(path)) fs.DeleteFile(path.ToU8Span()); - fs.CreateFile(path, size, CreateFileOptions.None); + fs.CreateFile(path.ToU8Span(), size, CreateFileOptions.None); } } diff --git a/src/LibHac/FsSystem/FsPath.cs b/src/LibHac/FsSystem/FsPath.cs index 4818db0e..ca71e059 100644 --- a/src/LibHac/FsSystem/FsPath.cs +++ b/src/LibHac/FsSystem/FsPath.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using LibHac.Common; using LibHac.Fs; @@ -30,7 +31,9 @@ namespace LibHac.FsSystem return builder.Overflowed ? ResultFs.TooLongPath.Log() : Result.Success; } - public static implicit operator U8Span(FsPath value) => new U8Span(value.Str); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator U8Span(in FsPath value) => new U8Span(SpanHelpers.AsReadOnlyByteSpan(ref Unsafe.AsRef(in value))); + public override string ToString() => StringUtils.Utf8ZToString(Str); } } diff --git a/src/LibHac/FsSystem/LayeredFileSystem.cs b/src/LibHac/FsSystem/LayeredFileSystem.cs index 4a7f24f4..0e3ca2ce 100644 --- a/src/LibHac/FsSystem/LayeredFileSystem.cs +++ b/src/LibHac/FsSystem/LayeredFileSystem.cs @@ -35,10 +35,9 @@ namespace LibHac.FsSystem Sources.AddRange(sourceFileSystems); } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { directory = default; - path = PathTools.Normalize(path); // Open directories from all layers so they can be merged // Only allocate the list for multiple sources if needed @@ -107,10 +106,9 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; - path = PathTools.Normalize(path); foreach (IFileSystem fs in Sources) { @@ -137,10 +135,8 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { - path = PathTools.Normalize(path); - foreach (IFileSystem fs in Sources) { Result getEntryResult = fs.GetEntryType(out DirectoryEntryType type, path); @@ -156,10 +152,8 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path) { - path = PathTools.Normalize(path); - foreach (IFileSystem fs in Sources) { Result getEntryResult = fs.GetEntryType(out _, path); @@ -174,10 +168,9 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, + U8Span path) { - path = PathTools.Normalize(path); - foreach (IFileSystem fs in Sources) { Result getEntryResult = fs.GetEntryType(out _, path); @@ -196,31 +189,31 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperation.Log(); - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperation.Log(); - protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperation.Log(); - protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperation.Log(); - protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperation.Log(); - protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperation.Log(); - protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log(); - protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log(); + protected override Result CreateDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperation.Log(); + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperation.Log(); + protected override Result DeleteDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperation.Log(); + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperation.Log(); + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperation.Log(); + protected override Result DeleteFileImpl(U8Span path) => ResultFs.UnsupportedOperation.Log(); + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperation.Log(); + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperation.Log(); private class MergedDirectory : IDirectory { // Needed to open new directories for GetEntryCount private List SourceFileSystems { get; } private List SourceDirs { get; } - private string Path { get; } + private U8String Path { get; } private OpenDirectoryMode Mode { get; } // todo: Efficient way to remove duplicates private HashSet Names { get; } = new HashSet(); - public MergedDirectory(List sourceFileSystems, string path, OpenDirectoryMode mode) + public MergedDirectory(List sourceFileSystems, U8Span path, OpenDirectoryMode mode) { SourceFileSystems = sourceFileSystems; SourceDirs = new List(sourceFileSystems.Count); - Path = path; + Path = path.ToU8String(); Mode = mode; } @@ -280,7 +273,7 @@ namespace LibHac.FsSystem long entriesRead; do { - dir.Read(out entriesRead, SpanHelpers.AsSpan(ref entry)); + rc = dir.Read(out entriesRead, SpanHelpers.AsSpan(ref entry)); if (rc.IsFailure()) return rc; if (entriesRead == 1 && names.Add(StringUtils.Utf8ZToString(entry.Name))) diff --git a/src/LibHac/FsSystem/LocalFileSystem.cs b/src/LibHac/FsSystem/LocalFileSystem.cs index 110f93eb..148c8dc0 100644 --- a/src/LibHac/FsSystem/LocalFileSystem.cs +++ b/src/LibHac/FsSystem/LocalFileSystem.cs @@ -30,18 +30,49 @@ namespace LibHac.FsSystem } } - internal string ResolveLocalPath(string path) + private Result ResolveFullPath(out string fullPath, U8Span path) { - return PathTools.Combine(BasePath, path); + fullPath = default; + + FsPath normalizedPath; + unsafe { _ = &normalizedPath; } // workaround for CS0165 + + Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false); + if (rc.IsFailure()) return rc; + + fullPath = PathTools.Combine(BasePath, normalizedPath.ToString()); + return Result.Success; } - protected override Result GetFileAttributesImpl(string path, out NxFileAttributes attributes) + private Result CheckSubPath(U8Span path1, U8Span path2) + { + FsPath normalizedPath1; + FsPath normalizedPath2; + unsafe { _ = &normalizedPath1; } // workaround for CS0165 + unsafe { _ = &normalizedPath2; } // workaround for CS0165 + + Result rc = PathTool.Normalize(normalizedPath1.Str, out _, path1, false, false); + if (rc.IsFailure()) return rc; + + rc = PathTool.Normalize(normalizedPath2.Str, out _, path2, false, false); + if (rc.IsFailure()) return rc; + + if (PathTool.IsSubpath(normalizedPath1, normalizedPath2)) + { + return ResultFs.DestinationIsSubPathOfSource.Log(); + } + + return Result.Success; + } + + protected override Result GetFileAttributesImpl(out NxFileAttributes attributes, U8Span path) { attributes = default; - string localPath = ResolveLocalPath(PathTools.Normalize(path)); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; - Result rc = GetFileInfo(out FileInfo info, localPath); + rc = GetFileInfo(out FileInfo info, fullPath); if (rc.IsFailure()) return rc; if (info.Attributes == (FileAttributes)(-1)) @@ -54,11 +85,12 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result SetFileAttributesImpl(string path, NxFileAttributes attributes) + protected override Result SetFileAttributesImpl(U8Span path, NxFileAttributes attributes) { - string localPath = ResolveLocalPath(PathTools.Normalize(path)); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; - Result rc = GetFileInfo(out FileInfo info, localPath); + rc = GetFileInfo(out FileInfo info, fullPath); if (rc.IsFailure()) return rc; if (info.Attributes == (FileAttributes)(-1)) @@ -81,27 +113,30 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result GetFileSizeImpl(out long fileSize, string path) + protected override Result GetFileSizeImpl(out long fileSize, U8Span path) { fileSize = default; - string localPath = ResolveLocalPath(PathTools.Normalize(path)); - Result rc = GetFileInfo(out FileInfo info, localPath); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; + + rc = GetFileInfo(out FileInfo info, fullPath); if (rc.IsFailure()) return rc; return GetSizeInternal(out fileSize, info); } - protected override Result CreateDirectoryImpl(string path) + protected override Result CreateDirectoryImpl(U8Span path) { return CreateDirectory(path, NxFileAttributes.None); } - protected override Result CreateDirectoryImpl(string path, NxFileAttributes archiveAttribute) + protected override Result CreateDirectoryImpl(U8Span path, NxFileAttributes archiveAttribute) { - string localPath = ResolveLocalPath(PathTools.Normalize(path)); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; - Result rc = GetDirInfo(out DirectoryInfo dir, localPath); + rc = GetDirInfo(out DirectoryInfo dir, fullPath); if (rc.IsFailure()) return rc; if (dir.Exists) @@ -117,11 +152,12 @@ namespace LibHac.FsSystem return CreateDirInternal(dir, archiveAttribute); } - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) { - string localPath = ResolveLocalPath(PathTools.Normalize(path)); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; - Result rc = GetFileInfo(out FileInfo file, localPath); + rc = GetFileInfo(out FileInfo file, fullPath); if (rc.IsFailure()) return rc; if (file.Exists) @@ -144,42 +180,45 @@ namespace LibHac.FsSystem } } - protected override Result DeleteDirectoryImpl(string path) + protected override Result DeleteDirectoryImpl(U8Span path) { - string localPath = ResolveLocalPath(PathTools.Normalize(path)); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; - Result rc = GetDirInfo(out DirectoryInfo dir, localPath); + rc = GetDirInfo(out DirectoryInfo dir, fullPath); if (rc.IsFailure()) return rc; return DeleteDirectoryInternal(dir, false); } - protected override Result DeleteDirectoryRecursivelyImpl(string path) + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) { - string localPath = ResolveLocalPath(PathTools.Normalize(path)); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; - Result rc = GetDirInfo(out DirectoryInfo dir, localPath); + rc = GetDirInfo(out DirectoryInfo dir, fullPath); if (rc.IsFailure()) return rc; return DeleteDirectoryInternal(dir, true); } - protected override Result CleanDirectoryRecursivelyImpl(string path) + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) { - string localPath = ResolveLocalPath(PathTools.Normalize(path)); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; - foreach (string file in Directory.EnumerateFiles(localPath)) + foreach (string file in Directory.EnumerateFiles(fullPath)) { - Result rc = GetFileInfo(out FileInfo fileInfo, file); + rc = GetFileInfo(out FileInfo fileInfo, file); if (rc.IsFailure()) return rc; rc = DeleteFileInternal(fileInfo); if (rc.IsFailure()) return rc; } - foreach (string dir in Directory.EnumerateDirectories(localPath)) + foreach (string dir in Directory.EnumerateDirectories(fullPath)) { - Result rc = GetDirInfo(out DirectoryInfo dirInfo, dir); + rc = GetDirInfo(out DirectoryInfo dirInfo, dir); if (rc.IsFailure()) return rc; rc = DeleteDirectoryInternal(dirInfo, true); @@ -189,22 +228,24 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result DeleteFileImpl(string path) + protected override Result DeleteFileImpl(U8Span path) { - string localPath = ResolveLocalPath(PathTools.Normalize(path)); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; - Result rc = GetFileInfo(out FileInfo file, localPath); + rc = GetFileInfo(out FileInfo file, fullPath); if (rc.IsFailure()) return rc; return DeleteFileInternal(file); } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { directory = default; - string localPath = ResolveLocalPath(PathTools.Normalize(path)); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; - Result rc = GetDirInfo(out DirectoryInfo dirInfo, localPath); + rc = GetDirInfo(out DirectoryInfo dirInfo, fullPath); if (rc.IsFailure()) return rc; if (!dirInfo.Attributes.HasFlag(FileAttributes.Directory)) @@ -225,12 +266,14 @@ namespace LibHac.FsSystem } } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; - string localPath = ResolveLocalPath(PathTools.Normalize(path)); - Result rc = GetEntryType(out DirectoryEntryType entryType, path); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; + + rc = GetEntryType(out DirectoryEntryType entryType, path); if (rc.IsFailure()) return rc; if (entryType == DirectoryEntryType.Directory) @@ -238,59 +281,64 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - rc = OpenFileInternal(out FileStream fileStream, localPath, mode); + rc = OpenFileInternal(out FileStream fileStream, fullPath, mode); if (rc.IsFailure()) return rc; file = new LocalFile(fileStream, mode); return Result.Success; } - protected override Result RenameDirectoryImpl(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) { - oldPath = PathTools.Normalize(oldPath); - newPath = PathTools.Normalize(newPath); + Result rc = CheckSubPath(oldPath, newPath); + if (rc.IsFailure()) return rc; + + rc = ResolveFullPath(out string fullCurrentPath, oldPath); + if (rc.IsFailure()) return rc; + + rc = ResolveFullPath(out string fullNewPath, newPath); + if (rc.IsFailure()) return rc; // Official FS behavior is to do nothing in this case - if (oldPath == newPath) return Result.Success; + if (fullCurrentPath == fullNewPath) return Result.Success; - // FS does the subpath check before verifying the path exists - if (PathTools.IsSubPath(oldPath.AsSpan(), newPath.AsSpan())) - { - ThrowHelper.ThrowResult(ResultFs.DestinationIsSubPathOfSource.Value); - } - - Result rc = GetDirInfo(out DirectoryInfo srcDir, ResolveLocalPath(oldPath)); + rc = GetDirInfo(out DirectoryInfo currentDirInfo, fullCurrentPath); if (rc.IsFailure()) return rc; - rc = GetDirInfo(out DirectoryInfo dstDir, ResolveLocalPath(newPath)); + rc = GetDirInfo(out DirectoryInfo newDirInfo, fullNewPath); if (rc.IsFailure()) return rc; - return RenameDirInternal(srcDir, dstDir); + return RenameDirInternal(currentDirInfo, newDirInfo); } - protected override Result RenameFileImpl(string oldPath, string newPath) + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) { - string srcLocalPath = ResolveLocalPath(PathTools.Normalize(oldPath)); - string dstLocalPath = ResolveLocalPath(PathTools.Normalize(newPath)); + Result rc = ResolveFullPath(out string fullCurrentPath, oldPath); + if (rc.IsFailure()) return rc; + + rc = ResolveFullPath(out string fullNewPath, newPath); + if (rc.IsFailure()) return rc; // Official FS behavior is to do nothing in this case - if (srcLocalPath == dstLocalPath) return Result.Success; + if (fullCurrentPath == fullNewPath) return Result.Success; - Result rc = GetFileInfo(out FileInfo srcFile, srcLocalPath); + rc = GetFileInfo(out FileInfo currentFileInfo, fullCurrentPath); if (rc.IsFailure()) return rc; - rc = GetFileInfo(out FileInfo dstFile, dstLocalPath); + rc = GetFileInfo(out FileInfo newFileInfo, fullNewPath); if (rc.IsFailure()) return rc; - return RenameFileInternal(srcFile, dstFile); + return RenameFileInternal(currentFileInfo, newFileInfo); } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { entryType = default; - string localPath = ResolveLocalPath(PathTools.Normalize(path)); - Result rc = GetDirInfo(out DirectoryInfo dir, localPath); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; + + rc = GetDirInfo(out DirectoryInfo dir, fullPath); if (rc.IsFailure()) return rc; if (dir.Exists) @@ -299,7 +347,7 @@ namespace LibHac.FsSystem return Result.Success; } - rc = GetFileInfo(out FileInfo file, localPath); + rc = GetFileInfo(out FileInfo file, fullPath); if (rc.IsFailure()) return rc; if (file.Exists) @@ -312,30 +360,32 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path) { timeStamp = default; - string localPath = ResolveLocalPath(PathTools.Normalize(path)); - Result rc = GetFileInfo(out FileInfo file, localPath); + Result rc = ResolveFullPath(out string fullPath, path); + if (rc.IsFailure()) return rc; + + rc = GetFileInfo(out FileInfo file, fullPath); if (rc.IsFailure()) return rc; if (!file.Exists) return ResultFs.PathNotFound.Log(); - timeStamp.Created = new DateTimeOffset(File.GetCreationTime(localPath)).ToUnixTimeSeconds(); - timeStamp.Accessed = new DateTimeOffset(File.GetLastAccessTime(localPath)).ToUnixTimeSeconds(); - timeStamp.Modified = new DateTimeOffset(File.GetLastWriteTime(localPath)).ToUnixTimeSeconds(); + timeStamp.Created = new DateTimeOffset(file.CreationTimeUtc).ToUnixTimeSeconds(); + timeStamp.Accessed = new DateTimeOffset(file.LastAccessTimeUtc).ToUnixTimeSeconds(); + timeStamp.Modified = new DateTimeOffset(file.LastWriteTime).ToUnixTimeSeconds(); return Result.Success; } - protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path) { freeSpace = new DriveInfo(BasePath).AvailableFreeSpace; return Result.Success; } - protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path) { totalSpace = new DriveInfo(BasePath).TotalSize; return Result.Success; @@ -346,7 +396,8 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, + U8Span path) { return ResultFs.UnsupportedOperation.Log(); } diff --git a/src/LibHac/FsSystem/PartitionFileSystem.cs b/src/LibHac/FsSystem/PartitionFileSystem.cs index 7993eb27..11c514d5 100644 --- a/src/LibHac/FsSystem/PartitionFileSystem.cs +++ b/src/LibHac/FsSystem/PartitionFileSystem.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using LibHac.Common; using LibHac.Crypto; using LibHac.Fs; @@ -31,17 +32,17 @@ namespace LibHac.FsSystem BaseStorage = storage; } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { - directory = new PartitionDirectory(this, path, mode); + directory = new PartitionDirectory(this, path.ToString(), mode); return Result.Success; } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { - path = PathTools.Normalize(path).TrimStart('/'); + path = PathTools.Normalize(path.ToString()).TrimStart('/').ToU8Span(); - if (!FileDict.TryGetValue(path, out PartitionFileEntry entry)) + if (!FileDict.TryGetValue(path.ToString(), out PartitionFileEntry entry)) { ThrowHelper.ThrowResult(ResultFs.PathNotFound.Value); } @@ -55,18 +56,17 @@ namespace LibHac.FsSystem return new PartitionFile(BaseStorage, HeaderSize + entry.Offset, entry.Size, mode); } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { entryType = default; - path = PathTools.Normalize(path); - if (path == "/") + if (path.ToString() == "/") { entryType = DirectoryEntryType.Directory; return Result.Success; } - if (FileDict.ContainsKey(path.TrimStart('/'))) + if (FileDict.ContainsKey(path.ToString().TrimStart('/'))) { entryType = DirectoryEntryType.File; return Result.Success; @@ -75,14 +75,14 @@ namespace LibHac.FsSystem return ResultFs.PathNotFound.Log(); } - protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result CreateDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result DeleteDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result DeleteFileImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); protected override Result CommitImpl() { diff --git a/src/LibHac/FsSystem/PartitionFileSystemBuilder.cs b/src/LibHac/FsSystem/PartitionFileSystemBuilder.cs index 4c1f4738..158f2db1 100644 --- a/src/LibHac/FsSystem/PartitionFileSystemBuilder.cs +++ b/src/LibHac/FsSystem/PartitionFileSystemBuilder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; +using LibHac.Common; using LibHac.Crypto; using LibHac.Fs; @@ -26,7 +27,7 @@ namespace LibHac.FsSystem foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File) .OrderBy(x => x.FullPath, StringComparer.Ordinal)) { - input.OpenFile(out IFile file, entry.FullPath, OpenMode.Read).ThrowIfFailure(); + input.OpenFile(out IFile file, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); AddFile(entry.FullPath.TrimStart('/'), file); } diff --git a/src/LibHac/FsSystem/PartitionFileSystemCore.cs b/src/LibHac/FsSystem/PartitionFileSystemCore.cs index f4731758..81a84b6b 100644 --- a/src/LibHac/FsSystem/PartitionFileSystemCore.cs +++ b/src/LibHac/FsSystem/PartitionFileSystemCore.cs @@ -31,7 +31,7 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { directory = default; @@ -40,7 +40,7 @@ namespace LibHac.FsSystem ReadOnlySpan rootPath = new[] { (byte)'/' }; - if (StringUtils.Compare(rootPath, path.ToU8Span(), 2) != 0) + if (StringUtils.Compare(rootPath, path, 2) != 0) return ResultFs.PathNotFound.Log(); directory = new PartitionDirectory(this, mode); @@ -48,7 +48,7 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; @@ -58,7 +58,7 @@ namespace LibHac.FsSystem if (!mode.HasFlag(OpenMode.Read) && !mode.HasFlag(OpenMode.Write)) return ResultFs.InvalidArgument.Log(); - int entryIndex = MetaData.FindEntry(path.ToU8Span().Slice(1)); + int entryIndex = MetaData.FindEntry(path.Slice(1)); if (entryIndex < 0) return ResultFs.PathNotFound.Log(); ref T entry = ref MetaData.GetEntry(entryIndex); @@ -68,25 +68,25 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { entryType = default; if (!IsInitialized) return ResultFs.PreconditionViolation.Log(); - if (string.IsNullOrEmpty(path) || path[0] != '/') + if (path.IsEmpty() || path[0] != '/') return ResultFs.InvalidPathFormat.Log(); ReadOnlySpan rootPath = new[] { (byte)'/' }; - if (StringUtils.Compare(rootPath, path.ToU8Span(), 2) == 0) + if (StringUtils.Compare(rootPath, path, 2) == 0) { entryType = DirectoryEntryType.Directory; return Result.Success; } - if (MetaData.FindEntry(path.ToU8Span().Slice(1)) >= 0) + if (MetaData.FindEntry(path.Slice(1)) >= 0) { entryType = DirectoryEntryType.File; return Result.Success; @@ -100,14 +100,14 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result CreateDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result DeleteDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result DeleteFileImpl(U8Span path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); private class PartitionFile : FileBase { diff --git a/src/LibHac/FsSystem/ReadOnlyFileSystem.cs b/src/LibHac/FsSystem/ReadOnlyFileSystem.cs index a3c4860c..c61d959e 100644 --- a/src/LibHac/FsSystem/ReadOnlyFileSystem.cs +++ b/src/LibHac/FsSystem/ReadOnlyFileSystem.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem { @@ -11,12 +12,12 @@ namespace LibHac.FsSystem BaseFs = baseFileSystem; } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { return BaseFs.OpenDirectory(out directory, path, mode); } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; @@ -27,12 +28,12 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { return BaseFs.GetEntryType(out entryType, path); } - protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path) { freeSpace = 0; return Result.Success; @@ -41,7 +42,7 @@ namespace LibHac.FsSystem // return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log(); } - protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path) { return BaseFs.GetTotalSpaceSize(out totalSpace, path); @@ -49,7 +50,7 @@ namespace LibHac.FsSystem // return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log(); } - protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path) { return BaseFs.GetFileTimeStampRaw(out timeStamp, path); @@ -62,20 +63,20 @@ namespace LibHac.FsSystem return Result.Success; } - protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result CreateDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result DeleteDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result DeleteFileImpl(U8Span path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); } } diff --git a/src/LibHac/FsSystem/RomFs/RomFsBuilder.cs b/src/LibHac/FsSystem/RomFs/RomFsBuilder.cs index 5f95e172..dae93716 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsBuilder.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsBuilder.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsSystem.RomFs @@ -36,7 +37,7 @@ namespace LibHac.FsSystem.RomFs foreach (DirectoryEntryEx entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File) .OrderBy(x => x.FullPath, StringComparer.Ordinal)) { - input.OpenFile(out IFile file, entry.FullPath, OpenMode.Read).ThrowIfFailure(); + input.OpenFile(out IFile file, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); AddFile(entry.FullPath, file); } diff --git a/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs b/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs index 8b84fe83..764a60b5 100644 --- a/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs +++ b/src/LibHac/FsSystem/RomFs/RomFsFileSystem.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; namespace LibHac.FsSystem.RomFs { @@ -22,18 +23,17 @@ namespace LibHac.FsSystem.RomFs FileTable = new HierarchicalRomFileTable(dirHashTable, dirEntryTable, fileHashTable, fileEntryTable); } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { entryType = default; - path = PathTools.Normalize(path); - if (FileTable.TryOpenFile(path, out RomFileInfo _)) + if (FileTable.TryOpenFile(path.ToString(), out RomFileInfo _)) { entryType = DirectoryEntryType.File; return Result.Success; } - if (FileTable.TryOpenDirectory(path, out FindPosition _)) + if (FileTable.TryOpenDirectory(path.ToString(), out FindPosition _)) { entryType = DirectoryEntryType.Directory; return Result.Success; @@ -47,12 +47,11 @@ namespace LibHac.FsSystem.RomFs return Result.Success; } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { directory = default; - path = PathTools.Normalize(path); - if (!FileTable.TryOpenDirectory(path, out FindPosition position)) + if (!FileTable.TryOpenDirectory(path.ToString(), out FindPosition position)) { return ResultFs.PathNotFound.Log(); } @@ -61,12 +60,11 @@ namespace LibHac.FsSystem.RomFs return Result.Success; } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; - path = PathTools.Normalize(path); - if (!FileTable.TryOpenFile(path, out RomFileInfo info)) + if (!FileTable.TryOpenFile(path.ToString(), out RomFileInfo info)) { return ResultFs.PathNotFound.Log(); } @@ -86,22 +84,22 @@ namespace LibHac.FsSystem.RomFs return BaseStorage; } - protected override Result CreateDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - protected override Result DeleteDirectoryImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - protected override Result DeleteDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - protected override Result CleanDirectoryRecursivelyImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - protected override Result DeleteFileImpl(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - protected override Result RenameDirectoryImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - protected override Result RenameFileImpl(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result CreateDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result DeleteDirectoryImpl(U8Span path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result DeleteFileImpl(U8Span path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path) { freeSpace = default; return ResultFs.UnsupportedOperationRomFsFileSystemGetSpace.Log(); } - protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path) { totalSpace = default; return ResultFs.UnsupportedOperationRomFsFileSystemGetSpace.Log(); diff --git a/src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs b/src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs index 236af46b..859182a8 100644 --- a/src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs +++ b/src/LibHac/FsSystem/Save/HierarchicalSaveFileTable.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Runtime.InteropServices; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsSystem.Save @@ -16,9 +17,9 @@ namespace LibHac.FsSystem.Save DirectoryTable = new SaveFsList>(dirTable); } - public bool TryOpenFile(string path, out SaveFileInfo fileInfo) + public bool TryOpenFile(U8Span path, out SaveFileInfo fileInfo) { - if (!FindPathRecursive(Util.GetUtf8Bytes(path), out SaveEntryKey key)) + if (!FindPathRecursive(path, out SaveEntryKey key)) { fileInfo = default; return false; @@ -89,24 +90,18 @@ namespace LibHac.FsSystem.Save return true; } - public void AddFile(string path, ref SaveFileInfo fileInfo) + public void AddFile(U8Span path, ref SaveFileInfo fileInfo) { - path = PathTools.Normalize(path); - ReadOnlySpan pathBytes = Util.GetUtf8Bytes(path); + if (path.Length == 1 && path[0] == '/') throw new ArgumentException("Path cannot be empty"); - if (path == "/") throw new ArgumentException("Path cannot be empty"); - - CreateFileRecursive(pathBytes, ref fileInfo); + CreateFileRecursive(path, ref fileInfo); } - public void AddDirectory(string path) + public void AddDirectory(U8Span path) { - path = PathTools.Normalize(path); - ReadOnlySpan pathBytes = Util.GetUtf8Bytes(path); + if (path.Length == 1 && path[0] == '/') throw new ArgumentException("Path cannot be empty"); - if (path == "/") throw new ArgumentException("Path cannot be empty"); - - CreateDirectoryRecursive(pathBytes); + CreateDirectoryRecursive(path); } private void CreateFileRecursive(ReadOnlySpan path, ref SaveFileInfo fileInfo) @@ -269,12 +264,9 @@ namespace LibHac.FsSystem.Save } } - public void DeleteFile(string path) + public void DeleteFile(U8Span path) { - path = PathTools.Normalize(path); - ReadOnlySpan pathBytes = Util.GetUtf8Bytes(path); - - FindPathRecursive(pathBytes, out SaveEntryKey key); + FindPathRecursive(path, out SaveEntryKey key); int parentIndex = key.Parent; int toDeleteIndex = FileTable.GetIndexFromKey(ref key).Index; @@ -285,12 +277,9 @@ namespace LibHac.FsSystem.Save FileTable.Remove(ref key); } - public void DeleteDirectory(string path) + public void DeleteDirectory(U8Span path) { - path = PathTools.Normalize(path); - ReadOnlySpan pathBytes = Util.GetUtf8Bytes(path); - - FindPathRecursive(pathBytes, out SaveEntryKey key); + FindPathRecursive(path, out SaveEntryKey key); int parentIndex = key.Parent; int toDeleteIndex = DirectoryTable.GetIndexFromKey(ref key).Index; @@ -308,24 +297,21 @@ namespace LibHac.FsSystem.Save DirectoryTable.Remove(ref key); } - public void RenameFile(string srcPath, string dstPath) + public void RenameFile(U8Span srcPath, U8Span dstPath) { - if (srcPath == dstPath || TryOpenFile(dstPath, out _) || TryOpenDirectory(dstPath, out _)) + if (srcPath.Value == dstPath.Value || TryOpenFile(dstPath, out _) || TryOpenDirectory(dstPath, out _)) { throw new IOException("Destination path already exists."); } - ReadOnlySpan oldPathBytes = Util.GetUtf8Bytes(srcPath); - ReadOnlySpan newPathBytes = Util.GetUtf8Bytes(dstPath); - - if (!FindPathRecursive(oldPathBytes, out SaveEntryKey oldKey)) + if (!FindPathRecursive(srcPath, out SaveEntryKey oldKey)) { throw new FileNotFoundException(); } int fileIndex = FileTable.GetIndexFromKey(ref oldKey).Index; - if (!FindPathRecursive(newPathBytes, out SaveEntryKey newKey)) + if (!FindPathRecursive(dstPath, out SaveEntryKey newKey)) { throw new FileNotFoundException(); } @@ -339,29 +325,26 @@ namespace LibHac.FsSystem.Save FileTable.ChangeKey(ref oldKey, ref newKey); } - public Result RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(U8Span srcPath, U8Span dstPath) { - if (srcPath == dstPath || TryOpenFile(dstPath, out _) || TryOpenDirectory(dstPath, out _)) + if (srcPath.Value == dstPath.Value || TryOpenFile(dstPath, out _) || TryOpenDirectory(dstPath, out _)) { return ResultFs.PathAlreadyExists.Log(); } - ReadOnlySpan oldPathBytes = Util.GetUtf8Bytes(srcPath); - ReadOnlySpan newPathBytes = Util.GetUtf8Bytes(dstPath); - - if (!FindPathRecursive(oldPathBytes, out SaveEntryKey oldKey)) + if (!FindPathRecursive(srcPath, out SaveEntryKey oldKey)) { return ResultFs.PathNotFound.Log(); } int dirIndex = DirectoryTable.GetIndexFromKey(ref oldKey).Index; - if (!FindPathRecursive(newPathBytes, out SaveEntryKey newKey)) + if (!FindPathRecursive(dstPath, out SaveEntryKey newKey)) { return ResultFs.PathNotFound.Log(); } - if (PathTools.IsSubPath(oldPathBytes, newPathBytes)) + if (PathTools.IsSubPath(srcPath, dstPath)) { return ResultFs.DestinationIsSubPathOfSource.Log(); } @@ -377,9 +360,9 @@ namespace LibHac.FsSystem.Save return Result.Success; } - public bool TryOpenDirectory(string path, out SaveFindPosition position) + public bool TryOpenDirectory(U8Span path, out SaveFindPosition position) { - if (!FindPathRecursive(Util.GetUtf8Bytes(path), out SaveEntryKey key)) + if (!FindPathRecursive(path, out SaveEntryKey key)) { position = default; return false; diff --git a/src/LibHac/FsSystem/Save/SaveDataFile.cs b/src/LibHac/FsSystem/Save/SaveDataFile.cs index 6310bff1..1718411f 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFile.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFile.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsSystem.Save @@ -7,16 +8,16 @@ namespace LibHac.FsSystem.Save public class SaveDataFile : FileBase { private AllocationTableStorage BaseStorage { get; } - private string Path { get; } + private U8String Path { get; } private HierarchicalSaveFileTable FileTable { get; } private long Size { get; set; } private OpenMode Mode { get; } - public SaveDataFile(AllocationTableStorage baseStorage, string path, HierarchicalSaveFileTable fileTable, long size, OpenMode mode) + public SaveDataFile(AllocationTableStorage baseStorage, U8Span path, HierarchicalSaveFileTable fileTable, long size, OpenMode mode) { Mode = mode; BaseStorage = baseStorage; - Path = path; + Path = path.ToU8String(); FileTable = fileTable; Size = size; } diff --git a/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs b/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs index ee35f1d2..f36cf6fd 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFileSystem.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.IO; +using LibHac.Common; using LibHac.Crypto; using LibHac.Fs; @@ -143,91 +144,91 @@ namespace LibHac.FsSystem.Save IntegrityStorageType.Save, integrityCheckLevel, LeaveOpen); } - protected override Result CreateDirectoryImpl(string path) + protected override Result CreateDirectoryImpl(U8Span path) { Result result = SaveDataFileSystemCore.CreateDirectory(path); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) { Result result = SaveDataFileSystemCore.CreateFile(path, size, options); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result DeleteDirectoryImpl(string path) + protected override Result DeleteDirectoryImpl(U8Span path) { Result result = SaveDataFileSystemCore.DeleteDirectory(path); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result DeleteDirectoryRecursivelyImpl(string path) + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) { Result result = SaveDataFileSystemCore.DeleteDirectoryRecursively(path); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result CleanDirectoryRecursivelyImpl(string path) + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) { Result result = SaveDataFileSystemCore.CleanDirectoryRecursively(path); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result DeleteFileImpl(string path) + protected override Result DeleteFileImpl(U8Span path) { Result result = SaveDataFileSystemCore.DeleteFile(path); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { Result result = SaveDataFileSystemCore.OpenDirectory(out directory, path, mode); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { Result result = SaveDataFileSystemCore.OpenFile(out file, path, mode); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result RenameDirectoryImpl(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) { Result result = SaveDataFileSystemCore.RenameDirectory(oldPath, newPath); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result RenameFileImpl(string oldPath, string newPath) + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) { Result result = SaveDataFileSystemCore.RenameFile(oldPath, newPath); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { Result result = SaveDataFileSystemCore.GetEntryType(out entryType, path); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path) { Result result = SaveDataFileSystemCore.GetFreeSpaceSize(out freeSpace, path); return SaveResults.ConvertToExternalResult(result).LogConverted(result); } - protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path) { Result result = SaveDataFileSystemCore.GetTotalSpaceSize(out totalSpace, path); diff --git a/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs b/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs index 5e61542f..a20b56b9 100644 --- a/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs +++ b/src/LibHac/FsSystem/Save/SaveDataFileSystemCore.cs @@ -1,4 +1,5 @@ using System.IO; +using LibHac.Common; using LibHac.Fs; namespace LibHac.FsSystem.Save @@ -27,23 +28,31 @@ namespace LibHac.FsSystem.Save FileTable = new HierarchicalSaveFileTable(dirTableStorage, fileTableStorage); } - protected override Result CreateDirectoryImpl(string path) + protected override Result CreateDirectoryImpl(U8Span path) { - path = PathTools.Normalize(path); + FsPath normalizedPath; + unsafe { _ = &normalizedPath; } // workaround for CS0165 - FileTable.AddDirectory(path); + Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false); + if (rc.IsFailure()) return rc; + + FileTable.AddDirectory(normalizedPath); return Result.Success; } - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) { - path = PathTools.Normalize(path); + FsPath normalizedPath; + unsafe { _ = &normalizedPath; } // workaround for CS0165 + + Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false); + if (rc.IsFailure()) return rc; if (size == 0) { var emptyFileEntry = new SaveFileInfo { StartBlock = int.MinValue, Length = size }; - FileTable.AddFile(path, ref emptyFileEntry); + FileTable.AddFile(normalizedPath, ref emptyFileEntry); return Result.Success; } @@ -58,46 +67,63 @@ namespace LibHac.FsSystem.Save var fileEntry = new SaveFileInfo { StartBlock = startBlock, Length = size }; - FileTable.AddFile(path, ref fileEntry); + FileTable.AddFile(normalizedPath, ref fileEntry); return Result.Success; } - protected override Result DeleteDirectoryImpl(string path) + protected override Result DeleteDirectoryImpl(U8Span path) { - path = PathTools.Normalize(path); + FsPath normalizedPath; + unsafe { _ = &normalizedPath; } // workaround for CS0165 - FileTable.DeleteDirectory(path); - - return Result.Success; - } - - protected override Result DeleteDirectoryRecursivelyImpl(string path) - { - path = PathTools.Normalize(path); - - Result rc = CleanDirectoryRecursively(path); + Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false); if (rc.IsFailure()) return rc; - DeleteDirectory(path); + FileTable.DeleteDirectory(normalizedPath); return Result.Success; } - protected override Result CleanDirectoryRecursivelyImpl(string path) + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) { - path = PathTools.Normalize(path); + FsPath normalizedPath; + unsafe { _ = &normalizedPath; } // workaround for CS0165 - FileSystemExtensions.CleanDirectoryRecursivelyGeneric(this, path); + Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false); + if (rc.IsFailure()) return rc; + + rc = CleanDirectoryRecursively(normalizedPath); + if (rc.IsFailure()) return rc; + + rc = DeleteDirectory(normalizedPath); + if (rc.IsFailure()) return rc; return Result.Success; } - protected override Result DeleteFileImpl(string path) + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) { - path = PathTools.Normalize(path); + FsPath normalizedPath; + unsafe { _ = &normalizedPath; } // workaround for CS0165 - if (!FileTable.TryOpenFile(path, out SaveFileInfo fileInfo)) + Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false); + if (rc.IsFailure()) return rc; + + FileSystemExtensions.CleanDirectoryRecursivelyGeneric(this, normalizedPath.ToString()); + + return Result.Success; + } + + protected override Result DeleteFileImpl(U8Span path) + { + FsPath normalizedPath; + unsafe { _ = &normalizedPath; } // workaround for CS0165 + + Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false); + if (rc.IsFailure()) return rc; + + if (!FileTable.TryOpenFile(normalizedPath, out SaveFileInfo fileInfo)) { return ResultFs.PathNotFound.Log(); } @@ -107,17 +133,22 @@ namespace LibHac.FsSystem.Save AllocationTable.Free(fileInfo.StartBlock); } - FileTable.DeleteFile(path); + FileTable.DeleteFile(normalizedPath); return Result.Success; } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { directory = default; - path = PathTools.Normalize(path); - if (!FileTable.TryOpenDirectory(path, out SaveFindPosition position)) + FsPath normalizedPath; + unsafe { _ = &normalizedPath; } // workaround for CS0165 + + Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false); + if (rc.IsFailure()) return rc; + + if (!FileTable.TryOpenDirectory(normalizedPath, out SaveFindPosition position)) { return ResultFs.PathNotFound.Log(); } @@ -127,52 +158,79 @@ namespace LibHac.FsSystem.Save return Result.Success; } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; - path = PathTools.Normalize(path); - if (!FileTable.TryOpenFile(path, out SaveFileInfo fileInfo)) + FsPath normalizedPath; + unsafe { _ = &normalizedPath; } // workaround for CS0165 + + Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false); + if (rc.IsFailure()) return rc; + + if (!FileTable.TryOpenFile(normalizedPath, out SaveFileInfo fileInfo)) { return ResultFs.PathNotFound.Log(); } AllocationTableStorage storage = OpenFatStorage(fileInfo.StartBlock); - file = new SaveDataFile(storage, path, FileTable, fileInfo.Length, mode); + file = new SaveDataFile(storage, normalizedPath, FileTable, fileInfo.Length, mode); return Result.Success; } - protected override Result RenameDirectoryImpl(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) { - oldPath = PathTools.Normalize(oldPath); - newPath = PathTools.Normalize(newPath); + FsPath normalizedCurrentPath; + FsPath normalizedNewPath; + unsafe { _ = &normalizedCurrentPath; } // workaround for CS0165 + unsafe { _ = &normalizedNewPath; } // workaround for CS0165 - return FileTable.RenameDirectory(oldPath, newPath); + Result rc = PathTool.Normalize(normalizedCurrentPath.Str, out _, oldPath, false, false); + if (rc.IsFailure()) return rc; + + rc = PathTool.Normalize(normalizedNewPath.Str, out _, newPath, false, false); + if (rc.IsFailure()) return rc; + + return FileTable.RenameDirectory(normalizedCurrentPath, normalizedNewPath); } - protected override Result RenameFileImpl(string oldPath, string newPath) + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) { - oldPath = PathTools.Normalize(oldPath); - newPath = PathTools.Normalize(newPath); + FsPath normalizedCurrentPath; + FsPath normalizedNewPath; + unsafe { _ = &normalizedCurrentPath; } // workaround for CS0165 + unsafe { _ = &normalizedNewPath; } // workaround for CS0165 - FileTable.RenameFile(oldPath, newPath); + Result rc = PathTool.Normalize(normalizedCurrentPath.Str, out _, oldPath, false, false); + if (rc.IsFailure()) return rc; + + rc = PathTool.Normalize(normalizedNewPath.Str, out _, newPath, false, false); + if (rc.IsFailure()) return rc; + + FileTable.RenameFile(normalizedCurrentPath, normalizedNewPath); return Result.Success; } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { - path = PathTools.Normalize(path); + entryType = default; - if (FileTable.TryOpenFile(path, out SaveFileInfo _)) + FsPath normalizedPath; + unsafe { _ = &normalizedPath; } // workaround for CS0165 + + Result rc = PathTool.Normalize(normalizedPath.Str, out _, path, false, false); + if (rc.IsFailure()) return rc; + + if (FileTable.TryOpenFile(normalizedPath, out SaveFileInfo _)) { entryType = DirectoryEntryType.File; return Result.Success; } - if (FileTable.TryOpenDirectory(path, out SaveFindPosition _)) + if (FileTable.TryOpenDirectory(normalizedPath, out SaveFindPosition _)) { entryType = DirectoryEntryType.Directory; return Result.Success; @@ -182,7 +240,7 @@ namespace LibHac.FsSystem.Save return ResultFs.PathNotFound.Log(); } - protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path) { int freeBlockCount = AllocationTable.GetFreeListLength(); freeSpace = Header.BlockSize * freeBlockCount; @@ -190,7 +248,7 @@ namespace LibHac.FsSystem.Save return Result.Success; } - protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path) { totalSpace = Header.BlockSize * Header.BlockCount; @@ -211,7 +269,7 @@ namespace LibHac.FsSystem.Save foreach (DirectoryEntryEx file in this.EnumerateEntries("*", SearchOptions.RecurseSubdirectories)) { - if (FileTable.TryOpenFile(file.FullPath, out SaveFileInfo fileInfo) && fileInfo.StartBlock >= 0) + if (FileTable.TryOpenFile(file.FullPath.ToU8Span(), out SaveFileInfo fileInfo) && fileInfo.StartBlock >= 0) { AllocationTable.FsTrimList(fileInfo.StartBlock); diff --git a/src/LibHac/FsSystem/SubdirectoryFileSystem.cs b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs index b8ac9a27..f32c92e2 100644 --- a/src/LibHac/FsSystem/SubdirectoryFileSystem.cs +++ b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs @@ -72,140 +72,121 @@ namespace LibHac.FsSystem return PathTool.Normalize(outPath.Slice(RootPath.Length - 2), out _, relativePath, PreserveUnc, false); } - protected override Result CreateDirectoryImpl(string path) + protected override Result CreateDirectoryImpl(U8Span path) { - var u8Path = new U8String(path); - Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.CreateDirectory(StringUtils.Utf8ZToString(fullPath)); + return BaseFileSystem.CreateDirectory(new U8Span(fullPath)); } - protected override Result CreateFileImpl(string path, long size, CreateFileOptions options) + protected override Result CreateFileImpl(U8Span path, long size, CreateFileOptions options) { - var u8Path = new U8String(path); - Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.CreateFile(StringUtils.Utf8ZToString(fullPath), size, options); + return BaseFileSystem.CreateFile(new U8Span(fullPath), size, options); } - protected override Result DeleteDirectoryImpl(string path) + protected override Result DeleteDirectoryImpl(U8Span path) { - var u8Path = new U8String(path); - Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.DeleteDirectory(StringUtils.Utf8ZToString(fullPath)); + return BaseFileSystem.DeleteDirectory(new U8Span(fullPath)); } - protected override Result DeleteDirectoryRecursivelyImpl(string path) + protected override Result DeleteDirectoryRecursivelyImpl(U8Span path) { - var u8Path = new U8String(path); - Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.DeleteDirectoryRecursively(StringUtils.Utf8ZToString(fullPath)); + return BaseFileSystem.DeleteDirectoryRecursively(new U8Span(fullPath)); } - protected override Result CleanDirectoryRecursivelyImpl(string path) + protected override Result CleanDirectoryRecursivelyImpl(U8Span path) { - var u8Path = new U8String(path); - Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.CleanDirectoryRecursively(StringUtils.Utf8ZToString(fullPath)); + return BaseFileSystem.CleanDirectoryRecursively(new U8Span(fullPath)); } - protected override Result DeleteFileImpl(string path) + protected override Result DeleteFileImpl(U8Span path) { - var u8Path = new U8String(path); - Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.DeleteFile(StringUtils.Utf8ZToString(fullPath)); + return BaseFileSystem.DeleteFile(new U8Span(fullPath)); } - protected override Result OpenDirectoryImpl(out IDirectory directory, string path, OpenDirectoryMode mode) + protected override Result OpenDirectoryImpl(out IDirectory directory, U8Span path, OpenDirectoryMode mode) { directory = default; - var u8Path = new U8String(path); Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.OpenDirectory(out directory, StringUtils.Utf8ZToString(fullPath), mode); + return BaseFileSystem.OpenDirectory(out directory, new U8Span(fullPath), mode); } - protected override Result OpenFileImpl(out IFile file, string path, OpenMode mode) + protected override Result OpenFileImpl(out IFile file, U8Span path, OpenMode mode) { file = default; - var u8Path = new U8String(path); Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.OpenFile(out file, StringUtils.Utf8ZToString(fullPath), mode); + return BaseFileSystem.OpenFile(out file, new U8Span(fullPath), mode); } - protected override Result RenameDirectoryImpl(string oldPath, string newPath) + protected override Result RenameDirectoryImpl(U8Span oldPath, U8Span newPath) { - var u8OldPath = new U8String(oldPath); - var u8NewPath = new U8String(newPath); - Span fullOldPath = stackalloc byte[PathTools.MaxPathLength + 1]; Span fullNewPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullOldPath, u8OldPath); + Result rc = ResolveFullPath(fullOldPath, oldPath); if (rc.IsFailure()) return rc; - rc = ResolveFullPath(fullNewPath, u8NewPath); + rc = ResolveFullPath(fullNewPath, newPath); if (rc.IsFailure()) return rc; - return BaseFileSystem.RenameDirectory(StringUtils.Utf8ZToString(fullOldPath), StringUtils.Utf8ZToString(fullNewPath)); + return BaseFileSystem.RenameDirectory(new U8Span(fullOldPath), new U8Span(fullNewPath)); } - protected override Result RenameFileImpl(string oldPath, string newPath) + protected override Result RenameFileImpl(U8Span oldPath, U8Span newPath) { - var u8OldPath = new U8String(oldPath); - var u8NewPath = new U8String(newPath); - Span fullOldPath = stackalloc byte[PathTools.MaxPathLength + 1]; Span fullNewPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullOldPath, u8OldPath); + Result rc = ResolveFullPath(fullOldPath, oldPath); if (rc.IsFailure()) return rc; - rc = ResolveFullPath(fullNewPath, u8NewPath); + rc = ResolveFullPath(fullNewPath, newPath); if (rc.IsFailure()) return rc; - return BaseFileSystem.RenameFile(StringUtils.Utf8ZToString(fullOldPath), StringUtils.Utf8ZToString(fullNewPath)); + return BaseFileSystem.RenameFile(new U8Span(fullOldPath), new U8Span(fullNewPath)); } - protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, string path) + protected override Result GetEntryTypeImpl(out DirectoryEntryType entryType, U8Span path) { entryType = default; - var u8Path = new U8String(path); - Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + FsPath fullPath; + unsafe { _ = &fullPath; } // workaround for CS0165 + + Result rc = ResolveFullPath(fullPath.Str, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.GetEntryType(out entryType, StringUtils.Utf8ZToString(fullPath)); + return BaseFileSystem.GetEntryType(out entryType, fullPath); } protected override Result CommitImpl() @@ -213,51 +194,47 @@ namespace LibHac.FsSystem return BaseFileSystem.Commit(); } - protected override Result GetFreeSpaceSizeImpl(out long freeSpace, string path) + protected override Result GetFreeSpaceSizeImpl(out long freeSpace, U8Span path) { freeSpace = default; - var u8Path = new U8String(path); Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.GetFreeSpaceSize(out freeSpace, StringUtils.Utf8ZToString(fullPath)); + return BaseFileSystem.GetFreeSpaceSize(out freeSpace, new U8Span(fullPath)); } - protected override Result GetTotalSpaceSizeImpl(out long totalSpace, string path) + protected override Result GetTotalSpaceSizeImpl(out long totalSpace, U8Span path) { totalSpace = default; - var u8Path = new U8String(path); Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.GetTotalSpaceSize(out totalSpace, StringUtils.Utf8ZToString(fullPath)); + return BaseFileSystem.GetTotalSpaceSize(out totalSpace, new U8Span(fullPath)); } - protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, string path) + protected override Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path) { timeStamp = default; - var u8Path = new U8String(path); Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, StringUtils.Utf8ZToString(fullPath)); + return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, new U8Span(fullPath)); } - protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + protected override Result QueryEntryImpl(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, + U8Span path) { - var u8Path = new U8String(path); - Span fullPath = stackalloc byte[PathTools.MaxPathLength + 1]; - Result rc = ResolveFullPath(fullPath, u8Path); + Result rc = ResolveFullPath(fullPath, path); if (rc.IsFailure()) return rc; - return BaseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, StringUtils.Utf8ZToString(fullPath)); + return BaseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, new U8Span(fullPath)); } } } diff --git a/src/LibHac/Kvdb/KeyValueDatabase.cs b/src/LibHac/Kvdb/KeyValueDatabase.cs index cfa79254..1ea5680d 100644 --- a/src/LibHac/Kvdb/KeyValueDatabase.cs +++ b/src/LibHac/Kvdb/KeyValueDatabase.cs @@ -13,16 +13,16 @@ namespace LibHac.Kvdb private Dictionary KvDict { get; } = new Dictionary(); private FileSystemClient FsClient { get; } - private string FileName { get; } + private U8String FileName { get; } public int Count => KvDict.Count; public KeyValueDatabase() { } - public KeyValueDatabase(FileSystemClient fsClient, string fileName) + public KeyValueDatabase(FileSystemClient fsClient, U8Span fileName) { FsClient = fsClient; - FileName = fileName; + FileName = fileName.ToU8String(); } public Result Get(ref TKey key, Span valueBuffer) @@ -109,7 +109,7 @@ namespace LibHac.Kvdb public Result ReadDatabaseFromFile() { - if (FsClient == null || FileName == null) + if (FsClient == null || FileName.IsNull()) return ResultFs.PreconditionViolation.Log(); Result rc = ReadFile(out byte[] data); @@ -124,7 +124,7 @@ namespace LibHac.Kvdb public Result WriteDatabaseToFile() { - if (FsClient == null || FileName == null) + if (FsClient == null || FileName.IsNull()) return ResultFs.PreconditionViolation.Log(); var buffer = new byte[GetExportedSize()]; @@ -157,7 +157,7 @@ namespace LibHac.Kvdb private Result ReadFile(out byte[] data) { Debug.Assert(FsClient != null); - Debug.Assert(!string.IsNullOrWhiteSpace(FileName)); + Debug.Assert(!FileName.IsEmpty()); data = default; @@ -180,7 +180,7 @@ namespace LibHac.Kvdb private Result WriteFile(ReadOnlySpan data) { Debug.Assert(FsClient != null); - Debug.Assert(!string.IsNullOrWhiteSpace(FileName)); + Debug.Assert(!FileName.IsEmpty()); FsClient.DeleteFile(FileName); diff --git a/src/LibHac/SwitchFs.cs b/src/LibHac/SwitchFs.cs index 9dbc8b74..1d1af95c 100644 --- a/src/LibHac/SwitchFs.cs +++ b/src/LibHac/SwitchFs.cs @@ -84,7 +84,7 @@ namespace LibHac SwitchFsNca nca = null; try { - ContentFs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure(); + ContentFs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); nca = new SwitchFsNca(new Nca(Keyset, ncaFile.AsStorage())); @@ -122,7 +122,7 @@ namespace LibHac try { - SaveFs.OpenFile(out IFile file, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure(); + SaveFs.OpenFile(out IFile file, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); save = new SaveDataFileSystem(Keyset, file.AsStorage(), IntegrityCheckLevel.None, true); } @@ -149,7 +149,7 @@ namespace LibHac IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; - fs.OpenFile(out IFile file, cnmtPath, OpenMode.Read).ThrowIfFailure(); + fs.OpenFile(out IFile file, cnmtPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); var metadata = new Cnmt(file.AsStream()); title.Id = metadata.TitleId; @@ -193,7 +193,7 @@ namespace LibHac foreach (Title title in Titles.Values.Where(x => x.ControlNca != null)) { IFileSystem romfs = title.ControlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - romfs.OpenFile(out IFile control, "control.nacp", OpenMode.Read).ThrowIfFailure(); + romfs.OpenFile(out IFile control, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); title.Control = new Nacp(control.AsStream()); diff --git a/src/LibHac/Xci.cs b/src/LibHac/Xci.cs index b8250571..e2bb6fb9 100644 --- a/src/LibHac/Xci.cs +++ b/src/LibHac/Xci.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using LibHac.FsSystem; namespace LibHac @@ -29,7 +30,7 @@ namespace LibHac XciPartition root = GetRootPartition(); if (type == XciPartitionType.Root) return root; - root.OpenFile(out IFile partitionFile, type.GetFileName(), OpenMode.Read).ThrowIfFailure(); + root.OpenFile(out IFile partitionFile, type.GetFileName().ToU8Span(), OpenMode.Read).ThrowIfFailure(); return new XciPartition(partitionFile.AsStorage()); } diff --git a/src/hactoolnet/FsUtils.cs b/src/hactoolnet/FsUtils.cs index e7d06748..8dfff38e 100644 --- a/src/hactoolnet/FsUtils.cs +++ b/src/hactoolnet/FsUtils.cs @@ -1,6 +1,7 @@ using System; using System.Buffers; using LibHac; +using LibHac.Common; using LibHac.Fs; using LibHac.FsSystem; @@ -8,14 +9,14 @@ namespace hactoolnet { public static class FsUtils { - public static void CopyDirectoryWithProgress(FileSystemClient fs, string sourcePath, string destPath, + public static Result CopyDirectoryWithProgress(FileSystemClient fs, U8Span sourcePath, U8Span destPath, CreateFileOptions options = CreateFileOptions.None, IProgressReport logger = null) { try { logger?.SetTotal(GetTotalSize(fs, sourcePath)); - CopyDirectoryWithProgressInternal(fs, sourcePath, destPath, options, logger); + return CopyDirectoryWithProgressInternal(fs, sourcePath, destPath, options, logger); } finally { @@ -23,41 +24,51 @@ namespace hactoolnet } } - private static void CopyDirectoryWithProgressInternal(FileSystemClient fs, string sourcePath, string destPath, + private static Result CopyDirectoryWithProgressInternal(FileSystemClient fs, U8Span sourcePath, U8Span destPath, CreateFileOptions options, IProgressReport logger) { - fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All).ThrowIfFailure(); + string sourcePathStr = sourcePath.ToString(); + string destPathStr = destPath.ToString(); + + Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; using (sourceHandle) { - foreach (DirectoryEntryEx entry in fs.EnumerateEntries(sourcePath, "*", SearchOptions.Default)) + foreach (DirectoryEntryEx entry in fs.EnumerateEntries(sourcePathStr, "*", SearchOptions.Default)) { - string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); - string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); + string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePathStr, entry.Name)); + string subDstPath = PathTools.Normalize(PathTools.Combine(destPathStr, entry.Name)); if (entry.Type == DirectoryEntryType.Directory) { fs.EnsureDirectoryExists(subDstPath); - CopyDirectoryWithProgressInternal(fs, subSrcPath, subDstPath, options, logger); + rc = CopyDirectoryWithProgressInternal(fs, subSrcPath.ToU8Span(), subDstPath.ToU8Span(), options, logger); + if (rc.IsFailure()) return rc; } if (entry.Type == DirectoryEntryType.File) { logger?.LogMessage(subSrcPath); - fs.CreateOrOverwriteFile(subDstPath, entry.Size, options); - CopyFileWithProgress(fs, subSrcPath, subDstPath, logger); + rc = fs.CreateOrOverwriteFile(subDstPath, entry.Size, options); + if (rc.IsFailure()) return rc; + + rc = CopyFileWithProgress(fs, subSrcPath.ToU8Span(), subDstPath.ToU8Span(), logger); + if (rc.IsFailure()) return rc; } } } + + return Result.Success; } - public static long GetTotalSize(FileSystemClient fs, string path, string searchPattern = "*") + public static long GetTotalSize(FileSystemClient fs, U8Span path, string searchPattern = "*") { long size = 0; - foreach (DirectoryEntryEx entry in fs.EnumerateEntries(path, searchPattern)) + foreach (DirectoryEntryEx entry in fs.EnumerateEntries(path.ToString(), searchPattern)) { size += entry.Size; } @@ -65,7 +76,7 @@ namespace hactoolnet return size; } - public static Result CopyFileWithProgress(FileSystemClient fs, string sourcePath, string destPath, IProgressReport logger = null) + public static Result CopyFileWithProgress(FileSystemClient fs, U8Span sourcePath, U8Span destPath, IProgressReport logger = null) { Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read); if (rc.IsFailure()) return rc; diff --git a/src/hactoolnet/ProcessDelta.cs b/src/hactoolnet/ProcessDelta.cs index 3f80126b..9c9d03b1 100644 --- a/src/hactoolnet/ProcessDelta.cs +++ b/src/hactoolnet/ProcessDelta.cs @@ -2,6 +2,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Text; +using LibHac.Common; using LibHac.Fs; using LibHac.FsSystem; using LibHac.FsSystem.NcaUtils; @@ -34,7 +35,7 @@ namespace hactoolnet throw new FileNotFoundException("Specified NCA does not contain a delta fragment"); } - fs.OpenFile(out IFile deltaFragmentFile, FragmentFileName, OpenMode.Read).ThrowIfFailure(); + fs.OpenFile(out IFile deltaFragmentFile, FragmentFileName.ToU8String(), OpenMode.Read).ThrowIfFailure(); deltaStorage = deltaFragmentFile.AsStorage(); } diff --git a/src/hactoolnet/ProcessNax0.cs b/src/hactoolnet/ProcessNax0.cs index 61cd737c..3d429b41 100644 --- a/src/hactoolnet/ProcessNax0.cs +++ b/src/hactoolnet/ProcessNax0.cs @@ -27,7 +27,7 @@ namespace hactoolnet try { - xtsFile = new AesXtsFile(OpenMode.Read, baseFile, ctx.Options.SdPath, kekSource, validationKey, 0x4000); + xtsFile = new AesXtsFile(OpenMode.Read, baseFile, ctx.Options.SdPath.ToU8String(), kekSource, validationKey, 0x4000); contentType = i; break; diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index 169d19d4..47697630 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -51,10 +51,10 @@ namespace hactoolnet fs.Register(mountName.ToU8Span(), OpenFileSystem(i)); fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.SectionOutDir[i])); - FsUtils.CopyDirectoryWithProgress(fs, mountName + ":/", "output:/", logger: ctx.Logger); + FsUtils.CopyDirectoryWithProgress(fs, (mountName + ":/").ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure(); - fs.Unmount(mountName); - fs.Unmount("output"); + fs.Unmount(mountName.ToU8Span()); + fs.Unmount("output".ToU8Span()); } if (ctx.Options.Validate && nca.SectionExists(i)) @@ -100,10 +100,10 @@ namespace hactoolnet fs.Register("rom".ToU8Span(), OpenFileSystemByType(NcaSectionType.Data)); fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.RomfsOutDir)); - FsUtils.CopyDirectoryWithProgress(fs, "rom:/", "output:/", logger: ctx.Logger); + FsUtils.CopyDirectoryWithProgress(fs, "rom:/".ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure(); - fs.Unmount("rom"); - fs.Unmount("output"); + fs.Unmount("rom".ToU8Span()); + fs.Unmount("output".ToU8Span()); } if (ctx.Options.ReadBench) @@ -157,10 +157,10 @@ namespace hactoolnet fs.Register("code".ToU8Span(), OpenFileSystemByType(NcaSectionType.Code)); fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.ExefsOutDir)); - FsUtils.CopyDirectoryWithProgress(fs, "code:/", "output:/", logger: ctx.Logger); + FsUtils.CopyDirectoryWithProgress(fs, "code:/".ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure(); - fs.Unmount("code"); - fs.Unmount("output"); + fs.Unmount("code".ToU8Span()); + fs.Unmount("output".ToU8Span()); } } @@ -211,7 +211,7 @@ namespace hactoolnet IFileSystem pfs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid); if (!pfs.FileExists("main.npdm")) return Validity.Unchecked; - pfs.OpenFile(out IFile npdmFile, "main.npdm", OpenMode.Read).ThrowIfFailure(); + pfs.OpenFile(out IFile npdmFile, "main.npdm".ToU8String(), OpenMode.Read).ThrowIfFailure(); var npdm = new NpdmBinary(npdmFile.AsStream()); return nca.Header.VerifySignature2(npdm.AciD.Rsa2048Modulus); @@ -234,7 +234,7 @@ namespace hactoolnet PrintItem(sb, colLen, "TitleID:", $"{nca.Header.TitleId:X16}"); if (nca.CanOpenSection(NcaSectionType.Code)) { IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.None); - Result r = fs.OpenFile(out IFile file, "/main.npdm", OpenMode.Read); + Result r = fs.OpenFile(out IFile file, "/main.npdm".ToU8String(), OpenMode.Read); if (r.IsSuccess()) { var npdm = new NpdmBinary(file.AsStream(), null); PrintItem(sb, colLen, "Title Name:", npdm.TitleName); diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index 93f02784..170b0b55 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -42,9 +42,9 @@ namespace hactoolnet { fs.Register("output".ToU8Span(), new LocalFileSystem(ctx.Options.OutDir)); - FsUtils.CopyDirectoryWithProgress(fs, "save:/", "output:/", logger: ctx.Logger); + FsUtils.CopyDirectoryWithProgress(fs, "save:/".ToU8Span(), "output:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure(); - fs.Unmount("output"); + fs.Unmount("output".ToU8Span()); } if (ctx.Options.DebugOutDir != null) @@ -63,7 +63,7 @@ namespace hactoolnet using (IFile inFile = new LocalFile(ctx.Options.ReplaceFileSource, OpenMode.Read)) { - save.OpenFile(out IFile outFile, destFilename, OpenMode.ReadWrite).ThrowIfFailure(); + save.OpenFile(out IFile outFile, destFilename.ToU8String(), OpenMode.ReadWrite).ThrowIfFailure(); using (outFile) { @@ -88,13 +88,13 @@ namespace hactoolnet { fs.Register("input".ToU8Span(), new LocalFileSystem(ctx.Options.RepackSource)); - fs.CleanDirectoryRecursively("save:/"); - fs.Commit("save"); + fs.CleanDirectoryRecursively("save:/".ToU8Span()); + fs.Commit("save".ToU8Span()); - FsUtils.CopyDirectoryWithProgress(fs, "input:/", "save:/", logger: ctx.Logger); + FsUtils.CopyDirectoryWithProgress(fs, "input:/".ToU8Span(), "save:/".ToU8Span(), logger: ctx.Logger).ThrowIfFailure(); - fs.Commit("save"); - fs.Unmount("input"); + fs.Commit("save".ToU8Span()); + fs.Unmount("input".ToU8Span()); signNeeded = true; } @@ -134,7 +134,7 @@ namespace hactoolnet ctx.Logger.LogMessage("Unable to sign save file. Do you have all the required keys?"); } - fs.Unmount("save"); + fs.Unmount("save".ToU8Span()); return; } @@ -149,7 +149,7 @@ namespace hactoolnet ctx.Logger.LogMessage(save.Print(ctx.Keyset)); //ctx.Logger.LogMessage(PrintFatLayout(save.SaveDataFileSystemCore)); - fs.Unmount("save"); + fs.Unmount("save".ToU8Span()); } } @@ -239,7 +239,7 @@ namespace hactoolnet foreach (DirectoryEntryEx entry in save.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File)) { - save.FileTable.TryOpenFile(entry.FullPath, out SaveFileInfo fileInfo); + save.FileTable.TryOpenFile(entry.FullPath.ToU8Span(), out SaveFileInfo fileInfo); if (fileInfo.StartBlock < 0) continue; IEnumerable<(int block, int length)> chain = save.AllocationTable.DumpChain(fileInfo.StartBlock); @@ -321,7 +321,7 @@ namespace hactoolnet var sb = new StringBuilder(); sb.AppendLine(); - save.GetFreeSpaceSize(out long freeSpace, "").ThrowIfFailure(); + save.GetFreeSpaceSize(out long freeSpace, "".ToU8String()).ThrowIfFailure(); sb.AppendLine("Savefile:"); PrintItem(sb, colLen, "CMAC Key Used:", keyset.SaveMacKey); diff --git a/tests/LibHac.Tests/Fs/FileSystemClientTests/ShimTests/SaveData.cs b/tests/LibHac.Tests/Fs/FileSystemClientTests/ShimTests/SaveData.cs index 61c5fd5a..3f4fbeda 100644 --- a/tests/LibHac.Tests/Fs/FileSystemClientTests/ShimTests/SaveData.cs +++ b/tests/LibHac.Tests/Fs/FileSystemClientTests/ShimTests/SaveData.cs @@ -16,7 +16,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests fs.CreateCacheStorage(applicationId, SaveDataSpaceId.User, applicationId, 0, 0, SaveDataFlags.None); - Assert.Success(fs.MountCacheStorage("cache".ToU8String(), applicationId)); + Assert.Success(fs.MountCacheStorage("cache".ToU8Span(), applicationId)); } [Fact] @@ -26,14 +26,14 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests FileSystemClient fs = FileSystemServerFactory.CreateClient(true); fs.CreateCacheStorage(applicationId, SaveDataSpaceId.SdCache, applicationId, 0, 0, SaveDataFlags.None); - fs.MountCacheStorage("cache".ToU8String(), applicationId); + fs.MountCacheStorage("cache".ToU8Span(), applicationId); - fs.CreateFile("cache:/file", 0); - fs.Commit("cache"); - fs.Unmount("cache"); + fs.CreateFile("cache:/file".ToU8Span(), 0); + fs.Commit("cache".ToU8Span()); + fs.Unmount("cache".ToU8Span()); - Assert.Success(fs.MountCacheStorage("cache".ToU8String(), applicationId)); - Assert.Success(fs.GetEntryType(out DirectoryEntryType type, "cache:/file")); + Assert.Success(fs.MountCacheStorage("cache".ToU8Span(), applicationId)); + Assert.Success(fs.GetEntryType(out DirectoryEntryType type, "cache:/file".ToU8Span())); Assert.Equal(DirectoryEntryType.File, type); } [Fact] @@ -43,25 +43,25 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests FileSystemClient fs = FileSystemServerFactory.CreateClient(true); fs.CreateCacheStorage(applicationId, SaveDataSpaceId.SdCache, applicationId, 0, 0, SaveDataFlags.None); - fs.MountCacheStorage("cache".ToU8String(), applicationId); - fs.CreateFile("cache:/sd", 0); - fs.Commit("cache"); - fs.Unmount("cache"); + fs.MountCacheStorage("cache".ToU8Span(), applicationId); + fs.CreateFile("cache:/sd".ToU8Span(), 0); + fs.Commit("cache".ToU8Span()); + fs.Unmount("cache".ToU8Span()); // Turn off the SD card so the User save is mounted fs.SetSdCardAccessibility(false); fs.CreateCacheStorage(applicationId, SaveDataSpaceId.User, applicationId, 0, 0, SaveDataFlags.None); - fs.MountCacheStorage("cache".ToU8String(), applicationId); - fs.CreateFile("cache:/bis", 0); - fs.Commit("cache"); - fs.Unmount("cache"); + fs.MountCacheStorage("cache".ToU8Span(), applicationId); + fs.CreateFile("cache:/bis".ToU8Span(), 0); + fs.Commit("cache".ToU8Span()); + fs.Unmount("cache".ToU8Span()); fs.SetSdCardAccessibility(true); Assert.Success(fs.MountCacheStorage("cache".ToU8String(), applicationId)); - Assert.Success(fs.GetEntryType(out _, "cache:/sd")); - Assert.Failure(fs.GetEntryType(out _, "cache:/bis")); + Assert.Success(fs.GetEntryType(out _, "cache:/sd".ToU8Span())); + Assert.Failure(fs.GetEntryType(out _, "cache:/bis".ToU8Span())); } } } diff --git a/tests/LibHac.Tests/Fs/FileSystemClientTests/ShimTests/SdCard.cs b/tests/LibHac.Tests/Fs/FileSystemClientTests/ShimTests/SdCard.cs index 86000580..f4742175 100644 --- a/tests/LibHac.Tests/Fs/FileSystemClientTests/ShimTests/SdCard.cs +++ b/tests/LibHac.Tests/Fs/FileSystemClientTests/ShimTests/SdCard.cs @@ -12,7 +12,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests { FileSystemClient fs = FileSystemServerFactory.CreateClient(true); - Assert.Success(fs.MountSdCard("sdcard".ToU8String())); + Assert.Success(fs.MountSdCard("sdcard".ToU8Span())); } [Fact] @@ -20,7 +20,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests { FileSystemClient fs = FileSystemServerFactory.CreateClient(false); - Assert.Result(ResultFs.SdCardNotFound, fs.MountSdCard("sdcard".ToU8String())); + Assert.Result(ResultFs.SdCardNotFound, fs.MountSdCard("sdcard".ToU8Span())); } [Fact] @@ -30,7 +30,7 @@ namespace LibHac.Tests.Fs.FileSystemClientTests.ShimTests fs.MountSdCard("sdcard".ToU8String()); - Assert.Success(fs.CreateFile("sdcard:/file", 100, CreateFileOptions.None)); + Assert.Success(fs.CreateFile("sdcard:/file".ToU8Span(), 100, CreateFileOptions.None)); } [Fact] diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IAttributeFileSystemTests.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IAttributeFileSystemTests.cs index 2dcef3c2..59b35933 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IAttributeFileSystemTests.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IAttributeFileSystemTests.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -12,9 +13,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IAttributeFileSystem fs = CreateAttributeFileSystem(); - Assert.True(fs.CreateDirectory("/dir", NxFileAttributes.None).IsSuccess()); + Assert.True(fs.CreateDirectory("/dir".ToU8Span(), NxFileAttributes.None).IsSuccess()); - Assert.True(fs.GetFileAttributes(out NxFileAttributes attributes, "/dir").IsSuccess()); + Assert.True(fs.GetFileAttributes(out NxFileAttributes attributes, "/dir".ToU8Span()).IsSuccess()); Assert.Equal(NxFileAttributes.Directory, attributes); } @@ -23,9 +24,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IAttributeFileSystem fs = CreateAttributeFileSystem(); - Assert.True(fs.CreateDirectory("/dir", NxFileAttributes.Archive).IsSuccess()); + Assert.True(fs.CreateDirectory("/dir".ToU8Span(), NxFileAttributes.Archive).IsSuccess()); - Assert.True(fs.GetFileAttributes(out NxFileAttributes attributes, "/dir").IsSuccess()); + Assert.True(fs.GetFileAttributes(out NxFileAttributes attributes, "/dir".ToU8Span()).IsSuccess()); Assert.Equal(NxFileAttributes.Directory | NxFileAttributes.Archive, attributes); } @@ -33,9 +34,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase public void GetFileAttributes_AttributesOnNewFileAreEmpty() { IAttributeFileSystem fs = CreateAttributeFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); - Result rc = fs.GetFileAttributes(out NxFileAttributes attributes, "/file"); + Result rc = fs.GetFileAttributes(out NxFileAttributes attributes, "/file".ToU8Span()); Assert.True(rc.IsSuccess()); Assert.Equal(NxFileAttributes.None, attributes); @@ -45,9 +46,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase public void GetFileAttributes_AttributesOnNewDirHaveOnlyDirFlagSet() { IAttributeFileSystem fs = CreateAttributeFileSystem(); - fs.CreateDirectory("/dir"); + fs.CreateDirectory("/dir".ToU8Span()); - Result rc = fs.GetFileAttributes(out NxFileAttributes attributes, "/dir"); + Result rc = fs.GetFileAttributes(out NxFileAttributes attributes, "/dir".ToU8Span()); Assert.True(rc.IsSuccess()); Assert.Equal(NxFileAttributes.Directory, attributes); @@ -58,7 +59,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IAttributeFileSystem fs = CreateAttributeFileSystem(); - Result rc = fs.GetFileAttributes(out _, "/path"); + Result rc = fs.GetFileAttributes(out _, "/path".ToU8Span()); Assert.Equal(ResultFs.PathNotFound.Value, rc); } @@ -68,7 +69,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IAttributeFileSystem fs = CreateAttributeFileSystem(); - Result rc = fs.SetFileAttributes("/path", NxFileAttributes.None); + Result rc = fs.SetFileAttributes("/path".ToU8Span(), NxFileAttributes.None); Assert.Equal(ResultFs.PathNotFound.Value, rc); } @@ -77,10 +78,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase public void SetFileAttributes_SetAttributeOnFile() { IAttributeFileSystem fs = CreateAttributeFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); - Result rcSet = fs.SetFileAttributes("/file", NxFileAttributes.Archive); - Result rcGet = fs.GetFileAttributes(out NxFileAttributes attributes, "/file"); + Result rcSet = fs.SetFileAttributes("/file".ToU8Span(), NxFileAttributes.Archive); + Result rcGet = fs.GetFileAttributes(out NxFileAttributes attributes, "/file".ToU8Span()); Assert.True(rcSet.IsSuccess()); Assert.True(rcGet.IsSuccess()); @@ -91,10 +92,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase public void SetFileAttributes_SetAttributeOnDirectory() { IAttributeFileSystem fs = CreateAttributeFileSystem(); - fs.CreateDirectory("/dir"); + fs.CreateDirectory("/dir".ToU8Span()); - Result rcSet = fs.SetFileAttributes("/dir", NxFileAttributes.Archive); - Result rcGet = fs.GetFileAttributes(out NxFileAttributes attributes, "/dir"); + Result rcSet = fs.SetFileAttributes("/dir".ToU8Span(), NxFileAttributes.Archive); + Result rcGet = fs.GetFileAttributes(out NxFileAttributes attributes, "/dir".ToU8Span()); Assert.True(rcSet.IsSuccess()); Assert.True(rcGet.IsSuccess()); @@ -106,9 +107,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IAttributeFileSystem fs = CreateAttributeFileSystem(); - fs.CreateFile("/file", 845, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 845, CreateFileOptions.None); - Assert.True(fs.GetFileSize(out long fileSize, "/file").IsSuccess()); + Assert.True(fs.GetFileSize(out long fileSize, "/file".ToU8Span()).IsSuccess()); Assert.Equal(845, fileSize); } @@ -117,7 +118,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IAttributeFileSystem fs = CreateAttributeFileSystem(); - Result rc = fs.GetFileSize(out _, "/path"); + Result rc = fs.GetFileSize(out _, "/path".ToU8Span()); Assert.Equal(ResultFs.PathNotFound.Value, rc); } @@ -126,9 +127,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase public void GetFileSize_PathIsDirectory_ReturnsPathNotFound() { IAttributeFileSystem fs = CreateAttributeFileSystem(); - fs.CreateDirectory("/dir"); + fs.CreateDirectory("/dir".ToU8Span()); - Result rc = fs.GetFileSize(out _, "/dir"); + Result rc = fs.GetFileSize(out _, "/dir".ToU8Span()); Assert.Equal(ResultFs.PathNotFound.Value, rc); } diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CleanDirectoryRecursively.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CleanDirectoryRecursively.cs index c9a8a901..20a2bd27 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CleanDirectoryRecursively.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CleanDirectoryRecursively.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,15 +11,15 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir"); - fs.CreateDirectory("/dir/dir2"); - fs.CreateFile("/dir/file1", 0, CreateFileOptions.None); + fs.CreateDirectory("/dir".ToU8Span()); + fs.CreateDirectory("/dir/dir2".ToU8Span()); + fs.CreateFile("/dir/file1".ToU8Span(), 0, CreateFileOptions.None); - Result rcDelete = fs.CleanDirectoryRecursively("/dir"); + Result rcDelete = fs.CleanDirectoryRecursively("/dir".ToU8Span()); - Result rcDir1Type = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir"); - Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2"); - Result rcFileType = fs.GetEntryType(out _, "/dir/file1"); + Result rcDir1Type = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir".ToU8Span()); + Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2".ToU8Span()); + Result rcFileType = fs.GetEntryType(out _, "/dir/file1".ToU8Span()); Assert.True(rcDelete.IsSuccess()); diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateDirectory.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateDirectory.cs index 8a7eb9b5..5169b447 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateDirectory.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateDirectory.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,8 +11,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir"); - Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir"); + fs.CreateDirectory("/dir".ToU8Span()); + Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir".ToU8Span()); Assert.True(rc.IsSuccess()); Assert.Equal(DirectoryEntryType.Directory, type); @@ -22,9 +23,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir"); + fs.CreateDirectory("/dir".ToU8Span()); - Result rc = fs.CreateDirectory("/dir"); + Result rc = fs.CreateDirectory("/dir".ToU8Span()); Assert.Equal(ResultFs.PathAlreadyExists.Value, rc); } @@ -34,9 +35,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); - Result rc = fs.CreateDirectory("/file"); + Result rc = fs.CreateDirectory("/file".ToU8Span()); Assert.Equal(ResultFs.PathAlreadyExists.Value, rc); } @@ -46,7 +47,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - Result rc = fs.CreateFile("/dir1/dir2", 0, CreateFileOptions.None); + Result rc = fs.CreateFile("/dir1/dir2".ToU8Span(), 0, CreateFileOptions.None); Assert.Equal(ResultFs.PathNotFound.Value, rc); } @@ -56,8 +57,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir/"); - Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir/"); + fs.CreateDirectory("/dir/".ToU8Span()); + Result rc = fs.GetEntryType(out DirectoryEntryType type, "/dir/".ToU8Span()); Assert.True(rc.IsSuccess()); Assert.Equal(DirectoryEntryType.Directory, type); @@ -68,11 +69,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir1"); - fs.CreateDirectory("/dir2"); + fs.CreateDirectory("/dir1".ToU8Span()); + fs.CreateDirectory("/dir2".ToU8Span()); - Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1"); - Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2"); + Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1".ToU8Span()); + Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2".ToU8Span()); Assert.True(rc1.IsSuccess()); Assert.True(rc2.IsSuccess()); @@ -85,14 +86,14 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir1"); - fs.CreateDirectory("/dir2"); + fs.CreateDirectory("/dir1".ToU8Span()); + fs.CreateDirectory("/dir2".ToU8Span()); - fs.CreateDirectory("/dir1/dir1a"); - fs.CreateDirectory("/dir2/dir2a"); + fs.CreateDirectory("/dir1/dir1a".ToU8Span()); + fs.CreateDirectory("/dir2/dir2a".ToU8Span()); - Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/dir1a"); - Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/dir2a"); + Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/dir1a".ToU8Span()); + Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/dir2a".ToU8Span()); Assert.True(rc1.IsSuccess()); Assert.True(rc2.IsSuccess()); diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateFile.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateFile.cs index ca251868..8f437383 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateFile.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.CreateFile.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,8 +11,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); - Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file"); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); + Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file".ToU8Span()); Assert.True(rc.IsSuccess()); Assert.Equal(DirectoryEntryType.File, type); @@ -22,9 +23,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir"); + fs.CreateDirectory("/dir".ToU8Span()); - Result rc = fs.CreateFile("/dir", 0, CreateFileOptions.None); + Result rc = fs.CreateFile("/dir".ToU8Span(), 0, CreateFileOptions.None); Assert.Equal(ResultFs.PathAlreadyExists.Value, rc); } @@ -34,9 +35,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); - Result rc = fs.CreateFile("/file", 0, CreateFileOptions.None); + Result rc = fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); Assert.Equal(ResultFs.PathAlreadyExists.Value, rc); } @@ -46,7 +47,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - Result rc = fs.CreateFile("/dir/file", 0, CreateFileOptions.None); + Result rc = fs.CreateFile("/dir/file".ToU8Span(), 0, CreateFileOptions.None); Assert.Equal(ResultFs.PathNotFound.Value, rc); } @@ -56,8 +57,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file/", 0, CreateFileOptions.None); - Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file/"); + fs.CreateFile("/file/".ToU8Span(), 0, CreateFileOptions.None); + Result rc = fs.GetEntryType(out DirectoryEntryType type, "/file/".ToU8Span()); Assert.True(rc.IsSuccess()); Assert.Equal(DirectoryEntryType.File, type); @@ -70,9 +71,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", expectedSize, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), expectedSize, CreateFileOptions.None); - fs.OpenFile(out IFile file, "/file", OpenMode.Read); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read); Result rc = file.GetSize(out long fileSize); Assert.True(rc.IsSuccess()); @@ -84,11 +85,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file1", 0, CreateFileOptions.None); - fs.CreateFile("/file2", 0, CreateFileOptions.None); + fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None); + fs.CreateFile("/file2".ToU8Span(), 0, CreateFileOptions.None); - Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/file1"); - Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/file2"); + Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/file1".ToU8Span()); + Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/file2".ToU8Span()); Assert.True(rc1.IsSuccess()); Assert.True(rc2.IsSuccess()); @@ -101,14 +102,14 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir1"); - fs.CreateDirectory("/dir2"); + fs.CreateDirectory("/dir1".ToU8Span()); + fs.CreateDirectory("/dir2".ToU8Span()); - fs.CreateFile("/dir1/file1", 0, CreateFileOptions.None); - fs.CreateFile("/dir2/file2", 0, CreateFileOptions.None); + fs.CreateFile("/dir1/file1".ToU8Span(), 0, CreateFileOptions.None); + fs.CreateFile("/dir2/file2".ToU8Span(), 0, CreateFileOptions.None); - Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/file1"); - Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/file2"); + Result rc1 = fs.GetEntryType(out DirectoryEntryType type1, "/dir1/file1".ToU8Span()); + Result rc2 = fs.GetEntryType(out DirectoryEntryType type2, "/dir2/file2".ToU8Span()); Assert.True(rc1.IsSuccess()); Assert.True(rc2.IsSuccess()); diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectory.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectory.cs index 527b9be3..a4f18b73 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectory.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectory.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,7 +11,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - Result rc = fs.DeleteDirectory("/dir"); + Result rc = fs.DeleteDirectory("/dir".ToU8Span()); Assert.Equal(ResultFs.PathNotFound.Value, rc); } @@ -20,10 +21,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir"); + fs.CreateDirectory("/dir".ToU8Span()); - Result rcDelete = fs.DeleteDirectory("/dir"); - Result rcEntry = fs.GetEntryType(out _, "/dir"); + Result rcDelete = fs.DeleteDirectory("/dir".ToU8Span()); + Result rcEntry = fs.GetEntryType(out _, "/dir".ToU8Span()); Assert.True(rcDelete.IsSuccess()); Assert.Equal(ResultFs.PathNotFound.Value, rcEntry); @@ -34,9 +35,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); - Result rc = fs.DeleteDirectory("/file"); + Result rc = fs.DeleteDirectory("/file".ToU8Span()); Assert.Equal(ResultFs.PathNotFound.Value, rc); } @@ -46,12 +47,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir1"); - fs.CreateDirectory("/dir2"); + fs.CreateDirectory("/dir1".ToU8Span()); + fs.CreateDirectory("/dir2".ToU8Span()); - Result rcDelete = fs.DeleteDirectory("/dir2"); - Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1"); - Result rcEntry2 = fs.GetEntryType(out _, "/dir2"); + Result rcDelete = fs.DeleteDirectory("/dir2".ToU8Span()); + Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1".ToU8Span()); + Result rcEntry2 = fs.GetEntryType(out _, "/dir2".ToU8Span()); Assert.True(rcDelete.IsSuccess()); Assert.True(rcEntry1.IsSuccess()); @@ -65,12 +66,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir2"); - fs.CreateDirectory("/dir1"); + fs.CreateDirectory("/dir2".ToU8Span()); + fs.CreateDirectory("/dir1".ToU8Span()); - Result rcDelete = fs.DeleteDirectory("/dir2"); - Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1"); - Result rcEntry2 = fs.GetEntryType(out _, "/dir2"); + Result rcDelete = fs.DeleteDirectory("/dir2".ToU8Span()); + Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1".ToU8Span()); + Result rcEntry2 = fs.GetEntryType(out _, "/dir2".ToU8Span()); Assert.True(rcDelete.IsSuccess()); Assert.True(rcEntry1.IsSuccess()); @@ -84,10 +85,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir"); - fs.CreateFile("/dir/file", 0, CreateFileOptions.None); + fs.CreateDirectory("/dir".ToU8Span()); + fs.CreateFile("/dir/file".ToU8Span(), 0, CreateFileOptions.None); - Result rc = fs.DeleteDirectory("/dir"); + Result rc = fs.DeleteDirectory("/dir".ToU8Span()); Assert.Equal(ResultFs.DirectoryNotEmpty.Value, rc); } diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectoryRecursively.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectoryRecursively.cs index 6dfe38f8..8d27bd17 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectoryRecursively.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteDirectoryRecursively.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,15 +11,15 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir"); - fs.CreateDirectory("/dir/dir2"); - fs.CreateFile("/dir/file1", 0, CreateFileOptions.None); + fs.CreateDirectory("/dir".ToU8Span()); + fs.CreateDirectory("/dir/dir2".ToU8Span()); + fs.CreateFile("/dir/file1".ToU8Span(), 0, CreateFileOptions.None); - Result rcDelete = fs.DeleteDirectoryRecursively("/dir"); + Result rcDelete = fs.DeleteDirectoryRecursively("/dir".ToU8Span()); - Result rcDir1Type = fs.GetEntryType(out _, "/dir"); - Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2"); - Result rcFileType = fs.GetEntryType(out _, "/dir/file1"); + Result rcDir1Type = fs.GetEntryType(out _, "/dir".ToU8Span()); + Result rcDir2Type = fs.GetEntryType(out _, "/dir/dir2".ToU8Span()); + Result rcFileType = fs.GetEntryType(out _, "/dir/file1".ToU8Span()); Assert.True(rcDelete.IsSuccess()); diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteFile.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteFile.cs index bcaafd19..c9fe658d 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteFile.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.DeleteFile.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,7 +11,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - Result rc = fs.DeleteFile("/file"); + Result rc = fs.DeleteFile("/file".ToU8Span()); Assert.Equal(ResultFs.PathNotFound.Value, rc); } @@ -19,10 +20,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); - Result rcDelete = fs.DeleteFile("/file"); - Result rcEntry = fs.GetEntryType(out _, "/file"); + Result rcDelete = fs.DeleteFile("/file".ToU8Span()); + Result rcEntry = fs.GetEntryType(out _, "/file".ToU8Span()); Assert.True(rcDelete.IsSuccess()); Assert.Equal(ResultFs.PathNotFound.Value, rcEntry); @@ -33,9 +34,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir"); + fs.CreateDirectory("/dir".ToU8Span()); - Result rc = fs.DeleteFile("/dir"); + Result rc = fs.DeleteFile("/dir".ToU8Span()); Assert.Equal(ResultFs.PathNotFound.Value, rc); } @@ -45,12 +46,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file1", 0, CreateFileOptions.None); - fs.CreateFile("/file2", 0, CreateFileOptions.None); + fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None); + fs.CreateFile("/file2".ToU8Span(), 0, CreateFileOptions.None); - Result rcDelete = fs.DeleteFile("/file2"); - Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1"); - Result rcEntry2 = fs.GetEntryType(out _, "/file2"); + Result rcDelete = fs.DeleteFile("/file2".ToU8Span()); + Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1".ToU8Span()); + Result rcEntry2 = fs.GetEntryType(out _, "/file2".ToU8Span()); Assert.True(rcDelete.IsSuccess()); Assert.True(rcEntry1.IsSuccess()); @@ -64,12 +65,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file2", 0, CreateFileOptions.None); - fs.CreateFile("/file1", 0, CreateFileOptions.None); + fs.CreateFile("/file2".ToU8Span(), 0, CreateFileOptions.None); + fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None); - Result rcDelete = fs.DeleteFile("/file2"); - Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1"); - Result rcEntry2 = fs.GetEntryType(out _, "/file2"); + Result rcDelete = fs.DeleteFile("/file2".ToU8Span()); + Result rcEntry1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/file1".ToU8Span()); + Result rcEntry2 = fs.GetEntryType(out _, "/file2".ToU8Span()); Assert.True(rcDelete.IsSuccess()); Assert.True(rcEntry1.IsSuccess()); diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.GetEntryType.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.GetEntryType.cs index f0758c4b..d94df8f3 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.GetEntryType.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.GetEntryType.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,9 +11,8 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - Result rc = fs.GetEntryType(out DirectoryEntryType type, "/"); + Assert.Success(fs.GetEntryType(out DirectoryEntryType type, "/".ToU8Span())); - Assert.True(rc.IsSuccess()); Assert.Equal(DirectoryEntryType.Directory, type); } @@ -21,9 +21,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - Result rc = fs.GetEntryType(out _, "/path"); - - Assert.Equal(ResultFs.PathNotFound.Value, rc); + Assert.Result(ResultFs.PathNotFound, fs.GetEntryType(out _, "/path".ToU8Span())); } } } \ No newline at end of file diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IDirectory.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IDirectory.cs index ce7a9aa1..cb0bc160 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IDirectory.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IDirectory.cs @@ -13,7 +13,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase IFileSystem fs = CreateFileSystem(); Span entries = stackalloc DirectoryEntry[1]; - Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All)); + Assert.Success(fs.OpenDirectory(out IDirectory directory, "/".ToU8Span(), OpenDirectoryMode.All)); Assert.Success(directory.Read(out long entriesRead, entries)); Assert.Equal(0, entriesRead); @@ -24,7 +24,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All)); + Assert.Success(fs.OpenDirectory(out IDirectory directory, "/".ToU8Span(), OpenDirectoryMode.All)); Assert.Success(directory.GetEntryCount(out long entryCount)); Assert.Equal(0, entryCount); @@ -34,13 +34,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase public void IDirectoryRead_AllEntriesAreReturned() { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir"); - fs.CreateDirectory("/dir/dir1"); - fs.CreateFile("/dir/dir1/file1", 0, CreateFileOptions.None); - fs.CreateFile("/dir/file1", 0, CreateFileOptions.None); - fs.CreateFile("/dir/file2", 0, CreateFileOptions.None); + fs.CreateDirectory("/dir".ToU8Span()); + fs.CreateDirectory("/dir/dir1".ToU8Span()); + fs.CreateFile("/dir/dir1/file1".ToU8Span(), 0, CreateFileOptions.None); + fs.CreateFile("/dir/file1".ToU8Span(), 0, CreateFileOptions.None); + fs.CreateFile("/dir/file2".ToU8Span(), 0, CreateFileOptions.None); - Result rc = fs.OpenDirectory(out IDirectory dir, "/dir", OpenDirectoryMode.All); + Result rc = fs.OpenDirectory(out IDirectory dir, "/dir".ToU8Span(), OpenDirectoryMode.All); Assert.True(rc.IsSuccess()); var entry1 = new DirectoryEntry(); diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Read.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Read.cs index 8d9196f8..8233e9ba 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Read.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Read.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Common; using LibHac.Fs; using Xunit; @@ -11,10 +12,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 100, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 100, CreateFileOptions.None); var buffer = new byte[20]; - fs.OpenFile(out IFile file, "/file", OpenMode.Read); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read); using (file) { Assert.True(file.Read(out long bytesRead, 50, buffer, ReadOption.None).IsSuccess()); @@ -27,10 +28,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); var buffer = new byte[10]; - fs.OpenFile(out IFile file, "/file", OpenMode.Read); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read); using (file) { Result rc = file.Read(out _, 1, buffer, ReadOption.None); @@ -43,10 +44,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); var buffer = new byte[10]; - fs.OpenFile(out IFile file, "/file", OpenMode.Write); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write); using (file) { Result rc = file.Read(out _, 0, buffer, ReadOption.None); @@ -59,10 +60,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); var buffer = new byte[10]; - fs.OpenFile(out IFile file, "/file", OpenMode.Write); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write); using (file) { Result rc = file.Read(out _, -5, buffer, ReadOption.None); @@ -75,10 +76,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); var buffer = new byte[10]; - fs.OpenFile(out IFile file, "/file", OpenMode.Write); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write); using (file) { Result rc = file.Read(out _, long.MaxValue - 5, buffer, ReadOption.None); @@ -91,10 +92,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 100, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 100, CreateFileOptions.None); var buffer = new byte[200]; - fs.OpenFile(out IFile file, "/file", OpenMode.Read); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read); using (file) { Assert.True(file.Read(out long bytesRead, 90, buffer, ReadOption.None).IsSuccess()); @@ -107,10 +108,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 100, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 100, CreateFileOptions.None); // The contents of a created file are undefined, so zero the file - fs.OpenFile(out IFile file, "/file", OpenMode.Write); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write); using (file) { file.Write(0, new byte[100], WriteOption.None); @@ -122,7 +123,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase var buffer = new byte[200]; buffer.AsSpan().Fill(0xCC); - fs.OpenFile(out file, "/file", OpenMode.Read); + fs.OpenFile(out file, "/file".ToU8Span(), OpenMode.Read); using (file) { Assert.True(file.Read(out _, 90, buffer, ReadOption.None).IsSuccess()); diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Size.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Size.cs index 5ef77363..4660e8e2 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Size.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Size.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -9,13 +10,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase public void SetSize_FileSizeModified() { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); - fs.OpenFile(out IFile file, "/file", OpenMode.All); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.All); Result rc = file.SetSize(54321); file.Dispose(); - fs.OpenFile(out file, "/file", OpenMode.All); + fs.OpenFile(out file, "/file".ToU8Span(), OpenMode.All); file.GetSize(out long fileSize); file.Dispose(); diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Write.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Write.cs index add95007..0c259473 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Write.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.IFile.Write.cs @@ -1,4 +1,5 @@ using System; +using LibHac.Common; using LibHac.Fs; using Xunit; @@ -13,15 +14,15 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", data.Length, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), data.Length, CreateFileOptions.None); - fs.OpenFile(out IFile file, "/file", OpenMode.Write); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write); file.Write(0, data, WriteOption.None); file.Dispose(); var readData = new byte[data.Length]; - fs.OpenFile(out file, "/file", OpenMode.Read); + fs.OpenFile(out file, "/file".ToU8Span(), OpenMode.Read); using (file) { Assert.True(file.Read(out long bytesRead, 0, readData, ReadOption.None).IsSuccess()); @@ -36,10 +37,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 10, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None); var buffer = new byte[10]; - fs.OpenFile(out IFile file, "/file", OpenMode.Write); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write); using (file) { Result rc = file.Write(5, buffer, WriteOption.None); @@ -52,10 +53,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 10, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None); var buffer = new byte[10]; - fs.OpenFile(out IFile file, "/file", OpenMode.Read); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read); using (file) { Result rc = file.Write(5, buffer, WriteOption.None); @@ -68,10 +69,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 10, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None); var buffer = new byte[10]; - fs.OpenFile(out IFile file, "/file", OpenMode.Read); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read); using (file) { Result rc = file.Write(-5, buffer, WriteOption.None); @@ -84,10 +85,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 10, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None); var buffer = new byte[10]; - fs.OpenFile(out IFile file, "/file", OpenMode.Read); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Read); using (file) { Result rc = file.Write(long.MaxValue - 5, buffer, WriteOption.None); @@ -100,10 +101,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 10, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None); var buffer = new byte[10]; - fs.OpenFile(out IFile file, "/file", OpenMode.All); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.All); using (file) { Assert.True(file.Write(5, buffer, WriteOption.None).IsSuccess()); @@ -118,10 +119,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 10, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None); var buffer = new byte[10]; - fs.OpenFile(out IFile file, "/file", OpenMode.All); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.All); using (file) { Assert.True(file.Write(15, buffer, WriteOption.None).IsSuccess()); @@ -136,7 +137,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 10, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 10, CreateFileOptions.None); var bufferExpected = new byte[25]; bufferExpected.AsSpan(15).Fill(0xCC); @@ -144,7 +145,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase var writeBuffer = new byte[10]; writeBuffer.AsSpan().Fill(0xCC); - fs.OpenFile(out IFile file, "/file", OpenMode.All); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.All); using (file) { Assert.True(file.Write(15, writeBuffer, WriteOption.None).IsSuccess()); @@ -155,7 +156,7 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase var readBuffer = new byte[25]; - fs.OpenFile(out file, "/file", OpenMode.Read); + fs.OpenFile(out file, "/file".ToU8Span(), OpenMode.Read); using (file) { file.Read(out _, 0, readBuffer, ReadOption.None); diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenDirectory.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenDirectory.cs index c25edfdc..94e408bb 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenDirectory.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenDirectory.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,9 +11,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); - Result rc = fs.OpenDirectory(out _, "/file", OpenDirectoryMode.All); + Result rc = fs.OpenDirectory(out _, "/file".ToU8Span(), OpenDirectoryMode.All); Assert.Equal(ResultFs.PathNotFound.Value, rc); } diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenFile.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenFile.cs index 4540d71b..a6c5dfe6 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenFile.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.OpenFile.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,9 +11,9 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir"); + fs.CreateDirectory("/dir".ToU8Span()); - Result rc = fs.OpenFile(out _, "/dir", OpenMode.All); + Result rc = fs.OpenFile(out _, "/dir".ToU8Span(), OpenMode.All); Assert.Equal(ResultFs.PathNotFound.Value, rc); } diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameDirectory.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameDirectory.cs index 72f81dc5..c6343f0f 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameDirectory.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameDirectory.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,11 +11,11 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir1"); - Result rcRename = fs.RenameDirectory("/dir1", "/dir2"); + fs.CreateDirectory("/dir1".ToU8Span()); + Result rcRename = fs.RenameDirectory("/dir1".ToU8Span(), "/dir2".ToU8Span()); - Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2"); - Result rcDir1 = fs.GetEntryType(out _, "/dir1"); + Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2".ToU8Span()); + Result rcDir1 = fs.GetEntryType(out _, "/dir1".ToU8Span()); Assert.True(rcRename.IsSuccess()); @@ -29,21 +30,21 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir1"); - fs.CreateDirectory("/dir1/dirC"); - fs.CreateFile("/dir1/file1", 0, CreateFileOptions.None); + fs.CreateDirectory("/dir1".ToU8Span()); + fs.CreateDirectory("/dir1/dirC".ToU8Span()); + fs.CreateFile("/dir1/file1".ToU8Span(), 0, CreateFileOptions.None); - Result rcRename = fs.RenameDirectory("/dir1", "/dir2"); + Result rcRename = fs.RenameDirectory("/dir1".ToU8Span(), "/dir2".ToU8Span()); // Check that renamed structure exists - Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2"); - Result rcDirC = fs.GetEntryType(out DirectoryEntryType dir1CType, "/dir2/dirC"); - Result rcFile1 = fs.GetEntryType(out DirectoryEntryType file1Type, "/dir2/file1"); + Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2".ToU8Span()); + Result rcDirC = fs.GetEntryType(out DirectoryEntryType dir1CType, "/dir2/dirC".ToU8Span()); + Result rcFile1 = fs.GetEntryType(out DirectoryEntryType file1Type, "/dir2/file1".ToU8Span()); // Check that old structure doesn't exist - Result rcDir1 = fs.GetEntryType(out _, "/dir1"); - Result rcDirCOld = fs.GetEntryType(out _, "/dir1/dirC"); - Result rcFile1Old = fs.GetEntryType(out _, "/dir1/file1"); + Result rcDir1 = fs.GetEntryType(out _, "/dir1".ToU8Span()); + Result rcDirCOld = fs.GetEntryType(out _, "/dir1/dirC".ToU8Span()); + Result rcFile1Old = fs.GetEntryType(out _, "/dir1/file1".ToU8Span()); Assert.True(rcRename.IsSuccess()); @@ -65,14 +66,14 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/parent1"); - fs.CreateDirectory("/parent2"); - fs.CreateDirectory("/parent1/dir1"); + fs.CreateDirectory("/parent1".ToU8Span()); + fs.CreateDirectory("/parent2".ToU8Span()); + fs.CreateDirectory("/parent1/dir1".ToU8Span()); - Result rcRename = fs.RenameDirectory("/parent1/dir1", "/parent2/dir2"); + Result rcRename = fs.RenameDirectory("/parent1/dir1".ToU8Span(), "/parent2/dir2".ToU8Span()); - Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/parent2/dir2"); - Result rcDir1 = fs.GetEntryType(out _, "/parent1/dir1"); + Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/parent2/dir2".ToU8Span()); + Result rcDir1 = fs.GetEntryType(out _, "/parent1/dir1".ToU8Span()); Assert.True(rcRename.IsSuccess()); @@ -88,13 +89,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateDirectory("/dir1"); - fs.CreateDirectory("/dir2"); + fs.CreateDirectory("/dir1".ToU8Span()); + fs.CreateDirectory("/dir2".ToU8Span()); - Result rcRename = fs.RenameDirectory("/dir1", "/dir2"); + Result rcRename = fs.RenameDirectory("/dir1".ToU8Span(), "/dir2".ToU8Span()); - Result rcDir1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1"); - Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2"); + Result rcDir1 = fs.GetEntryType(out DirectoryEntryType dir1Type, "/dir1".ToU8Span()); + Result rcDir2 = fs.GetEntryType(out DirectoryEntryType dir2Type, "/dir2".ToU8Span()); Assert.Equal(ResultFs.PathAlreadyExists.Value, rcRename); diff --git a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameFile.cs b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameFile.cs index 5106055a..f588af0d 100644 --- a/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameFile.cs +++ b/tests/LibHac.Tests/Fs/IFileSystemTestBase/IFileSystemTests.RenameFile.cs @@ -1,4 +1,5 @@ -using LibHac.Fs; +using LibHac.Common; +using LibHac.Fs; using Xunit; namespace LibHac.Tests.Fs.IFileSystemTestBase @@ -10,12 +11,12 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file1", 0, CreateFileOptions.None); + fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None); - Assert.True(fs.RenameFile("/file1", "/file2").IsSuccess()); + Assert.True(fs.RenameFile("/file1".ToU8Span(), "/file2".ToU8Span()).IsSuccess()); - Assert.True(fs.GetEntryType(out DirectoryEntryType type, "/file2").IsSuccess()); - Result rc = fs.GetEntryType(out _, "/file1"); + Assert.True(fs.GetEntryType(out DirectoryEntryType type, "/file2".ToU8Span()).IsSuccess()); + Result rc = fs.GetEntryType(out _, "/file1".ToU8Span()); Assert.Equal(DirectoryEntryType.File, type); Assert.Equal(ResultFs.PathNotFound.Value, rc); @@ -25,13 +26,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file1", 0, CreateFileOptions.None); - fs.CreateDirectory("/dir"); + fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None); + fs.CreateDirectory("/dir".ToU8Span()); - Assert.True(fs.RenameFile("/file1", "/dir/file2").IsSuccess()); + Assert.True(fs.RenameFile("/file1".ToU8Span(), "/dir/file2".ToU8Span()).IsSuccess()); - Assert.True(fs.GetEntryType(out DirectoryEntryType type, "/dir/file2").IsSuccess()); - Result rc = fs.GetEntryType(out _, "/file1"); + Assert.True(fs.GetEntryType(out DirectoryEntryType type, "/dir/file2".ToU8Span()).IsSuccess()); + Result rc = fs.GetEntryType(out _, "/file1".ToU8Span()); Assert.Equal(DirectoryEntryType.File, type); Assert.Equal(ResultFs.PathNotFound.Value, rc); @@ -42,10 +43,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file1", 0, CreateFileOptions.None); - fs.CreateFile("/file2", 0, CreateFileOptions.None); + fs.CreateFile("/file1".ToU8Span(), 0, CreateFileOptions.None); + fs.CreateFile("/file2".ToU8Span(), 0, CreateFileOptions.None); - Result rc = fs.RenameFile("/file1", "/file2"); + Result rc = fs.RenameFile("/file1".ToU8Span(), "/file2".ToU8Span()); Assert.Equal(ResultFs.PathAlreadyExists.Value, rc); } @@ -55,10 +56,10 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", 0, CreateFileOptions.None); - fs.CreateDirectory("/dir"); + fs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); + fs.CreateDirectory("/dir".ToU8Span()); - Result rc = fs.RenameFile("/file", "/dir"); + Result rc = fs.RenameFile("/file".ToU8Span(), "/dir".ToU8Span()); Assert.Equal(ResultFs.PathAlreadyExists.Value, rc); } @@ -68,13 +69,13 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase { IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file1", 54321, CreateFileOptions.None); - fs.CreateFile("/file2", 12345, CreateFileOptions.None); + fs.CreateFile("/file1".ToU8Span(), 54321, CreateFileOptions.None); + fs.CreateFile("/file2".ToU8Span(), 12345, CreateFileOptions.None); - fs.RenameFile("/file1", "/file2"); + fs.RenameFile("/file1".ToU8Span(), "/file2".ToU8Span()); - Assert.True(fs.OpenFile(out IFile file1, "/file1", OpenMode.Read).IsSuccess()); - Assert.True(fs.OpenFile(out IFile file2, "/file2", OpenMode.Read).IsSuccess()); + Assert.True(fs.OpenFile(out IFile file1, "/file1".ToU8Span(), OpenMode.Read).IsSuccess()); + Assert.True(fs.OpenFile(out IFile file2, "/file2".ToU8Span(), OpenMode.Read).IsSuccess()); using (file1) using (file2) @@ -94,17 +95,17 @@ namespace LibHac.Tests.Fs.IFileSystemTestBase IFileSystem fs = CreateFileSystem(); - fs.CreateFile("/file", data.Length, CreateFileOptions.None); + fs.CreateFile("/file".ToU8Span(), data.Length, CreateFileOptions.None); - fs.OpenFile(out IFile file, "/file", OpenMode.Write); + fs.OpenFile(out IFile file, "/file".ToU8Span(), OpenMode.Write); file.Write(0, data, WriteOption.None); file.Dispose(); - fs.RenameFile("/file", "/renamed"); + fs.RenameFile("/file".ToU8Span(), "/renamed".ToU8Span()); var readData = new byte[data.Length]; - fs.OpenFile(out file, "/renamed", OpenMode.Read); + fs.OpenFile(out file, "/renamed".ToU8Span(), OpenMode.Read); Result rc = file.Read(out long bytesRead, 0, readData, ReadOption.None); file.Dispose(); diff --git a/tests/LibHac.Tests/Fs/LayeredFileSystemTests.cs b/tests/LibHac.Tests/Fs/LayeredFileSystemTests.cs index ff361aec..5e7949ee 100644 --- a/tests/LibHac.Tests/Fs/LayeredFileSystemTests.cs +++ b/tests/LibHac.Tests/Fs/LayeredFileSystemTests.cs @@ -15,30 +15,30 @@ namespace LibHac.Tests.Fs var layeredFs = new LayeredFileSystem(lowerLayerFs, upperLayerFs); - lowerLayerFs.CreateDirectory("/dir").ThrowIfFailure(); - upperLayerFs.CreateDirectory("/dir").ThrowIfFailure(); - lowerLayerFs.CreateDirectory("/dir2").ThrowIfFailure(); - upperLayerFs.CreateDirectory("/dir2").ThrowIfFailure(); - lowerLayerFs.CreateDirectory("/dir3").ThrowIfFailure(); - upperLayerFs.CreateDirectory("/dir3").ThrowIfFailure(); + lowerLayerFs.CreateDirectory("/dir".ToU8Span()).ThrowIfFailure(); + upperLayerFs.CreateDirectory("/dir".ToU8Span()).ThrowIfFailure(); + lowerLayerFs.CreateDirectory("/dir2".ToU8Span()).ThrowIfFailure(); + upperLayerFs.CreateDirectory("/dir2".ToU8Span()).ThrowIfFailure(); + lowerLayerFs.CreateDirectory("/dir3".ToU8Span()).ThrowIfFailure(); + upperLayerFs.CreateDirectory("/dir3".ToU8Span()).ThrowIfFailure(); - lowerLayerFs.CreateDirectory("/lowerDir").ThrowIfFailure(); - upperLayerFs.CreateDirectory("/upperDir").ThrowIfFailure(); + lowerLayerFs.CreateDirectory("/lowerDir".ToU8Span()).ThrowIfFailure(); + upperLayerFs.CreateDirectory("/upperDir".ToU8Span()).ThrowIfFailure(); - lowerLayerFs.CreateFile("/dir/replacedFile", 1, CreateFileOptions.None).ThrowIfFailure(); - upperLayerFs.CreateFile("/dir/replacedFile", 2, CreateFileOptions.None).ThrowIfFailure(); + lowerLayerFs.CreateFile("/dir/replacedFile".ToU8Span(), 1, CreateFileOptions.None).ThrowIfFailure(); + upperLayerFs.CreateFile("/dir/replacedFile".ToU8Span(), 2, CreateFileOptions.None).ThrowIfFailure(); - lowerLayerFs.CreateFile("/dir2/lowerFile", 0, CreateFileOptions.None).ThrowIfFailure(); - upperLayerFs.CreateFile("/dir2/upperFile", 0, CreateFileOptions.None).ThrowIfFailure(); + lowerLayerFs.CreateFile("/dir2/lowerFile".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure(); + upperLayerFs.CreateFile("/dir2/upperFile".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure(); - lowerLayerFs.CreateFile("/dir3/lowerFile", 0, CreateFileOptions.None).ThrowIfFailure(); - upperLayerFs.CreateFile("/dir3/upperFile", 2, CreateFileOptions.None).ThrowIfFailure(); - lowerLayerFs.CreateFile("/dir3/replacedFile", 1, CreateFileOptions.None).ThrowIfFailure(); - upperLayerFs.CreateFile("/dir3/replacedFile", 2, CreateFileOptions.None).ThrowIfFailure(); + lowerLayerFs.CreateFile("/dir3/lowerFile".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure(); + upperLayerFs.CreateFile("/dir3/upperFile".ToU8Span(), 2, CreateFileOptions.None).ThrowIfFailure(); + lowerLayerFs.CreateFile("/dir3/replacedFile".ToU8Span(), 1, CreateFileOptions.None).ThrowIfFailure(); + upperLayerFs.CreateFile("/dir3/replacedFile".ToU8Span(), 2, CreateFileOptions.None).ThrowIfFailure(); - lowerLayerFs.CreateFile("/replacedWithDir", 0, CreateFileOptions.None).ThrowIfFailure(); - upperLayerFs.CreateDirectory("/replacedWithDir").ThrowIfFailure(); - upperLayerFs.CreateFile("/replacedWithDir/subFile", 0, CreateFileOptions.None).ThrowIfFailure(); + lowerLayerFs.CreateFile("/replacedWithDir".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure(); + upperLayerFs.CreateDirectory("/replacedWithDir".ToU8Span()).ThrowIfFailure(); + upperLayerFs.CreateFile("/replacedWithDir/subFile".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure(); return layeredFs; } @@ -56,7 +56,7 @@ namespace LibHac.Tests.Fs { IFileSystem fs = CreateFileSystem(); - Assert.Result(ResultFs.PathNotFound, fs.OpenFile(out _, "/fakefile", OpenMode.All)); + Assert.Result(ResultFs.PathNotFound, fs.OpenFile(out _, "/fakefile".ToU8Span(), OpenMode.All)); } [Fact] @@ -64,7 +64,7 @@ namespace LibHac.Tests.Fs { IFileSystem fs = CreateFileSystem(); - Assert.Success(fs.OpenFile(out IFile file, "/dir/replacedFile", OpenMode.All)); + Assert.Success(fs.OpenFile(out IFile file, "/dir/replacedFile".ToU8Span(), OpenMode.All)); Assert.Success(file.GetSize(out long fileSize)); Assert.Equal(2, fileSize); @@ -75,8 +75,8 @@ namespace LibHac.Tests.Fs { IFileSystem fs = CreateFileSystem(); - Assert.Success(fs.OpenFile(out _, "/dir2/lowerFile", OpenMode.All)); - Assert.Success(fs.OpenFile(out _, "/dir2/upperFile", OpenMode.All)); + Assert.Success(fs.OpenFile(out _, "/dir2/lowerFile".ToU8Span(), OpenMode.All)); + Assert.Success(fs.OpenFile(out _, "/dir2/upperFile".ToU8Span(), OpenMode.All)); } [Fact] @@ -84,7 +84,7 @@ namespace LibHac.Tests.Fs { IFileSystem fs = CreateFileSystem(); - Assert.Result(ResultFs.PathNotFound, fs.OpenDirectory(out _, "/fakedir", OpenDirectoryMode.All)); + Assert.Result(ResultFs.PathNotFound, fs.OpenDirectory(out _, "/fakedir".ToU8Span(), OpenDirectoryMode.All)); } [Fact] @@ -92,7 +92,7 @@ namespace LibHac.Tests.Fs { IFileSystem fs = CreateFileSystem(); - Assert.Success(fs.OpenDirectory(out IDirectory dir, "/lowerDir", OpenDirectoryMode.All)); + Assert.Success(fs.OpenDirectory(out IDirectory dir, "/lowerDir".ToU8Span(), OpenDirectoryMode.All)); Assert.Equal(typeof(InMemoryFileSystem), dir.GetType().DeclaringType); } @@ -101,7 +101,7 @@ namespace LibHac.Tests.Fs { IFileSystem fs = CreateFileSystem(); - Assert.Success(fs.OpenDirectory(out IDirectory dir, "/dir", OpenDirectoryMode.All)); + Assert.Success(fs.OpenDirectory(out IDirectory dir, "/dir".ToU8Span(), OpenDirectoryMode.All)); Assert.Equal(typeof(LayeredFileSystem), dir.GetType().DeclaringType); } @@ -110,8 +110,8 @@ namespace LibHac.Tests.Fs { IFileSystem fs = CreateFileSystem(); - Assert.Success(fs.GetEntryType(out _, "/dir2/lowerFile")); - Assert.Success(fs.GetEntryType(out _, "/dir2/upperFile")); + Assert.Success(fs.GetEntryType(out _, "/dir2/lowerFile".ToU8Span())); + Assert.Success(fs.GetEntryType(out _, "/dir2/upperFile".ToU8Span())); } [Fact] @@ -120,7 +120,7 @@ namespace LibHac.Tests.Fs IFileSystem fs = CreateFileSystem(); Span entries = stackalloc DirectoryEntry[4]; - Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3", OpenDirectoryMode.All)); + Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3".ToU8Span(), OpenDirectoryMode.All)); Assert.Success(directory.Read(out long entriesRead, entries)); Assert.Equal(3, entriesRead); @@ -132,7 +132,7 @@ namespace LibHac.Tests.Fs IFileSystem fs = CreateFileSystem(); var entry = new DirectoryEntry(); - Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir", OpenDirectoryMode.All)); + Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir".ToU8Span(), OpenDirectoryMode.All)); Assert.Success(directory.Read(out _, SpanHelpers.AsSpan(ref entry))); Assert.Equal("replacedFile", StringUtils.Utf8ZToString(entry.Name)); @@ -145,7 +145,7 @@ namespace LibHac.Tests.Fs IFileSystem fs = CreateEmptyFileSystem(); var entry = new DirectoryEntry(); - Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All)); + Assert.Success(fs.OpenDirectory(out IDirectory directory, "/".ToU8Span(), OpenDirectoryMode.All)); Assert.Success(directory.Read(out long entriesRead, SpanHelpers.AsSpan(ref entry))); Assert.Equal(0, entriesRead); @@ -156,7 +156,7 @@ namespace LibHac.Tests.Fs { IFileSystem fs = CreateFileSystem(); - Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3", OpenDirectoryMode.All)); + Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3".ToU8Span(), OpenDirectoryMode.All)); Assert.Success(directory.GetEntryCount(out long entryCount)); Assert.Equal(3, entryCount); @@ -168,7 +168,7 @@ namespace LibHac.Tests.Fs IFileSystem fs = CreateFileSystem(); var entry = new DirectoryEntry(); - Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3", OpenDirectoryMode.All)); + Assert.Success(fs.OpenDirectory(out IDirectory directory, "/dir3".ToU8Span(), OpenDirectoryMode.All)); // Read all entries long entriesRead; @@ -186,7 +186,7 @@ namespace LibHac.Tests.Fs { IFileSystem fs = CreateEmptyFileSystem(); - Assert.Success(fs.OpenDirectory(out IDirectory directory, "/", OpenDirectoryMode.All)); + Assert.Success(fs.OpenDirectory(out IDirectory directory, "/".ToU8Span(), OpenDirectoryMode.All)); Assert.Success(directory.GetEntryCount(out long entryCount)); Assert.Equal(0, entryCount); diff --git a/tests/LibHac.Tests/Fs/SubdirectoryFileSystemTests.cs b/tests/LibHac.Tests/Fs/SubdirectoryFileSystemTests.cs index d2112350..ab91e662 100644 --- a/tests/LibHac.Tests/Fs/SubdirectoryFileSystemTests.cs +++ b/tests/LibHac.Tests/Fs/SubdirectoryFileSystemTests.cs @@ -16,8 +16,8 @@ namespace LibHac.Tests.Fs private (IFileSystem baseFs, IFileSystem subDirFs) CreateFileSystemInternal() { var baseFs = new InMemoryFileSystem(); - baseFs.CreateDirectory("/sub"); - baseFs.CreateDirectory("/sub/path"); + baseFs.CreateDirectory("/sub".ToU8Span()); + baseFs.CreateDirectory("/sub/path".ToU8Span()); SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem subFs, baseFs, "/sub/path".ToU8String()).ThrowIfFailure(); return (baseFs, subFs); @@ -28,8 +28,8 @@ namespace LibHac.Tests.Fs { (IFileSystem baseFs, IFileSystem subDirFs) = CreateFileSystemInternal(); - subDirFs.CreateFile("/file", 0, CreateFileOptions.None); - Result rc = baseFs.GetEntryType(out DirectoryEntryType type, "/sub/path/file"); + subDirFs.CreateFile("/file".ToU8Span(), 0, CreateFileOptions.None); + Result rc = baseFs.GetEntryType(out DirectoryEntryType type, "/sub/path/file".ToU8Span()); Assert.True(rc.IsSuccess()); Assert.Equal(DirectoryEntryType.File, type); @@ -40,8 +40,8 @@ namespace LibHac.Tests.Fs { (IFileSystem baseFs, IFileSystem subDirFs) = CreateFileSystemInternal(); - subDirFs.CreateDirectory("/dir"); - Result rc = baseFs.GetEntryType(out DirectoryEntryType type, "/sub/path/dir"); + subDirFs.CreateDirectory("/dir".ToU8Span()); + Result rc = baseFs.GetEntryType(out DirectoryEntryType type, "/sub/path/dir".ToU8Span()); Assert.True(rc.IsSuccess()); Assert.Equal(DirectoryEntryType.Directory, type);