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