From 9e9fd19f6356b8ee233c6fbe6721be619edeb981 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 8 Sep 2019 14:28:42 -0500 Subject: [PATCH] Return Result from IFileSystem methods --- src/LibHac/Fs/AesXtsDirectory.cs | 4 +- src/LibHac/Fs/AesXtsFileSystem.cs | 145 ++++++---- src/LibHac/Fs/ConcatenationFile.cs | 20 +- src/LibHac/Fs/ConcatenationFileSystem.cs | 156 ++++++----- src/LibHac/Fs/DirectorySaveDataFileSystem.cs | 126 +++++---- src/LibHac/Fs/FileSystemExtensions.cs | 60 ++-- src/LibHac/Fs/IFileSystem.cs | 115 ++++---- src/LibHac/Fs/LayeredFileSystem.cs | 124 +++++---- src/LibHac/Fs/LocalFileSystem.cs | 242 ++++++++++------- src/LibHac/Fs/PartitionFileSystem.cs | 69 +++-- src/LibHac/Fs/PartitionFileSystemBuilder.cs | 8 +- src/LibHac/Fs/ReadOnlyFileSystem.cs | 81 +++--- src/LibHac/Fs/ResultFs.cs | 1 - src/LibHac/Fs/RomFs/RomFsBuilder.cs | 6 +- src/LibHac/Fs/RomFs/RomFsFileSystem.cs | 92 +++---- .../Fs/Save/HierarchicalSaveFileTable.cs | 12 +- src/LibHac/Fs/Save/SaveDataFileSystem.cs | 217 +++++---------- src/LibHac/Fs/Save/SaveDataFileSystemCore.cs | 118 +++++--- src/LibHac/Fs/SubdirectoryFileSystem.cs | 75 ++--- .../FsClient/Accessors/FileSystemAccessor.cs | 90 +++--- src/LibHac/FsClient/DirectoryHandle.cs | 2 +- src/LibHac/FsClient/FileHandle.cs | 2 +- .../FsClient/FileSystemClient.FileSystem.cs | 4 +- src/LibHac/FsClient/FileSystemManager.cs | 256 ++++++++++-------- src/LibHac/FsClient/FileSystemManagerUtils.cs | 91 ++++--- .../Creators/IHostFileSystemCreator.cs | 2 +- .../ITargetManagerFileSystemCreator.cs | 2 +- .../Creators/SubDirectoryFileSystemCreator.cs | 12 +- src/LibHac/FsService/Util.cs | 20 +- src/LibHac/SwitchFs.cs | 16 +- src/LibHac/Xci.cs | 4 +- src/hactoolnet/FsUtils.cs | 62 +++-- src/hactoolnet/ProcessDelta.cs | 4 +- src/hactoolnet/ProcessNca.cs | 4 +- src/hactoolnet/ProcessSave.cs | 10 +- 35 files changed, 1246 insertions(+), 1006 deletions(-) diff --git a/src/LibHac/Fs/AesXtsDirectory.cs b/src/LibHac/Fs/AesXtsDirectory.cs index d1b14e92..67106723 100644 --- a/src/LibHac/Fs/AesXtsDirectory.cs +++ b/src/LibHac/Fs/AesXtsDirectory.cs @@ -56,7 +56,9 @@ namespace LibHac.Fs { try { - using (IFile file = BaseFileSystem.OpenFile(path, OpenMode.Read)) + BaseFileSystem.OpenFile(out IFile file, path, OpenMode.Read).ThrowIfFailure(); + + using (file) { file.GetSize(out long fileSize).ThrowIfFailure(); diff --git a/src/LibHac/Fs/AesXtsFileSystem.cs b/src/LibHac/Fs/AesXtsFileSystem.cs index 545c556f..3078bd05 100644 --- a/src/LibHac/Fs/AesXtsFileSystem.cs +++ b/src/LibHac/Fs/AesXtsFileSystem.cs @@ -27,14 +27,14 @@ namespace LibHac.Fs BlockSize = blockSize; } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { - BaseFileSystem.CreateDirectory(path); + return BaseFileSystem.CreateDirectory(path); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { - CreateFile(path, size, options, new byte[0x20]); + return CreateFile(path, size, options, new byte[0x20]); } /// @@ -45,83 +45,109 @@ namespace LibHac.Fs /// 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 void CreateFile(string path, long size, CreateFileOptions options, byte[] key) + public Result CreateFile(string path, long size, CreateFileOptions options, byte[] key) { long containerSize = AesXtsFile.HeaderLength + Util.AlignUp(size, 0x10); BaseFileSystem.CreateFile(path, containerSize, options); var header = new AesXtsFileHeader(key, size, path, KekSource, ValidationKey); - using (IFile baseFile = BaseFileSystem.OpenFile(path, OpenMode.Write)) + Result rc = BaseFileSystem.OpenFile(out IFile baseFile, path, OpenMode.Write); + if (rc.IsFailure()) return rc; + + using (baseFile) { - baseFile.Write(0, header.ToBytes(false)).ThrowIfFailure(); + rc = baseFile.Write(0, header.ToBytes(false)); + if (rc.IsFailure()) return rc; } + + return Result.Success; } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { - BaseFileSystem.DeleteDirectory(path); + return BaseFileSystem.DeleteDirectory(path); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { - BaseFileSystem.DeleteDirectoryRecursively(path); + return BaseFileSystem.DeleteDirectoryRecursively(path); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { - BaseFileSystem.CleanDirectoryRecursively(path); + return BaseFileSystem.CleanDirectoryRecursively(path); } - public void DeleteFile(string path) + public Result DeleteFile(string path) { - BaseFileSystem.DeleteFile(path); + return BaseFileSystem.DeleteFile(path); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { + directory = default; path = PathTools.Normalize(path); - IDirectory baseDir = BaseFileSystem.OpenDirectory(path, mode); + Result rc = BaseFileSystem.OpenDirectory(out IDirectory baseDir, path, mode); + if (rc.IsFailure()) return rc; - var dir = new AesXtsDirectory(this, baseDir, mode); - return dir; + directory = new AesXtsDirectory(this, baseDir, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; path = PathTools.Normalize(path); - IFile baseFile = BaseFileSystem.OpenFile(path, mode | OpenMode.Read); - var file = new AesXtsFile(mode, baseFile, path, KekSource, ValidationKey, BlockSize); + Result rc = BaseFileSystem.OpenFile(out IFile baseFile, path, mode | OpenMode.Read); + if (rc.IsFailure()) return rc; - file.ToDispose.Add(baseFile); - return file; + var xtsFile = new AesXtsFile(mode, baseFile, path, KekSource, ValidationKey, BlockSize); + + xtsFile.ToDispose.Add(baseFile); + + file = xtsFile; + return Result.Success; } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - BaseFileSystem.RenameDirectory(srcPath, dstPath); + // todo: Return proper result codes + + // Official code procedure: + // Make sure all file headers can be decrypted + // Rename directory to the new path + // Reencrypt file headers with new path + // If no errors, return + // Reencrypt any modified file headers with the old path + // Rename directory to the old path + + Result rc = BaseFileSystem.RenameDirectory(oldPath, newPath); + if (rc.IsFailure()) return rc; try { - RenameDirectoryImpl(srcPath, dstPath, false); + RenameDirectoryImpl(oldPath, newPath, false); } catch (Exception) { - RenameDirectoryImpl(srcPath, dstPath, true); - BaseFileSystem.RenameDirectory(dstPath, srcPath); + RenameDirectoryImpl(oldPath, newPath, true); + BaseFileSystem.RenameDirectory(oldPath, newPath); throw; } + + return Result.Success; } private void RenameDirectoryImpl(string srcDir, string dstDir, bool doRollback) { - IDirectory dir = OpenDirectory(dstDir, OpenDirectoryMode.All); + OpenDirectory(out IDirectory dir, dstDir, OpenDirectoryMode.All); foreach (DirectoryEntry entry in dir.Read()) { @@ -151,56 +177,60 @@ namespace LibHac.Fs } } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - AesXtsFileHeader header = ReadXtsHeader(srcPath, srcPath); + // todo: Return proper result codes - BaseFileSystem.RenameFile(srcPath, dstPath); + AesXtsFileHeader header = ReadXtsHeader(oldPath, oldPath); + + BaseFileSystem.RenameFile(oldPath, newPath); try { - WriteXtsHeader(header, dstPath, dstPath); + WriteXtsHeader(header, newPath, newPath); } catch (Exception) { - BaseFileSystem.RenameFile(dstPath, srcPath); - WriteXtsHeader(header, srcPath, srcPath); + BaseFileSystem.RenameFile(newPath, oldPath); + WriteXtsHeader(header, oldPath, oldPath); throw; } + + return Result.Success; } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { - return BaseFileSystem.GetEntryType(path); + return BaseFileSystem.GetEntryType(out entryType, path); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - return BaseFileSystem.GetFileTimeStampRaw(path); + return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, path); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - return BaseFileSystem.GetFreeSpaceSize(path); + return BaseFileSystem.GetFreeSpaceSize(out freeSpace, path); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return BaseFileSystem.GetTotalSpaceSize(path); + return BaseFileSystem.GetTotalSpaceSize(out totalSpace, path); } - public void Commit() + public Result Commit() { - BaseFileSystem.Commit(); + return BaseFileSystem.Commit(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - BaseFileSystem.QueryEntry(outBuffer, inBuffer, path, queryId); + return BaseFileSystem.QueryEntry(outBuffer, inBuffer, queryId, path); } private AesXtsFileHeader ReadXtsHeader(string filePath, string keyPath) @@ -218,7 +248,12 @@ namespace LibHac.Fs Debug.Assert(PathTools.IsNormalized(filePath.AsSpan())); Debug.Assert(PathTools.IsNormalized(keyPath.AsSpan())); - using (IFile file = BaseFileSystem.OpenFile(filePath, OpenMode.Read)) + header = null; + + Result rc = BaseFileSystem.OpenFile(out IFile file, filePath, OpenMode.Read); + if (rc.IsFailure()) return false; + + using (file) { header = new AesXtsFileHeader(file); @@ -233,7 +268,9 @@ namespace LibHac.Fs header.EncryptHeader(keyPath, KekSource, ValidationKey); - using (IFile file = BaseFileSystem.OpenFile(filePath, OpenMode.ReadWrite)) + BaseFileSystem.OpenFile(out IFile file, filePath, OpenMode.ReadWrite); + + using (file) { file.Write(0, header.ToBytes(false), WriteOption.Flush).ThrowIfFailure(); } diff --git a/src/LibHac/Fs/ConcatenationFile.cs b/src/LibHac/Fs/ConcatenationFile.cs index b50c7594..ad6842a8 100644 --- a/src/LibHac/Fs/ConcatenationFile.cs +++ b/src/LibHac/Fs/ConcatenationFile.cs @@ -130,7 +130,8 @@ namespace LibHac.Fs public override Result SetSize(long size) { - GetSize(out long currentSize).ThrowIfFailure(); + Result rc = GetSize(out long currentSize); + if (rc.IsFailure()) return rc; if (currentSize == size) return Result.Success; @@ -142,7 +143,7 @@ namespace LibHac.Fs IFile currentLastSubFile = Sources[currentSubFileCount - 1]; long newSubFileSize = QuerySubFileSize(currentSubFileCount - 1, size, SubFileSize); - Result rc = currentLastSubFile.SetSize(newSubFileSize); + rc = currentLastSubFile.SetSize(newSubFileSize); if (rc.IsFailure()) return rc; for (int i = currentSubFileCount; i < newSubFileCount; i++) @@ -150,8 +151,13 @@ namespace LibHac.Fs string newSubFilePath = ConcatenationFileSystem.GetSubFilePath(FilePath, i); newSubFileSize = QuerySubFileSize(i, size, SubFileSize); - BaseFileSystem.CreateFile(newSubFilePath, newSubFileSize, CreateFileOptions.None); - Sources.Add(BaseFileSystem.OpenFile(newSubFilePath, Mode)); + rc = BaseFileSystem.CreateFile(newSubFilePath, newSubFileSize, CreateFileOptions.None); + if (rc.IsFailure()) return rc; + + rc = BaseFileSystem.OpenFile(out IFile newSubFile, newSubFilePath, Mode); + if (rc.IsFailure()) return rc; + + Sources.Add(newSubFile); } } else @@ -162,12 +168,14 @@ namespace LibHac.Fs Sources.RemoveAt(i); string subFilePath = ConcatenationFileSystem.GetSubFilePath(FilePath, i); - BaseFileSystem.DeleteFile(subFilePath); + + rc = BaseFileSystem.DeleteFile(subFilePath); + if (rc.IsFailure()) return rc; } long newLastFileSize = QuerySubFileSize(newSubFileCount - 1, size, SubFileSize); - Result rc = Sources[newSubFileCount - 1].SetSize(newLastFileSize); + rc = Sources[newSubFileCount - 1].SetSize(newLastFileSize); if (rc.IsFailure()) return rc; } diff --git a/src/LibHac/Fs/ConcatenationFileSystem.cs b/src/LibHac/Fs/ConcatenationFileSystem.cs index f9df0964..9c2a4471 100644 --- a/src/LibHac/Fs/ConcatenationFileSystem.cs +++ b/src/LibHac/Fs/ConcatenationFileSystem.cs @@ -68,11 +68,19 @@ namespace LibHac.Fs #if CROSS_PLATFORM private bool IsConcatenationFileHeuristic(string path) { - if (BaseFileSystem.GetEntryType(path) != DirectoryEntryType.Directory) return false; + // Check if the path is a directory + Result getTypeResult = BaseFileSystem.GetEntryType(out DirectoryEntryType pathType, path); + if (getTypeResult.IsFailure() || pathType != DirectoryEntryType.Directory) return false; - if (BaseFileSystem.GetEntryType(PathTools.Combine(path, "00")) != DirectoryEntryType.File) return false; + // Check if the directory contains at least one subfile + getTypeResult = BaseFileSystem.GetEntryType(out DirectoryEntryType subFileType, PathTools.Combine(path, "00")); + if (getTypeResult.IsFailure() || subFileType != DirectoryEntryType.File) return false; - if (BaseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directory).GetEntryCount() > 0) return false; + // Make sure the directory contains no subdirectories + Result rc = BaseFileSystem.OpenDirectory(out IDirectory dir, path, OpenDirectoryMode.Directory); + if (rc.IsFailure()) return false; + + if (dir.GetEntryCount() > 0) return false; // Should be enough checks to avoid most false positives. Maybe return true; @@ -91,21 +99,21 @@ namespace LibHac.Fs BaseFileSystem.SetFileAttributes(path, attributes); } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { path = PathTools.Normalize(path); string parent = PathTools.GetParentDirectory(path); if (IsConcatenationFile(parent)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, - "Cannot create a directory inside of a concatenation file"); + // Cannot create a directory inside of a concatenation file + return ResultFs.PathNotFound.Log(); } - BaseFileSystem.CreateDirectory(path); + return BaseFileSystem.CreateDirectory(path); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { path = PathTools.Normalize(path); @@ -113,8 +121,7 @@ namespace LibHac.Fs if (!options.HasFlag(CreateFileOptions.CreateConcatenationFile)) { - BaseFileSystem.CreateFile(path, size, newOptions); - return; + return BaseFileSystem.CreateFile(path, size, newOptions); } // A concatenation file directory can't contain normal files @@ -122,11 +129,13 @@ namespace LibHac.Fs if (IsConcatenationFile(parentDir)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, - "Cannot create a concatenation file inside of a concatenation file"); + // Cannot create a file inside of a concatenation file + return ResultFs.PathNotFound.Log(); } - BaseFileSystem.CreateDirectory(path); + Result rc = BaseFileSystem.CreateDirectory(path); + if (rc.IsFailure()) return rc; + SetConcatenationFileAttribute(path); long remaining = size; @@ -136,82 +145,95 @@ namespace LibHac.Fs long fileSize = Math.Min(SubFileSize, remaining); string fileName = GetSubFilePath(path, i); - BaseFileSystem.CreateFile(fileName, fileSize, CreateFileOptions.None); + Result createSubFileResult = BaseFileSystem.CreateFile(fileName, fileSize, CreateFileOptions.None); + + if (createSubFileResult.IsFailure()) + { + BaseFileSystem.DeleteDirectoryRecursively(path); + return createSubFileResult; + } remaining -= fileSize; } + + return Result.Success; } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { path = PathTools.Normalize(path); if (IsConcatenationFile(path)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - BaseFileSystem.DeleteDirectory(path); + return BaseFileSystem.DeleteDirectory(path); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { path = PathTools.Normalize(path); - if (IsConcatenationFile(path)) ThrowHelper.ThrowResult(ResultFs.PathNotFound); + if (IsConcatenationFile(path)) return ResultFs.PathNotFound.Log(); - BaseFileSystem.DeleteDirectoryRecursively(path); + return BaseFileSystem.DeleteDirectoryRecursively(path); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { path = PathTools.Normalize(path); - if (IsConcatenationFile(path)) ThrowHelper.ThrowResult(ResultFs.PathNotFound); + if (IsConcatenationFile(path)) return ResultFs.PathNotFound.Log(); - BaseFileSystem.CleanDirectoryRecursively(path); + return BaseFileSystem.CleanDirectoryRecursively(path); } - public void DeleteFile(string path) + public Result DeleteFile(string path) { path = PathTools.Normalize(path); if (!IsConcatenationFile(path)) { - BaseFileSystem.DeleteFile(path); + return BaseFileSystem.DeleteFile(path); } int count = GetSubFileCount(path); for (int i = 0; i < count; i++) { - BaseFileSystem.DeleteFile(GetSubFilePath(path, i)); + Result rc = BaseFileSystem.DeleteFile(GetSubFilePath(path, i)); + if (rc.IsFailure()) return rc; } - BaseFileSystem.DeleteDirectory(path); + return BaseFileSystem.DeleteDirectory(path); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { + directory = default; path = PathTools.Normalize(path); if (IsConcatenationFile(path)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - IDirectory parentDir = BaseFileSystem.OpenDirectory(path, OpenDirectoryMode.All); - var dir = new ConcatenationDirectory(this, parentDir, mode); - return dir; + Result rc = BaseFileSystem.OpenDirectory(out IDirectory parentDir, path, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + directory = new ConcatenationDirectory(this, parentDir, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; path = PathTools.Normalize(path); if (!IsConcatenationFile(path)) { - return BaseFileSystem.OpenFile(path, mode); + return BaseFileSystem.OpenFile(out file, path, mode); } int fileCount = GetSubFileCount(path); @@ -221,75 +243,85 @@ namespace LibHac.Fs for (int i = 0; i < fileCount; i++) { string filePath = GetSubFilePath(path, i); - IFile file = BaseFileSystem.OpenFile(filePath, mode); - files.Add(file); + + Result rc = BaseFileSystem.OpenFile(out IFile subFile, filePath, mode); + if (rc.IsFailure()) return rc; + + files.Add(subFile); } - return new ConcatenationFile(BaseFileSystem, path, files, SubFileSize, mode); + file = new ConcatenationFile(BaseFileSystem, path, files, SubFileSize, mode); + return Result.Success; } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - if (IsConcatenationFile(srcPath)) + if (IsConcatenationFile(oldPath)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - BaseFileSystem.RenameDirectory(srcPath, dstPath); + return BaseFileSystem.RenameDirectory(oldPath, newPath); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - if (IsConcatenationFile(srcPath)) + if (IsConcatenationFile(oldPath)) { - BaseFileSystem.RenameDirectory(srcPath, dstPath); + return BaseFileSystem.RenameDirectory(oldPath, newPath); } else { - BaseFileSystem.RenameFile(srcPath, dstPath); + return BaseFileSystem.RenameFile(oldPath, newPath); } } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); - if (IsConcatenationFile(path)) return DirectoryEntryType.File; + if (IsConcatenationFile(path)) + { + entryType = DirectoryEntryType.File; + return Result.Success; + } - return BaseFileSystem.GetEntryType(path); + return BaseFileSystem.GetEntryType(out entryType, path); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - return BaseFileSystem.GetFreeSpaceSize(path); + return BaseFileSystem.GetFreeSpaceSize(out freeSpace, path); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return BaseFileSystem.GetTotalSpaceSize(path); + return BaseFileSystem.GetTotalSpaceSize(out totalSpace, path); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - return BaseFileSystem.GetFileTimeStampRaw(path); + return BaseFileSystem.GetFileTimeStampRaw(out timeStamp, path); } - public void Commit() + public Result Commit() { - BaseFileSystem.Commit(); + return BaseFileSystem.Commit(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - if (queryId != QueryId.MakeConcatFile) ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationInConcatFsQueryEntry); + if (queryId != QueryId.MakeConcatFile) return ResultFs.UnsupportedOperationInConcatFsQueryEntry.Log(); SetConcatenationFileAttribute(path); + + return Result.Success; } private int GetSubFileCount(string dirPath) diff --git a/src/LibHac/Fs/DirectorySaveDataFileSystem.cs b/src/LibHac/Fs/DirectorySaveDataFileSystem.cs index 3fe9f866..9e4aca7e 100644 --- a/src/LibHac/Fs/DirectorySaveDataFileSystem.cs +++ b/src/LibHac/Fs/DirectorySaveDataFileSystem.cs @@ -33,162 +33,170 @@ namespace LibHac.Fs } } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.CreateDirectory(fullPath); + return BaseFs.CreateDirectory(fullPath); } } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.CreateFile(fullPath, size, options); + return BaseFs.CreateFile(fullPath, size, options); } } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.DeleteDirectory(fullPath); + return BaseFs.DeleteDirectory(fullPath); } } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.DeleteDirectoryRecursively(fullPath); + return BaseFs.DeleteDirectoryRecursively(fullPath); } } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.CleanDirectoryRecursively(fullPath); + return BaseFs.CleanDirectoryRecursively(fullPath); } } - public void DeleteFile(string path) + public Result DeleteFile(string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - BaseFs.DeleteFile(fullPath); + return BaseFs.DeleteFile(fullPath); } } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - return BaseFs.OpenDirectory(fullPath, mode); + return BaseFs.OpenDirectory(out directory, fullPath, mode); } } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - IFile baseFile = BaseFs.OpenFile(fullPath, mode); - var file = new DirectorySaveDataFile(this, baseFile); + Result rc = BaseFs.OpenFile(out IFile baseFile, fullPath, mode); + if (rc.IsFailure()) return rc; + + file = new DirectorySaveDataFile(this, baseFile); if (mode.HasFlag(OpenMode.Write)) { OpenWritableFileCount++; } - return file; + return Result.Success; } } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - string fullSrcPath = GetFullPath(PathTools.Normalize(srcPath)); - string fullDstPath = GetFullPath(PathTools.Normalize(dstPath)); + string fullOldPath = GetFullPath(PathTools.Normalize(oldPath)); + string fullNewPath = GetFullPath(PathTools.Normalize(newPath)); lock (Locker) { - BaseFs.RenameDirectory(fullSrcPath, fullDstPath); + return BaseFs.RenameDirectory(fullOldPath, fullNewPath); } } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - string fullSrcPath = GetFullPath(PathTools.Normalize(srcPath)); - string fullDstPath = GetFullPath(PathTools.Normalize(dstPath)); + string fullOldPath = GetFullPath(PathTools.Normalize(oldPath)); + string fullNewPath = GetFullPath(PathTools.Normalize(newPath)); lock (Locker) { - BaseFs.RenameFile(fullSrcPath, fullDstPath); + return BaseFs.RenameFile(fullOldPath, fullNewPath); } } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { string fullPath = GetFullPath(PathTools.Normalize(path)); lock (Locker) { - return BaseFs.GetEntryType(fullPath); + return BaseFs.GetEntryType(out entryType, fullPath); } } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + freeSpace = default; + return ResultFs.NotImplemented.Log(); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + totalSpace = default; + return ResultFs.NotImplemented.Log(); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + timeStamp = default; + return ResultFs.NotImplemented.Log(); } - public void Commit() + public Result Commit() { - if (OpenWritableFileCount > 0) + lock (Locker) { - ThrowHelper.ThrowResult(ResultFs.WritableFileOpen, - "All files must be closed before commiting save data."); + if (OpenWritableFileCount > 0) + { + // All files must be closed before commiting save data. + return ResultFs.WritableFileOpen.Log(); + } + + Result rc = SynchronizeDirectory(SyncDir, WorkingDir); + if (rc.IsFailure()) return rc; + + rc = BaseFs.DeleteDirectoryRecursively(CommittedDir); + if (rc.IsFailure()) return rc; + + return BaseFs.RenameDirectory(SyncDir, CommittedDir); } - - SynchronizeDirectory(SyncDir, WorkingDir); - - BaseFs.DeleteDirectoryRecursively(CommittedDir); - - BaseFs.RenameDirectory(SyncDir, CommittedDir); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); + return ResultFs.NotImplemented.Log(); } private string GetFullPath(string path) @@ -196,19 +204,21 @@ namespace LibHac.Fs return PathTools.Normalize(PathTools.Combine(WorkingDir, path)); } - private void SynchronizeDirectory(string dest, string src) + private Result SynchronizeDirectory(string dest, string src) { - if (BaseFs.DirectoryExists(dest)) - { - BaseFs.DeleteDirectoryRecursively(dest); - } + Result rc = BaseFs.DeleteDirectoryRecursively(dest); + if (rc.IsFailure() && rc != ResultFs.PathNotFound) return rc; - BaseFs.CreateDirectory(dest); + rc = BaseFs.CreateDirectory(dest); + if (rc.IsFailure()) return rc; - IDirectory sourceDir = BaseFs.OpenDirectory(src, OpenDirectoryMode.All); - IDirectory destDir = BaseFs.OpenDirectory(dest, OpenDirectoryMode.All); + rc = BaseFs.OpenDirectory(out IDirectory sourceDir, src, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; - sourceDir.CopyDirectory(destDir); + rc = BaseFs.OpenDirectory(out IDirectory destDir, dest, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + return sourceDir.CopyDirectory(destDir); } internal void NotifyCloseWritableFile() diff --git a/src/LibHac/Fs/FileSystemExtensions.cs b/src/LibHac/Fs/FileSystemExtensions.cs index 22643be6..50997c48 100644 --- a/src/LibHac/Fs/FileSystemExtensions.cs +++ b/src/LibHac/Fs/FileSystemExtensions.cs @@ -7,10 +7,11 @@ namespace LibHac.Fs { public static class FileSystemExtensions { - public static void CopyDirectory(this IDirectory source, IDirectory dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) + public static Result CopyDirectory(this IDirectory source, IDirectory dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) { IFileSystem sourceFs = source.ParentFileSystem; IFileSystem destFs = dest.ParentFileSystem; + Result rc; foreach (DirectoryEntry entry in source.Read()) { @@ -20,32 +21,47 @@ namespace LibHac.Fs if (entry.Type == DirectoryEntryType.Directory) { destFs.EnsureDirectoryExists(subDstPath); - IDirectory subSrcDir = sourceFs.OpenDirectory(subSrcPath, OpenDirectoryMode.All); - IDirectory subDstDir = destFs.OpenDirectory(subDstPath, OpenDirectoryMode.All); - subSrcDir.CopyDirectory(subDstDir, logger, options); + rc = sourceFs.OpenDirectory(out IDirectory subSrcDir, subSrcPath, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + rc = destFs.OpenDirectory(out IDirectory subDstDir, subDstPath, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + rc = subSrcDir.CopyDirectory(subDstDir, logger, options); + if (rc.IsFailure()) return rc; } if (entry.Type == DirectoryEntryType.File) { destFs.CreateOrOverwriteFile(subDstPath, entry.Size, options); - using (IFile srcFile = sourceFs.OpenFile(subSrcPath, OpenMode.Read)) - using (IFile dstFile = destFs.OpenFile(subDstPath, OpenMode.Write | OpenMode.AllowAppend)) + rc = sourceFs.OpenFile(out IFile srcFile, subSrcPath, OpenMode.Read); + if (rc.IsFailure()) return rc; + + using (srcFile) { - logger?.LogMessage(subSrcPath); - srcFile.CopyTo(dstFile, logger); + rc = destFs.OpenFile(out IFile dstFile, subDstPath, OpenMode.Write | OpenMode.AllowAppend); + if (rc.IsFailure()) return rc; + + using (dstFile) + { + logger?.LogMessage(subSrcPath); + srcFile.CopyTo(dstFile, logger); + } } } } + + return Result.Success; } public static void CopyFileSystem(this IFileSystem source, IFileSystem dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) { - IDirectory sourceRoot = source.OpenDirectory("/", OpenDirectoryMode.All); - IDirectory destRoot = dest.OpenDirectory("/", OpenDirectoryMode.All); + source.OpenDirectory(out IDirectory sourceRoot, "/", OpenDirectoryMode.All).ThrowIfFailure(); + dest.OpenDirectory(out IDirectory destRoot, "/", OpenDirectoryMode.All).ThrowIfFailure(); - sourceRoot.CopyDirectory(destRoot, logger, options); + sourceRoot.CopyDirectory(destRoot, logger, options).ThrowIfFailure(); } public static void Extract(this IFileSystem source, string destinationPath, IProgressReport logger = null) @@ -67,7 +83,9 @@ namespace LibHac.Fs public static IEnumerable EnumerateEntries(this IFileSystem fileSystem, string searchPattern, SearchOptions searchOptions) { - return fileSystem.OpenDirectory("/", OpenDirectoryMode.All).EnumerateEntries(searchPattern, searchOptions); + fileSystem.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.All).ThrowIfFailure(); + + return rootDir.EnumerateEntries(searchPattern, searchOptions); } public static IEnumerable EnumerateEntries(this IDirectory directory) @@ -91,7 +109,7 @@ namespace LibHac.Fs if (entry.Type != DirectoryEntryType.Directory || !recurse) continue; - IDirectory subDir = fs.OpenDirectory(PathTools.Combine(directory.FullPath, entry.Name), OpenDirectoryMode.All); + fs.OpenDirectory(out IDirectory subDir, PathTools.Combine(directory.FullPath, entry.Name), OpenDirectoryMode.All).ThrowIfFailure(); foreach (DirectoryEntry subEntry in subDir.EnumerateEntries(searchPattern, searchOptions)) { @@ -139,7 +157,9 @@ namespace LibHac.Fs public static int GetEntryCount(this IFileSystem fs, OpenDirectoryMode mode) { - return fs.OpenDirectory("/", OpenDirectoryMode.All).GetEntryCountRecursive(mode); + fs.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.All).ThrowIfFailure(); + + return rootDir.GetEntryCountRecursive(mode); } public static int GetEntryCountRecursive(this IDirectory directory, OpenDirectoryMode mode) @@ -171,7 +191,7 @@ namespace LibHac.Fs public static void SetConcatenationFileAttribute(this IFileSystem fs, string path) { - fs.QueryEntry(Span.Empty, Span.Empty, path, QueryId.MakeConcatFile); + fs.QueryEntry(Span.Empty, Span.Empty, QueryId.MakeConcatFile, path); } public static void CleanDirectoryRecursivelyGeneric(IDirectory directory) @@ -184,7 +204,7 @@ namespace LibHac.Fs if (entry.Type == DirectoryEntryType.Directory) { - IDirectory subDir = fs.OpenDirectory(subPath, OpenDirectoryMode.All); + fs.OpenDirectory(out IDirectory subDir, subPath, OpenDirectoryMode.All).ThrowIfFailure(); CleanDirectoryRecursivelyGeneric(subDir); fs.DeleteDirectory(subPath); @@ -208,12 +228,16 @@ namespace LibHac.Fs public static bool DirectoryExists(this IFileSystem fs, string path) { - return fs.GetEntryType(path) == DirectoryEntryType.Directory; + Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + + return (rc.IsSuccess() && type == DirectoryEntryType.Directory); } public static bool FileExists(this IFileSystem fs, string path) { - return fs.GetEntryType(path) == DirectoryEntryType.File; + Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + + return (rc.IsSuccess() && type == DirectoryEntryType.File); } public static void EnsureDirectoryExists(this IFileSystem fs, string path) diff --git a/src/LibHac/Fs/IFileSystem.cs b/src/LibHac/Fs/IFileSystem.cs index dc62fb24..0703baf9 100644 --- a/src/LibHac/Fs/IFileSystem.cs +++ b/src/LibHac/Fs/IFileSystem.cs @@ -11,14 +11,15 @@ namespace LibHac.Fs /// Creates all directories and subdirectories in the specified path unless they already exist. /// /// The full path of the directory to create. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The parent directory of the specified path does not exist: /// Specified path already exists as either a file or directory: /// Insufficient free space to create the directory: /// - void CreateDirectory(string path); + Result CreateDirectory(string path); /// /// Creates or overwrites a file at the specified path. @@ -27,162 +28,177 @@ namespace LibHac.Fs /// The initial size of the created file. /// Flags to control how the file is created. /// Should usually be + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The parent directory of the specified path does not exist: /// Specified path already exists as either a file or directory: /// Insufficient free space to create the file: /// - void CreateFile(string path, long size, CreateFileOptions options); + Result CreateFile(string path, long size, CreateFileOptions options); /// /// Deletes the specified directory. /// /// The full path of the directory to delete. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a file: /// The specified directory is not empty: /// - void DeleteDirectory(string path); + Result DeleteDirectory(string path); /// /// Deletes the specified directory and any subdirectories and files in the directory. /// /// The full path of the directory to delete. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a file: /// - void DeleteDirectoryRecursively(string path); + Result DeleteDirectoryRecursively(string path); /// /// Deletes any subdirectories and files in the specified directory. /// /// The full path of the directory to clean. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a file: /// - void CleanDirectoryRecursively(string path); + Result CleanDirectoryRecursively(string path); /// /// Deletes the specified file. /// /// The full path of the file to delete. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a directory: /// - void DeleteFile(string path); + Result DeleteFile(string path); /// /// Creates an instance for enumerating the specified directory. /// + /// If the operation returns successfully, + /// An instance for the specified directory. /// The directory's full path. /// Specifies which sub-entries should be enumerated. - /// An instance for the specified directory. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a file: /// - IDirectory OpenDirectory(string path, OpenDirectoryMode mode); + Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode); /// /// Opens an instance for the specified path. /// + /// If the operation returns successfully, + /// An instance for the specified path. /// The full path of the file to open. /// Specifies the access permissions of the created . - /// An instance for the specified path. + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist or is a directory: /// - IFile OpenFile(string path, OpenMode mode); + Result OpenFile(out IFile file, string path, OpenMode mode); /// /// Renames or moves a directory to a new location. /// - /// The full path of the directory to rename. - /// The new full path of the directory. - /// An instance for the specified path. + /// The full path of the directory to rename. + /// The new full path of the directory. + /// The of the requested operation. /// - /// If and are the same, this function does nothing and returns successfully. - /// A will be thrown with the given under the following conditions: + /// If and are the same, this function does nothing and returns . + /// The following codes may be returned under certain conditions: /// - /// does not exist or is a file: - /// 's parent directory does not exist: - /// already exists as either a file or directory: - /// Either or is a subpath of the other: + /// does not exist or is a file: + /// 's parent directory does not exist: + /// already exists as either a file or directory: + /// Either or is a subpath of the other: /// - void RenameDirectory(string srcPath, string dstPath); + Result RenameDirectory(string oldPath, string newPath); /// /// Renames or moves a file to a new location. /// - /// The full path of the file to rename. - /// The new full path of the file. + /// The full path of the file to rename. + /// The new full path of the file. + /// The of the requested operation. /// - /// If and are the same, this function does nothing and returns successfully. - /// A will be thrown with the given under the following conditions: + /// If and are the same, this function does nothing and returns successfully. + /// The following codes may be returned under certain conditions: /// - /// does not exist or is a directory: - /// 's parent directory does not exist: - /// already exists as either a file or directory: + /// does not exist or is a directory: + /// 's parent directory does not exist: + /// already exists as either a file or directory: /// - void RenameFile(string srcPath, string dstPath); + Result RenameFile(string oldPath, string newPath); /// /// Determines whether the specified path is a file or directory, or does not exist. /// + /// If the operation returns successfully, the of the file. /// The full path to check. - /// The of the file. + /// The of the requested operation. /// /// This function operates slightly differently than it does in Horizon OS. /// Instead of returning when an entry is missing, /// the function will return . /// - DirectoryEntryType GetEntryType(string path); + Result GetEntryType(out DirectoryEntryType entryType, string path); /// /// Gets the amount of available free space on a drive, in bytes. /// + /// 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 amount of free space available on the drive, in bytes. - long GetFreeSpaceSize(string path); + /// The of the requested operation. + Result GetFreeSpaceSize(out long freeSpace, string path); /// /// Gets the total size of storage space on a drive, in bytes. /// + /// 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 total size of the drive, in bytes. - long GetTotalSpaceSize(string path); + /// The of the requested operation. + Result GetTotalSpaceSize(out long totalSpace, string path); /// /// Gets the creation, last accessed, and last modified timestamps of a file or directory. /// + /// If the operation returns successfully, the timestamps for the specified file or directory. + /// These value are expressed as Unix timestamps. /// The path of the file or directory. - /// The timestamps for the specified file or directory. - /// This value is expressed as a Unix timestamp + /// The of the requested operation. /// - /// A will be thrown with the given under the following conditions: + /// The following codes may be returned under certain conditions: /// /// The specified path does not exist: /// - FileTimeStampRaw GetFileTimeStampRaw(string path); + Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path); /// /// Commits any changes to a transactional file system. /// Does nothing if called on a non-transactional file system. /// - void Commit(); + /// The of the requested operation. + Result Commit(); /// /// Performs a query on the specified file. @@ -193,9 +209,10 @@ namespace LibHac.Fs /// May be unused depending on the query type. /// The buffer for sending data to the query operation. /// May be unused depending on the query type. - /// The full path of the file to query. /// The type of query to perform. - void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId); + /// The full path of the file to query. + /// The of the requested operation. + Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path); } /// diff --git a/src/LibHac/Fs/LayeredFileSystem.cs b/src/LibHac/Fs/LayeredFileSystem.cs index d0e23930..500dde46 100644 --- a/src/LibHac/Fs/LayeredFileSystem.cs +++ b/src/LibHac/Fs/LayeredFileSystem.cs @@ -12,122 +12,138 @@ namespace LibHac.Fs Sources.AddRange(sourceFileSystems); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { + directory = default; path = PathTools.Normalize(path); var dirs = new List(); foreach (IFileSystem fs in Sources) { - DirectoryEntryType type = fs.GetEntryType(path); + Result rc = fs.GetEntryType(out DirectoryEntryType entryType, path); + if (rc.IsFailure()) return rc; - if (type == DirectoryEntryType.File && dirs.Count == 0) + if (entryType == DirectoryEntryType.File && dirs.Count == 0) { ThrowHelper.ThrowResult(ResultFs.PathNotFound); } - if (fs.GetEntryType(path) == DirectoryEntryType.Directory) + if (entryType == DirectoryEntryType.Directory) { - dirs.Add(fs.OpenDirectory(path, mode)); + rc = fs.OpenDirectory(out IDirectory subDirectory, path, mode); + if (rc.IsFailure()) return rc; + + dirs.Add(subDirectory); } } - var dir = new LayeredFileSystemDirectory(this, dirs, path, mode); - - return dir; + directory = new LayeredFileSystemDirectory(this, dirs, path, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; path = PathTools.Normalize(path); foreach (IFileSystem fs in Sources) { - DirectoryEntryType type = fs.GetEntryType(path); + Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + if (rc.IsFailure()) return rc; if (type == DirectoryEntryType.File) { - return fs.OpenFile(path, mode); + return fs.OpenFile(out file, path, mode); } if (type == DirectoryEntryType.Directory) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } } - ThrowHelper.ThrowResult(ResultFs.PathNotFound); - return default; + return ResultFs.PathNotFound.Log(); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); foreach (IFileSystem fs in Sources) { - DirectoryEntryType type = fs.GetEntryType(path); + Result getEntryResult = fs.GetEntryType(out DirectoryEntryType type, path); - if (type != DirectoryEntryType.NotFound) return type; - } - - return DirectoryEntryType.NotFound; - } - - public FileTimeStampRaw GetFileTimeStampRaw(string path) - { - path = PathTools.Normalize(path); - - foreach (IFileSystem fs in Sources) - { - if (fs.GetEntryType(path) != DirectoryEntryType.NotFound) + if (getEntryResult.IsSuccess() && type != DirectoryEntryType.NotFound) { - return fs.GetFileTimeStampRaw(path); + entryType = type; + return Result.Success; } } - ThrowHelper.ThrowResult(ResultFs.PathNotFound); - return default; + entryType = DirectoryEntryType.NotFound; + return ResultFs.PathNotFound.Log(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { path = PathTools.Normalize(path); foreach (IFileSystem fs in Sources) { - if (fs.GetEntryType(path) != DirectoryEntryType.NotFound) + Result getEntryResult = fs.GetEntryType(out DirectoryEntryType type, path); + + if (getEntryResult.IsSuccess() && type != DirectoryEntryType.NotFound) { - fs.QueryEntry(outBuffer, inBuffer, path, queryId); - return; + return fs.GetFileTimeStampRaw(out timeStamp, path); } } - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + timeStamp = default; + return ResultFs.PathNotFound.Log(); } - public void Commit() { } - - public void CreateDirectory(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void CreateFile(string path, long size, CreateFileOptions options) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void DeleteDirectory(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void DeleteDirectoryRecursively(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void CleanDirectoryRecursively(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void DeleteFile(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void RenameDirectory(string srcPath, string dstPath) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - public void RenameFile(string srcPath, string dstPath) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - - public long GetFreeSpaceSize(string path) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - return default; + path = PathTools.Normalize(path); + + foreach (IFileSystem fs in Sources) + { + Result getEntryResult = fs.GetEntryType(out DirectoryEntryType type, path); + + if (getEntryResult.IsSuccess() && type != DirectoryEntryType.NotFound) + { + return fs.QueryEntry(outBuffer, inBuffer, queryId, path); + } + } + + return ResultFs.PathNotFound.Log(); } - public long GetTotalSpaceSize(string path) + public Result Commit() { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); - return default; + return Result.Success; + } + + public Result CreateDirectory(string path) => ResultFs.UnsupportedOperation.Log(); + public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperation.Log(); + public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperation.Log(); + public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperation.Log(); + public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperation.Log(); + public Result DeleteFile(string path) => ResultFs.UnsupportedOperation.Log(); + public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log(); + public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperation.Log(); + + public Result GetFreeSpaceSize(out long freeSpace, string path) + { + freeSpace = default; + return ResultFs.UnsupportedOperation.Log(); + } + + public Result GetTotalSpaceSize(out long totalSpace, string path) + { + totalSpace = default; + return ResultFs.UnsupportedOperation.Log(); } } } diff --git a/src/LibHac/Fs/LocalFileSystem.cs b/src/LibHac/Fs/LocalFileSystem.cs index 048e5c71..33c4b28b 100644 --- a/src/LibHac/Fs/LocalFileSystem.cs +++ b/src/LibHac/Fs/LocalFileSystem.cs @@ -58,7 +58,7 @@ namespace LibHac.Fs return GetSizeInternal(info); } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); @@ -66,18 +66,18 @@ namespace LibHac.Fs if (dir.Exists) { - ThrowHelper.ThrowResult(ResultFs.PathAlreadyExists); + return ResultFs.PathAlreadyExists.Log(); } if (dir.Parent?.Exists != true) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - CreateDirInternal(dir); + return CreateDirInternal(dir); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); @@ -85,121 +85,140 @@ namespace LibHac.Fs if (file.Exists) { - ThrowHelper.ThrowResult(ResultFs.PathAlreadyExists); + return ResultFs.PathAlreadyExists.Log(); } if (file.Directory?.Exists != true) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - using (FileStream stream = CreateFileInternal(file)) + Result rc = CreateFileInternal(out FileStream stream, file); + + using (stream) { - SetStreamLengthInternal(stream, size); + if (rc.IsFailure()) return rc; + + return SetStreamLengthInternal(stream, size); } } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); DirectoryInfo dir = GetDirInfo(localPath); - DeleteDirectoryInternal(dir, false); + return DeleteDirectoryInternal(dir, false); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); DirectoryInfo dir = GetDirInfo(localPath); - DeleteDirectoryInternal(dir, true); + return DeleteDirectoryInternal(dir, true); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); foreach (string file in Directory.EnumerateFiles(localPath)) { - DeleteFileInternal(GetFileInfo(file)); + Result rc = DeleteFileInternal(GetFileInfo(file)); + if (rc.IsFailure()) return rc; } foreach (string dir in Directory.EnumerateDirectories(localPath)) { - DeleteDirectoryInternal(GetDirInfo(dir), true); + Result rc = DeleteDirectoryInternal(GetDirInfo(dir), true); + if (rc.IsFailure()) return rc; } + + return Result.Success; } - public void DeleteFile(string path) + public Result DeleteFile(string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); FileInfo file = GetFileInfo(localPath); - DeleteFileInternal(file); + return DeleteFileInternal(file); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { + // Getting the local path is done in the LocalDirectory constructor path = PathTools.Normalize(path); + directory = default; - if (GetEntryType(path) == DirectoryEntryType.File) + Result rc = GetEntryType(out DirectoryEntryType entryType, path); + if (rc.IsFailure()) return rc; + + if (entryType == DirectoryEntryType.File) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - return new LocalDirectory(this, path, mode); + directory = new LocalDirectory(this, path, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; string localPath = ResolveLocalPath(PathTools.Normalize(path)); - if (GetEntryType(path) == DirectoryEntryType.Directory) + Result rc = GetEntryType(out DirectoryEntryType entryType, path); + if (rc.IsFailure()) return rc; + + if (entryType == DirectoryEntryType.Directory) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - return new LocalFile(localPath, mode); + file = new LocalFile(localPath, mode); + return Result.Success; } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); // Official FS behavior is to do nothing in this case - if (srcPath == dstPath) return; + if (oldPath == newPath) return Result.Success; // FS does the subpath check before verifying the path exists - if (PathTools.IsSubPath(srcPath.AsSpan(), dstPath.AsSpan())) + if (PathTools.IsSubPath(oldPath.AsSpan(), newPath.AsSpan())) { ThrowHelper.ThrowResult(ResultFs.DestinationIsSubPathOfSource); } - DirectoryInfo srcDir = GetDirInfo(ResolveLocalPath(srcPath)); - DirectoryInfo dstDir = GetDirInfo(ResolveLocalPath(dstPath)); + DirectoryInfo srcDir = GetDirInfo(ResolveLocalPath(oldPath)); + DirectoryInfo dstDir = GetDirInfo(ResolveLocalPath(newPath)); - RenameDirInternal(srcDir, dstDir); + return RenameDirInternal(srcDir, dstDir); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - string srcLocalPath = ResolveLocalPath(PathTools.Normalize(srcPath)); - string dstLocalPath = ResolveLocalPath(PathTools.Normalize(dstPath)); + string srcLocalPath = ResolveLocalPath(PathTools.Normalize(oldPath)); + string dstLocalPath = ResolveLocalPath(PathTools.Normalize(newPath)); // Official FS behavior is to do nothing in this case - if (srcLocalPath == dstLocalPath) return; + if (srcLocalPath == dstLocalPath) return Result.Success; FileInfo srcFile = GetFileInfo(srcLocalPath); FileInfo dstFile = GetFileInfo(dstLocalPath); - RenameFileInternal(srcFile, dstFile); + return RenameFileInternal(srcFile, dstFile); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { string localPath = ResolveLocalPath(PathTools.Normalize(path)); @@ -207,48 +226,57 @@ namespace LibHac.Fs if (dir.Exists) { - return DirectoryEntryType.Directory; + entryType = DirectoryEntryType.Directory; + return Result.Success; } FileInfo file = GetFileInfo(localPath); if (file.Exists) { - return DirectoryEntryType.File; + entryType = DirectoryEntryType.File; + return Result.Success; } - return DirectoryEntryType.NotFound; + entryType = DirectoryEntryType.NotFound; + return ResultFs.PathNotFound.Log(); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { + timeStamp = default; string localPath = ResolveLocalPath(PathTools.Normalize(path)); - if (!GetFileInfo(localPath).Exists) ThrowHelper.ThrowResult(ResultFs.PathNotFound); - - FileTimeStampRaw timeStamp = default; + if (!GetFileInfo(localPath).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(); - return timeStamp; + return Result.Success; } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - return new DriveInfo(BasePath).AvailableFreeSpace; + freeSpace = new DriveInfo(BasePath).AvailableFreeSpace; + return Result.Success; } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return new DriveInfo(BasePath).TotalSize; + totalSpace = new DriveInfo(BasePath).TotalSize; + return Result.Success; } - public void Commit() { } + public Result Commit() + { + return Result.Success; + } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperation); + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + { + return ResultFs.UnsupportedOperation.Log(); + } private static long GetSizeInternal(FileInfo file) { @@ -268,35 +296,36 @@ namespace LibHac.Fs } } - private static FileStream CreateFileInternal(FileInfo file) + private static Result CreateFileInternal(out FileStream file, FileInfo fileInfo) { + file = default; + try { - return new FileStream(file.FullName, FileMode.CreateNew, FileAccess.ReadWrite); + file = new FileStream(fileInfo.FullName, FileMode.CreateNew, FileAccess.ReadWrite); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) { - ThrowHelper.ThrowResult(ResultFs.InsufficientFreeSpace, ex); - throw; + return ResultFs.InsufficientFreeSpace.Log(); } catch (IOException ex) when (ex.HResult == ErrorFileExists) { - ThrowHelper.ThrowResult(ResultFs.PathAlreadyExists, ex); - throw; + return ResultFs.PathAlreadyExists.Log(); } catch (Exception ex) when (ex is SecurityException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } + + return Result.Success; } - private static void SetStreamLengthInternal(Stream stream, long size) + private static Result SetStreamLengthInternal(Stream stream, long size) { try { @@ -304,128 +333,131 @@ namespace LibHac.Fs } catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) { - ThrowHelper.ThrowResult(ResultFs.InsufficientFreeSpace, ex); - throw; + return ResultFs.InsufficientFreeSpace.Log(); } + + return Result.Success; } - private static void DeleteDirectoryInternal(DirectoryInfo dir, bool recursive) + private static Result DeleteDirectoryInternal(DirectoryInfo dir, bool recursive) { - if (!dir.Exists) ThrowHelper.ThrowResult(ResultFs.PathNotFound); + if (!dir.Exists) return ResultFs.PathNotFound.Log(); try { dir.Delete(recursive); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (IOException ex) when (ex.HResult == ErrorDirNotEmpty) { - ThrowHelper.ThrowResult(ResultFs.DirectoryNotEmpty, ex); - throw; + return ResultFs.DirectoryNotEmpty.Log(); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } EnsureDeleted(dir); + + return Result.Success; } - private static void DeleteFileInternal(FileInfo file) + private static Result DeleteFileInternal(FileInfo file) { - if (!file.Exists) ThrowHelper.ThrowResult(ResultFs.PathNotFound); + if (!file.Exists) return ResultFs.PathNotFound.Log(); try { file.Delete(); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (IOException ex) when (ex.HResult == ErrorDirNotEmpty) { - ThrowHelper.ThrowResult(ResultFs.DirectoryNotEmpty, ex); - throw; + return ResultFs.DirectoryNotEmpty.Log(); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } EnsureDeleted(file); + + return Result.Success; } - private static void CreateDirInternal(DirectoryInfo dir) + private static Result CreateDirInternal(DirectoryInfo dir) { try { dir.Create(); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (IOException ex) when (ex.HResult == ErrorDiskFull || ex.HResult == ErrorHandleDiskFull) { - ThrowHelper.ThrowResult(ResultFs.InsufficientFreeSpace, ex); - throw; + return ResultFs.InsufficientFreeSpace.Log(); } catch (Exception ex) when (ex is SecurityException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } + + return Result.Success; } - private static void RenameDirInternal(DirectoryInfo source, DirectoryInfo dest) + private static Result RenameDirInternal(DirectoryInfo source, DirectoryInfo dest) { - if (!source.Exists) ThrowHelper.ThrowResult(ResultFs.PathNotFound); - if (dest.Exists) ThrowHelper.ThrowResult(ResultFs.PathAlreadyExists); + if (!source.Exists) return ResultFs.PathNotFound.Log(); + if (dest.Exists) return ResultFs.PathAlreadyExists.Log(); try { source.MoveTo(dest.FullName); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } + + return Result.Success; } - private static void RenameFileInternal(FileInfo source, FileInfo dest) + private static Result RenameFileInternal(FileInfo source, FileInfo dest) { - if (!source.Exists) ThrowHelper.ThrowResult(ResultFs.PathNotFound); - if (dest.Exists) ThrowHelper.ThrowResult(ResultFs.PathAlreadyExists); + if (!source.Exists) return ResultFs.PathNotFound.Log(); + if (dest.Exists) return ResultFs.PathAlreadyExists.Log(); try { source.MoveTo(dest.FullName); } - catch (DirectoryNotFoundException ex) + catch (DirectoryNotFoundException) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound, ex); - throw; + return ResultFs.PathNotFound.Log(); } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) { - // todo: Should a HorizonResultException be thrown? + // todo: What Result value should be returned? throw; } + + return Result.Success; } diff --git a/src/LibHac/Fs/PartitionFileSystem.cs b/src/LibHac/Fs/PartitionFileSystem.cs index e8d75888..a8ba92d4 100644 --- a/src/LibHac/Fs/PartitionFileSystem.cs +++ b/src/LibHac/Fs/PartitionFileSystem.cs @@ -29,12 +29,13 @@ namespace LibHac.Fs BaseStorage = storage; } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { - return new PartitionDirectory(this, path, mode); + directory = new PartitionDirectory(this, path, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { path = PathTools.Normalize(path).TrimStart('/'); @@ -43,7 +44,8 @@ namespace LibHac.Fs ThrowHelper.ThrowResult(ResultFs.PathNotFound); } - return OpenFile(entry, mode); + file = OpenFile(entry, mode); + return Result.Success; } public IFile OpenFile(PartitionFileEntry entry, OpenMode mode) @@ -51,46 +53,59 @@ namespace LibHac.Fs return new PartitionFile(BaseStorage, HeaderSize + entry.Offset, entry.Size, mode); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { + entryType = DirectoryEntryType.NotFound; path = PathTools.Normalize(path); - if (path == "/") return DirectoryEntryType.Directory; + if (path == "/") + { + entryType = DirectoryEntryType.Directory; + return Result.Success; + } - if (FileDict.ContainsKey(path.TrimStart('/'))) return DirectoryEntryType.File; + if (FileDict.ContainsKey(path.TrimStart('/'))) + { + entryType = DirectoryEntryType.File; + return Result.Success; + } - return DirectoryEntryType.NotFound; + return ResultFs.PathNotFound.Log(); } - public void CreateDirectory(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void CreateFile(string path, long size, CreateFileOptions options) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void DeleteDirectory(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void DeleteDirectoryRecursively(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void CleanDirectoryRecursively(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void DeleteFile(string path) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void RenameDirectory(string srcPath, string dstPath) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); - public void RenameFile(string srcPath, string dstPath) => ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyPartitionFileSystem); + public Result CreateDirectory(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result DeleteFile(string path) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); + public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyPartitionFileSystem.Log(); - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + freeSpace = default; + return ResultFs.NotImplemented.Log(); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + totalSpace = default; + return ResultFs.NotImplemented.Log(); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + timeStamp = default; + return ResultFs.NotImplemented.Log(); } - public void Commit() { } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) => ThrowHelper.ThrowResult(ResultFs.NotImplemented); + public Result Commit() + { + return Result.Success; + } + + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) => ResultFs.NotImplemented.Log(); } public enum PartitionFileSystemType diff --git a/src/LibHac/Fs/PartitionFileSystemBuilder.cs b/src/LibHac/Fs/PartitionFileSystemBuilder.cs index d997dd0f..9a41c18d 100644 --- a/src/LibHac/Fs/PartitionFileSystemBuilder.cs +++ b/src/LibHac/Fs/PartitionFileSystemBuilder.cs @@ -22,11 +22,13 @@ namespace LibHac.Fs /// public PartitionFileSystemBuilder(IFileSystem input) { - IDirectory rootDir = input.OpenDirectory("/", OpenDirectoryMode.File); + input.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.File).ThrowIfFailure(); - foreach (DirectoryEntry file in rootDir.Read().OrderBy(x => x.FullPath, StringComparer.Ordinal)) + foreach (DirectoryEntry entry in rootDir.Read().OrderBy(x => x.FullPath, StringComparer.Ordinal)) { - AddFile(file.FullPath.TrimStart('/'), input.OpenFile(file.FullPath, OpenMode.Read)); + input.OpenFile(out IFile file, entry.FullPath, OpenMode.Read).ThrowIfFailure(); + + AddFile(entry.FullPath.TrimStart('/'), file); } } diff --git a/src/LibHac/Fs/ReadOnlyFileSystem.cs b/src/LibHac/Fs/ReadOnlyFileSystem.cs index 43a9d8c3..417b2526 100644 --- a/src/LibHac/Fs/ReadOnlyFileSystem.cs +++ b/src/LibHac/Fs/ReadOnlyFileSystem.cs @@ -11,71 +11,82 @@ namespace LibHac.Fs BaseFs = baseFileSystem; } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { - IDirectory baseDir = BaseFs.OpenDirectory(path, mode); - return new ReadOnlyDirectory(this, baseDir); + directory = default; + + Result rc = BaseFs.OpenDirectory(out IDirectory baseDir, path, mode); + if (rc.IsFailure()) return rc; + + directory = new ReadOnlyDirectory(this, baseDir); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { - IFile baseFile = BaseFs.OpenFile(path, mode); - return new ReadOnlyFile(baseFile); + file = default; + + Result rc = BaseFs.OpenFile(out IFile baseFile, path, mode); + if (rc.IsFailure()) return rc; + + file = new ReadOnlyFile(baseFile); + return Result.Success; } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { - return BaseFs.GetEntryType(path); + return BaseFs.GetEntryType(out entryType, path); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - return 0; + freeSpace = 0; + return Result.Success; + + // FS does: + // return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log(); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return BaseFs.GetTotalSpaceSize(path); + return BaseFs.GetTotalSpaceSize(out totalSpace, path); + + // FS does: + // return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log(); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - return BaseFs.GetFileTimeStampRaw(path); + return BaseFs.GetFileTimeStampRaw(out timeStamp, path); + + // FS does: + // return ResultFs.NotImplemented.Log(); } - public void Commit() + public Result Commit() { - + return Result.Success; } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { - BaseFs.QueryEntry(outBuffer, inBuffer, path, queryId); + return ResultFs.NotImplemented.Log(); } - public void CreateDirectory(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result CreateDirectory(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void CreateFile(string path, long size, CreateFileOptions options) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void DeleteDirectory(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void DeleteDirectoryRecursively(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void CleanDirectoryRecursively(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void DeleteFile(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result DeleteFile(string path) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); - public void RenameDirectory(string srcPath, string dstPath) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); - - public void RenameFile(string srcPath, string dstPath) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyReadOnlyFileSystem); + public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); + public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyReadOnlyFileSystem.Log(); } } diff --git a/src/LibHac/Fs/ResultFs.cs b/src/LibHac/Fs/ResultFs.cs index a3733289..fcc8eb68 100644 --- a/src/LibHac/Fs/ResultFs.cs +++ b/src/LibHac/Fs/ResultFs.cs @@ -11,7 +11,6 @@ public static Result InsufficientFreeSpace => new Result(ModuleFs, 30); public static Result MountNameAlreadyExists => new Result(ModuleFs, 60); - public static Result ResultPartitionNotFound => new Result(ModuleFs, 1002); public static Result TargetNotFound => new Result(ModuleFs, 1002); public static Result NotImplemented => new Result(ModuleFs, 3001); diff --git a/src/LibHac/Fs/RomFs/RomFsBuilder.cs b/src/LibHac/Fs/RomFs/RomFsBuilder.cs index 8d067e6e..055e2c4f 100644 --- a/src/LibHac/Fs/RomFs/RomFsBuilder.cs +++ b/src/LibHac/Fs/RomFs/RomFsBuilder.cs @@ -32,10 +32,12 @@ namespace LibHac.Fs.RomFs /// public RomFsBuilder(IFileSystem input) { - foreach (DirectoryEntry file in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File) + foreach (DirectoryEntry entry in input.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File) .OrderBy(x => x.FullPath, StringComparer.Ordinal)) { - AddFile(file.FullPath, input.OpenFile(file.FullPath, OpenMode.Read)); + input.OpenFile(out IFile file, entry.FullPath, OpenMode.Read).ThrowIfFailure(); + + AddFile(entry.FullPath, file); } } diff --git a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs b/src/LibHac/Fs/RomFs/RomFsFileSystem.cs index ee944186..0b9970a4 100644 --- a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs +++ b/src/LibHac/Fs/RomFs/RomFsFileSystem.cs @@ -22,52 +22,63 @@ namespace LibHac.Fs.RomFs FileTable = new HierarchicalRomFileTable(dirHashTable, dirEntryTable, fileHashTable, fileEntryTable); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { + entryType = DirectoryEntryType.NotFound; path = PathTools.Normalize(path); if (FileTable.TryOpenFile(path, out RomFileInfo _)) { - return DirectoryEntryType.File; + entryType = DirectoryEntryType.File; + return Result.Success; } if (FileTable.TryOpenDirectory(path, out FindPosition _)) { - return DirectoryEntryType.Directory; + entryType = DirectoryEntryType.Directory; + return Result.Success; } - return DirectoryEntryType.NotFound; + return ResultFs.PathNotFound.Log(); } - public void Commit() { } - - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result Commit() { + return Result.Success; + } + + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) + { + directory = default; path = PathTools.Normalize(path); if (!FileTable.TryOpenDirectory(path, out FindPosition position)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - return new RomFsDirectory(this, path, position, mode); + directory = new RomFsDirectory(this, path, position, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; path = PathTools.Normalize(path); if (!FileTable.TryOpenFile(path, out RomFileInfo info)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } if (mode != OpenMode.Read) { - ThrowHelper.ThrowResult(ResultFs.InvalidArgument, "RomFs files must be opened read-only."); + // RomFs files must be opened read-only. + return ResultFs.InvalidArgument.Log(); } - return new RomFsFile(BaseStorage, Header.DataOffset + info.Offset, info.Length); + file = new RomFsFile(BaseStorage, Header.DataOffset + info.Offset, info.Length); + return Result.Success; } public IStorage GetBaseStorage() @@ -75,50 +86,37 @@ namespace LibHac.Fs.RomFs return BaseStorage; } - public void CreateDirectory(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); + public Result CreateDirectory(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result CreateFile(string path, long size, CreateFileOptions options) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result DeleteDirectory(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result DeleteDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result CleanDirectoryRecursively(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result DeleteFile(string path) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result RenameDirectory(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); + public Result RenameFile(string oldPath, string newPath) => ResultFs.UnsupportedOperationModifyRomFsFileSystem.Log(); - public void CreateFile(string path, long size, CreateFileOptions options) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void DeleteDirectory(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void DeleteDirectoryRecursively(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void CleanDirectoryRecursively(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void DeleteFile(string path) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void RenameDirectory(string srcPath, string dstPath) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public void RenameFile(string srcPath, string dstPath) => - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationModifyRomFsFileSystem); - - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationRomFsFileSystemGetSpace); - return default; + freeSpace = default; + return ResultFs.UnsupportedOperationRomFsFileSystemGetSpace.Log(); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - ThrowHelper.ThrowResult(ResultFs.UnsupportedOperationRomFsFileSystemGetSpace); - return default; + totalSpace = default; + return ResultFs.UnsupportedOperationRomFsFileSystemGetSpace.Log(); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + timeStamp = default; + return ResultFs.NotImplemented.Log(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) => - ThrowHelper.ThrowResult(ResultFs.NotImplemented); + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + { + return ResultFs.NotImplemented.Log(); + } } public class RomfsHeader diff --git a/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs b/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs index 07b8ac5e..78555ee3 100644 --- a/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs +++ b/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs @@ -338,11 +338,11 @@ namespace LibHac.Fs.Save FileTable.ChangeKey(ref oldKey, ref newKey); } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string srcPath, string dstPath) { if (srcPath == dstPath || TryOpenFile(dstPath, out _) || TryOpenDirectory(dstPath, out _)) { - throw new IOException(Messages.DestPathAlreadyExists); + return ResultFs.PathAlreadyExists.Log(); } ReadOnlySpan oldPathBytes = Util.GetUtf8Bytes(srcPath); @@ -350,19 +350,19 @@ namespace LibHac.Fs.Save if (!FindPathRecursive(oldPathBytes, out SaveEntryKey oldKey)) { - throw new DirectoryNotFoundException(); + return ResultFs.PathNotFound.Log(); } int dirIndex = DirectoryTable.GetIndexFromKey(ref oldKey).Index; if (!FindPathRecursive(newPathBytes, out SaveEntryKey newKey)) { - throw new IOException(Messages.PartialPathNotFound); + return ResultFs.PathNotFound.Log(); } if (PathTools.IsSubPath(oldPathBytes, newPathBytes)) { - ThrowHelper.ThrowResult(ResultFs.DestinationIsSubPathOfSource); + return ResultFs.DestinationIsSubPathOfSource.Log(); } if (oldKey.Parent != newKey.Parent) @@ -372,6 +372,8 @@ namespace LibHac.Fs.Save } DirectoryTable.ChangeKey(ref oldKey, ref newKey); + + return Result.Success; } public bool TryOpenDirectory(string path, out SaveFindPosition position) diff --git a/src/LibHac/Fs/Save/SaveDataFileSystem.cs b/src/LibHac/Fs/Save/SaveDataFileSystem.cs index 8191ccba..e71d1a0c 100644 --- a/src/LibHac/Fs/Save/SaveDataFileSystem.cs +++ b/src/LibHac/Fs/Save/SaveDataFileSystem.cs @@ -142,198 +142,114 @@ namespace LibHac.Fs.Save IntegrityStorageType.Save, integrityCheckLevel, LeaveOpen); } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { - try - { - SaveDataFileSystemCore.CreateDirectory(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.CreateDirectory(path); + + return SaveResults.ConvertToExternalResult(result); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { - try - { - SaveDataFileSystemCore.CreateFile(path, size, options); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.CreateFile(path, size, options); + + return SaveResults.ConvertToExternalResult(result); } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { - try - { - SaveDataFileSystemCore.DeleteDirectory(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.DeleteDirectory(path); + + return SaveResults.ConvertToExternalResult(result); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { - try - { - SaveDataFileSystemCore.DeleteDirectoryRecursively(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.DeleteDirectoryRecursively(path); + + return SaveResults.ConvertToExternalResult(result); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { - try - { - SaveDataFileSystemCore.CleanDirectoryRecursively(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.CleanDirectoryRecursively(path); + + return SaveResults.ConvertToExternalResult(result); } - public void DeleteFile(string path) + public Result DeleteFile(string path) { - try - { - SaveDataFileSystemCore.DeleteFile(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.DeleteFile(path); + + return SaveResults.ConvertToExternalResult(result); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { - try - { - return SaveDataFileSystemCore.OpenDirectory(path, mode); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.OpenDirectory(out directory, path, mode); + + return SaveResults.ConvertToExternalResult(result); } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { - try - { - return SaveDataFileSystemCore.OpenFile(path, mode); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.OpenFile(out file, path, mode); + + return SaveResults.ConvertToExternalResult(result); } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - try - { - SaveDataFileSystemCore.RenameDirectory(srcPath, dstPath); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.RenameDirectory(oldPath, newPath); + + return SaveResults.ConvertToExternalResult(result); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - try - { - SaveDataFileSystemCore.RenameFile(srcPath, dstPath); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.RenameFile(oldPath, newPath); + + return SaveResults.ConvertToExternalResult(result); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { - try - { - return SaveDataFileSystemCore.GetEntryType(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.GetEntryType(out entryType, path); + + return SaveResults.ConvertToExternalResult(result); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - try - { - return SaveDataFileSystemCore.GetFreeSpaceSize(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.GetFreeSpaceSize(out freeSpace, path); + + return SaveResults.ConvertToExternalResult(result); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - try - { - return SaveDataFileSystemCore.GetTotalSpaceSize(path); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = SaveDataFileSystemCore.GetTotalSpaceSize(out totalSpace, path); + + return SaveResults.ConvertToExternalResult(result); } - public void Commit() + public Result Commit() { - try - { - Commit(Keyset); - } - catch (HorizonResultException ex) - { - ConvertResultException(ex); - throw; - } + Result result = Commit(Keyset); + + return SaveResults.ConvertToExternalResult(result); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + timeStamp = default; + return ResultFs.NotImplemented.Log(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) => - ThrowHelper.ThrowResult(ResultFs.NotImplemented); + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) => + ResultFs.NotImplemented.Log(); - public bool Commit(Keyset keyset) + public Result Commit(Keyset keyset) { CoreDataIvfcStorage.Flush(); FatIvfcStorage?.Flush(); @@ -349,7 +265,7 @@ namespace LibHac.Fs.Save headerStream.Position = 0x108; headerStream.Write(hash, 0, hash.Length); - if (keyset == null || keyset.SaveMacKey.IsEmpty()) return false; + if (keyset == null || keyset.SaveMacKey.IsEmpty()) return ResultFs.PreconditionViolation; var cmacData = new byte[0x200]; var cmac = new byte[0x10]; @@ -363,7 +279,7 @@ namespace LibHac.Fs.Save headerStream.Write(cmac, 0, 0x10); headerStream.Flush(); - return true; + return Result.Success; } public void FsTrim() @@ -395,10 +311,5 @@ namespace LibHac.Fs.Save return journalValidity; } - - private void ConvertResultException(HorizonResultException ex) - { - ex.ResultValue = SaveResults.ConvertToExternalResult(ex.ResultValue); - } } } diff --git a/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs b/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs index a1fe5c3c..721fe75b 100644 --- a/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs +++ b/src/LibHac/Fs/Save/SaveDataFileSystemCore.cs @@ -27,14 +27,16 @@ namespace LibHac.Fs.Save FileTable = new HierarchicalSaveFileTable(dirTableStorage, fileTableStorage); } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { path = PathTools.Normalize(path); FileTable.AddDirectory(path); + + return Result.Success; } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { path = PathTools.Normalize(path); @@ -43,7 +45,7 @@ namespace LibHac.Fs.Save var emptyFileEntry = new SaveFileInfo { StartBlock = int.MinValue, Length = size }; FileTable.AddFile(path, ref emptyFileEntry); - return; + return Result.Success; } int blockCount = (int)Util.DivideByRoundUp(size, AllocationTable.Header.BlockSize); @@ -51,45 +53,56 @@ namespace LibHac.Fs.Save if (startBlock == -1) { - ThrowHelper.ThrowResult(ResultFs.AllocationTableInsufficientFreeBlocks, - "Not enough available space to create file."); + return ResultFs.AllocationTableInsufficientFreeBlocks.Log(); } var fileEntry = new SaveFileInfo { StartBlock = startBlock, Length = size }; FileTable.AddFile(path, ref fileEntry); + + return Result.Success; } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { path = PathTools.Normalize(path); FileTable.DeleteDirectory(path); + + return Result.Success; } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { path = PathTools.Normalize(path); - CleanDirectoryRecursively(path); + Result rc = CleanDirectoryRecursively(path); + if (rc.IsFailure()) return rc; + DeleteDirectory(path); + + return Result.Success; } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { path = PathTools.Normalize(path); - IDirectory dir = OpenDirectory(path, OpenDirectoryMode.All); + Result rc = OpenDirectory(out IDirectory dir, path, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + FileSystemExtensions.CleanDirectoryRecursivelyGeneric(dir); + + return Result.Success; } - public void DeleteFile(string path) + public Result DeleteFile(string path) { path = PathTools.Normalize(path); if (!FileTable.TryOpenFile(path, out SaveFileInfo fileInfo)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } if (fileInfo.StartBlock != int.MinValue) @@ -98,91 +111,110 @@ namespace LibHac.Fs.Save } FileTable.DeleteFile(path); + + return Result.Success; } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { + directory = default; path = PathTools.Normalize(path); if (!FileTable.TryOpenDirectory(path, out SaveFindPosition position)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - return new SaveDataDirectory(this, path, position, mode); + directory = new SaveDataDirectory(this, path, position, mode); + + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { + file = default; path = PathTools.Normalize(path); - if (!FileTable.TryOpenFile(path, out SaveFileInfo file)) + if (!FileTable.TryOpenFile(path, out SaveFileInfo fileInfo)) { - ThrowHelper.ThrowResult(ResultFs.PathNotFound); + return ResultFs.PathNotFound.Log(); } - AllocationTableStorage storage = OpenFatStorage(file.StartBlock); + AllocationTableStorage storage = OpenFatStorage(fileInfo.StartBlock); - return new SaveDataFile(storage, path, FileTable, file.Length, mode); + file = new SaveDataFile(storage, path, FileTable, fileInfo.Length, mode); + + return Result.Success; } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - FileTable.RenameDirectory(srcPath, dstPath); + return FileTable.RenameDirectory(oldPath, newPath); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - FileTable.RenameFile(srcPath, dstPath); + FileTable.RenameFile(oldPath, newPath); + + return Result.Success; } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); if (FileTable.TryOpenFile(path, out SaveFileInfo _)) { - return DirectoryEntryType.File; + entryType = DirectoryEntryType.File; + return Result.Success; } if (FileTable.TryOpenDirectory(path, out SaveFindPosition _)) { - return DirectoryEntryType.Directory; + entryType = DirectoryEntryType.Directory; + return Result.Success; } - return DirectoryEntryType.NotFound; + entryType = DirectoryEntryType.NotFound; + return ResultFs.PathNotFound.Log(); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { int freeBlockCount = AllocationTable.GetFreeListLength(); - return Header.BlockSize * freeBlockCount; + freeSpace = Header.BlockSize * freeBlockCount; + + return Result.Success; } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return Header.BlockSize * Header.BlockCount; + totalSpace = Header.BlockSize * Header.BlockCount; + + return Result.Success; } - public void Commit() + public Result Commit() { - + return Result.Success; } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - ThrowHelper.ThrowResult(ResultFs.NotImplemented); - return default; + timeStamp = default; + return ResultFs.NotImplemented.Log(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) => - ThrowHelper.ThrowResult(ResultFs.NotImplemented); + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) + { + return ResultFs.NotImplemented.Log(); + } public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); diff --git a/src/LibHac/Fs/SubdirectoryFileSystem.cs b/src/LibHac/Fs/SubdirectoryFileSystem.cs index db5f0ab5..57f80d1a 100644 --- a/src/LibHac/Fs/SubdirectoryFileSystem.cs +++ b/src/LibHac/Fs/SubdirectoryFileSystem.cs @@ -18,118 +18,119 @@ namespace LibHac.Fs RootPath = PathTools.Normalize(rootPath); } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { path = PathTools.Normalize(path); - ParentFileSystem.CreateDirectory(ResolveFullPath(path)); + return ParentFileSystem.CreateDirectory(ResolveFullPath(path)); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { path = PathTools.Normalize(path); - ParentFileSystem.CreateFile(ResolveFullPath(path), size, options); + return ParentFileSystem.CreateFile(ResolveFullPath(path), size, options); } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { path = PathTools.Normalize(path); - ParentFileSystem.DeleteDirectory(ResolveFullPath(path)); + return ParentFileSystem.DeleteDirectory(ResolveFullPath(path)); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { path = PathTools.Normalize(path); - ParentFileSystem.DeleteDirectoryRecursively(ResolveFullPath(path)); + return ParentFileSystem.DeleteDirectoryRecursively(ResolveFullPath(path)); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { path = PathTools.Normalize(path); - ParentFileSystem.CleanDirectoryRecursively(ResolveFullPath(path)); + return ParentFileSystem.CleanDirectoryRecursively(ResolveFullPath(path)); } - public void DeleteFile(string path) + public Result DeleteFile(string path) { path = PathTools.Normalize(path); - ParentFileSystem.DeleteFile(ResolveFullPath(path)); + return ParentFileSystem.DeleteFile(ResolveFullPath(path)); } - public IDirectory OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out IDirectory directory, string path, OpenDirectoryMode mode) { path = PathTools.Normalize(path); - IDirectory baseDir = ParentFileSystem.OpenDirectory(ResolveFullPath(path), mode); + ParentFileSystem.OpenDirectory(out IDirectory baseDir, ResolveFullPath(path), mode); - return new SubdirectoryFileSystemDirectory(this, baseDir, path, mode); + directory = new SubdirectoryFileSystemDirectory(this, baseDir, path, mode); + return Result.Success; } - public IFile OpenFile(string path, OpenMode mode) + public Result OpenFile(out IFile file, string path, OpenMode mode) { path = PathTools.Normalize(path); - return ParentFileSystem.OpenFile(ResolveFullPath(path), mode); + return ParentFileSystem.OpenFile(out file, ResolveFullPath(path), mode); } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - ParentFileSystem.RenameDirectory(ResolveFullPath(srcPath), ResolveFullPath(dstPath)); + return ParentFileSystem.RenameDirectory(oldPath, newPath); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - srcPath = PathTools.Normalize(srcPath); - dstPath = PathTools.Normalize(dstPath); + oldPath = PathTools.Normalize(oldPath); + newPath = PathTools.Normalize(newPath); - ParentFileSystem.RenameFile(ResolveFullPath(srcPath), ResolveFullPath(dstPath)); + return ParentFileSystem.RenameFile(oldPath, newPath); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType entryType, string path) { path = PathTools.Normalize(path); - return ParentFileSystem.GetEntryType(ResolveFullPath(path)); + return ParentFileSystem.GetEntryType(out entryType, ResolveFullPath(path)); } - public void Commit() + public Result Commit() { - ParentFileSystem.Commit(); + return ParentFileSystem.Commit(); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { path = PathTools.Normalize(path); - return ParentFileSystem.GetFreeSpaceSize(ResolveFullPath(path)); + return ParentFileSystem.GetFreeSpaceSize(out freeSpace, ResolveFullPath(path)); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { path = PathTools.Normalize(path); - return ParentFileSystem.GetTotalSpaceSize(ResolveFullPath(path)); + return ParentFileSystem.GetTotalSpaceSize(out totalSpace, ResolveFullPath(path)); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { path = PathTools.Normalize(path); - return ParentFileSystem.GetFileTimeStampRaw(ResolveFullPath(path)); + return ParentFileSystem.GetFileTimeStampRaw(out timeStamp, ResolveFullPath(path)); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, string path) { path = PathTools.Normalize(path); - ParentFileSystem.QueryEntry(outBuffer, inBuffer, ResolveFullPath(path), queryId); + return ParentFileSystem.QueryEntry(outBuffer, inBuffer, queryId, ResolveFullPath(path)); } } } diff --git a/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs b/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs index 391f7381..317e7dd0 100644 --- a/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs +++ b/src/LibHac/FsClient/Accessors/FileSystemAccessor.cs @@ -26,117 +26,125 @@ namespace LibHac.FsClient.Accessors FsManager = fsManager; } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { - FileSystem.CreateDirectory(path); + return FileSystem.CreateDirectory(path); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { - FileSystem.CreateFile(path, size, options); + return FileSystem.CreateFile(path, size, options); } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { - FileSystem.DeleteDirectory(path); + return FileSystem.DeleteDirectory(path); } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { - FileSystem.DeleteDirectoryRecursively(path); + return FileSystem.DeleteDirectoryRecursively(path); } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { - FileSystem.CleanDirectoryRecursively(path); + return FileSystem.CleanDirectoryRecursively(path); } - public void DeleteFile(string path) + public Result DeleteFile(string path) { - FileSystem.DeleteFile(path); + return FileSystem.DeleteFile(path); } - public DirectoryAccessor OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out DirectoryAccessor directory, string path, OpenDirectoryMode mode) { - IDirectory dir = FileSystem.OpenDirectory(path, mode); + directory = default; - var accessor = new DirectoryAccessor(dir, this); + Result rc = FileSystem.OpenDirectory(out IDirectory rawDirectory, path, mode); + if (rc.IsFailure()) return rc; + + var accessor = new DirectoryAccessor(rawDirectory, this); lock (_locker) { OpenDirectories.Add(accessor); } - return accessor; + directory = accessor; + return Result.Success; } - public FileAccessor OpenFile(string path, OpenMode mode) + public Result OpenFile(out FileAccessor file, string path, OpenMode mode) { - IFile file = FileSystem.OpenFile(path, mode); + file = default; - var accessor = new FileAccessor(file, this, mode); + Result rc = FileSystem.OpenFile(out IFile rawFile, path, mode); + if (rc.IsFailure()) return rc; + + var accessor = new FileAccessor(rawFile, this, mode); lock (_locker) { OpenFiles.Add(accessor); } - return accessor; + file = accessor; + return Result.Success; } - public void RenameDirectory(string srcPath, string dstPath) + public Result RenameDirectory(string oldPath, string newPath) { - FileSystem.RenameDirectory(srcPath, dstPath); + return FileSystem.RenameDirectory(oldPath, newPath); } - public void RenameFile(string srcPath, string dstPath) + public Result RenameFile(string oldPath, string newPath) { - FileSystem.RenameFile(srcPath, dstPath); + return FileSystem.RenameFile(oldPath, newPath); } - public void DirectoryExists(string path) + public bool DirectoryExists(string path) { - FileSystem.DirectoryExists(path); + return FileSystem.DirectoryExists(path); } - public void FileExists(string path) + public bool FileExists(string path) { - FileSystem.FileExists(path); + return FileSystem.FileExists(path); } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType type, string path) { - return FileSystem.GetEntryType(path); + return FileSystem.GetEntryType(out type, path); } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - return FileSystem.GetFreeSpaceSize(path); + return FileSystem.GetFreeSpaceSize(out freeSpace, path); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - return FileSystem.GetTotalSpaceSize(path); + return FileSystem.GetTotalSpaceSize(out totalSpace, path); } - public FileTimeStampRaw GetFileTimeStampRaw(string path) + public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, string path) { - return FileSystem.GetFileTimeStampRaw(path); + return FileSystem.GetFileTimeStampRaw(out timeStamp, path); } - public void Commit() + public Result Commit() { if (OpenFiles.Any(x => (x.OpenMode & OpenMode.Write) != 0)) { - ThrowHelper.ThrowResult(ResultFs.WritableFileOpen); + return ResultFs.WritableFileOpen.Log(); } - FileSystem.Commit(); + return FileSystem.Commit(); } - public void QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) + public Result QueryEntry(Span outBuffer, ReadOnlySpan inBuffer, string path, QueryId queryId) { - FileSystem.QueryEntry(outBuffer, inBuffer, path, queryId); + return FileSystem.QueryEntry(outBuffer, inBuffer, queryId, path); } internal void NotifyCloseFile(FileAccessor file) diff --git a/src/LibHac/FsClient/DirectoryHandle.cs b/src/LibHac/FsClient/DirectoryHandle.cs index 9eb8cf2f..cab42040 100644 --- a/src/LibHac/FsClient/DirectoryHandle.cs +++ b/src/LibHac/FsClient/DirectoryHandle.cs @@ -12,7 +12,7 @@ namespace LibHac.FsClient Directory = directory; } - public int GetId() => Directory.GetHashCode(); + public int GetId() => Directory?.GetHashCode() ?? 0; public void Dispose() { diff --git a/src/LibHac/FsClient/FileHandle.cs b/src/LibHac/FsClient/FileHandle.cs index 387efe01..0c728291 100644 --- a/src/LibHac/FsClient/FileHandle.cs +++ b/src/LibHac/FsClient/FileHandle.cs @@ -12,7 +12,7 @@ namespace LibHac.FsClient File = file; } - public int GetId() => File.GetHashCode(); + public int GetId() => File?.GetHashCode() ?? 0; public void Dispose() { diff --git a/src/LibHac/FsClient/FileSystemClient.FileSystem.cs b/src/LibHac/FsClient/FileSystemClient.FileSystem.cs index f3676a12..ebd4ed12 100644 --- a/src/LibHac/FsClient/FileSystemClient.FileSystem.cs +++ b/src/LibHac/FsClient/FileSystemClient.FileSystem.cs @@ -55,12 +55,12 @@ namespace LibHac.FsClient throw new NotImplementedException(); } - public FileHandle OpenFile(out FileHandle handle, string path, OpenMode mode) + public Result OpenFile(out FileHandle handle, string path, OpenMode mode) { throw new NotImplementedException(); } - public DirectoryHandle OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) + public Result OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) { throw new NotImplementedException(); } diff --git a/src/LibHac/FsClient/FileSystemManager.cs b/src/LibHac/FsClient/FileSystemManager.cs index 10ca268f..7b4688bf 100644 --- a/src/LibHac/FsClient/FileSystemManager.cs +++ b/src/LibHac/FsClient/FileSystemManager.cs @@ -6,6 +6,7 @@ using LibHac.FsClient.Accessors; namespace LibHac.FsClient { + // Todo: Access log for FindFileSystem public class FileSystemManager { internal Horizon Os { get; } @@ -66,213 +67,229 @@ namespace LibHac.FsClient if (accessLog != null) AccessLog = accessLog; } - public void CreateDirectory(string path) + public Result CreateDirectory(string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.CreateDirectory(subPath.ToString()); + rc = fileSystem.CreateDirectory(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - fileSystem.CreateDirectory(subPath.ToString()); + rc = fileSystem.CreateDirectory(subPath.ToString()); } + + return rc; } - public void CreateFile(string path, long size) + public Result CreateFile(string path, long size) { - CreateFile(path, size, CreateFileOptions.None); + return CreateFile(path, size, CreateFileOptions.None); } - public void CreateFile(string path, long size, CreateFileOptions options) + public Result CreateFile(string path, long size, CreateFileOptions options) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.CreateFile(subPath.ToString(), size, options); + rc = fileSystem.CreateFile(subPath.ToString(), size, options); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\", size: {size}"); } else { - fileSystem.CreateFile(subPath.ToString(), size, options); + rc = fileSystem.CreateFile(subPath.ToString(), size, options); } + + return rc; } - public void DeleteDirectory(string path) + public Result DeleteDirectory(string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.DeleteDirectory(subPath.ToString()); + rc = fileSystem.DeleteDirectory(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - fileSystem.DeleteDirectory(subPath.ToString()); + rc = fileSystem.DeleteDirectory(subPath.ToString()); } + + return rc; } - public void DeleteDirectoryRecursively(string path) + public Result DeleteDirectoryRecursively(string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.DeleteDirectoryRecursively(subPath.ToString()); + rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - fileSystem.DeleteDirectoryRecursively(subPath.ToString()); + rc = fileSystem.DeleteDirectoryRecursively(subPath.ToString()); } + + return rc; } - public void CleanDirectoryRecursively(string path) + public Result CleanDirectoryRecursively(string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.CleanDirectoryRecursively(subPath.ToString()); + rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - fileSystem.CleanDirectoryRecursively(subPath.ToString()); + rc = fileSystem.CleanDirectoryRecursively(subPath.ToString()); } + + return rc; } - public void DeleteFile(string path) + public Result DeleteFile(string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.DeleteFile(subPath.ToString()); + rc = fileSystem.DeleteFile(subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - fileSystem.DeleteFile(subPath.ToString()); + rc = fileSystem.DeleteFile(subPath.ToString()); } + + return rc; } - public void RenameDirectory(string oldPath, string newPath) + public Result RenameDirectory(string oldPath, string newPath) { - FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath); + if (rc.IsFailure()) return rc; - FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath) - .ThrowIfFailure(); + rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath); + if (rc.IsFailure()) return rc; if (oldFileSystem != newFileSystem) { - ThrowHelper.ThrowResult(ResultFs.DifferentDestFileSystem); + return ResultFs.DifferentDestFileSystem.Log(); } if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); } else { - oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameDirectory(oldSubPath.ToString(), newSubPath.ToString()); } + + return rc; } - public void RenameFile(string oldPath, string newPath) + public Result RenameFile(string oldPath, string newPath) { - FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath) - .ThrowIfFailure(); + Result rc = FindFileSystem(oldPath.AsSpan(), out FileSystemAccessor oldFileSystem, out ReadOnlySpan oldSubPath); + if (rc.IsFailure()) return rc; - FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath) - .ThrowIfFailure(); + rc = FindFileSystem(newPath.AsSpan(), out FileSystemAccessor newFileSystem, out ReadOnlySpan newSubPath); + if (rc.IsFailure()) return rc; if (oldFileSystem != newFileSystem) { - ThrowHelper.ThrowResult(ResultFs.DifferentDestFileSystem); + return ResultFs.DifferentDestFileSystem.Log(); } if (IsEnabledAccessLog() && oldFileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{oldPath}\", new_path: \"{newPath}\""); } else { - oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); + rc = oldFileSystem.RenameFile(oldSubPath.ToString(), newSubPath.ToString()); } + + return rc; } - public DirectoryEntryType GetEntryType(string path) + public Result GetEntryType(out DirectoryEntryType type, string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + type = default; - DirectoryEntryType type; + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - type = fileSystem.GetEntryType(subPath.ToString()); + rc = fileSystem.GetEntryType(out type, subPath.ToString()); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", path: \"{path}\""); } else { - type = fileSystem.GetEntryType(subPath.ToString()); + rc = fileSystem.GetEntryType(out type, subPath.ToString()); } - return type; + return rc; } - public FileHandle OpenFile(string path, OpenMode mode) + public Result OpenFile(out FileHandle handle, string path, OpenMode mode) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + handle = default; - FileHandle handle; + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - FileAccessor file = fileSystem.OpenFile(subPath.ToString(), mode); + rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode); handle = new FileHandle(file); TimeSpan endTime = Time.GetCurrent(); @@ -280,24 +297,24 @@ namespace LibHac.FsClient } else { - FileAccessor file = fileSystem.OpenFile(subPath.ToString(), mode); + rc = fileSystem.OpenFile(out FileAccessor file, subPath.ToString(), mode); handle = new FileHandle(file); } - return handle; + return rc; } - public DirectoryHandle OpenDirectory(string path, OpenDirectoryMode mode) + public Result OpenDirectory(out DirectoryHandle handle, string path, OpenDirectoryMode mode) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + handle = default; - DirectoryHandle handle; + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - DirectoryAccessor dir = fileSystem.OpenDirectory(subPath.ToString(), mode); + rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode); handle = new DirectoryHandle(dir); TimeSpan endTime = Time.GetCurrent(); @@ -305,94 +322,105 @@ namespace LibHac.FsClient } else { - DirectoryAccessor dir = fileSystem.OpenDirectory(subPath.ToString(), mode); + rc = fileSystem.OpenDirectory(out DirectoryAccessor dir, subPath.ToString(), mode); handle = new DirectoryHandle(dir); } - return handle; + return rc; } - public long GetFreeSpaceSize(string path) + public Result GetFreeSpaceSize(out long freeSpace, string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + freeSpace = default; - return fileSystem.GetFreeSpaceSize(subPath.ToString()); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + return fileSystem.GetFreeSpaceSize(out freeSpace, subPath.ToString()); } - public long GetTotalSpaceSize(string path) + public Result GetTotalSpaceSize(out long totalSpace, string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + totalSpace = default; - return fileSystem.GetTotalSpaceSize(subPath.ToString()); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + return fileSystem.GetTotalSpaceSize(out totalSpace, subPath.ToString()); } - public FileTimeStampRaw GetFileTimeStamp(string path) + public Result GetFileTimeStamp(out FileTimeStampRaw timeStamp, string path) { - FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath) - .ThrowIfFailure(); + timeStamp = default; - return fileSystem.GetFileTimeStampRaw(subPath.ToString()); + Result rc = FindFileSystem(path.AsSpan(), out FileSystemAccessor fileSystem, out ReadOnlySpan subPath); + if (rc.IsFailure()) return rc; + + return fileSystem.GetFileTimeStampRaw(out timeStamp, subPath.ToString()); } - public void Commit(string mountName) + public Result Commit(string mountName) { - MountTable.Find(mountName, out FileSystemAccessor fileSystem).ThrowIfFailure(); + Result rc = MountTable.Find(mountName, out FileSystemAccessor fileSystem); + if (rc.IsFailure()) return rc; if (IsEnabledAccessLog() && fileSystem.IsAccessLogEnabled) { TimeSpan startTime = Time.GetCurrent(); - fileSystem.Commit(); + rc = fileSystem.Commit(); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, $", name: \"{mountName}\""); } else { - fileSystem.Commit(); + rc = fileSystem.Commit(); } + + return rc; } // ========================== // Operations on file handles // ========================== - public int ReadFile(FileHandle handle, Span destination, long offset) + public Result ReadFile(out long bytesRead, FileHandle handle, Span destination, long offset) { - return ReadFile(handle, destination, offset, ReadOption.None); + return ReadFile(out bytesRead, handle, destination, offset, ReadOption.None); } - public int ReadFile(FileHandle handle, Span destination, long offset, ReadOption option) + public Result ReadFile(out long bytesRead, FileHandle handle, Span destination, long offset, ReadOption option) { - long bytesRead; + Result rc; if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - handle.File.Read(out bytesRead, offset, destination, option).ThrowIfFailure(); + rc = handle.File.Read(out bytesRead, offset, destination, option); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, handle, $", offset: {offset}, size: {destination.Length}"); } else { - handle.File.Read(out bytesRead, offset, destination, option).ThrowIfFailure(); + rc = handle.File.Read(out bytesRead, offset, destination, option); } - return (int)bytesRead; + return rc; } - public void WriteFile(FileHandle handle, ReadOnlySpan source, long offset) + public Result WriteFile(FileHandle handle, ReadOnlySpan source, long offset) { - WriteFile(handle, source, offset, WriteOption.None); + return WriteFile(handle, source, offset, WriteOption.None); } - public void WriteFile(FileHandle handle, ReadOnlySpan source, long offset, WriteOption option) + public Result WriteFile(FileHandle handle, ReadOnlySpan source, long offset, WriteOption option) { + Result rc; + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - handle.File.Write(offset, source, option); + rc = handle.File.Write(offset, source, option); TimeSpan endTime = Time.GetCurrent(); string optionString = (option & WriteOption.Flush) == 0 ? "" : $", write_option: {option}"; @@ -401,47 +429,55 @@ namespace LibHac.FsClient } else { - handle.File.Write(offset, source, option); + rc = handle.File.Write(offset, source, option); } + + return rc; } - public void FlushFile(FileHandle handle) + public Result FlushFile(FileHandle handle) { + Result rc; + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - handle.File.Flush(); + rc = handle.File.Flush(); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, handle, string.Empty); } else { - handle.File.Flush(); + rc = handle.File.Flush(); } + + return rc; } - public long GetFileSize(FileHandle handle) + public Result GetFileSize(out long fileSize, FileHandle handle) { - handle.File.GetSize(out long fileSize).ThrowIfFailure(); - - return fileSize; + return handle.File.GetSize(out fileSize); } - public void SetFileSize(FileHandle handle, long size) + public Result SetFileSize(FileHandle handle, long size) { + Result rc; + if (IsEnabledAccessLog() && IsEnabledHandleAccessLog(handle)) { TimeSpan startTime = Time.GetCurrent(); - handle.File.SetSize(size); + rc = handle.File.SetSize(size); TimeSpan endTime = Time.GetCurrent(); OutputAccessLog(startTime, endTime, handle, $", size: {size}"); } else { - handle.File.SetSize(size); + rc = handle.File.SetSize(size); } + + return rc; } public OpenMode GetFileOpenMode(FileHandle handle) @@ -468,9 +504,11 @@ namespace LibHac.FsClient // ========================== // Operations on directory handles // ========================== - public int GetDirectoryEntryCount(DirectoryHandle handle) + public Result GetDirectoryEntryCount(out long count, DirectoryHandle handle) { - return handle.Directory.GetEntryCount(); + count = handle.Directory.GetEntryCount(); + + return Result.Success; } public IEnumerable ReadDirectory(DirectoryHandle handle) diff --git a/src/LibHac/FsClient/FileSystemManagerUtils.cs b/src/LibHac/FsClient/FileSystemManagerUtils.cs index bce4b6e4..60d3244c 100644 --- a/src/LibHac/FsClient/FileSystemManagerUtils.cs +++ b/src/LibHac/FsClient/FileSystemManagerUtils.cs @@ -7,10 +7,13 @@ namespace LibHac.FsClient { public static class FileSystemManagerUtils { - public static void CopyDirectory(this FileSystemManager fs, string sourcePath, string destPath, + public static Result CopyDirectory(this FileSystemManager fs, string sourcePath, string destPath, CreateFileOptions options = CreateFileOptions.None, IProgressReport logger = null) { - using (DirectoryHandle sourceHandle = fs.OpenDirectory(sourcePath, OpenDirectoryMode.All)) + Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All); + if (rc.IsFailure()) return rc; + + using (sourceHandle) { foreach (DirectoryEntry entry in fs.ReadDirectory(sourceHandle)) { @@ -21,7 +24,8 @@ namespace LibHac.FsClient { fs.EnsureDirectoryExists(subDstPath); - fs.CopyDirectory(subSrcPath, subDstPath, options, logger); + rc = fs.CopyDirectory(subSrcPath, subDstPath, options, logger); + if (rc.IsFailure()) return rc; } if (entry.Type == DirectoryEntryType.File) @@ -29,46 +33,65 @@ namespace LibHac.FsClient logger?.LogMessage(subSrcPath); fs.CreateOrOverwriteFile(subDstPath, entry.Size, options); - fs.CopyFile(subSrcPath, subDstPath, logger); + rc = fs.CopyFile(subSrcPath, subDstPath, logger); + if (rc.IsFailure()) return rc; } } } + + return Result.Success; } - public static void CopyFile(this FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) + public static Result CopyFile(this FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) { - using (FileHandle sourceHandle = fs.OpenFile(sourcePath, OpenMode.Read)) - using (FileHandle destHandle = fs.OpenFile(destPath, OpenMode.Write | OpenMode.AllowAppend)) + Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read); + if (rc.IsFailure()) return rc; + + using (sourceHandle) { - const int maxBufferSize = 0x10000; + rc = fs.OpenFile(out FileHandle destHandle, destPath, OpenMode.Write | OpenMode.AllowAppend); + if (rc.IsFailure()) return rc; - long fileSize = fs.GetFileSize(sourceHandle); - int bufferSize = (int)Math.Min(maxBufferSize, fileSize); - - logger?.SetTotal(fileSize); - - byte[] buffer = ArrayPool.Shared.Rent(bufferSize); - try + using (destHandle) { - for (long offset = 0; offset < fileSize; offset += bufferSize) + const int maxBufferSize = 0x10000; + + rc = fs.GetFileSize(out long fileSize, sourceHandle); + if (rc.IsFailure()) return rc; + + int bufferSize = (int)Math.Min(maxBufferSize, fileSize); + + logger?.SetTotal(fileSize); + + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + try { - int toRead = (int)Math.Min(fileSize - offset, bufferSize); - Span buf = buffer.AsSpan(0, toRead); + for (long offset = 0; offset < fileSize; offset += bufferSize) + { + int toRead = (int)Math.Min(fileSize - offset, bufferSize); + Span buf = buffer.AsSpan(0, toRead); - fs.ReadFile(sourceHandle, buf, offset); - fs.WriteFile(destHandle, buf, offset); + rc = fs.ReadFile(out long _, sourceHandle, buf, offset); + if (rc.IsFailure()) return rc; - logger?.ReportAdd(toRead); + rc = fs.WriteFile(destHandle, buf, offset); + if (rc.IsFailure()) return rc; + + logger?.ReportAdd(toRead); + } + } + finally + { + ArrayPool.Shared.Return(buffer); + logger?.SetTotal(0); } - } - finally - { - ArrayPool.Shared.Return(buffer); - logger?.SetTotal(0); - } - fs.FlushFile(destHandle); + rc = fs.FlushFile(destHandle); + if (rc.IsFailure()) return rc; + } } + + return Result.Success; } public static IEnumerable EnumerateEntries(this FileSystemManager fs, string path) @@ -86,7 +109,9 @@ namespace LibHac.FsClient bool ignoreCase = searchOptions.HasFlag(SearchOptions.CaseInsensitive); bool recurse = searchOptions.HasFlag(SearchOptions.RecurseSubdirectories); - using (DirectoryHandle sourceHandle = fs.OpenDirectory(path, OpenDirectoryMode.All)) + fs.OpenDirectory(out DirectoryHandle sourceHandle, path, OpenDirectoryMode.All).ThrowIfFailure(); + + using (sourceHandle) { foreach (DirectoryEntry entry in fs.ReadDirectory(sourceHandle)) { @@ -112,12 +137,16 @@ namespace LibHac.FsClient public static bool DirectoryExists(this FileSystemManager fs, string path) { - return fs.GetEntryType(path) == DirectoryEntryType.Directory; + Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + + return (rc.IsSuccess() && type == DirectoryEntryType.Directory); } public static bool FileExists(this FileSystemManager fs, string path) { - return fs.GetEntryType(path) == DirectoryEntryType.File; + Result rc = fs.GetEntryType(out DirectoryEntryType type, path); + + return (rc.IsSuccess() && type == DirectoryEntryType.File); } public static void EnsureDirectoryExists(this FileSystemManager fs, string path) diff --git a/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs b/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs index f00dde73..d7c50ff5 100644 --- a/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/IHostFileSystemCreator.cs @@ -5,6 +5,6 @@ namespace LibHac.FsService.Creators public interface IHostFileSystemCreator { Result Create(out IFileSystem fileSystem, bool someBool); - Result Create(out IFileSystem fileSystem, string path, bool someBool); + Result Create(out IFileSystem fileSystem, string path, bool openCaseSensitive); } } \ No newline at end of file diff --git a/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs b/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs index 7de7c485..e0858de4 100644 --- a/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/ITargetManagerFileSystemCreator.cs @@ -4,7 +4,7 @@ namespace LibHac.FsService.Creators { public interface ITargetManagerFileSystemCreator { - Result Create(out IFileSystem fileSystem, bool someBool); + Result Create(out IFileSystem fileSystem, bool openCaseSensitive); Result GetCaseSensitivePath(out bool isSuccess, ref string path); } } \ No newline at end of file diff --git a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs index 5f19cdc4..ad2ecf8b 100644 --- a/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsService/Creators/SubDirectoryFileSystemCreator.cs @@ -6,16 +6,10 @@ namespace LibHac.FsService.Creators { public Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, string path) { - try - { - baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directory); - } - catch (HorizonResultException ex) - { - subDirFileSystem = default; + subDirFileSystem = default; - return ex.ResultValue; - } + Result rc = baseFileSystem.OpenDirectory(out IDirectory _, path, OpenDirectoryMode.Directory); + if (rc.IsFailure()) return rc; subDirFileSystem = new SubdirectoryFileSystem(baseFileSystem, path); diff --git a/src/LibHac/FsService/Util.cs b/src/LibHac/FsService/Util.cs index 0a0b8a62..8ac791bd 100644 --- a/src/LibHac/FsService/Util.cs +++ b/src/LibHac/FsService/Util.cs @@ -11,11 +11,13 @@ namespace LibHac.FsService if (!createPathIfMissing) { - if (path == null) return ResultFs.NullArgument; + if (path == null) return ResultFs.NullArgument.Log(); - if (baseFileSystem.GetEntryType(path) != DirectoryEntryType.Directory) + Result rc = baseFileSystem.GetEntryType(out DirectoryEntryType entryType, path); + + if (rc.IsFailure() || entryType != DirectoryEntryType.Directory) { - return ResultFs.PathNotFound; + return ResultFs.PathNotFound.Log(); } } @@ -28,16 +30,10 @@ namespace LibHac.FsService { subFileSystem = default; - if (path == null) return ResultFs.NullArgument; + if (path == null) return ResultFs.NullArgument.Log(); - try - { - baseFileSystem.OpenDirectory(path, OpenDirectoryMode.Directory); - } - catch (HorizonResultException ex) - { - return ex.ResultValue; - } + Result rc = baseFileSystem.OpenDirectory(out IDirectory _, path, OpenDirectoryMode.Directory); + if (rc.IsFailure()) return rc; subFileSystem = new SubdirectoryFileSystem(baseFileSystem, path); diff --git a/src/LibHac/SwitchFs.cs b/src/LibHac/SwitchFs.cs index 98b42155..2f91685c 100644 --- a/src/LibHac/SwitchFs.cs +++ b/src/LibHac/SwitchFs.cs @@ -67,9 +67,10 @@ namespace LibHac private void OpenAllNcas() { + ContentFs.OpenDirectory(out IDirectory rootDir, "/", OpenDirectoryMode.All).ThrowIfFailure(); + // Todo: give warning if directories named "*.nca" are found or manually fix the archive bit - IEnumerable files = ContentFs.OpenDirectory("/", OpenDirectoryMode.All) - .EnumerateEntries("*.nca", SearchOptions.RecurseSubdirectories) + IEnumerable files = rootDir.EnumerateEntries("*.nca", SearchOptions.RecurseSubdirectories) .Where(x => x.Type == DirectoryEntryType.File); foreach (DirectoryEntry fileEntry in files) @@ -77,9 +78,9 @@ namespace LibHac SwitchFsNca nca = null; try { - IStorage storage = ContentFs.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage(); + ContentFs.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure(); - nca = new SwitchFsNca(new Nca(Keyset, storage)); + nca = new SwitchFsNca(new Nca(Keyset, ncaFile.AsStorage())); nca.NcaId = GetNcaFilename(fileEntry.Name, nca); string extension = nca.Nca.Header.ContentType == NcaContentType.Meta ? ".cnmt.nca" : ".nca"; @@ -115,7 +116,8 @@ namespace LibHac try { - IFile file = SaveFs.OpenFile(fileEntry.FullPath, OpenMode.Read); + SaveFs.OpenFile(out IFile file, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure(); + save = new SaveDataFileSystem(Keyset, file.AsStorage(), IntegrityCheckLevel.None, true); } catch (Exception ex) @@ -141,7 +143,7 @@ namespace LibHac IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); string cnmtPath = fs.EnumerateEntries("*.cnmt").Single().FullPath; - IFile file = fs.OpenFile(cnmtPath, OpenMode.Read); + fs.OpenFile(out IFile file, cnmtPath, OpenMode.Read).ThrowIfFailure(); var metadata = new Cnmt(file.AsStream()); title.Id = metadata.TitleId; @@ -185,7 +187,7 @@ namespace LibHac foreach (Title title in Titles.Values.Where(x => x.ControlNca != null)) { IFileSystem romfs = title.ControlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - IFile control = romfs.OpenFile("control.nacp", OpenMode.Read); + romfs.OpenFile(out IFile control, "control.nacp", OpenMode.Read).ThrowIfFailure(); title.Control = new Nacp(control.AsStream()); diff --git a/src/LibHac/Xci.cs b/src/LibHac/Xci.cs index 3587f12f..9fe8c7f1 100644 --- a/src/LibHac/Xci.cs +++ b/src/LibHac/Xci.cs @@ -28,8 +28,8 @@ namespace LibHac XciPartition root = GetRootPartition(); if (type == XciPartitionType.Root) return root; - IStorage partitionStorage = root.OpenFile(type.GetFileName(), OpenMode.Read).AsStorage(); - return new XciPartition(partitionStorage); + root.OpenFile(out IFile partitionFile, type.GetFileName(), OpenMode.Read).ThrowIfFailure(); + return new XciPartition(partitionFile.AsStorage()); } private XciPartition GetRootPartition() diff --git a/src/hactoolnet/FsUtils.cs b/src/hactoolnet/FsUtils.cs index 0f41f501..0e3d2c1b 100644 --- a/src/hactoolnet/FsUtils.cs +++ b/src/hactoolnet/FsUtils.cs @@ -26,7 +26,9 @@ namespace hactoolnet private static void CopyDirectoryWithProgressInternal(FileSystemManager fs, string sourcePath, string destPath, CreateFileOptions options, IProgressReport logger) { - using (DirectoryHandle sourceHandle = fs.OpenDirectory(sourcePath, OpenDirectoryMode.All)) + fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All).ThrowIfFailure(); + + using (sourceHandle) { foreach (DirectoryEntry entry in fs.ReadDirectory(sourceHandle)) { @@ -63,37 +65,53 @@ namespace hactoolnet return size; } - public static void CopyFileWithProgress(FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) + public static Result CopyFileWithProgress(FileSystemManager fs, string sourcePath, string destPath, IProgressReport logger = null) { - using (FileHandle sourceHandle = fs.OpenFile(sourcePath, OpenMode.Read)) - using (FileHandle destHandle = fs.OpenFile(destPath, OpenMode.Write | OpenMode.AllowAppend)) + Result rc = fs.OpenFile(out FileHandle sourceHandle, sourcePath, OpenMode.Read); + if (rc.IsFailure()) return rc; + + using (sourceHandle) { - const int maxBufferSize = 1024 * 1024; + rc = fs.OpenFile(out FileHandle destHandle, destPath, OpenMode.Write | OpenMode.AllowAppend); + if (rc.IsFailure()) return rc; - long fileSize = fs.GetFileSize(sourceHandle); - int bufferSize = (int)Math.Min(maxBufferSize, fileSize); - - byte[] buffer = ArrayPool.Shared.Rent(bufferSize); - try + using (destHandle) { - for (long offset = 0; offset < fileSize; offset += bufferSize) + const int maxBufferSize = 1024 * 1024; + + rc = fs.GetFileSize(out long fileSize, sourceHandle); + if (rc.IsFailure()) return rc; + + int bufferSize = (int)Math.Min(maxBufferSize, fileSize); + + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + try { - int toRead = (int)Math.Min(fileSize - offset, bufferSize); - Span buf = buffer.AsSpan(0, toRead); + for (long offset = 0; offset < fileSize; offset += bufferSize) + { + int toRead = (int)Math.Min(fileSize - offset, bufferSize); + Span buf = buffer.AsSpan(0, toRead); - fs.ReadFile(sourceHandle, buf, offset); - fs.WriteFile(destHandle, buf, offset); + rc = fs.ReadFile(out long _, sourceHandle, buf, offset); + if (rc.IsFailure()) return rc; - logger?.ReportAdd(toRead); + rc = fs.WriteFile(destHandle, buf, offset); + if (rc.IsFailure()) return rc; + + logger?.ReportAdd(toRead); + } + } + finally + { + ArrayPool.Shared.Return(buffer); } - } - finally - { - ArrayPool.Shared.Return(buffer); - } - fs.FlushFile(destHandle); + rc = fs.FlushFile(destHandle); + if (rc.IsFailure()) return rc; + } } + + return Result.Success; } } } diff --git a/src/hactoolnet/ProcessDelta.cs b/src/hactoolnet/ProcessDelta.cs index d8c1c4b7..b03dde02 100644 --- a/src/hactoolnet/ProcessDelta.cs +++ b/src/hactoolnet/ProcessDelta.cs @@ -33,7 +33,9 @@ namespace hactoolnet throw new FileNotFoundException("Specified NCA does not contain a delta fragment"); } - deltaStorage = fs.OpenFile(FragmentFileName, OpenMode.Read).AsStorage(); + fs.OpenFile(out IFile deltaFragmentFile, FragmentFileName, OpenMode.Read).ThrowIfFailure(); + + deltaStorage = deltaFragmentFile.AsStorage(); } catch (InvalidDataException) { } // Ignore non-NCA3 files } diff --git a/src/hactoolnet/ProcessNca.cs b/src/hactoolnet/ProcessNca.cs index da1caf58..5b301917 100644 --- a/src/hactoolnet/ProcessNca.cs +++ b/src/hactoolnet/ProcessNca.cs @@ -210,8 +210,8 @@ namespace hactoolnet IFileSystem pfs = nca.OpenFileSystem(NcaSectionType.Code, IntegrityCheckLevel.ErrorOnInvalid); if (!pfs.FileExists("main.npdm")) return Validity.Unchecked; - IFile npdmStorage = pfs.OpenFile("main.npdm", OpenMode.Read); - var npdm = new NpdmBinary(npdmStorage.AsStream()); + pfs.OpenFile(out IFile npdmFile, "main.npdm", OpenMode.Read).ThrowIfFailure(); + var npdm = new NpdmBinary(npdmFile.AsStream()); return nca.Header.VerifySignature2(npdm.AciD.Rsa2048Modulus); } diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs index 6be16758..e95f8340 100644 --- a/src/hactoolnet/ProcessSave.cs +++ b/src/hactoolnet/ProcessSave.cs @@ -62,7 +62,9 @@ namespace hactoolnet using (IFile inFile = new LocalFile(ctx.Options.ReplaceFileSource, OpenMode.Read)) { - using (IFile outFile = save.OpenFile(destFilename, OpenMode.ReadWrite)) + save.OpenFile(out IFile outFile, destFilename, OpenMode.ReadWrite).ThrowIfFailure(); + + using (outFile) { inFile.GetSize(out long inFileSize).ThrowIfFailure(); outFile.GetSize(out long outFileSize).ThrowIfFailure(); @@ -100,7 +102,7 @@ namespace hactoolnet { if (signNeeded) { - save.Commit(ctx.Keyset); + save.Commit(ctx.Keyset).ThrowIfFailure(); signNeeded = false; } } @@ -114,7 +116,7 @@ namespace hactoolnet if (signNeeded) { - if (save.Commit(ctx.Keyset)) + if (save.Commit(ctx.Keyset).IsSuccess()) { ctx.Logger.LogMessage("Successfully signed save file"); } @@ -310,7 +312,7 @@ namespace hactoolnet var sb = new StringBuilder(); sb.AppendLine(); - long freeSpace = save.GetFreeSpaceSize(""); + save.GetFreeSpaceSize(out long freeSpace, "").ThrowIfFailure(); sb.AppendLine("Savefile:"); PrintItem(sb, colLen, $"CMAC Signature{save.Header.SignatureValidity.GetValidityString()}:", save.Header.Cmac);