From 2c2fed445f77e53248648c349ba34e46d675d902 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Tue, 25 Jan 2022 17:02:44 -0700 Subject: [PATCH] Ensure more FS classes are updated for 13.1.0 - FsSystem.ForwardingDirectory - FsSystem.ForwardingFile - FsSystem.ForwardingFileSystem - FsSystem.StorageLayoutTypeSetDirectory - FsSystem.StorageLayoutTypeSetFile - FsSystem.StorageLayoutTypeSetFileSystem - FsSystem.StorageLayoutTypeSetStorage - Fs.MemoryStorage - Fs.ReadOnlyFile - Fs.ReadOnlyFileSystem --- src/LibHac/Fs/MemoryStorage.cs | 34 +++- src/LibHac/Fs/ReadOnlyFileSystem.cs | 159 ++++++++++++++++++ src/LibHac/FsSystem/ForwardingFileSystem.cs | 74 +++++++- src/LibHac/FsSystem/ReadOnlyFile.cs | 54 ------ src/LibHac/FsSystem/ReadOnlyFileSystem.cs | 87 ---------- .../FsSystem/StorageLayoutTypeSetter.cs | 53 ++++-- 6 files changed, 299 insertions(+), 162 deletions(-) create mode 100644 src/LibHac/Fs/ReadOnlyFileSystem.cs delete mode 100644 src/LibHac/FsSystem/ReadOnlyFile.cs delete mode 100644 src/LibHac/FsSystem/ReadOnlyFileSystem.cs diff --git a/src/LibHac/Fs/MemoryStorage.cs b/src/LibHac/Fs/MemoryStorage.cs index 9a9dde6d..f9cdf523 100644 --- a/src/LibHac/Fs/MemoryStorage.cs +++ b/src/LibHac/Fs/MemoryStorage.cs @@ -1,14 +1,20 @@ using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace LibHac.Fs; +/// +/// Allows interacting with a array via the interface. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) public class MemoryStorage : IStorage { - private byte[] StorageBuffer { get; } + private byte[] _storageBuffer; public MemoryStorage(byte[] buffer) { - StorageBuffer = buffer; + _storageBuffer = buffer; } public override Result Read(long offset, Span destination) @@ -16,10 +22,10 @@ public class MemoryStorage : IStorage if (destination.Length == 0) return Result.Success; - if (!CheckAccessRange(offset, destination.Length, StorageBuffer.Length)) + if (!CheckAccessRange(offset, destination.Length, _storageBuffer.Length)) return ResultFs.OutOfRange.Log(); - StorageBuffer.AsSpan((int)offset, destination.Length).CopyTo(destination); + _storageBuffer.AsSpan((int)offset, destination.Length).CopyTo(destination); return Result.Success; } @@ -29,10 +35,10 @@ public class MemoryStorage : IStorage if (source.Length == 0) return Result.Success; - if (!CheckAccessRange(offset, source.Length, StorageBuffer.Length)) + if (!CheckAccessRange(offset, source.Length, _storageBuffer.Length)) return ResultFs.OutOfRange.Log(); - source.CopyTo(StorageBuffer.AsSpan((int)offset)); + source.CopyTo(_storageBuffer.AsSpan((int)offset)); return Result.Success; } @@ -49,7 +55,7 @@ public class MemoryStorage : IStorage public override Result GetSize(out long size) { - size = StorageBuffer.Length; + size = _storageBuffer.Length; return Result.Success; } @@ -57,6 +63,18 @@ public class MemoryStorage : IStorage public override Result OperateRange(Span outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan inBuffer) { - throw new NotImplementedException(); + switch (operationId) + { + case OperationId.InvalidateCache: + return Result.Success; + case OperationId.QueryRange: + if (outBuffer.Length != Unsafe.SizeOf()) + return ResultFs.InvalidSize.Log(); + + Unsafe.As(ref MemoryMarshal.GetReference(outBuffer)).Clear(); + return Result.Success; + default: + return ResultFs.UnsupportedOperateRangeForMemoryStorage.Log(); + } } } \ No newline at end of file diff --git a/src/LibHac/Fs/ReadOnlyFileSystem.cs b/src/LibHac/Fs/ReadOnlyFileSystem.cs new file mode 100644 index 00000000..e8a15436 --- /dev/null +++ b/src/LibHac/Fs/ReadOnlyFileSystem.cs @@ -0,0 +1,159 @@ +using System; +using System.Runtime.CompilerServices; +using LibHac.Common; +using LibHac.Diag; +using LibHac.Fs.Fsa; + +namespace LibHac.Fs; + +/// +/// Wraps an and only allows read operations on it. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) +internal class ReadOnlyFile : IFile +{ + private UniqueRef _baseFile; + + public ReadOnlyFile(ref UniqueRef baseFile) + { + _baseFile = new UniqueRef(ref baseFile); + + Assert.SdkRequires(_baseFile.HasValue); + } + + public override void Dispose() + { + _baseFile.Destroy(); + + base.Dispose(); + } + + protected override Result DoRead(out long bytesRead, long offset, Span destination, + in ReadOption option) + { + return _baseFile.Get.Read(out bytesRead, offset, destination, option); + } + + protected override Result DoGetSize(out long size) + { + return _baseFile.Get.GetSize(out size); + } + + protected override Result DoFlush() + { + return Result.Success; + } + + protected override Result DoWrite(long offset, ReadOnlySpan source, in WriteOption option) + { + return ResultFs.UnsupportedWriteForReadOnlyFile.Log(); + } + + protected override Result DoSetSize(long size) + { + return ResultFs.UnsupportedWriteForReadOnlyFile.Log(); + } + + protected override Result DoOperateRange(Span outBuffer, OperationId operationId, long offset, long size, + ReadOnlySpan inBuffer) + { + switch (operationId) + { + case OperationId.InvalidateCache: + case OperationId.QueryRange: + return _baseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer); + default: + return ResultFs.UnsupportedOperateRangeForReadOnlyFile.Log(); + } + } +} + +/// +/// Wraps an and only allows read operations on it. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) +public class ReadOnlyFileSystem : IFileSystem +{ + private SharedRef _baseFileSystem; + + public ReadOnlyFileSystem(ref SharedRef baseFileSystem) + { + _baseFileSystem = SharedRef.CreateMove(ref baseFileSystem); + + Assert.SdkRequires(_baseFileSystem.HasValue); + } + + public override void Dispose() + { + _baseFileSystem.Destroy(); + + base.Dispose(); + } + + protected override Result DoOpenFile(ref UniqueRef outFile, in Path path, OpenMode mode) + { + // The Read flag must be the only flag set + if ((mode & OpenMode.All) != OpenMode.Read) + return ResultFs.InvalidModeForFileOpen.Log(); + + using var baseFile = new UniqueRef(); + Result rc = _baseFileSystem.Get.OpenFile(ref baseFile.Ref(), in path, mode); + if (rc.IsFailure()) return rc; + + outFile.Reset(new ReadOnlyFile(ref baseFile.Ref())); + return Result.Success; + } + + protected override Result DoOpenDirectory(ref UniqueRef outDirectory, in Path path, + OpenDirectoryMode mode) + { + // An IDirectory is already read-only so we don't need a wrapper ReadOnlyDictionary class + return _baseFileSystem.Get.OpenDirectory(ref outDirectory, in path, mode); + } + + protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path) + { + return _baseFileSystem.Get.GetEntryType(out entryType, in path); + } + + protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option) => + ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); + + protected override Result DoDeleteFile(in Path path) => + ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); + + protected override Result DoCreateDirectory(in Path path) => + ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); + + protected override Result DoDeleteDirectory(in Path path) => + ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); + + protected override Result DoDeleteDirectoryRecursively(in Path path) => + ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); + + protected override Result DoCleanDirectoryRecursively(in Path path) => + ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); + + protected override Result DoRenameFile(in Path currentPath, in Path newPath) => + ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); + + protected override Result DoRenameDirectory(in Path currentPath, in Path newPath) => + ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); + + protected override Result DoCommit() => + Result.Success; + + protected override Result DoCommitProvisionally(long counter) => + ResultFs.UnsupportedCommitProvisionallyForReadOnlyFileSystem.Log(); + + protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path) + { + return _baseFileSystem.Get.GetFreeSpaceSize(out freeSpace, in path); + } + + protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path) + { + Unsafe.SkipInit(out totalSpace); + return ResultFs.UnsupportedGetTotalSpaceSizeForReadOnlyFileSystem.Log(); + } +} \ No newline at end of file diff --git a/src/LibHac/FsSystem/ForwardingFileSystem.cs b/src/LibHac/FsSystem/ForwardingFileSystem.cs index ea0b18ca..d82c8f82 100644 --- a/src/LibHac/FsSystem/ForwardingFileSystem.cs +++ b/src/LibHac/FsSystem/ForwardingFileSystem.cs @@ -5,11 +5,80 @@ using LibHac.Fs.Fsa; namespace LibHac.FsSystem; +/// +/// An wrapper that forwards all calls to the base . +/// Meant for use as a base class when the derived class only needs to override some of the methods. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) +public class ForwardingFile : IFile +{ + protected UniqueRef BaseFile; + + protected ForwardingFile(ref UniqueRef baseFile) + { + BaseFile = new UniqueRef(ref baseFile); + } + + public override void Dispose() + { + BaseFile.Destroy(); + + base.Dispose(); + } + + protected override Result DoRead(out long bytesRead, long offset, Span destination, in ReadOption option) => + BaseFile.Get.Read(out bytesRead, offset, destination, in option); + + protected override Result DoWrite(long offset, ReadOnlySpan source, in WriteOption option) => + BaseFile.Get.Write(offset, source, in option); + + protected override Result DoFlush() => BaseFile.Get.Flush(); + + protected override Result DoSetSize(long size) => BaseFile.Get.SetSize(size); + + protected override Result DoGetSize(out long size) => BaseFile.Get.GetSize(out size); + + protected override Result DoOperateRange(Span outBuffer, OperationId operationId, long offset, long size, + ReadOnlySpan inBuffer) => BaseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer); +} + +/// +/// An wrapper that forwards all calls to the base . +/// Primarily meant for use as a base class when the derived class only needs to override some of the methods. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) +public class ForwardingDirectory : IDirectory +{ + protected UniqueRef BaseDirectory; + + protected ForwardingDirectory(ref UniqueRef baseDirectory) + { + BaseDirectory = new UniqueRef(ref baseDirectory); + } + + public override void Dispose() + { + BaseDirectory.Destroy(); + + base.Dispose(); + } + + protected override Result DoRead(out long entriesRead, Span entryBuffer) => + BaseDirectory.Get.Read(out entriesRead, entryBuffer); + + protected override Result DoGetEntryCount(out long entryCount) => BaseDirectory.Get.GetEntryCount(out entryCount); +} + +/// +/// An wrapper that forwards all calls to the base . +/// Primarily meant for use as a base class when the derived class only needs to override some of the methods. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) public class ForwardingFileSystem : IFileSystem { protected SharedRef BaseFileSystem; - public ForwardingFileSystem(ref SharedRef baseFileSystem) + protected ForwardingFileSystem(ref SharedRef baseFileSystem) { BaseFileSystem = SharedRef.CreateMove(ref baseFileSystem); } @@ -17,6 +86,7 @@ public class ForwardingFileSystem : IFileSystem public override void Dispose() { BaseFileSystem.Destroy(); + base.Dispose(); } @@ -71,4 +141,4 @@ public class ForwardingFileSystem : IFileSystem protected override Result DoQueryEntry(Span outBuffer, ReadOnlySpan inBuffer, QueryId queryId, in Path path) => BaseFileSystem.Get.QueryEntry(outBuffer, inBuffer, queryId, in path); -} +} \ No newline at end of file diff --git a/src/LibHac/FsSystem/ReadOnlyFile.cs b/src/LibHac/FsSystem/ReadOnlyFile.cs deleted file mode 100644 index ab7a8030..00000000 --- a/src/LibHac/FsSystem/ReadOnlyFile.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Fsa; - -namespace LibHac.FsSystem; - -public class ReadOnlyFile : IFile -{ - private UniqueRef _baseFile; - - public ReadOnlyFile(ref UniqueRef baseFile) - { - _baseFile = new UniqueRef(ref baseFile); - } - - protected override Result DoRead(out long bytesRead, long offset, Span destination, - in ReadOption option) - { - return _baseFile.Get.Read(out bytesRead, offset, destination, option); - } - - protected override Result DoGetSize(out long size) - { - return _baseFile.Get.GetSize(out size); - } - - protected override Result DoFlush() - { - return Result.Success; - } - - protected override Result DoWrite(long offset, ReadOnlySpan source, in WriteOption option) - { - return ResultFs.WriteUnpermitted.Log(); - } - - protected override Result DoSetSize(long size) - { - return ResultFs.WriteUnpermitted.Log(); - } - - protected override Result DoOperateRange(Span outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan inBuffer) - { - switch (operationId) - { - case OperationId.InvalidateCache: - case OperationId.QueryRange: - return _baseFile.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer); - default: - return ResultFs.UnsupportedOperateRangeForReadOnlyFile.Log(); - } - } -} diff --git a/src/LibHac/FsSystem/ReadOnlyFileSystem.cs b/src/LibHac/FsSystem/ReadOnlyFileSystem.cs deleted file mode 100644 index d868d559..00000000 --- a/src/LibHac/FsSystem/ReadOnlyFileSystem.cs +++ /dev/null @@ -1,87 +0,0 @@ -using LibHac.Common; -using LibHac.Diag; -using LibHac.Fs; -using LibHac.Fs.Fsa; - -namespace LibHac.FsSystem; - -public class ReadOnlyFileSystem : IFileSystem -{ - private SharedRef _baseFileSystem; - - public ReadOnlyFileSystem(ref SharedRef baseFileSystem) - { - _baseFileSystem = SharedRef.CreateMove(ref baseFileSystem); - - Assert.SdkRequires(_baseFileSystem.HasValue); - } - - public override void Dispose() - { - _baseFileSystem.Destroy(); - base.Dispose(); - } - - protected override Result DoOpenDirectory(ref UniqueRef outDirectory, in Path path, - OpenDirectoryMode mode) - { - return _baseFileSystem.Get.OpenDirectory(ref outDirectory, in path, mode); - } - - protected override Result DoOpenFile(ref UniqueRef outFile, in Path path, OpenMode mode) - { - using var baseFile = new UniqueRef(); - Result rc = _baseFileSystem.Get.OpenFile(ref baseFile.Ref(), in path, mode); - if (rc.IsFailure()) return rc; - - outFile.Reset(new ReadOnlyFile(ref baseFile.Ref())); - return Result.Success; - } - - protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path) - { - return _baseFileSystem.Get.GetEntryType(out entryType, in path); - } - - protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path) - { - return _baseFileSystem.Get.GetFreeSpaceSize(out freeSpace, in path); - } - - protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path) - { - return _baseFileSystem.Get.GetTotalSpaceSize(out totalSpace, in path); - - // FS does: - // return ResultFs.UnsupportedOperationReadOnlyFileSystemGetSpace.Log(); - } - - protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path) - { - return _baseFileSystem.Get.GetFileTimeStampRaw(out timeStamp, in path); - - // FS does: - // return ResultFs.NotImplemented.Log(); - } - - protected override Result DoCommit() - { - return Result.Success; - } - - protected override Result DoCreateDirectory(in Path path) => ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); - - protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option) => ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); - - protected override Result DoDeleteDirectory(in Path path) => ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); - - protected override Result DoDeleteDirectoryRecursively(in Path path) => ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); - - protected override Result DoCleanDirectoryRecursively(in Path path) => ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); - - protected override Result DoDeleteFile(in Path path) => ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); - - protected override Result DoRenameDirectory(in Path currentPath, in Path newPath) => ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); - - protected override Result DoRenameFile(in Path currentPath, in Path newPath) => ResultFs.UnsupportedWriteForReadOnlyFileSystem.Log(); -} diff --git a/src/LibHac/FsSystem/StorageLayoutTypeSetter.cs b/src/LibHac/FsSystem/StorageLayoutTypeSetter.cs index 36fbe6b9..3450513e 100644 --- a/src/LibHac/FsSystem/StorageLayoutTypeSetter.cs +++ b/src/LibHac/FsSystem/StorageLayoutTypeSetter.cs @@ -18,6 +18,10 @@ internal enum StorageType All = Bis | SdCard | GameCard | Usb } +/// +/// Contains functions for validating the storage layout type flag. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) internal static class StorageLayoutType { public static bool IsStorageFlagValid(StorageType storageFlag) @@ -40,6 +44,11 @@ internal struct ScopedStorageLayoutTypeSetter : IDisposable } } +/// +/// Wraps an , automatically setting the thread's storage type when accessing the storage. +/// This is used to determine which storage speed emulation parameters to use for the current thread. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) internal class StorageLayoutTypeSetStorage : IStorage { private SharedRef _baseStorage; @@ -55,8 +64,10 @@ internal class StorageLayoutTypeSetStorage : IStorage public override void Dispose() { - using var scopedContext = new ScopedStorageLayoutTypeSetter(_storageFlag); - _baseStorage.Destroy(); + using (new ScopedStorageLayoutTypeSetter(_storageFlag)) + { + _baseStorage.Destroy(); + } base.Dispose(); } @@ -99,6 +110,11 @@ internal class StorageLayoutTypeSetStorage : IStorage } } +/// +/// Wraps an , automatically setting the thread's storage type when accessing the file. +/// This is used to determine which storage speed emulation parameters to use for the current thread. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) internal class StorageLayoutTypeSetFile : IFile { private IFile _baseFile; @@ -126,11 +142,12 @@ internal class StorageLayoutTypeSetFile : IFile public override void Dispose() { - using var scopedContext = new ScopedStorageLayoutTypeSetter(_storageFlag); - - _baseFile = null; - _baseFileUnique.Destroy(); - _baseFileShared.Destroy(); + using (new ScopedStorageLayoutTypeSetter(_storageFlag)) + { + _baseFile = null; + _baseFileUnique.Destroy(); + _baseFileShared.Destroy(); + } base.Dispose(); } @@ -173,6 +190,11 @@ internal class StorageLayoutTypeSetFile : IFile } } +/// +/// Wraps an , automatically setting the thread's storage type when accessing the directory. +/// This is used to determine which storage speed emulation parameters to use for the current thread. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) internal class StorageLayoutTypeSetDirectory : IDirectory { private UniqueRef _baseDirectory; @@ -186,8 +208,10 @@ internal class StorageLayoutTypeSetDirectory : IDirectory public override void Dispose() { - using var scopedContext = new ScopedStorageLayoutTypeSetter(_storageFlag); - _baseDirectory.Destroy(); + using (new ScopedStorageLayoutTypeSetter(_storageFlag)) + { + _baseDirectory.Destroy(); + } base.Dispose(); } @@ -205,6 +229,10 @@ internal class StorageLayoutTypeSetDirectory : IDirectory } } +/// +/// Wraps an , automatically setting the thread's storage type when accessing the file system. +/// This is used to determine which storage speed emulation parameters to use for the current thread. +/// internal class StorageLayoutTypeSetFileSystem : IFileSystem { private SharedRef _baseFileSystem; @@ -220,8 +248,11 @@ internal class StorageLayoutTypeSetFileSystem : IFileSystem public override void Dispose() { - using var scopedContext = new ScopedStorageLayoutTypeSetter(_storageFlag); - _baseFileSystem.Destroy(); + using (new ScopedStorageLayoutTypeSetter(_storageFlag)) + { + _baseFileSystem.Destroy(); + } + base.Dispose(); }