Ensure shim classes are updated to 13.1.0

- Fs.Impl.DirectoryServiceObjectAdapter
- Fs.Impl.FileServiceObjectAdapter
- Fs.Impl.FileSystemServiceObjectAdapter
- Fs.Impl.StorageServiceObjectAdapter

- Fs.Shim.Application
- Fs.Shim.BcatSaveData
- Fs.Shim.Bis
- Fs.Shim.Code
- Fs.Shim.Content
- Fs.Shim.ContentStorage
- Fs.Shim.CustomStorage
- Fs.Shim.LoaderApi
This commit is contained in:
Alex Barney 2022-01-16 18:43:12 -07:00
parent 330bc2b483
commit 0b9af17dfd
11 changed files with 66 additions and 56 deletions

View file

@ -10,7 +10,7 @@ namespace LibHac.Fs.Impl;
/// An adapter for using an <see cref="IStorageSf"/> service object as an <see cref="IStorage"/>. Used /// An adapter for using an <see cref="IStorageSf"/> service object as an <see cref="IStorage"/>. Used
/// when receiving a Horizon IPC storage object so it can be used as an <see cref="IStorage"/> locally. /// when receiving a Horizon IPC storage object so it can be used as an <see cref="IStorage"/> locally.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
internal class StorageServiceObjectAdapter : IStorage internal class StorageServiceObjectAdapter : IStorage
{ {
private SharedRef<IStorageSf> _baseStorage; private SharedRef<IStorageSf> _baseStorage;
@ -20,6 +20,12 @@ internal class StorageServiceObjectAdapter : IStorage
_baseStorage = SharedRef<IStorageSf>.CreateMove(ref baseStorage); _baseStorage = SharedRef<IStorageSf>.CreateMove(ref baseStorage);
} }
public override void Dispose()
{
_baseStorage.Destroy();
base.Dispose();
}
public override Result Read(long offset, Span<byte> destination) public override Result Read(long offset, Span<byte> destination)
{ {
return _baseStorage.Get.Read(offset, new OutBuffer(destination), destination.Length); return _baseStorage.Get.Read(offset, new OutBuffer(destination), destination.Length);
@ -50,8 +56,6 @@ internal class StorageServiceObjectAdapter : IStorage
{ {
switch (operationId) switch (operationId)
{ {
case OperationId.InvalidateCache:
return _baseStorage.Get.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size);
case OperationId.QueryRange: case OperationId.QueryRange:
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>()) if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
return ResultFs.InvalidSize.Log(); return ResultFs.InvalidSize.Log();
@ -59,14 +63,12 @@ internal class StorageServiceObjectAdapter : IStorage
ref QueryRangeInfo info = ref SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer); ref QueryRangeInfo info = ref SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer);
return _baseStorage.Get.OperateRange(out info, (int)OperationId.QueryRange, offset, size); 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: default:
return ResultFs.UnsupportedOperateRangeForStorageServiceObjectAdapter.Log(); return ResultFs.UnsupportedOperateRangeForStorageServiceObjectAdapter.Log();
} }
} }
public override void Dispose()
{
_baseStorage.Destroy();
base.Dispose();
}
} }

View file

@ -14,7 +14,7 @@ namespace LibHac.Fs.Shim;
/// <summary> /// <summary>
/// Contains functions for mounting application packages. /// Contains functions for mounting application packages.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
[SkipLocalsInit] [SkipLocalsInit]
public static class Application public static class Application
{ {

View file

@ -14,7 +14,7 @@ namespace LibHac.Fs.Shim;
/// <summary> /// <summary>
/// Contains functions for mounting BCAT save data. /// Contains functions for mounting BCAT save data.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
[SkipLocalsInit] [SkipLocalsInit]
public static class BcatSaveData public static class BcatSaveData
{ {

View file

@ -19,7 +19,7 @@ namespace LibHac.Fs.Shim;
/// Contains functions for mounting built-in-storage partition file systems /// Contains functions for mounting built-in-storage partition file systems
/// and opening the raw partitions as <see cref="IStorage"/>s. /// and opening the raw partitions as <see cref="IStorage"/>s.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
[SkipLocalsInit] [SkipLocalsInit]
public static class Bis public static class Bis
{ {
@ -122,7 +122,7 @@ public static class Bis
public static Result MountBis(this FileSystemClient fs, U8Span mountName, BisPartitionId partitionId) 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) 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<IStorage> outPartitionStorage, public static Result OpenBisPartition(this FileSystemClient fs, ref UniqueRef<IStorage> outPartitionStorage,
BisPartitionId partitionId) BisPartitionId partitionId)
{ {
using var storage = new SharedRef<IStorageSf>();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject(); using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var storage = new SharedRef<IStorageSf>();
Result rc = fileSystemProxy.Get.OpenBisStorage(ref storage.Ref(), partitionId); Result rc = fileSystemProxy.Get.OpenBisStorage(ref storage.Ref(), partitionId);
fs.Impl.AbortIfNeeded(rc); fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc.Miss();
using var storageAdapter = new UniqueRef<IStorage>(new StorageServiceObjectAdapter(ref storage.Ref())); using var storageAdapter = new UniqueRef<IStorage>(new StorageServiceObjectAdapter(ref storage.Ref()));
if (!storageAdapter.HasValue) 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()); outPartitionStorage.Set(ref storageAdapter.Ref());
return Result.Success; return Result.Success;

View file

@ -15,7 +15,7 @@ namespace LibHac.Fs.Shim;
/// <summary> /// <summary>
/// Contains functions for mounting code file systems. /// Contains functions for mounting code file systems.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
[SkipLocalsInit] [SkipLocalsInit]
public static class Code public static class Code
{ {
@ -59,20 +59,19 @@ public static class Code
Result rc = fs.Impl.CheckMountName(mountName); Result rc = fs.Impl.CheckMountName(mountName);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
if (path.IsNull()) rc = PathUtility.ConvertToFspPath(out FspPath sfPath, path);
return ResultFs.NullptrArgument.Log();
rc = PathUtility.ConvertToFspPath(out FspPath fsPath, path);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
using SharedRef<IFileSystemProxyForLoader> fileSystemProxy = using SharedRef<IFileSystemProxyForLoader> fileSystemProxy =
fs.Impl.GetFileSystemProxyForLoaderServiceObject(); 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<IFileSystemSf>(); using var fileSystem = new SharedRef<IFileSystemSf>();
rc = fileSystemProxy.Get.OpenCodeFileSystem(ref fileSystem.Ref(), out verificationData, in fsPath, rc = fileSystemProxy.Get.OpenCodeFileSystem(ref fileSystem.Ref(), out verificationData, in sfPath,
programId); programId);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;

View file

@ -16,7 +16,7 @@ namespace LibHac.Fs.Shim;
/// <summary> /// <summary>
/// Contains functions for mounting content file systems. /// Contains functions for mounting content file systems.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
[SkipLocalsInit] [SkipLocalsInit]
public static class Content public static class Content
{ {
@ -42,16 +42,13 @@ public static class Content
FileSystemProxyType fsType = ConvertToFileSystemProxyType(contentType); FileSystemProxyType fsType = ConvertToFileSystemProxyType(contentType);
if (path.IsNull()) rc = PathUtility.ConvertToFspPath(out FspPath sfPath, path);
return ResultFs.NullptrArgument.Log();
rc = PathUtility.ConvertToFspPath(out FspPath fsPath, path);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject(); using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var fileSystem = new SharedRef<IFileSystemSf>(); using var fileSystem = new SharedRef<IFileSystemSf>();
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; if (rc.IsFailure()) return rc;
using var fileSystemAdapter = using var fileSystemAdapter =
@ -66,8 +63,7 @@ public static class Content
return Result.Success; return Result.Success;
} }
public static Result MountContent(this FileSystemClient fs, U8Span mountName, U8Span path, public static Result MountContent(this FileSystemClient fs, U8Span mountName, U8Span path, ContentType contentType)
ContentType contentType)
{ {
Result rc; Result rc;
Span<byte> logBuffer = stackalloc byte[0x300]; Span<byte> logBuffer = stackalloc byte[0x300];
@ -95,12 +91,12 @@ public static class Content
fs.Impl.AbortIfNeeded(rc); fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
const ulong programId = 0; ProgramId programId = default;
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System)) if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
{ {
Tick start = fs.Hos.Os.GetSystemTick(); 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(); Tick end = fs.Hos.Os.GetSystemTick();
var idString = new IdString(); var idString = new IdString();
@ -108,14 +104,14 @@ public static class Content
sb.Append(LogName).Append(mountName).Append(LogQuote) sb.Append(LogName).Append(mountName).Append(LogQuote)
.Append(LogPath).Append(path).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)); .Append(LogContentType).Append(idString.ToString(contentType));
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer)); fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
} }
else else
{ {
rc = MountContentImpl(fs, mountName, path, programId, contentType); rc = MountContentImpl(fs, mountName, path, programId.Value, contentType);
} }
fs.Impl.AbortIfNeeded(rc); fs.Impl.AbortIfNeeded(rc);
@ -128,7 +124,7 @@ public static class Content
static Result PreMount(ContentType contentType) static Result PreMount(ContentType contentType)
{ {
if (contentType == ContentType.Meta) if (contentType != ContentType.Meta)
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
return Result.Success; return Result.Success;

View file

@ -16,7 +16,7 @@ namespace LibHac.Fs.Shim;
/// <summary> /// <summary>
/// Contains functions for mounting the directories where content is stored. /// Contains functions for mounting the directories where content is stored.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
[SkipLocalsInit] [SkipLocalsInit]
public static class ContentStorage public static class ContentStorage
{ {
@ -109,6 +109,8 @@ public static class ContentStorage
if (!ResultFs.SystemPartitionNotReady.Includes(rc)) if (!ResultFs.SystemPartitionNotReady.Includes(rc))
return 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) if (i == maxRetries - 1)
return rc; return rc;

View file

@ -13,7 +13,7 @@ namespace LibHac.Fs.Shim;
/// <summary> /// <summary>
/// Contains functions for mounting custom storage file systems. /// Contains functions for mounting custom storage file systems.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
[SkipLocalsInit] [SkipLocalsInit]
public static class CustomStorage public static class CustomStorage
{ {
@ -60,7 +60,8 @@ public static class CustomStorage
} }
} }
private static ReadOnlySpan<byte> CustomStorageDirectoryName => // "CustomStorage0" /// <summary>"<c>CustomStorage0</c>"</summary>
private static ReadOnlySpan<byte> CustomStorageDirectoryName =>
new[] new[]
{ {
(byte)'C', (byte)'u', (byte)'s', (byte)'t', (byte)'o', (byte)'m', (byte)'S', (byte)'t', (byte)'C', (byte)'u', (byte)'s', (byte)'t', (byte)'o', (byte)'m', (byte)'S', (byte)'t',

View file

@ -21,7 +21,7 @@ namespace LibHac.Fs.Impl;
/// An adapter for using an <see cref="IFileSf"/> service object as an <see cref="IFile"/>. Used /// An adapter for using an <see cref="IFileSf"/> service object as an <see cref="IFile"/>. Used
/// when receiving a Horizon IPC file object so it can be used as an <see cref="IFile"/> locally. /// when receiving a Horizon IPC file object so it can be used as an <see cref="IFile"/> locally.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
internal class FileServiceObjectAdapter : IFile internal class FileServiceObjectAdapter : IFile
{ {
private SharedRef<IFileSf> _baseFile; private SharedRef<IFileSf> _baseFile;
@ -67,8 +67,6 @@ internal class FileServiceObjectAdapter : IFile
{ {
switch (operationId) switch (operationId)
{ {
case OperationId.InvalidateCache:
return _baseFile.Get.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size);
case OperationId.QueryRange: case OperationId.QueryRange:
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>()) if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
return ResultFs.InvalidSize.Log(); return ResultFs.InvalidSize.Log();
@ -76,6 +74,8 @@ internal class FileServiceObjectAdapter : IFile
ref QueryRangeInfo info = ref SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer); ref QueryRangeInfo info = ref SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer);
return _baseFile.Get.OperateRange(out info, (int)OperationId.QueryRange, offset, size); 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: default:
return _baseFile.Get.OperateRangeWithBuffer(new OutBuffer(outBuffer), new InBuffer(inBuffer), return _baseFile.Get.OperateRangeWithBuffer(new OutBuffer(outBuffer), new InBuffer(inBuffer),
(int)operationId, offset, size); (int)operationId, offset, size);
@ -87,7 +87,7 @@ internal class FileServiceObjectAdapter : IFile
/// An adapter for using an <see cref="IDirectorySf"/> service object as an <see cref="IDirectory"/>. Used /// An adapter for using an <see cref="IDirectorySf"/> service object as an <see cref="IDirectory"/>. Used
/// when receiving a Horizon IPC directory object so it can be used as an <see cref="IDirectory"/> locally. /// when receiving a Horizon IPC directory object so it can be used as an <see cref="IDirectory"/> locally.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
internal class DirectoryServiceObjectAdapter : IDirectory internal class DirectoryServiceObjectAdapter : IDirectory
{ {
private SharedRef<IDirectorySf> _baseDirectory; private SharedRef<IDirectorySf> _baseDirectory;
@ -119,7 +119,7 @@ internal class DirectoryServiceObjectAdapter : IDirectory
/// An adapter for using an <see cref="IFileSystemSf"/> service object as an <see cref="IFileSystem"/>. Used /// An adapter for using an <see cref="IFileSystemSf"/> service object as an <see cref="IFileSystem"/>. Used
/// when receiving a Horizon IPC file system object so it can be used as an <see cref="IFileSystem"/> locally. /// when receiving a Horizon IPC file system object so it can be used as an <see cref="IFileSystem"/> locally.
/// </summary> /// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks> /// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
internal class FileSystemServiceObjectAdapter : IFileSystem, IMultiCommitTarget internal class FileSystemServiceObjectAdapter : IFileSystem, IMultiCommitTarget
{ {
private SharedRef<IFileSystemSf> _baseFs; private SharedRef<IFileSystemSf> _baseFs;

View file

@ -4,6 +4,10 @@ using LibHac.Os;
namespace LibHac.Fs.Shim; namespace LibHac.Fs.Shim;
/// <summary>
/// Contains functions for use by the Loader service.
/// </summary>
/// <remarks>Based on nnSdk 13.4.0</remarks>
public static class LoaderApi public static class LoaderApi
{ {
public static Result IsArchivedProgram(this FileSystemClient fs, out bool isArchived, ProcessId processId) 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); Result rc = fileSystemProxy.Get.IsArchivedProgram(out isArchived, processId.Value);
fs.Impl.AbortIfNeeded(rc); fs.Impl.AbortIfNeeded(rc);
return rc; if (rc.IsFailure()) return rc.Miss();
return Result.Success;
} }
} }

View file

@ -31,7 +31,7 @@ public class AccessControlTests
StorageId.BuiltInUser, SpanHelpers.AsReadOnlyByteSpan(in dataHeader), StorageId.BuiltInUser, SpanHelpers.AsReadOnlyByteSpan(in dataHeader),
SpanHelpers.AsReadOnlyByteSpan(in descriptor))); 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); Assert.Result(ResultFs.PermissionDenied, rc);
} }
@ -57,7 +57,7 @@ public class AccessControlTests
SpanHelpers.AsReadOnlyByteSpan(in descriptor))); SpanHelpers.AsReadOnlyByteSpan(in descriptor)));
// We should get UnexpectedInNcaFileSystemServiceImplA because mounting NCAs from @System isn't allowed // 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); Assert.Result(ResultFs.UnexpectedInNcaFileSystemServiceImplA, rc);
} }
} }