From a3220cc8df45cbe40439bcc4db60bb88ee0f7ced Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 2 Nov 2020 17:05:13 -0700 Subject: [PATCH] Fix method signatures in IFileSystemProxy --- src/LibHac/Fs/FileSystemClient.AccessLog.cs | 3 +- src/LibHac/Fs/Shim/Bis.cs | 12 +- src/LibHac/Fs/Shim/CustomStorage.cs | 21 ++- src/LibHac/Fs/Shim/GameCard.cs | 54 ++++++-- src/LibHac/Fs/Shim/Host.cs | 53 +++++--- src/LibHac/Fs/Shim/SaveDataManagement.cs | 2 +- src/LibHac/Fs/Shim/SdCard.cs | 20 ++- .../Creators/EmulatedBisFileSystemCreator.cs | 9 +- .../ISubDirectoryFileSystemCreator.cs | 8 +- .../Creators/SubDirectoryFileSystemCreator.cs | 27 +--- src/LibHac/FsSrv/EmulatedDeviceOperator.cs | 2 + src/LibHac/FsSrv/FileSystemProxyCoreImpl.cs | 109 ++++++++++----- src/LibHac/FsSrv/FileSystemProxyImpl.cs | 94 +++++++++++-- src/LibHac/FsSrv/IDeviceOperator.cs | 6 +- src/LibHac/FsSrv/IFileSystemProxy.cs | 18 +-- .../FsSrv/Impl/StorageInterfaceAdapter.cs | 22 ++- src/LibHac/FsSrv/Impl/Utility.cs | 8 +- src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs | 128 +++++++++++------- .../FsSrv/SaveDataFileSystemServiceImpl.cs | 12 +- src/LibHac/FsSystem/SubdirectoryFileSystem.cs | 4 +- 20 files changed, 404 insertions(+), 208 deletions(-) diff --git a/src/LibHac/Fs/FileSystemClient.AccessLog.cs b/src/LibHac/Fs/FileSystemClient.AccessLog.cs index 7dd5f9eb..ed596f79 100644 --- a/src/LibHac/Fs/FileSystemClient.AccessLog.cs +++ b/src/LibHac/Fs/FileSystemClient.AccessLog.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using LibHac.Common; using LibHac.Fs.Accessors; using LibHac.FsSrv; +using LibHac.Sf; namespace LibHac.Fs { @@ -187,7 +188,7 @@ namespace LibHac.Fs string logString = AccessLogHelpers.BuildDefaultLogLine(result, startTime, endTime, handleId, message, caller); IFileSystemProxy fsProxy = GetFileSystemProxyServiceObject(); - fsProxy.OutputAccessLogToSdCard(logString.ToU8Span()); + fsProxy.OutputAccessLogToSdCard(new InBuffer(logString.ToU8Span())).IgnoreResult(); } } diff --git a/src/LibHac/Fs/Shim/Bis.cs b/src/LibHac/Fs/Shim/Bis.cs index d6cdb79c..004e666f 100644 --- a/src/LibHac/Fs/Shim/Bis.cs +++ b/src/LibHac/Fs/Shim/Bis.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Runtime.CompilerServices; using LibHac.Common; using LibHac.Fs.Impl; using LibHac.FsSrv; @@ -137,8 +138,7 @@ namespace LibHac.Fs.Shim // todo: Decide how to handle SetBisRootForHost since it allows mounting any directory on the user's computer public static Result SetBisRootForHost(this FileSystemClient fs, BisPartitionId partitionId, U8Span rootPath) { - FsPath sfPath; - unsafe { _ = &sfPath; } // workaround for CS0165 + Unsafe.SkipInit(out FsPath path); int pathLen = StringUtils.GetLength(rootPath, PathTools.MaxPathLength + 1); if (pathLen > PathTools.MaxPathLength) @@ -150,18 +150,20 @@ namespace LibHac.Fs.Shim ? StringTraits.NullTerminator : StringTraits.DirectorySeparator; - var sb = new U8StringBuilder(sfPath.Str); + var sb = new U8StringBuilder(path.Str); Result rc = sb.Append(rootPath).Append(endingSeparator).ToSfPath(); if (rc.IsFailure()) return rc; } else { - sfPath.Str[0] = StringTraits.NullTerminator; + path.Str[0] = StringTraits.NullTerminator; } + FspPath.FromSpan(out FspPath sfPath, path.Str); + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); - return fsProxy.SetBisRootForHost(partitionId, ref sfPath); + return fsProxy.SetBisRootForHost(partitionId, in sfPath); } public static Result OpenBisPartition(this FileSystemClient fs, out IStorage partitionStorage, BisPartitionId partitionId) diff --git a/src/LibHac/Fs/Shim/CustomStorage.cs b/src/LibHac/Fs/Shim/CustomStorage.cs index 4734acbd..73fbe3c2 100644 --- a/src/LibHac/Fs/Shim/CustomStorage.cs +++ b/src/LibHac/Fs/Shim/CustomStorage.cs @@ -1,7 +1,8 @@ using System; using LibHac.Common; -using LibHac.Fs.Fsa; +using LibHac.Fs.Impl; using LibHac.FsSrv; +using LibHac.FsSrv.Sf; namespace LibHac.Fs.Shim { @@ -12,12 +13,22 @@ namespace LibHac.Fs.Shim Result rc = MountHelpers.CheckMountName(mountName); if (rc.IsFailure()) return rc; - IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + ReferenceCountedDisposable customFs = null; + try + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); - rc = fsProxy.OpenCustomStorageFileSystem(out IFileSystem customFs, storageId); - if (rc.IsFailure()) return rc; + rc = fsProxy.OpenCustomStorageFileSystem(out customFs, storageId); + if (rc.IsFailure()) return rc; - return fs.Register(mountName, customFs); + var adapter = new FileSystemServiceObjectAdapter(customFs); + + return fs.Register(mountName, adapter); + } + finally + { + customFs?.Dispose(); + } } public static string GetCustomStorageDirectoryName(CustomStorageId storageId) diff --git a/src/LibHac/Fs/Shim/GameCard.cs b/src/LibHac/Fs/Shim/GameCard.cs index 2507f36d..735dcbfc 100644 --- a/src/LibHac/Fs/Shim/GameCard.cs +++ b/src/LibHac/Fs/Shim/GameCard.cs @@ -12,33 +12,63 @@ namespace LibHac.Fs.Shim { handle = default; - IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + ReferenceCountedDisposable deviceOperator = null; + try + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); - Result rc = fsProxy.OpenDeviceOperator(out IDeviceOperator deviceOperator); - if (rc.IsFailure()) return rc; + Result rc = fsProxy.OpenDeviceOperator(out deviceOperator); + if (rc.IsFailure()) return rc; - return deviceOperator.GetGameCardHandle(out handle); + return deviceOperator.Target.GetGameCardHandle(out handle); + } + finally + { + deviceOperator?.Dispose(); + } } public static bool IsGameCardInserted(this FileSystemClient fs) { - IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + ReferenceCountedDisposable deviceOperator = null; + try + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); - Result rc = fsProxy.OpenDeviceOperator(out IDeviceOperator deviceOperator); - if (rc.IsFailure()) throw new LibHacException("Abort"); + Result rc = fsProxy.OpenDeviceOperator(out deviceOperator); + if (rc.IsFailure()) throw new LibHacException("Abort"); - rc = deviceOperator.IsGameCardInserted(out bool isInserted); - if (rc.IsFailure()) throw new LibHacException("Abort"); + rc = deviceOperator.Target.IsGameCardInserted(out bool isInserted); + if (rc.IsFailure()) throw new LibHacException("Abort"); - return isInserted; + return isInserted; + } + finally + { + deviceOperator?.Dispose(); + } } public static Result OpenGameCardPartition(this FileSystemClient fs, out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionType) { - IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + storage = default; - return fsProxy.OpenGameCardStorage(out storage, handle, partitionType); + ReferenceCountedDisposable sfStorage = null; + try + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + + Result rc = fsProxy.OpenGameCardStorage(out sfStorage, handle, partitionType); + if (rc.IsFailure()) return rc; + + storage = new StorageServiceObjectAdapter(sfStorage); + return Result.Success; + } + finally + { + sfStorage?.Dispose(); + } } public static Result MountGameCardPartition(this FileSystemClient fs, U8Span mountName, GameCardHandle handle, diff --git a/src/LibHac/Fs/Shim/Host.cs b/src/LibHac/Fs/Shim/Host.cs index e7ecc24e..668aaec0 100644 --- a/src/LibHac/Fs/Shim/Host.cs +++ b/src/LibHac/Fs/Shim/Host.cs @@ -3,7 +3,9 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using LibHac.Common; using LibHac.Fs.Fsa; +using LibHac.Fs.Impl; using LibHac.FsSrv; +using LibHac.FsSrv.Sf; using LibHac.FsSystem; using LibHac.Util; using static LibHac.Fs.CommonPaths; @@ -76,12 +78,11 @@ namespace LibHac.Fs.Shim public static Result MountHostRoot(this FileSystemClient fs) { IFileSystem hostFileSystem = default; - var path = new FsPath(); - path.Str[0] = 0; + FspPath.CreateEmpty(out FspPath path); static string LogMessageGenerator() => $", name: \"{HostRootFileSystemMountName.ToString()}\""; - Result OpenHostFs() => OpenHostFileSystemImpl(fs, out hostFileSystem, ref path, MountHostOption.None); + Result OpenHostFs() => OpenHostFileSystemImpl(fs, out hostFileSystem, in path, MountHostOption.None); Result MountHostFs() => fs.Register(HostRootFileSystemMountName, hostFileSystem, new HostRootCommonMountNameGenerator()); @@ -110,13 +111,12 @@ namespace LibHac.Fs.Shim public static Result MountHostRoot(this FileSystemClient fs, MountHostOption option) { IFileSystem hostFileSystem = default; - var path = new FsPath(); - path.Str[0] = 0; + FspPath.CreateEmpty(out FspPath path); string LogMessageGenerator() => $", name: \"{HostRootFileSystemMountName.ToString()}, mount_host_option: {option}\""; - Result OpenHostFs() => OpenHostFileSystemImpl(fs, out hostFileSystem, ref path, option); + Result OpenHostFs() => OpenHostFileSystemImpl(fs, out hostFileSystem, in path, option); Result MountHostFs() => fs.Register(HostRootFileSystemMountName, hostFileSystem, new HostRootCommonMountNameGenerator()); @@ -318,8 +318,7 @@ namespace LibHac.Fs.Shim if (pathLength + 1 > PathTools.MaxPathLength) return ResultFs.TooLongPath.Log(); - FsPath fullPath; - unsafe { _ = &fullPath; } // workaround for CS0165 + Unsafe.SkipInit(out FsPath fullPath); var sb = new U8StringBuilder(fullPath.Str); sb.Append(StringTraits.DirectorySeparator).Append(path); @@ -341,7 +340,9 @@ namespace LibHac.Fs.Shim } } - return OpenHostFileSystemImpl(fs, out fileSystem, ref fullPath, option); + FspPath.FromSpan(out FspPath sfPath, fullPath.Str); + + return OpenHostFileSystemImpl(fs, out fileSystem, in sfPath, option); } /// @@ -352,26 +353,34 @@ namespace LibHac.Fs.Shim /// The path on the host computer to open. e.g. /C:\Windows\System32/ /// Options for opening the host file system. /// The of the operation. - private static Result OpenHostFileSystemImpl(FileSystemClient fs, out IFileSystem fileSystem, ref FsPath path, MountHostOption option) + private static Result OpenHostFileSystemImpl(FileSystemClient fs, out IFileSystem fileSystem, in FspPath path, + MountHostOption option) { fileSystem = default; IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); - IFileSystem hostFs; + ReferenceCountedDisposable hostFs = null; - if (option == MountHostOption.None) + try { - Result rc = fsProxy.OpenHostFileSystem(out hostFs, ref path); - if (rc.IsFailure()) return rc; - } - else - { - Result rc = fsProxy.OpenHostFileSystemWithOption(out hostFs, ref path, option); - if (rc.IsFailure()) return rc; - } + if (option == MountHostOption.None) + { + Result rc = fsProxy.OpenHostFileSystem(out hostFs, in path); + if (rc.IsFailure()) return rc; + } + else + { + Result rc = fsProxy.OpenHostFileSystemWithOption(out hostFs, in path, option); + if (rc.IsFailure()) return rc; + } - fileSystem = hostFs; - return Result.Success; + fileSystem = new FileSystemServiceObjectAdapter(hostFs); + return Result.Success; + } + finally + { + hostFs?.Dispose(); + } } } } diff --git a/src/LibHac/Fs/Shim/SaveDataManagement.cs b/src/LibHac/Fs/Shim/SaveDataManagement.cs index 8bedd679..7cc125eb 100644 --- a/src/LibHac/Fs/Shim/SaveDataManagement.cs +++ b/src/LibHac/Fs/Shim/SaveDataManagement.cs @@ -212,7 +212,7 @@ namespace LibHac.Fs.Shim SpaceId = spaceId }; - return fsProxy.CreateSaveDataFileSystemBySystemSaveDataId(ref attribute, ref createInfo); + return fsProxy.CreateSaveDataFileSystemBySystemSaveDataId(in attribute, in createInfo); }, () => $", savedataspaceid: {spaceId}, savedataid: 0x{saveDataId:X}, userid: 0x{userId.Id.High:X16}{userId.Id.Low:X16}, save_data_owner_id: 0x{ownerId:X}, save_data_size: {size}, save_data_journal_size: {journalSize}, save_data_flags: 0x{(int)flags:x8}"); } diff --git a/src/LibHac/Fs/Shim/SdCard.cs b/src/LibHac/Fs/Shim/SdCard.cs index 73e4cd2d..f0c4a6ec 100644 --- a/src/LibHac/Fs/Shim/SdCard.cs +++ b/src/LibHac/Fs/Shim/SdCard.cs @@ -56,15 +56,23 @@ namespace LibHac.Fs.Shim public static bool IsSdCardInserted(this FileSystemClient fs) { - IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); + ReferenceCountedDisposable deviceOperator = null; + try + { + IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject(); - Result rc = fsProxy.OpenDeviceOperator(out IDeviceOperator deviceOperator); - if (rc.IsFailure()) throw new HorizonResultException(rc, "Abort"); + Result rc = fsProxy.OpenDeviceOperator(out deviceOperator); + if (rc.IsFailure()) throw new HorizonResultException(rc, "Abort"); - rc = deviceOperator.IsSdCardInserted(out bool isInserted); - if (rc.IsFailure()) throw new HorizonResultException(rc, "Abort"); + rc = deviceOperator.Target.IsSdCardInserted(out bool isInserted); + if (rc.IsFailure()) throw new HorizonResultException(rc, "Abort"); - return isInserted; + return isInserted; + } + finally + { + deviceOperator?.Dispose(); + } } public static Result SetSdCardEncryptionSeed(this FileSystemClient fs, in EncryptionSeed seed) diff --git a/src/LibHac/FsSrv/Creators/EmulatedBisFileSystemCreator.cs b/src/LibHac/FsSrv/Creators/EmulatedBisFileSystemCreator.cs index 9ed7fd7f..66575804 100644 --- a/src/LibHac/FsSrv/Creators/EmulatedBisFileSystemCreator.cs +++ b/src/LibHac/FsSrv/Creators/EmulatedBisFileSystemCreator.cs @@ -110,12 +110,12 @@ namespace LibHac.FsSrv.Creators var partitionPath = GetPartitionPath(partitionId).ToU8String(); ReferenceCountedDisposable partitionFileSystem = null; + ReferenceCountedDisposable sharedRootFs = null; try { - // Todo: Store shared file systems - using var sharedRootFs = new ReferenceCountedDisposable(Config.RootFileSystem); + sharedRootFs = new ReferenceCountedDisposable(Config.RootFileSystem); - Result rc = Utility.WrapSubDirectory(out partitionFileSystem, sharedRootFs, partitionPath, true); + Result rc = Utility.WrapSubDirectory(out partitionFileSystem, ref sharedRootFs, partitionPath, true); if (rc.IsFailure()) return rc; @@ -125,11 +125,12 @@ namespace LibHac.FsSrv.Creators return Result.Success; } - return Utility.CreateSubDirectoryFileSystem(out fileSystem, partitionFileSystem, rootPath); + return Utility.CreateSubDirectoryFileSystem(out fileSystem, ref partitionFileSystem, rootPath); } finally { partitionFileSystem?.Dispose(); + sharedRootFs?.Dispose(); } } diff --git a/src/LibHac/FsSrv/Creators/ISubDirectoryFileSystemCreator.cs b/src/LibHac/FsSrv/Creators/ISubDirectoryFileSystemCreator.cs index 40563d35..2fd5b50f 100644 --- a/src/LibHac/FsSrv/Creators/ISubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsSrv/Creators/ISubDirectoryFileSystemCreator.cs @@ -5,11 +5,7 @@ namespace LibHac.FsSrv.Creators { public interface ISubDirectoryFileSystemCreator { - // Todo: Remove the raw IFileSystem overloads - Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, U8Span path); - Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, U8Span path, bool preserveUnc); - - Result Create(out ReferenceCountedDisposable subDirFileSystem, ReferenceCountedDisposable baseFileSystem, U8Span path); - Result Create(out ReferenceCountedDisposable subDirFileSystem, ReferenceCountedDisposable baseFileSystem, U8Span path, bool preserveUnc); + Result Create(out ReferenceCountedDisposable subDirFileSystem, ref ReferenceCountedDisposable baseFileSystem, U8Span path); + Result Create(out ReferenceCountedDisposable subDirFileSystem, ref ReferenceCountedDisposable baseFileSystem, U8Span path, bool preserveUnc); } } \ No newline at end of file diff --git a/src/LibHac/FsSrv/Creators/SubDirectoryFileSystemCreator.cs b/src/LibHac/FsSrv/Creators/SubDirectoryFileSystemCreator.cs index 9bfb6867..3d837daf 100644 --- a/src/LibHac/FsSrv/Creators/SubDirectoryFileSystemCreator.cs +++ b/src/LibHac/FsSrv/Creators/SubDirectoryFileSystemCreator.cs @@ -6,31 +6,14 @@ namespace LibHac.FsSrv.Creators { public class SubDirectoryFileSystemCreator : ISubDirectoryFileSystemCreator { - public Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, U8Span path) + public Result Create(out ReferenceCountedDisposable subDirFileSystem, + ref ReferenceCountedDisposable baseFileSystem, U8Span path) { - return Create(out subDirFileSystem, baseFileSystem, path, false); - } - - public Result Create(out IFileSystem subDirFileSystem, IFileSystem baseFileSystem, U8Span path, bool preserveUnc) - { - subDirFileSystem = default; - - Result rc = baseFileSystem.OpenDirectory(out IDirectory _, path, OpenDirectoryMode.Directory); - if (rc.IsFailure()) return rc; - - rc = SubdirectoryFileSystem.CreateNew(out SubdirectoryFileSystem fs, baseFileSystem, path.ToU8String(), preserveUnc); - subDirFileSystem = fs; - return rc; + return Create(out subDirFileSystem, ref baseFileSystem, path, false); } public Result Create(out ReferenceCountedDisposable subDirFileSystem, - ReferenceCountedDisposable baseFileSystem, U8Span path) - { - return Create(out subDirFileSystem, baseFileSystem, path, false); - } - - public Result Create(out ReferenceCountedDisposable subDirFileSystem, - ReferenceCountedDisposable baseFileSystem, U8Span path, bool preserveUnc) + ref ReferenceCountedDisposable baseFileSystem, U8Span path, bool preserveUnc) { subDirFileSystem = default; @@ -39,7 +22,7 @@ namespace LibHac.FsSrv.Creators if (rc.IsFailure()) return rc; // Initialize the SubdirectoryFileSystem - var subDir = new SubdirectoryFileSystem(baseFileSystem, preserveUnc); + var subDir = new SubdirectoryFileSystem(ref baseFileSystem, preserveUnc); using var subDirShared = new ReferenceCountedDisposable(subDir); rc = subDirShared.Target.Initialize(path); diff --git a/src/LibHac/FsSrv/EmulatedDeviceOperator.cs b/src/LibHac/FsSrv/EmulatedDeviceOperator.cs index 767186e9..ed206964 100644 --- a/src/LibHac/FsSrv/EmulatedDeviceOperator.cs +++ b/src/LibHac/FsSrv/EmulatedDeviceOperator.cs @@ -13,6 +13,8 @@ namespace LibHac.FsSrv SdCard = sdCard; } + public void Dispose() { } + public Result IsSdCardInserted(out bool isInserted) { isInserted = SdCard.IsSdCardInserted(); diff --git a/src/LibHac/FsSrv/FileSystemProxyCoreImpl.cs b/src/LibHac/FsSrv/FileSystemProxyCoreImpl.cs index c1da6f91..45e632d5 100644 --- a/src/LibHac/FsSrv/FileSystemProxyCoreImpl.cs +++ b/src/LibHac/FsSrv/FileSystemProxyCoreImpl.cs @@ -4,6 +4,8 @@ using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.Fs.Shim; using LibHac.FsSrv.Creators; +using LibHac.FsSrv.Impl; +using LibHac.FsSrv.Sf; namespace LibHac.FsSrv { @@ -13,7 +15,7 @@ namespace LibHac.FsSrv private FileSystemCreators FsCreators => Config.FsCreatorInterfaces; internal ProgramRegistryImpl ProgramRegistry { get; } - private IDeviceOperator DeviceOperator { get; } + private ReferenceCountedDisposable DeviceOperator { get; } private byte[] SdEncryptionSeed { get; } = new byte[0x10]; @@ -27,31 +29,57 @@ namespace LibHac.FsSrv { Config = config; ProgramRegistry = new ProgramRegistryImpl(Config.ProgramRegistryService); - DeviceOperator = deviceOperator; + DeviceOperator = new ReferenceCountedDisposable(deviceOperator); } - public Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId) + public Result OpenGameCardStorage(out ReferenceCountedDisposable storage, GameCardHandle handle, + GameCardPartitionRaw partitionId) { - switch (partitionId) + storage = default; + + Result rc; + IStorage gcStorage = null; + ReferenceCountedDisposable sharedGcStorage = null; + try { - case GameCardPartitionRaw.NormalReadOnly: - return FsCreators.GameCardStorageCreator.CreateNormal(handle, out storage); - case GameCardPartitionRaw.SecureReadOnly: - return FsCreators.GameCardStorageCreator.CreateSecure(handle, out storage); - case GameCardPartitionRaw.RootWriteOnly: - return FsCreators.GameCardStorageCreator.CreateWritable(handle, out storage); - default: - throw new ArgumentOutOfRangeException(nameof(partitionId), partitionId, null); + switch (partitionId) + { + case GameCardPartitionRaw.NormalReadOnly: + rc = FsCreators.GameCardStorageCreator.CreateNormal(handle, out gcStorage); + break; + case GameCardPartitionRaw.SecureReadOnly: + rc = FsCreators.GameCardStorageCreator.CreateSecure(handle, out gcStorage); + break; + case GameCardPartitionRaw.RootWriteOnly: + rc = FsCreators.GameCardStorageCreator.CreateWritable(handle, out gcStorage); + break; + default: + throw new ArgumentOutOfRangeException(nameof(partitionId), partitionId, null); + } + + if (rc.IsFailure()) return rc; + + sharedGcStorage = new ReferenceCountedDisposable(gcStorage); + gcStorage = null; + + storage = StorageInterfaceAdapter.CreateShared(ref sharedGcStorage); + return Result.Success; + } + finally + { + gcStorage?.Dispose(); + sharedGcStorage?.Dispose(); } } - public Result OpenDeviceOperator(out IDeviceOperator deviceOperator) + public Result OpenDeviceOperator(out ReferenceCountedDisposable deviceOperator) { - deviceOperator = DeviceOperator; + deviceOperator = DeviceOperator.AddReference(); return Result.Success; } - public Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId) + public Result OpenCustomStorageFileSystem(out ReferenceCountedDisposable fileSystem, + CustomStorageId storageId) { fileSystem = default; @@ -72,7 +100,7 @@ namespace LibHac.FsSrv EncryptedFsKeyId.CustomStorage, SdEncryptionSeed); if (rc.IsFailure()) return rc; - fileSystem = encryptedFs; + fileSystem = new ReferenceCountedDisposable(encryptedFs); return Result.Success; } case CustomStorageId.System: @@ -87,7 +115,8 @@ namespace LibHac.FsSrv rc = Util.CreateSubFileSystem(out IFileSystem subFs, userFs, subDirName, true); if (rc.IsFailure()) return rc; - fileSystem = subFs; + // Todo: Get shared object from earlier functions + fileSystem = new ReferenceCountedDisposable(subFs); return Result.Success; } default: @@ -95,7 +124,8 @@ namespace LibHac.FsSrv } } - public Result OpenHostFileSystem(out IFileSystem fileSystem, U8Span path, bool openCaseSensitive) + public Result OpenHostFileSystem(out ReferenceCountedDisposable fileSystem, U8Span path, + bool openCaseSensitive) { fileSystem = default; Result rc; @@ -106,27 +136,42 @@ namespace LibHac.FsSrv if (rc.IsFailure()) return rc; } + // Todo: Return shared fs from Create rc = FsCreators.TargetManagerFileSystemCreator.Create(out IFileSystem hostFs, openCaseSensitive); if (rc.IsFailure()) return rc; - if (path.IsEmpty()) + ReferenceCountedDisposable sharedHostFs = null; + ReferenceCountedDisposable subDirFs = null; + + try { - ReadOnlySpan rootHostPath = new[] { (byte)'C', (byte)':', (byte)'/' }; - rc = hostFs.GetEntryType(out _, new U8Span(rootHostPath)); + sharedHostFs = new ReferenceCountedDisposable(hostFs); - // Nintendo ignores all results other than this one - if (ResultFs.TargetNotFound.Includes(rc)) - return rc; + if (path.IsEmpty()) + { + ReadOnlySpan rootHostPath = new[] { (byte)'C', (byte)':', (byte)'/' }; + rc = sharedHostFs.Target.GetEntryType(out _, new U8Span(rootHostPath)); - fileSystem = hostFs; + // Nintendo ignores all results other than this one + if (ResultFs.TargetNotFound.Includes(rc)) + return rc; + + Shared.Move(out fileSystem, ref sharedHostFs); + return Result.Success; + } + + rc = FsCreators.SubDirectoryFileSystemCreator.Create(out subDirFs, ref sharedHostFs, path, + preserveUnc: true); + if (rc.IsFailure()) return rc; + + fileSystem = subDirFs; return Result.Success; } - - rc = FsCreators.SubDirectoryFileSystemCreator.Create(out IFileSystem subDirFs, hostFs, path, preserveUnc: true); - if (rc.IsFailure()) return rc; - - fileSystem = subDirFs; - return Result.Success; + finally + { + sharedHostFs?.Dispose(); + subDirFs?.Dispose(); + } } public Result SetSdCardEncryptionSeed(in EncryptionSeed seed) @@ -139,7 +184,7 @@ namespace LibHac.FsSrv return Result.Success; } - + public Result SetGlobalAccessLogMode(GlobalAccessLogMode mode) { LogMode = mode; diff --git a/src/LibHac/FsSrv/FileSystemProxyImpl.cs b/src/LibHac/FsSrv/FileSystemProxyImpl.cs index 3fe99c8f..f468d307 100644 --- a/src/LibHac/FsSrv/FileSystemProxyImpl.cs +++ b/src/LibHac/FsSrv/FileSystemProxyImpl.cs @@ -254,8 +254,8 @@ namespace LibHac.FsSrv in hashSalt); } - public Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute attribute, - ref SaveDataCreationInfo creationInfo) + public Result CreateSaveDataFileSystemBySystemSaveDataId(in SaveDataAttribute attribute, + in SaveDataCreationInfo creationInfo) { Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService); if (rc.IsFailure()) return rc; @@ -399,17 +399,44 @@ namespace LibHac.FsSrv throw new NotImplementedException(); } - public Result OpenHostFileSystem(out IFileSystem fileSystem, ref FsPath path) + public Result OpenHostFileSystem(out ReferenceCountedDisposable fileSystem, in FspPath path) { - return OpenHostFileSystemWithOption(out fileSystem, ref path, MountHostOption.None); + return OpenHostFileSystemWithOption(out fileSystem, in path, MountHostOption.None); } - public Result OpenHostFileSystemWithOption(out IFileSystem fileSystem, ref FsPath path, MountHostOption option) + public Result OpenHostFileSystemWithOption(out ReferenceCountedDisposable fileSystem, + in FspPath path, MountHostOption option) { - // Missing permission check + fileSystem = default; - return FsProxyCore.OpenHostFileSystem(out fileSystem, new U8Span(path.Str), - option.HasFlag(MountHostOption.PseudoCaseSensitive)); + Result rc = GetProgramInfo(out ProgramInfo programInfo); + if (rc.IsFailure()) return rc; + + Accessibility accessibility = programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountHost); + + if (!accessibility.CanRead || !accessibility.CanWrite) + return ResultFs.PermissionDenied.Log(); + + ReferenceCountedDisposable hostFs = null; + try + { + rc = FsProxyCore.OpenHostFileSystem(out hostFs, new U8Span(path.Str), + option.HasFlag(MountHostOption.PseudoCaseSensitive)); + if (rc.IsFailure()) return rc; + + bool isRootPath = path.Str[0] == 0; + + fileSystem = FileSystemInterfaceAdapter.CreateShared(ref hostFs, isRootPath); + + if (fileSystem is null) + return ResultFs.AllocationFailureInCreateShared.Log(); + + return Result.Success; + } + finally + { + hostFs?.Dispose(); + } } public Result OpenSdCardFileSystem(out ReferenceCountedDisposable fileSystem) @@ -432,20 +459,31 @@ namespace LibHac.FsSrv return GetBaseFileSystemService().IsExFatSupported(out isSupported); } - public Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId) + public Result OpenGameCardStorage(out ReferenceCountedDisposable storage, GameCardHandle handle, + GameCardPartitionRaw partitionId) { // Missing permission check and StorageInterfaceAdapter return FsProxyCore.OpenGameCardStorage(out storage, handle, partitionId); } - public Result OpenDeviceOperator(out IDeviceOperator deviceOperator) + public Result OpenDeviceOperator(out ReferenceCountedDisposable deviceOperator) { // Missing permission check return FsProxyCore.OpenDeviceOperator(out deviceOperator); } + public Result OpenSdCardDetectionEventNotifier(out ReferenceCountedDisposable eventNotifier) + { + throw new NotImplementedException(); + } + + public Result OpenGameCardDetectionEventNotifier(out ReferenceCountedDisposable eventNotifier) + { + throw new NotImplementedException(); + } + public Result OpenSystemDataUpdateEventNotifier(out ReferenceCountedDisposable eventNotifier) { Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService); @@ -659,11 +697,37 @@ namespace LibHac.FsSrv throw new NotImplementedException(); } - public Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId) + public Result OpenCustomStorageFileSystem(out ReferenceCountedDisposable fileSystem, CustomStorageId storageId) { - // Missing permission check, speed emulation storage type wrapper, and FileSystemInterfaceAdapter + fileSystem = default; + var storageFlag = StorageType.NonGameCard; + using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(storageFlag); - return FsProxyCore.OpenCustomStorageFileSystem(out fileSystem, storageId); + Result rc = GetProgramInfo(out ProgramInfo programInfo); + if (rc.IsFailure()) return rc; + + AccessibilityType accessType = storageId > CustomStorageId.SdCard + ? AccessibilityType.NotMount + : AccessibilityType.MountCustomStorage; + + Accessibility accessibility = programInfo.AccessControl.GetAccessibilityFor(accessType); + + if (!accessibility.CanRead || !accessibility.CanWrite) + return ResultFs.PermissionDenied.Log(); + + ReferenceCountedDisposable customFs = null; + try + { + customFs = StorageLayoutTypeSetFileSystem.CreateShared(ref customFs, storageFlag); + customFs = AsynchronousAccessFileSystem.CreateShared(ref customFs); + fileSystem = FileSystemInterfaceAdapter.CreateShared(ref customFs); + + return Result.Success; + } + finally + { + customFs?.Dispose(); + } } public Result OpenGameCardFileSystem(out ReferenceCountedDisposable fileSystem, @@ -766,7 +830,7 @@ namespace LibHac.FsSrv .RegisterProgramIndexMapInfo(programIndexMapInfoBuffer, programCount); } - public Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path) + public Result SetBisRootForHost(BisPartitionId partitionId, in FspPath path) { throw new NotImplementedException(); } @@ -839,7 +903,7 @@ namespace LibHac.FsSrv return GetProgramIndexRegistryService().GetProgramIndex(out programIndex, out programCount); } - public Result OutputAccessLogToSdCard(U8Span logString) + public Result OutputAccessLogToSdCard(InBuffer logString) { throw new NotImplementedException(); } diff --git a/src/LibHac/FsSrv/IDeviceOperator.cs b/src/LibHac/FsSrv/IDeviceOperator.cs index aa855d58..0b605385 100644 --- a/src/LibHac/FsSrv/IDeviceOperator.cs +++ b/src/LibHac/FsSrv/IDeviceOperator.cs @@ -1,6 +1,8 @@ -namespace LibHac.FsSrv +using System; + +namespace LibHac.FsSrv { - public interface IDeviceOperator + public interface IDeviceOperator : IDisposable { Result IsSdCardInserted(out bool isInserted); Result IsGameCardInserted(out bool isInserted); diff --git a/src/LibHac/FsSrv/IFileSystemProxy.cs b/src/LibHac/FsSrv/IFileSystemProxy.cs index ff67fd70..580bf5dd 100644 --- a/src/LibHac/FsSrv/IFileSystemProxy.cs +++ b/src/LibHac/FsSrv/IFileSystemProxy.cs @@ -20,24 +20,24 @@ namespace LibHac.FsSrv Result OpenBisFileSystem(out ReferenceCountedDisposable fileSystem, in FspPath rootPath, BisPartitionId partitionId); Result OpenBisStorage(out ReferenceCountedDisposable storage, BisPartitionId partitionId); Result InvalidateBisCache(); - Result OpenHostFileSystemWithOption(out IFileSystem fileSystem, ref FsPath path, MountHostOption option); - Result OpenHostFileSystem(out IFileSystem fileSystem, ref FsPath path); + Result OpenHostFileSystem(out ReferenceCountedDisposable fileSystem, in FspPath path); Result OpenSdCardFileSystem(out ReferenceCountedDisposable fileSystem); Result FormatSdCardFileSystem(); Result DeleteSaveDataFileSystem(ulong saveDataId); Result CreateSaveDataFileSystem(in SaveDataAttribute attribute, in SaveDataCreationInfo creationInfo, in SaveDataMetaInfo metaInfo); - Result CreateSaveDataFileSystemBySystemSaveDataId(ref SaveDataAttribute attribute, ref SaveDataCreationInfo creationInfo); + Result CreateSaveDataFileSystemBySystemSaveDataId(in SaveDataAttribute attribute, in SaveDataCreationInfo creationInfo); Result RegisterSaveDataFileSystemAtomicDeletion(InBuffer saveDataIds); Result DeleteSaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId); Result FormatSdCardDryRun(); Result IsExFatSupported(out bool isSupported); Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, in SaveDataAttribute attribute); - Result OpenGameCardStorage(out IStorage storage, GameCardHandle handle, GameCardPartitionRaw partitionId); + Result OpenGameCardStorage(out ReferenceCountedDisposable storage, GameCardHandle handle, GameCardPartitionRaw partitionId); Result OpenGameCardFileSystem(out ReferenceCountedDisposable fileSystem, GameCardHandle handle, GameCardPartition partitionId); Result ExtendSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, long dataSize, long journalSize); Result DeleteCacheStorage(ushort index); Result GetCacheStorageSize(out long dataSize, out long journalSize, ushort index); Result CreateSaveDataFileSystemWithHashSalt(in SaveDataAttribute attribute, in SaveDataCreationInfo creationInfo, in SaveDataMetaInfo metaInfo, in HashSalt hashSalt); + Result OpenHostFileSystemWithOption(out ReferenceCountedDisposable fileSystem, in FspPath path, MountHostOption option); Result OpenSaveDataFileSystem(out ReferenceCountedDisposable fileSystem, SaveDataSpaceId spaceId, in SaveDataAttribute attribute); Result OpenSaveDataFileSystemBySystemSaveDataId(out ReferenceCountedDisposable fileSystem, SaveDataSpaceId spaceId, in SaveDataAttribute attribute); Result OpenReadOnlySaveDataFileSystem(out ReferenceCountedDisposable fileSystem, SaveDataSpaceId spaceId, in SaveDataAttribute attribute); @@ -62,15 +62,17 @@ namespace LibHac.FsSrv Result OpenImageDirectoryFileSystem(out ReferenceCountedDisposable fileSystem, ImageDirectoryId directoryId); Result OpenContentStorageFileSystem(out ReferenceCountedDisposable fileSystem, ContentStorageId storageId); Result OpenCloudBackupWorkStorageFileSystem(out ReferenceCountedDisposable fileSystem, CloudBackupWorkStorageId storageId); - Result OpenCustomStorageFileSystem(out IFileSystem fileSystem, CustomStorageId storageId); + Result OpenCustomStorageFileSystem(out ReferenceCountedDisposable fileSystem, CustomStorageId storageId); Result OpenDataStorageByCurrentProcess(out ReferenceCountedDisposable storage); Result OpenDataStorageByProgramId(out ReferenceCountedDisposable storage, ProgramId programId); Result OpenDataStorageByDataId(out ReferenceCountedDisposable storage, DataId dataId, StorageId storageId); Result OpenPatchDataStorageByCurrentProcess(out ReferenceCountedDisposable storage); Result OpenDataFileSystemWithProgramIndex(out ReferenceCountedDisposable fileSystem, byte programIndex); Result OpenDataStorageWithProgramIndex(out ReferenceCountedDisposable storage, byte programIndex); - Result OpenDeviceOperator(out IDeviceOperator deviceOperator); + Result OpenDeviceOperator(out ReferenceCountedDisposable deviceOperator); + Result OpenSdCardDetectionEventNotifier(out ReferenceCountedDisposable eventNotifier); + Result OpenGameCardDetectionEventNotifier(out ReferenceCountedDisposable eventNotifier); Result OpenSystemDataUpdateEventNotifier(out ReferenceCountedDisposable eventNotifier); Result NotifySystemDataUpdateEvent(); @@ -96,13 +98,13 @@ namespace LibHac.FsSrv Result IsSdCardAccessible(out bool isAccessible); Result RegisterProgramIndexMapInfo(InBuffer programIndexMapInfoBuffer, int programCount); - Result SetBisRootForHost(BisPartitionId partitionId, ref FsPath path); + Result SetBisRootForHost(BisPartitionId partitionId, in FspPath path); Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize); Result SetSaveDataRootPath(in FspPath path); Result DisableAutoSaveDataCreation(); Result SetGlobalAccessLogMode(GlobalAccessLogMode mode); Result GetGlobalAccessLogMode(out GlobalAccessLogMode mode); - Result OutputAccessLogToSdCard(U8Span logString); + Result OutputAccessLogToSdCard(InBuffer logString); Result RegisterUpdatePartition(); Result OpenRegisteredUpdatePartition(out ReferenceCountedDisposable fileSystem); diff --git a/src/LibHac/FsSrv/Impl/StorageInterfaceAdapter.cs b/src/LibHac/FsSrv/Impl/StorageInterfaceAdapter.cs index 8c8c3528..5598f58d 100644 --- a/src/LibHac/FsSrv/Impl/StorageInterfaceAdapter.cs +++ b/src/LibHac/FsSrv/Impl/StorageInterfaceAdapter.cs @@ -10,9 +10,21 @@ namespace LibHac.FsSrv.Impl { private ReferenceCountedDisposable BaseStorage { get; } - public StorageInterfaceAdapter(ReferenceCountedDisposable baseStorage) + private StorageInterfaceAdapter(ref ReferenceCountedDisposable baseStorage) { - BaseStorage = baseStorage.AddReference(); + BaseStorage = Shared.Move(ref baseStorage); + } + + public static ReferenceCountedDisposable CreateShared( + ref ReferenceCountedDisposable baseStorage) + { + var adapter = new StorageInterfaceAdapter(ref baseStorage); + return new ReferenceCountedDisposable(adapter); + } + + public void Dispose() + { + BaseStorage?.Dispose(); } public Result Read(long offset, Span destination) @@ -47,7 +59,7 @@ namespace LibHac.FsSrv.Impl if (source.Length < 0) return ResultFs.InvalidSize.Log(); - // Note: Thread priority is temporarily when writing in FS + // Note: Thread priority is temporarily increased when writing in FS return BaseStorage.Target.Write(offset, source); } @@ -93,9 +105,5 @@ namespace LibHac.FsSrv.Impl return Result.Success; } - public void Dispose() - { - BaseStorage?.Dispose(); - } } } diff --git a/src/LibHac/FsSrv/Impl/Utility.cs b/src/LibHac/FsSrv/Impl/Utility.cs index bbb9ab05..51111b06 100644 --- a/src/LibHac/FsSrv/Impl/Utility.cs +++ b/src/LibHac/FsSrv/Impl/Utility.cs @@ -122,7 +122,7 @@ namespace LibHac.FsSrv.Impl } public static Result CreateSubDirectoryFileSystem(out ReferenceCountedDisposable subDirFileSystem, - ReferenceCountedDisposable baseFileSystem, U8Span subPath, bool preserveUnc = false) + ref ReferenceCountedDisposable baseFileSystem, U8Span subPath, bool preserveUnc = false) { subDirFileSystem = default; @@ -132,7 +132,7 @@ namespace LibHac.FsSrv.Impl dir.Dispose(); - var fs = new SubdirectoryFileSystem(baseFileSystem, preserveUnc); + var fs = new SubdirectoryFileSystem(ref baseFileSystem, preserveUnc); using (var subDirFs = new ReferenceCountedDisposable(fs)) { rc = subDirFs.Target.Initialize(subPath); @@ -144,7 +144,7 @@ namespace LibHac.FsSrv.Impl } public static Result WrapSubDirectory(out ReferenceCountedDisposable fileSystem, - ReferenceCountedDisposable baseFileSystem, U8Span path, bool createIfMissing) + ref ReferenceCountedDisposable baseFileSystem, U8Span path, bool createIfMissing) { fileSystem = default; @@ -159,7 +159,7 @@ namespace LibHac.FsSrv.Impl Result rc = EnsureDirectory(baseFileSystem.Target, path); if (rc.IsFailure()) return rc; - return CreateSubDirectoryFileSystem(out fileSystem, baseFileSystem, path); + return CreateSubDirectoryFileSystem(out fileSystem, ref baseFileSystem, path); } private static ReadOnlySpan FileSystemRootPath => // / diff --git a/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs b/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs index c2137239..5e785311 100644 --- a/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs +++ b/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs @@ -100,17 +100,29 @@ namespace LibHac.FsSrv if (type == FileSystemProxyType.Manual) { - rc = TryOpenCaseSensitiveContentDirectory( - out ReferenceCountedDisposable manualFileSystem, baseFileSystem, currentPath); - if (rc.IsFailure()) return rc; + ReferenceCountedDisposable manualFileSystem = null; + ReferenceCountedDisposable readOnlyFileSystem = null; + try + { + rc = TryOpenCaseSensitiveContentDirectory(out manualFileSystem, ref baseFileSystem, + currentPath); + if (rc.IsFailure()) return rc; - var readOnlyFs = new ReadOnlyFileSystem(manualFileSystem); - fileSystem = new ReferenceCountedDisposable(readOnlyFs); + readOnlyFileSystem = ReadOnlyFileSystem.CreateShared(ref manualFileSystem); + if (readOnlyFileSystem?.Target is null) + return ResultFs.AllocationFailureInAllocateShared.Log(); - return Result.Success; + Shared.Move(out fileSystem, ref readOnlyFileSystem); + return Result.Success; + } + finally + { + manualFileSystem?.Dispose(); + readOnlyFileSystem?.Dispose(); + } } - return TryOpenContentDirectory(currentPath, out fileSystem, baseFileSystem, type, true); + return TryOpenContentDirectory(currentPath, out fileSystem, ref baseFileSystem, type, true); } rc = TryOpenNsp(ref currentPath, out ReferenceCountedDisposable nspFileSystem, baseFileSystem); @@ -371,20 +383,27 @@ namespace LibHac.FsSrv private Result TryOpenContentDirectory(U8Span path, out ReferenceCountedDisposable contentFileSystem, - ReferenceCountedDisposable baseFileSystem, FileSystemProxyType fsType, bool preserveUnc) + ref ReferenceCountedDisposable baseFileSystem, FileSystemProxyType fsType, bool preserveUnc) { contentFileSystem = default; - Result rc = _config.SubDirectoryFsCreator.Create(out ReferenceCountedDisposable subDirFs, - baseFileSystem, path, preserveUnc); - if (rc.IsFailure()) return rc; + ReferenceCountedDisposable subDirFs = null; + try + { + Result rc = _config.SubDirectoryFsCreator.Create(out subDirFs, ref baseFileSystem, path, preserveUnc); + if (rc.IsFailure()) return rc; - return OpenSubDirectoryForFsType(out contentFileSystem, subDirFs, fsType); + return OpenSubDirectoryForFsType(out contentFileSystem, ref subDirFs, fsType); + } + finally + { + subDirFs?.Dispose(); + } } private Result TryOpenCaseSensitiveContentDirectory( out ReferenceCountedDisposable contentFileSystem, - ReferenceCountedDisposable baseFileSystem, U8Span path) + ref ReferenceCountedDisposable baseFileSystem, U8Span path) { contentFileSystem = default; Unsafe.SkipInit(out FsPath fullPath); @@ -408,11 +427,11 @@ namespace LibHac.FsSrv if (rc.IsFailure()) return rc; } - return _config.SubDirectoryFsCreator.Create(out contentFileSystem, baseFileSystem, fullPath); + return _config.SubDirectoryFsCreator.Create(out contentFileSystem, ref baseFileSystem, fullPath); } private Result OpenSubDirectoryForFsType(out ReferenceCountedDisposable fileSystem, - ReferenceCountedDisposable baseFileSystem, FileSystemProxyType fsType) + ref ReferenceCountedDisposable baseFileSystem, FileSystemProxyType fsType) { fileSystem = default; ReadOnlySpan dirName; @@ -442,19 +461,26 @@ namespace LibHac.FsSrv return ResultFs.InvalidArgument.Log(); } - // Open the subdirectory filesystem - Result rc = _config.SubDirectoryFsCreator.Create(out ReferenceCountedDisposable subDirFs, - baseFileSystem, new U8Span(dirName)); - if (rc.IsFailure()) return rc; - - if (fsType == FileSystemProxyType.Code) + ReferenceCountedDisposable subDirFs = null; + try { - rc = _config.StorageOnNcaCreator.VerifyAcidSignature(subDirFs.Target, null); + // Open the subdirectory filesystem + Result rc = _config.SubDirectoryFsCreator.Create(out subDirFs, ref baseFileSystem, new U8Span(dirName)); if (rc.IsFailure()) return rc; - } - fileSystem = subDirFs; - return Result.Success; + if (fsType == FileSystemProxyType.Code) + { + rc = _config.StorageOnNcaCreator.VerifyAcidSignature(subDirFs.Target, null); + if (rc.IsFailure()) return rc; + } + + Shared.Move(out fileSystem, ref subDirFs); + return Result.Success; + } + finally + { + subDirFs?.Dispose(); + } } private Result TryOpenNsp(ref U8Span path, out ReferenceCountedDisposable fileSystem, @@ -659,29 +685,37 @@ namespace LibHac.FsSrv if (rc.IsFailure()) return rc; } - rc = _config.TargetManagerFsCreator.Create(out ReferenceCountedDisposable hostFs, - openCaseSensitive); - if (rc.IsFailure()) return rc; - - if (path.IsEmpty()) + ReferenceCountedDisposable hostFs = null; + ReferenceCountedDisposable subDirFs = null; + try { - ReadOnlySpan rootHostPath = new[] { (byte)'C', (byte)':', (byte)'/' }; - rc = hostFs.Target.GetEntryType(out _, new U8Span(rootHostPath)); + rc = _config.TargetManagerFsCreator.Create(out hostFs, openCaseSensitive); + if (rc.IsFailure()) return rc; - // Nintendo ignores all results other than this one - if (ResultFs.TargetNotFound.Includes(rc)) - return rc; + if (path.IsEmpty()) + { + ReadOnlySpan rootHostPath = new[] { (byte)'C', (byte)':', (byte)'/' }; + rc = hostFs.Target.GetEntryType(out _, new U8Span(rootHostPath)); - fileSystem = hostFs; + // Nintendo ignores all results other than this one + if (ResultFs.TargetNotFound.Includes(rc)) + return rc; + + Shared.Move(out fileSystem, ref hostFs); + return Result.Success; + } + + rc = _config.SubDirectoryFsCreator.Create(out subDirFs, ref hostFs, path, preserveUnc: true); + if (rc.IsFailure()) return rc; + + Shared.Move(out fileSystem, ref subDirFs); return Result.Success; } - - rc = _config.SubDirectoryFsCreator.Create(out ReferenceCountedDisposable subDirFs, hostFs, - path, preserveUnc: true); - if (rc.IsFailure()) return rc; - - fileSystem = subDirFs; - return Result.Success; + finally + { + hostFs?.Dispose(); + subDirFs?.Dispose(); + } } public Result OpenFileSystemWithPatch(out ReferenceCountedDisposable fileSystem, @@ -746,7 +780,7 @@ namespace LibHac.FsSrv rc = Utility.EnsureDirectory(baseFileSystem.Target, new U8Span(contentStoragePath)); if (rc.IsFailure()) return rc; - rc = _config.SubDirectoryFsCreator.Create(out subDirFileSystem, baseFileSystem, + rc = _config.SubDirectoryFsCreator.Create(out subDirFileSystem, ref baseFileSystem, new U8Span(contentStoragePath)); if (rc.IsFailure()) return rc; @@ -754,8 +788,7 @@ namespace LibHac.FsSrv if (contentStorageId != ContentStorageId.SdCard) { // Move the shared reference to the out variable - fileSystem = subDirFileSystem; - subDirFileSystem = null; + Shared.Move(out fileSystem, ref subDirFileSystem); return Result.Success; } @@ -765,8 +798,7 @@ namespace LibHac.FsSrv EncryptedFsKeyId.Content, in _encryptionSeed); if (rc.IsFailure()) return rc; - fileSystem = encryptedFileSystem; - encryptedFileSystem = null; + Shared.Move(out fileSystem, ref encryptedFileSystem); return Result.Success; } diff --git a/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs b/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs index 835e4b7d..e980e111 100644 --- a/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs +++ b/src/LibHac/FsSrv/SaveDataFileSystemServiceImpl.cs @@ -437,7 +437,7 @@ namespace LibHac.FsSrv rc = _config.TargetManagerFsCreator.Create(out tmFs, isTargetFsCaseSensitive); if (rc.IsFailure()) return rc; - return Utility.CreateSubDirectoryFileSystem(out fileSystem, tmFs, new U8Span(path.Str), true); + return Utility.CreateSubDirectoryFileSystem(out fileSystem, ref tmFs, new U8Span(path.Str), true); } finally { @@ -482,14 +482,14 @@ namespace LibHac.FsSrv rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.System, true); if (rc.IsFailure()) return rc; - return Utility.WrapSubDirectory(out fileSystem, tempFs, basePath, createIfMissing); + return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing); case SaveDataSpaceId.User: case SaveDataSpaceId.Temporary: rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.User, true); if (rc.IsFailure()) return rc; - return Utility.WrapSubDirectory(out fileSystem, tempFs, basePath, createIfMissing); + return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing); case SaveDataSpaceId.SdSystem: case SaveDataSpaceId.SdCache: @@ -503,7 +503,7 @@ namespace LibHac.FsSrv .Append((byte)'/') .Append(CommonPaths.SdCardNintendoRootDirectoryName); - rc = Utility.WrapSubDirectory(out tempSubFs, tempFs, path, createIfMissing); + rc = Utility.WrapSubDirectory(out tempSubFs, ref tempFs, path, createIfMissing); if (rc.IsFailure()) return rc; return _config.EncryptedFsCreator.Create(out fileSystem, tempSubFs, EncryptedFsKeyId.Save, @@ -513,13 +513,13 @@ namespace LibHac.FsSrv rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.SystemProperPartition, true); if (rc.IsFailure()) return rc; - return Utility.WrapSubDirectory(out fileSystem, tempFs, basePath, createIfMissing); + return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing); case SaveDataSpaceId.SafeMode: rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.SafeMode, true); if (rc.IsFailure()) return rc; - return Utility.WrapSubDirectory(out fileSystem, tempFs, basePath, createIfMissing); + return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing); default: return ResultFs.InvalidArgument.Log(); diff --git a/src/LibHac/FsSystem/SubdirectoryFileSystem.cs b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs index fa8f693c..02a6df46 100644 --- a/src/LibHac/FsSystem/SubdirectoryFileSystem.cs +++ b/src/LibHac/FsSystem/SubdirectoryFileSystem.cs @@ -36,9 +36,9 @@ namespace LibHac.FsSystem PreserveUnc = preserveUnc; } - public SubdirectoryFileSystem(ReferenceCountedDisposable baseFileSystem, bool preserveUnc = false) + public SubdirectoryFileSystem(ref ReferenceCountedDisposable baseFileSystem, bool preserveUnc = false) { - BaseFileSystemShared = baseFileSystem.AddReference(); + BaseFileSystemShared = Shared.Move(ref baseFileSystem); BaseFileSystem = BaseFileSystemShared.Target; PreserveUnc = preserveUnc; }