diff --git a/src/LibHac/Fs/AccessLog.cs b/src/LibHac/Fs/AccessLog.cs
index 7f631a58..5039acf4 100644
--- a/src/LibHac/Fs/AccessLog.cs
+++ b/src/LibHac/Fs/AccessLog.cs
@@ -988,6 +988,15 @@ namespace LibHac.Fs.Impl
(byte)'i', (byte)'d', (byte)':', (byte)' '
};
+ /// ", imagedirectoryid: "
+ public static ReadOnlySpan LogImageDirectoryId => // ", imagedirectoryid: "
+ new[]
+ {
+ (byte)',', (byte)' ', (byte)'i', (byte)'m', (byte)'a', (byte)'g', (byte)'e', (byte)'d',
+ (byte)'i', (byte)'r', (byte)'e', (byte)'c', (byte)'t', (byte)'o', (byte)'r', (byte)'y',
+ (byte)'i', (byte)'d', (byte)':', (byte)' '
+ };
+
/// ", gamecard_handle: 0x"
public static ReadOnlySpan LogGameCardHandle => // ", gamecard_handle: 0x"
new[]
diff --git a/src/LibHac/Fs/Shim/BaseFileSystem.cs b/src/LibHac/Fs/Shim/BaseFileSystem.cs
new file mode 100644
index 00000000..a5563819
--- /dev/null
+++ b/src/LibHac/Fs/Shim/BaseFileSystem.cs
@@ -0,0 +1,68 @@
+using LibHac.Common;
+using LibHac.Fs.Fsa;
+using LibHac.Fs.Impl;
+using LibHac.FsSrv.Sf;
+
+using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
+using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
+
+namespace LibHac.Fs.Shim;
+
+///
+/// Contains functions for mounting base file systems.
+///
+/// Based on nnSdk 14.3.0
+public static class BaseFileSystem
+{
+ private static Result OpenBaseFileSystem(FileSystemClient fs, ref SharedRef outFileSystem,
+ BaseFileSystemId fileSystemId)
+ {
+ using SharedRef fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
+
+ Result rc = fileSystemProxy.Get.OpenBaseFileSystem(ref outFileSystem, fileSystemId);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
+ }
+
+ private static Result RegisterFileSystem(FileSystemClient fs, U8Span mountName,
+ ref SharedRef fileSystem)
+ {
+ using var fileSystemAdapter =
+ new UniqueRef(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
+
+ Result rc = fs.Register(mountName, ref fileSystemAdapter.Ref());
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
+ }
+
+ public static Result MountBaseFileSystem(this FileSystemClient fs, U8Span mountName, BaseFileSystemId fileSystemId)
+ {
+ Result rc = fs.Impl.CheckMountName(mountName);
+ fs.Impl.AbortIfNeeded(rc);
+ if (rc.IsFailure()) return rc.Miss();
+
+ using var fileSystem = new SharedRef();
+ rc = OpenBaseFileSystem(fs, ref fileSystem.Ref(), fileSystemId);
+ fs.Impl.AbortIfNeeded(rc);
+ if (rc.IsFailure()) return rc.Miss();
+
+ rc = RegisterFileSystem(fs, mountName, ref fileSystem.Ref());
+ fs.Impl.AbortIfNeeded(rc);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
+ }
+
+ public static Result FormatBaseFileSystem(this FileSystemClient fs, BaseFileSystemId fileSystemId)
+ {
+ using SharedRef fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
+
+ Result rc = fileSystemProxy.Get.FormatBaseFileSystem(fileSystemId);
+ fs.Impl.AbortIfNeeded(rc);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
+ }
+}
\ No newline at end of file
diff --git a/src/LibHac/Fs/Shim/ErrorInfo.cs b/src/LibHac/Fs/Shim/ErrorInfo.cs
new file mode 100644
index 00000000..7a951e54
--- /dev/null
+++ b/src/LibHac/Fs/Shim/ErrorInfo.cs
@@ -0,0 +1,23 @@
+using LibHac.Common;
+using LibHac.FsSrv.Sf;
+
+namespace LibHac.Fs.Shim;
+
+///
+/// Contains functions for obtaining error information from the file system proxy service.
+///
+/// Based on nnSdk 14.3.0
+public static class ErrorInfo
+{
+ public static Result GetAndClearFileSystemProxyErrorInfo(this FileSystemClient fs,
+ out FileSystemProxyErrorInfo outErrorInfo)
+ {
+ using SharedRef fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
+
+ Result rc = fileSystemProxy.Get.GetAndClearErrorInfo(out outErrorInfo);
+ fs.Impl.AbortIfNeeded(rc);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
+ }
+}
\ No newline at end of file
diff --git a/src/LibHac/Fs/Shim/FsStackUsage.cs b/src/LibHac/Fs/Shim/FsStackUsage.cs
new file mode 100644
index 00000000..cb8b25a2
--- /dev/null
+++ b/src/LibHac/Fs/Shim/FsStackUsage.cs
@@ -0,0 +1,21 @@
+using LibHac.Common;
+using LibHac.Diag;
+using LibHac.FsSrv.Sf;
+
+namespace LibHac.Fs.Shim;
+
+///
+/// Contains functions for getting the amount of stack space used by FS threads.
+///
+/// Based on nnSdk 14.3.0
+public static class FsStackUsage
+{
+ public static uint GetFsStackUsage(this FileSystemClient fs, FsStackUsageThreadType threadType)
+ {
+ using SharedRef fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
+
+ Abort.DoAbortUnlessSuccess(fileSystemProxy.Get.GetFsStackUsage(out uint stackUsage, threadType));
+
+ return stackUsage;
+ }
+}
\ No newline at end of file
diff --git a/src/LibHac/Fs/Shim/ImageDirectory.cs b/src/LibHac/Fs/Shim/ImageDirectory.cs
new file mode 100644
index 00000000..213d357e
--- /dev/null
+++ b/src/LibHac/Fs/Shim/ImageDirectory.cs
@@ -0,0 +1,75 @@
+using System;
+using LibHac.Common;
+using LibHac.Fs.Fsa;
+using LibHac.Fs.Impl;
+using LibHac.FsSrv.Sf;
+using LibHac.Os;
+using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
+using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
+
+using static LibHac.Fs.Impl.AccessLogStrings;
+
+namespace LibHac.Fs.Shim;
+
+///
+/// Contains functions for mounting the directories where images and videos are saved.
+///
+/// Based on nnSdk 14.3.0
+public static class ImageDirectory
+{
+ public static Result MountImageDirectory(this FileSystemClient fs, U8Span mountName, ImageDirectoryId directoryId)
+ {
+ Result rc;
+ Span logBuffer = stackalloc byte[0x50];
+
+ if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
+ {
+ Tick start = fs.Hos.Os.GetSystemTick();
+ rc = Mount(fs, mountName, directoryId);
+ Tick end = fs.Hos.Os.GetSystemTick();
+
+ var idString = new IdString();
+ var sb = new U8StringBuilder(logBuffer, true);
+
+ sb.Append(LogName).Append(mountName).Append(LogQuote)
+ .Append(LogImageDirectoryId).Append(idString.ToString(directoryId));
+
+ fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
+ }
+ else
+ {
+ rc = Mount(fs, mountName, directoryId);
+ }
+
+ fs.Impl.AbortIfNeeded(rc);
+ if (rc.IsFailure()) return rc.Miss();
+
+ if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
+ fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
+
+ return Result.Success;
+
+ static Result Mount(FileSystemClient fs, U8Span mountName, ImageDirectoryId directoryId)
+ {
+ Result rc = fs.Impl.CheckMountName(mountName);
+ if (rc.IsFailure()) return rc.Miss();
+
+ using SharedRef fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
+ using var fileSystem = new SharedRef();
+
+ rc = fileSystemProxy.Get.OpenImageDirectoryFileSystem(ref fileSystem.Ref(), directoryId);
+ if (rc.IsFailure()) return rc.Miss();
+
+ using var fileSystemAdapter =
+ new UniqueRef(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
+
+ if (!fileSystemAdapter.HasValue)
+ return ResultFs.AllocationMemoryFailedInImageDirectoryA.Log();
+
+ rc = fs.Impl.Fs.Register(mountName, ref fileSystemAdapter.Ref());
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LibHac/Fs/Shim/Logo.cs b/src/LibHac/Fs/Shim/Logo.cs
new file mode 100644
index 00000000..03659567
--- /dev/null
+++ b/src/LibHac/Fs/Shim/Logo.cs
@@ -0,0 +1,80 @@
+using System;
+using LibHac.Common;
+using LibHac.Fs.Fsa;
+using LibHac.Fs.Impl;
+using LibHac.FsSrv.Sf;
+using LibHac.Ncm;
+using LibHac.Os;
+using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
+using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
+
+using static LibHac.Fs.Impl.AccessLogStrings;
+
+namespace LibHac.Fs.Shim;
+
+///
+/// Contains functions for opening the logo partitions of NCA files.
+///
+/// Based on nnSdk 14.3.0
+public static class Logo
+{
+ public static Result MountLogo(this FileSystemClient fs, U8Span mountName, U8Span path, ProgramId programId)
+ {
+ Result rc;
+ Span logBuffer = stackalloc byte[0x300];
+
+ if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
+ {
+ Tick start = fs.Hos.Os.GetSystemTick();
+ rc = Mount(fs, mountName, path, programId);
+ Tick end = fs.Hos.Os.GetSystemTick();
+
+ var sb = new U8StringBuilder(logBuffer, true);
+
+ sb.Append(LogName).Append(mountName).Append(LogQuote)
+ .Append(LogPath).Append(path).Append(LogQuote)
+ .Append(LogProgramId).AppendFormat(programId.Value, 'X');
+
+ fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
+ }
+ else
+ {
+ rc = Mount(fs, mountName, path, programId);
+ }
+
+ fs.Impl.AbortIfNeeded(rc);
+ if (rc.IsFailure()) return rc.Miss();
+
+ if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
+ fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
+
+ return Result.Success;
+
+ static Result Mount(FileSystemClient fs, U8Span mountName, U8Span path, ProgramId programId)
+ {
+ Result rc = fs.Impl.CheckMountName(mountName);
+ if (rc.IsFailure()) return rc.Miss();
+
+ 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 sfPath, programId.Value,
+ FileSystemProxyType.Logo);
+ if (rc.IsFailure()) return rc.Miss();
+
+ using var fileSystemAdapter =
+ new UniqueRef(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
+
+ if (!fileSystemAdapter.HasValue)
+ return ResultFs.AllocationMemoryFailedInLogoA.Log();
+
+ rc = fs.Impl.Fs.Register(mountName, ref fileSystemAdapter.Ref());
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LibHac/Fs/Shim/MemoryReportInfo.cs b/src/LibHac/Fs/Shim/MemoryReportInfo.cs
new file mode 100644
index 00000000..8aa6fcb1
--- /dev/null
+++ b/src/LibHac/Fs/Shim/MemoryReportInfo.cs
@@ -0,0 +1,22 @@
+using LibHac.Common;
+using LibHac.FsSrv.Sf;
+
+namespace LibHac.Fs.Shim;
+
+///
+/// Contains functions for obtaining reports on memory usage from the file system proxy service.
+///
+/// Based on nnSdk 14.3.0
+public static class MemoryReportInfoShim
+{
+ public static Result GetAndClearMemoryReportInfo(this FileSystemClient fs, out MemoryReportInfo reportInfo)
+ {
+ using SharedRef fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
+
+ Result rc = fileSystemProxy.Get.GetAndClearMemoryReportInfo(out reportInfo);
+ fs.Impl.AbortIfNeeded(rc);
+ if (rc.IsFailure()) return rc.Miss();
+
+ return Result.Success;
+ }
+}
\ No newline at end of file
diff --git a/src/LibHac/Fs/Shim/SpeedEmulation.cs b/src/LibHac/Fs/Shim/SpeedEmulation.cs
new file mode 100644
index 00000000..a95fb0ae
--- /dev/null
+++ b/src/LibHac/Fs/Shim/SpeedEmulation.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace LibHac.Fs
+{
+ public enum SpeedEmulationMode
+ {
+ None = 0,
+ Faster = 1,
+ Slower = 2,
+ Random = 3
+ }
+}
+
+namespace LibHac.Fs.Shim
+{
+ public static class SpeedEmulationShim
+ {
+ public static Result SetSpeedEmulationMode(this FileSystemClient fs, SpeedEmulationMode mode)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static Result GetSpeedEmulationMode(this FileSystemClient fs, out SpeedEmulationMode outMode)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file