diff --git a/src/LibHac/Fs/Impl/StorageServiceObjectAdapter.cs b/src/LibHac/Fs/Impl/StorageServiceObjectAdapter.cs index 29285d2b..d837248f 100644 --- a/src/LibHac/Fs/Impl/StorageServiceObjectAdapter.cs +++ b/src/LibHac/Fs/Impl/StorageServiceObjectAdapter.cs @@ -10,7 +10,7 @@ namespace LibHac.Fs.Impl; /// An adapter for using an service object as an . Used /// when receiving a Horizon IPC storage object so it can be used as an locally. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) internal class StorageServiceObjectAdapter : IStorage { private SharedRef _baseStorage; @@ -20,6 +20,12 @@ internal class StorageServiceObjectAdapter : IStorage _baseStorage = SharedRef.CreateMove(ref baseStorage); } + public override void Dispose() + { + _baseStorage.Destroy(); + base.Dispose(); + } + public override Result Read(long offset, Span destination) { return _baseStorage.Get.Read(offset, new OutBuffer(destination), destination.Length); @@ -50,8 +56,6 @@ internal class StorageServiceObjectAdapter : IStorage { switch (operationId) { - case OperationId.InvalidateCache: - return _baseStorage.Get.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size); case OperationId.QueryRange: if (outBuffer.Length != Unsafe.SizeOf()) return ResultFs.InvalidSize.Log(); @@ -59,14 +63,12 @@ internal class StorageServiceObjectAdapter : IStorage ref QueryRangeInfo info = ref SpanHelpers.AsStruct(outBuffer); return _baseStorage.Get.OperateRange(out info, (int)OperationId.QueryRange, offset, size); + + case OperationId.InvalidateCache: + return _baseStorage.Get.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size); + default: return ResultFs.UnsupportedOperateRangeForStorageServiceObjectAdapter.Log(); } } - - public override void Dispose() - { - _baseStorage.Destroy(); - base.Dispose(); - } } \ No newline at end of file diff --git a/src/LibHac/Fs/Shim/Application.cs b/src/LibHac/Fs/Shim/Application.cs index 7f41e596..ba44e43d 100644 --- a/src/LibHac/Fs/Shim/Application.cs +++ b/src/LibHac/Fs/Shim/Application.cs @@ -14,7 +14,7 @@ namespace LibHac.Fs.Shim; /// /// Contains functions for mounting application packages. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) [SkipLocalsInit] public static class Application { @@ -76,4 +76,4 @@ public static class Application return Result.Success; } } -} +} \ No newline at end of file diff --git a/src/LibHac/Fs/Shim/BcatSaveData.cs b/src/LibHac/Fs/Shim/BcatSaveData.cs index 70cf4a6a..7dd3fa64 100644 --- a/src/LibHac/Fs/Shim/BcatSaveData.cs +++ b/src/LibHac/Fs/Shim/BcatSaveData.cs @@ -14,7 +14,7 @@ namespace LibHac.Fs.Shim; /// /// Contains functions for mounting BCAT save data. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) [SkipLocalsInit] public static class BcatSaveData { @@ -78,4 +78,4 @@ public static class BcatSaveData return Result.Success; } } -} +} \ No newline at end of file diff --git a/src/LibHac/Fs/Shim/Bis.cs b/src/LibHac/Fs/Shim/Bis.cs index 614678ea..6cfd7474 100644 --- a/src/LibHac/Fs/Shim/Bis.cs +++ b/src/LibHac/Fs/Shim/Bis.cs @@ -19,7 +19,7 @@ namespace LibHac.Fs.Shim; /// Contains functions for mounting built-in-storage partition file systems /// and opening the raw partitions as s. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) [SkipLocalsInit] public static class Bis { @@ -122,7 +122,7 @@ public static class Bis public static Result MountBis(this FileSystemClient fs, U8Span mountName, BisPartitionId partitionId) { - return MountBis(fs.Impl, mountName, partitionId, default); + return MountBis(fs.Impl, mountName, partitionId, U8Span.Empty); } public static Result MountBis(this FileSystemClient fs, BisPartitionId partitionId, U8Span rootPath) @@ -167,17 +167,21 @@ public static class Bis public static Result OpenBisPartition(this FileSystemClient fs, ref UniqueRef outPartitionStorage, BisPartitionId partitionId) { - using var storage = new SharedRef(); using SharedRef fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject(); + using var storage = new SharedRef(); Result rc = fileSystemProxy.Get.OpenBisStorage(ref storage.Ref(), partitionId); fs.Impl.AbortIfNeeded(rc); - if (rc.IsFailure()) return rc; + if (rc.IsFailure()) return rc.Miss(); using var storageAdapter = new UniqueRef(new StorageServiceObjectAdapter(ref storage.Ref())); if (!storageAdapter.HasValue) - return ResultFs.AllocationMemoryFailedInBisC.Log(); + { + rc = ResultFs.AllocationMemoryFailedInBisC.Value; + fs.Impl.AbortIfNeeded(rc); + if (rc.IsFailure()) return rc.Log(); + } outPartitionStorage.Set(ref storageAdapter.Ref()); return Result.Success; diff --git a/src/LibHac/Fs/Shim/Code.cs b/src/LibHac/Fs/Shim/Code.cs index 12b34d63..245286c6 100644 --- a/src/LibHac/Fs/Shim/Code.cs +++ b/src/LibHac/Fs/Shim/Code.cs @@ -15,7 +15,7 @@ namespace LibHac.Fs.Shim; /// /// Contains functions for mounting code file systems. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) [SkipLocalsInit] public static class Code { @@ -59,20 +59,19 @@ public static class Code Result rc = fs.Impl.CheckMountName(mountName); if (rc.IsFailure()) return rc; - if (path.IsNull()) - return ResultFs.NullptrArgument.Log(); - - rc = PathUtility.ConvertToFspPath(out FspPath fsPath, path); + rc = PathUtility.ConvertToFspPath(out FspPath sfPath, path); if (rc.IsFailure()) return rc; using SharedRef fileSystemProxy = fs.Impl.GetFileSystemProxyForLoaderServiceObject(); - // SetCurrentProcess + // Todo: IPC code should automatically set process ID + rc = fileSystemProxy.Get.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value); + if (rc.IsFailure()) return rc.Miss(); using var fileSystem = new SharedRef(); - rc = fileSystemProxy.Get.OpenCodeFileSystem(ref fileSystem.Ref(), out verificationData, in fsPath, + rc = fileSystemProxy.Get.OpenCodeFileSystem(ref fileSystem.Ref(), out verificationData, in sfPath, programId); if (rc.IsFailure()) return rc; @@ -88,4 +87,4 @@ public static class Code return Result.Success; } } -} +} \ No newline at end of file diff --git a/src/LibHac/Fs/Shim/Content.cs b/src/LibHac/Fs/Shim/Content.cs index 5f1c3643..7b04a708 100644 --- a/src/LibHac/Fs/Shim/Content.cs +++ b/src/LibHac/Fs/Shim/Content.cs @@ -16,7 +16,7 @@ namespace LibHac.Fs.Shim; /// /// Contains functions for mounting content file systems. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) [SkipLocalsInit] public static class Content { @@ -42,16 +42,13 @@ public static class Content FileSystemProxyType fsType = ConvertToFileSystemProxyType(contentType); - if (path.IsNull()) - return ResultFs.NullptrArgument.Log(); - - rc = PathUtility.ConvertToFspPath(out FspPath fsPath, path); + rc = PathUtility.ConvertToFspPath(out FspPath sfPath, path); if (rc.IsFailure()) return rc; using SharedRef fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject(); using var fileSystem = new SharedRef(); - rc = fileSystemProxy.Get.OpenFileSystemWithId(ref fileSystem.Ref(), in fsPath, id, fsType); + rc = fileSystemProxy.Get.OpenFileSystemWithId(ref fileSystem.Ref(), in sfPath, id, fsType); if (rc.IsFailure()) return rc; using var fileSystemAdapter = @@ -66,8 +63,7 @@ public static class Content return Result.Success; } - public static Result MountContent(this FileSystemClient fs, U8Span mountName, U8Span path, - ContentType contentType) + public static Result MountContent(this FileSystemClient fs, U8Span mountName, U8Span path, ContentType contentType) { Result rc; Span logBuffer = stackalloc byte[0x300]; @@ -95,12 +91,12 @@ public static class Content fs.Impl.AbortIfNeeded(rc); if (rc.IsFailure()) return rc; - const ulong programId = 0; + ProgramId programId = default; if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System)) { Tick start = fs.Hos.Os.GetSystemTick(); - rc = MountContentImpl(fs, mountName, path, programId, contentType); + rc = MountContentImpl(fs, mountName, path, programId.Value, contentType); Tick end = fs.Hos.Os.GetSystemTick(); var idString = new IdString(); @@ -108,14 +104,14 @@ public static class Content sb.Append(LogName).Append(mountName).Append(LogQuote) .Append(LogPath).Append(path).Append(LogQuote) - .Append(LogProgramId).AppendFormat(programId, 'X') + .Append(LogProgramId).AppendFormat(programId.Value, 'X') .Append(LogContentType).Append(idString.ToString(contentType)); fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer)); } else { - rc = MountContentImpl(fs, mountName, path, programId, contentType); + rc = MountContentImpl(fs, mountName, path, programId.Value, contentType); } fs.Impl.AbortIfNeeded(rc); @@ -128,7 +124,7 @@ public static class Content static Result PreMount(ContentType contentType) { - if (contentType == ContentType.Meta) + if (contentType != ContentType.Meta) return ResultFs.InvalidArgument.Log(); return Result.Success; @@ -268,4 +264,4 @@ public static class Content return Result.Success; } } -} +} \ No newline at end of file diff --git a/src/LibHac/Fs/Shim/ContentStorage.cs b/src/LibHac/Fs/Shim/ContentStorage.cs index ab9fc358..04a66784 100644 --- a/src/LibHac/Fs/Shim/ContentStorage.cs +++ b/src/LibHac/Fs/Shim/ContentStorage.cs @@ -16,7 +16,7 @@ namespace LibHac.Fs.Shim; /// /// Contains functions for mounting the directories where content is stored. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) [SkipLocalsInit] public static class ContentStorage { @@ -109,6 +109,8 @@ public static class ContentStorage if (!ResultFs.SystemPartitionNotReady.Includes(rc)) return rc; + // Note: Nintendo has an off-by-one error where they check if + // "i == maxRetries" instead of "i == maxRetries - 1" if (i == maxRetries - 1) return rc; @@ -149,4 +151,4 @@ public static class ContentStorage return default; } } -} +} \ No newline at end of file diff --git a/src/LibHac/Fs/Shim/CustomStorage.cs b/src/LibHac/Fs/Shim/CustomStorage.cs index 4ddd5f97..319c45ca 100644 --- a/src/LibHac/Fs/Shim/CustomStorage.cs +++ b/src/LibHac/Fs/Shim/CustomStorage.cs @@ -13,7 +13,7 @@ namespace LibHac.Fs.Shim; /// /// Contains functions for mounting custom storage file systems. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) [SkipLocalsInit] public static class CustomStorage { @@ -60,10 +60,11 @@ public static class CustomStorage } } - private static ReadOnlySpan CustomStorageDirectoryName => // "CustomStorage0" + /// "CustomStorage0" + private static ReadOnlySpan CustomStorageDirectoryName => new[] { (byte)'C', (byte)'u', (byte)'s', (byte)'t', (byte)'o', (byte)'m', (byte)'S', (byte)'t', (byte)'o', (byte)'r', (byte)'a', (byte)'g', (byte)'e', (byte)'0' }; -} +} \ No newline at end of file diff --git a/src/LibHac/Fs/Shim/FileSystemServiceObjectAdapter.cs b/src/LibHac/Fs/Shim/FileSystemServiceObjectAdapter.cs index f343795e..8d14426d 100644 --- a/src/LibHac/Fs/Shim/FileSystemServiceObjectAdapter.cs +++ b/src/LibHac/Fs/Shim/FileSystemServiceObjectAdapter.cs @@ -21,7 +21,7 @@ namespace LibHac.Fs.Impl; /// An adapter for using an service object as an . Used /// when receiving a Horizon IPC file object so it can be used as an locally. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) internal class FileServiceObjectAdapter : IFile { private SharedRef _baseFile; @@ -67,8 +67,6 @@ internal class FileServiceObjectAdapter : IFile { switch (operationId) { - case OperationId.InvalidateCache: - return _baseFile.Get.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size); case OperationId.QueryRange: if (outBuffer.Length != Unsafe.SizeOf()) return ResultFs.InvalidSize.Log(); @@ -76,6 +74,8 @@ internal class FileServiceObjectAdapter : IFile ref QueryRangeInfo info = ref SpanHelpers.AsStruct(outBuffer); return _baseFile.Get.OperateRange(out info, (int)OperationId.QueryRange, offset, size); + case OperationId.InvalidateCache: + return _baseFile.Get.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size); default: return _baseFile.Get.OperateRangeWithBuffer(new OutBuffer(outBuffer), new InBuffer(inBuffer), (int)operationId, offset, size); @@ -87,7 +87,7 @@ internal class FileServiceObjectAdapter : IFile /// An adapter for using an service object as an . Used /// when receiving a Horizon IPC directory object so it can be used as an locally. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) internal class DirectoryServiceObjectAdapter : IDirectory { private SharedRef _baseDirectory; @@ -119,7 +119,7 @@ internal class DirectoryServiceObjectAdapter : IDirectory /// An adapter for using an service object as an . Used /// when receiving a Horizon IPC file system object so it can be used as an locally. /// -/// Based on FS 12.1.0 (nnSdk 12.3.1) +/// Based on FS 13.1.0 (nnSdk 13.4.0) internal class FileSystemServiceObjectAdapter : IFileSystem, IMultiCommitTarget { private SharedRef _baseFs; @@ -312,4 +312,4 @@ internal class FileSystemServiceObjectAdapter : IFileSystem, IMultiCommitTarget { return GetFileSystem(); } -} +} \ No newline at end of file diff --git a/src/LibHac/Fs/Shim/LoaderApi.cs b/src/LibHac/Fs/Shim/LoaderApi.cs index 47e5976f..d7b0a7f5 100644 --- a/src/LibHac/Fs/Shim/LoaderApi.cs +++ b/src/LibHac/Fs/Shim/LoaderApi.cs @@ -4,6 +4,10 @@ using LibHac.Os; namespace LibHac.Fs.Shim; +/// +/// Contains functions for use by the Loader service. +/// +/// Based on nnSdk 13.4.0 public static class LoaderApi { public static Result IsArchivedProgram(this FileSystemClient fs, out bool isArchived, ProcessId processId) @@ -13,6 +17,8 @@ public static class LoaderApi Result rc = fileSystemProxy.Get.IsArchivedProgram(out isArchived, processId.Value); fs.Impl.AbortIfNeeded(rc); - return rc; + if (rc.IsFailure()) return rc.Miss(); + + return Result.Success; } -} +} \ No newline at end of file diff --git a/tests/LibHac.Tests/FsSrv/AccessControlTests.cs b/tests/LibHac.Tests/FsSrv/AccessControlTests.cs index ade5e02b..ed6c807b 100644 --- a/tests/LibHac.Tests/FsSrv/AccessControlTests.cs +++ b/tests/LibHac.Tests/FsSrv/AccessControlTests.cs @@ -31,7 +31,7 @@ public class AccessControlTests StorageId.BuiltInUser, SpanHelpers.AsReadOnlyByteSpan(in dataHeader), SpanHelpers.AsReadOnlyByteSpan(in descriptor))); - Result rc = client.Fs.MountContent("test".ToU8Span(), "@System:/fake.nca".ToU8Span(), ContentType.Control); + Result rc = client.Fs.MountContent("test".ToU8Span(), "@System:/fake.nca".ToU8Span(), ContentType.Meta); Assert.Result(ResultFs.PermissionDenied, rc); } @@ -57,7 +57,7 @@ public class AccessControlTests SpanHelpers.AsReadOnlyByteSpan(in descriptor))); // We should get UnexpectedInNcaFileSystemServiceImplA because mounting NCAs from @System isn't allowed - Result rc = client.Fs.MountContent("test".ToU8Span(), "@System:/fake.nca".ToU8Span(), ContentType.Control); + Result rc = client.Fs.MountContent("test".ToU8Span(), "@System:/fake.nca".ToU8Span(), ContentType.Meta); Assert.Result(ResultFs.UnexpectedInNcaFileSystemServiceImplA, rc); } -} +} \ No newline at end of file