Move code to use SharedRef instead of ReferenceCountedDisposable

This commit is contained in:
Alex Barney 2021-08-20 15:33:26 -07:00
parent c28128c7dd
commit a23d01e934
182 changed files with 5484 additions and 6235 deletions

View File

@ -1219,10 +1219,11 @@ Module,DescriptionStart,DescriptionEnd,Flags,Namespace,Name,Summary
6,8,,,,InvalidHandle,
6,1023,,,,InternalError,
8,1,,,,ResolverNotFound,
8,2,,,,ProgramNotFound,
8,3,,,,DataNotFound,
8,4,,,,UnknownStorageId,
8,5,,,,LocationResolverNotFound,
8,4,,,,UnknownResolver,
8,5,,,,ApplicationNotFound,
8,6,,,,HtmlDocumentNotFound,
8,7,,,,AddOnContentNotFound,
8,8,,,,ControlNotFound,

1 Module DescriptionStart DescriptionEnd Flags Namespace Name Summary
1219 22 9 8 NotAuthorized TooManyNrr
1220 22 10 9 InvalidNrrKind NotAuthorized
1221 22 1023 10 InternalError InvalidNrrKind
1222 22 1023 InternalError
1223 22 1025 InvalidAddress
1224 22 1026 InvalidSize
1225 22 1028 NotLoaded
1226 22 1029 NotRegistered
1227 22 1030 InvalidSession
1228 22 1031 InvalidProcess
1229 24 1 NoDevice

View File

@ -1,66 +1,74 @@
using LibHac.Arp.Impl;
using System;
using LibHac.Arp.Impl;
using LibHac.Common;
using LibHac.Ns;
namespace LibHac.Arp
{
public class ArpClient
public class ArpClient : IDisposable
{
private HorizonClient HosClient { get; }
private IReader Reader { get; set; }
private HorizonClient _hosClient;
private SharedRef<IReader> _reader;
private readonly object _readerInitLocker = new object();
internal ArpClient(HorizonClient horizonClient)
{
HosClient = horizonClient;
_hosClient = horizonClient;
}
public void Dispose()
{
_reader.Destroy();
}
public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty launchProperty, ulong processId)
{
EnsureReaderInitialized();
return Reader.GetApplicationLaunchProperty(out launchProperty, processId);
return _reader.Get.GetApplicationLaunchProperty(out launchProperty, processId);
}
public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty launchProperty, ApplicationId applicationId)
{
EnsureReaderInitialized();
return Reader.GetApplicationLaunchPropertyWithApplicationId(out launchProperty, applicationId);
return _reader.Get.GetApplicationLaunchPropertyWithApplicationId(out launchProperty, applicationId);
}
public Result GetApplicationControlProperty(out ApplicationControlProperty controlProperty, ulong processId)
{
EnsureReaderInitialized();
return Reader.GetApplicationControlProperty(out controlProperty, processId);
return _reader.Get.GetApplicationControlProperty(out controlProperty, processId);
}
public Result GetApplicationControlProperty(out ApplicationControlProperty controlProperty, ApplicationId applicationId)
{
EnsureReaderInitialized();
return Reader.GetApplicationControlPropertyWithApplicationId(out controlProperty, applicationId);
return _reader.Get.GetApplicationControlPropertyWithApplicationId(out controlProperty, applicationId);
}
private void EnsureReaderInitialized()
{
if (Reader != null)
if (_reader.HasValue)
return;
lock (_readerInitLocker)
{
if (Reader != null)
if (_reader.HasValue)
return;
Result rc = HosClient.Sm.GetService(out IReader reader, "arp:r");
using var reader = new SharedRef<IReader>();
Result rc = _hosClient.Sm.GetService(ref reader.Ref(), "arp:r");
if (rc.IsFailure())
{
throw new HorizonResultException(rc, "Failed to initialize arp reader.");
}
Reader = reader;
_reader.SetByMove(ref reader.Ref());
}
}
}

View File

@ -1,8 +1,9 @@
using LibHac.Ns;
using System;
using LibHac.Ns;
namespace LibHac.Arp.Impl
{
public interface IReader
public interface IReader : IDisposable
{
Result GetApplicationLaunchProperty(out ApplicationLaunchProperty launchProperty, ulong processId);
Result GetApplicationLaunchPropertyWithApplicationId(out ApplicationLaunchProperty launchProperty, ApplicationId applicationId);

View File

@ -2,6 +2,7 @@
using LibHac.Bcat.Impl.Ipc;
using LibHac.Bcat.Impl.Service;
using LibHac.Bcat.Impl.Service.Core;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.Bcat
@ -11,7 +12,7 @@ namespace LibHac.Bcat
private const int ServiceTypeCount = 4;
internal HorizonClient Hos { get; }
private ServiceCreator[] ServiceCreators { get; } = new ServiceCreator[ServiceTypeCount];
private SharedRef<ServiceCreator>[] _serviceCreators;
private readonly object _bcatServiceInitLocker = new object();
private readonly object _storageManagerInitLocker = new object();
@ -21,6 +22,7 @@ namespace LibHac.Bcat
public BcatServer(HorizonClient horizonClient)
{
Hos = horizonClient;
_serviceCreators = new SharedRef<ServiceCreator>[ServiceTypeCount];
InitBcatService(BcatServiceType.BcatU, "bcat:u", AccessControl.MountOwnDeliveryCacheStorage);
InitBcatService(BcatServiceType.BcatS, "bcat:s", AccessControl.MountOthersDeliveryCacheStorage);
@ -32,9 +34,9 @@ namespace LibHac.Bcat
{
InitServiceCreator(type, name, accessControl);
IServiceCreator service = GetServiceCreator(type);
using SharedRef<IServiceCreator> service = GetServiceCreator(type);
Result rc = Hos.Sm.RegisterService(new BcatServiceObject(service), name);
Result rc = Hos.Sm.RegisterService(new BcatServiceObject(ref service.Ref()), name);
if (rc.IsFailure())
{
throw new HorizonResultException(rc, "Abort");
@ -47,15 +49,18 @@ namespace LibHac.Bcat
{
Debug.Assert((uint)type < ServiceTypeCount);
ServiceCreators[(int)type] = new ServiceCreator(this, name, accessControl);
_serviceCreators[(int)type].Reset(new ServiceCreator(this, name, accessControl));
}
}
private IServiceCreator GetServiceCreator(BcatServiceType type)
private SharedRef<IServiceCreator> GetServiceCreator(BcatServiceType type)
{
Debug.Assert((uint)type < ServiceTypeCount);
lock (_bcatServiceInitLocker)
{
Debug.Assert((uint)type < ServiceTypeCount);
return ServiceCreators[(int)type];
return SharedRef<IServiceCreator>.CreateCopy(ref _serviceCreators[(int)type]);
}
}
internal DeliveryCacheStorageManager GetStorageManager()

View File

@ -1,19 +1,26 @@
using LibHac.Sm;
using System;
using LibHac.Common;
using LibHac.Sm;
namespace LibHac.Bcat.Impl.Ipc
{
internal class BcatServiceObject : IServiceObject
{
private IServiceCreator _serviceCreator;
private SharedRef<IServiceCreator> _serviceCreator;
public BcatServiceObject(IServiceCreator serviceCreator)
public BcatServiceObject(ref SharedRef<IServiceCreator> serviceCreator)
{
_serviceCreator = serviceCreator;
_serviceCreator = SharedRef<IServiceCreator>.CreateMove(ref serviceCreator);
}
public Result GetServiceObject(out object serviceObject)
public void Dispose()
{
serviceObject = _serviceCreator;
_serviceCreator.Destroy();
}
public Result GetServiceObject(ref SharedRef<IDisposable> serviceObject)
{
serviceObject.SetByCopy(ref _serviceCreator);
return Result.Success;
}
}

View File

@ -1,11 +1,14 @@
namespace LibHac.Bcat.Impl.Ipc
using System;
using LibHac.Common;
namespace LibHac.Bcat.Impl.Ipc
{
public interface IServiceCreator
public interface IServiceCreator : IDisposable
{
Result CreateDeliveryCacheStorageService(out IDeliveryCacheStorageService service,
Result CreateDeliveryCacheStorageService(ref SharedRef<IDeliveryCacheStorageService> outService,
ulong processId);
Result CreateDeliveryCacheStorageServiceWithApplicationId(out IDeliveryCacheStorageService service,
ApplicationId applicationId);
Result CreateDeliveryCacheStorageServiceWithApplicationId(
ref SharedRef<IDeliveryCacheStorageService> outService, ApplicationId applicationId);
}
}

View File

@ -4,6 +4,7 @@ using LibHac.Common;
namespace LibHac.Bcat.Impl.Service
{
// Todo: Update BCAT service object management
internal class ServiceCreator : IServiceCreator
{
private BcatServer Server { get; }
@ -19,43 +20,38 @@ namespace LibHac.Bcat.Impl.Service
AccessControl = accessControl;
}
public Result CreateDeliveryCacheStorageService(out IDeliveryCacheStorageService service, ulong processId)
public void Dispose() { }
public Result CreateDeliveryCacheStorageService(ref SharedRef<IDeliveryCacheStorageService> outService,
ulong processId)
{
Result rc = Server.Hos.Arp.GetApplicationLaunchProperty(out ApplicationLaunchProperty launchProperty,
processId);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out service);
return ResultBcat.NotFound.LogConverted(rc);
}
return CreateDeliveryCacheStorageServiceImpl(out service, launchProperty.ApplicationId);
return CreateDeliveryCacheStorageServiceImpl(ref outService, launchProperty.ApplicationId);
}
public Result CreateDeliveryCacheStorageServiceWithApplicationId(out IDeliveryCacheStorageService service,
ApplicationId applicationId)
public Result CreateDeliveryCacheStorageServiceWithApplicationId(
ref SharedRef<IDeliveryCacheStorageService> outService, ApplicationId applicationId)
{
if (!AccessControl.HasFlag(AccessControl.MountOthersDeliveryCacheStorage))
{
UnsafeHelpers.SkipParamInit(out service);
return ResultBcat.PermissionDenied.Log();
}
return CreateDeliveryCacheStorageServiceImpl(out service, applicationId);
return CreateDeliveryCacheStorageServiceImpl(ref outService, applicationId);
}
private Result CreateDeliveryCacheStorageServiceImpl(out IDeliveryCacheStorageService service,
private Result CreateDeliveryCacheStorageServiceImpl(ref SharedRef<IDeliveryCacheStorageService> outService,
ApplicationId applicationId)
{
UnsafeHelpers.SkipParamInit(out service);
Result rc = Server.GetStorageManager().Open(applicationId.Value);
if (rc.IsFailure()) return rc;
// todo: Check if network account required
service = new DeliveryCacheStorageService(Server, applicationId.Value, AccessControl);
outService.Reset(new DeliveryCacheStorageService(Server, applicationId.Value, AccessControl));
return Result.Success;
}

View File

@ -0,0 +1,26 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace LibHac.Common.FixedArrays
{
[StructLayout(LayoutKind.Sequential)]
public struct Array5<T>
{
public const int Length = 5;
private T _1;
private T _2;
private T _3;
private T _4;
private T _5;
public ref T this[int i] => ref Items[i];
public Span<T> Items => SpanHelpers.CreateSpan(ref _1, Length);
public readonly ReadOnlySpan<T> ItemsRo => SpanHelpers.CreateReadOnlySpan(in _1, Length);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlySpan<T>(in Array5<T> value) => value.ItemsRo;
}
}

View File

@ -254,6 +254,46 @@ namespace LibHac.Common
oldRefCount?.Decrement();
}
public void Set<TFrom>(ref UniqueRef<TFrom> other) where TFrom : class, T
{
RefCount oldRefCount = _refCount;
TFrom otherValue = other.Release();
if (otherValue is not null)
{
_value = Unsafe.As<TFrom, T>(ref otherValue);
_refCount = new RefCount(otherValue);
}
else
{
_value = null;
_refCount = null;
}
oldRefCount?.Decrement();
}
public bool TryCastSet<TFrom>(ref SharedRef<TFrom> other) where TFrom : class, IDisposable
{
RefCount oldRefCount = _refCount;
TFrom otherValue = other.Get;
if (otherValue is T)
{
_value = Unsafe.As<TFrom, T>(ref other._value);
_refCount = other._refCount;
other._value = null;
other._refCount = null;
oldRefCount?.Decrement();
return true;
}
return false;
}
private static void ThrowBadWeakPtr()
{
throw new ObjectDisposedException(string.Empty, "bad_weak_ptr");

View File

@ -68,6 +68,14 @@ namespace LibHac.Diag
DoAbort(result, message);
}
public static void DoAbortUnlessSuccess(Result result, string message = null)
{
if (!result.IsSuccess())
{
DoAbort(result, message);
}
}
[DoesNotReturn]
public static void UnexpectedDefault([CallerMemberName] string caller = "")
{

View File

@ -63,9 +63,9 @@ namespace LibHac.Fs
return Result.Success;
}
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.GetGlobalAccessLogMode(out mode);
Result rc = fileSystemProxy.Get.GetGlobalAccessLogMode(out mode);
fs.Impl.AbortIfNeeded(rc);
return rc;
}
@ -79,9 +79,9 @@ namespace LibHac.Fs
return Result.Success;
}
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.SetGlobalAccessLogMode(mode);
Result rc = fileSystemProxy.Get.SetGlobalAccessLogMode(mode);
fs.Impl.AbortIfNeeded(rc);
return rc;
}
@ -133,8 +133,8 @@ namespace LibHac.Fs
public static void OutputApplicationInfoAccessLog(this FileSystemClient fs, in ApplicationInfo applicationInfo)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
fsProxy.Target.OutputApplicationInfoAccessLog(in applicationInfo).IgnoreResult();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
fileSystemProxy.Get.OutputApplicationInfoAccessLog(in applicationInfo).IgnoreResult();
}
}
}
@ -323,14 +323,14 @@ namespace LibHac.Fs.Impl
private static void FlushAccessLogOnSdCardImpl(FileSystemClientImpl fs)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
fsProxy.Target.FlushAccessLogOnSdCard().IgnoreResult();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
fileSystemProxy.Get.FlushAccessLogOnSdCard().IgnoreResult();
}
private static void OutputAccessLogToSdCardImpl(FileSystemClientImpl fs, U8Span message)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
fsProxy.Target.OutputAccessLogToSdCard(new InBuffer(message.Value)).IgnoreResult();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
fileSystemProxy.Get.OutputAccessLogToSdCard(new InBuffer(message.Value)).IgnoreResult();
}
// The original function creates a string using the input format string and format args.
@ -423,8 +423,8 @@ namespace LibHac.Fs.Impl
private static void GetProgramIndexForAccessLog(FileSystemClientImpl fs, out int index, out int count)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.GetProgramIndexForAccessLog(out index, out count);
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fileSystemProxy.Get.GetProgramIndexForAccessLog(out index, out count);
Abort.DoAbortUnless(rc.IsSuccess());
}

View File

@ -0,0 +1,286 @@
using System;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs.Fsa;
using LibHac.Os;
// ReSharper disable once CheckNamespace
namespace LibHac.Fs
{
public class FileStorage : IStorage
{
private const long InvalidSize = -1;
private SharedRef<IFile> _baseFileShared;
private IFile _baseFile;
private long _fileSize;
protected FileStorage()
{
_fileSize = InvalidSize;
}
public FileStorage(IFile baseFile)
{
_baseFile = baseFile;
_fileSize = InvalidSize;
}
public FileStorage(ref SharedRef<IFile> baseFile)
{
_baseFile = baseFile.Get;
_baseFileShared = SharedRef<IFile>.CreateMove(ref baseFile);
_fileSize = InvalidSize;
}
public override void Dispose()
{
_baseFileShared.Destroy();
base.Dispose();
}
protected void SetFile(IFile file)
{
Assert.SdkRequiresNotNull(file);
Assert.SdkRequiresNull(_baseFile);
_baseFile = file;
}
protected override Result DoRead(long offset, Span<byte> destination)
{
if (destination.Length == 0)
return Result.Success;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
if (!CheckAccessRange(offset, destination.Length, _fileSize))
return ResultFs.OutOfRange.Log();
return _baseFile.Read(out _, offset, destination, ReadOption.None);
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source)
{
if (source.Length == 0)
return Result.Success;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
if (!CheckAccessRange(offset, source.Length, _fileSize))
return ResultFs.OutOfRange.Log();
return _baseFile.Write(offset, source, WriteOption.None);
}
protected override Result DoFlush()
{
return _baseFile.Flush();
}
protected override Result DoGetSize(out long size)
{
UnsafeHelpers.SkipParamInit(out size);
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
size = _fileSize;
return Result.Success;
}
protected override Result DoSetSize(long size)
{
_fileSize = InvalidSize;
return _baseFile.SetSize(size);
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan<byte> inBuffer)
{
if (operationId == OperationId.InvalidateCache || operationId == OperationId.QueryRange)
{
if (size == 0)
{
if (operationId == OperationId.QueryRange)
{
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
return ResultFs.InvalidSize.Log();
SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer).Clear();
}
return Result.Success;
}
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
if (!CheckOffsetAndSize(offset, size))
return ResultFs.OutOfRange.Log();
return _baseFile.OperateRange(outBuffer, operationId, offset, size, inBuffer);
}
return ResultFs.UnsupportedOperateRangeForFileStorage.Log();
}
private Result UpdateSize()
{
if (_fileSize != InvalidSize)
return Result.Success;
Result rc = _baseFile.GetSize(out long size);
if (rc.IsFailure()) return rc.Miss();
_fileSize = size;
return Result.Success;
}
}
public class FileStorageBasedFileSystem : FileStorage
{
private SharedRef<IFileSystem> _baseFileSystem;
private UniqueRef<IFile> _baseFile;
public override void Dispose()
{
_baseFile.Destroy();
_baseFileSystem.Destroy();
base.Dispose();
}
public Result Initialize(ref SharedRef<IFileSystem> baseFileSystem, in Path path, OpenMode mode)
{
using var baseFile = new UniqueRef<IFile>();
Result rc = baseFileSystem.Get.OpenFile(ref baseFile.Ref(), in path, mode);
if (rc.IsFailure()) return rc.Miss();
SetFile(baseFile.Get);
_baseFileSystem.SetByMove(ref baseFileSystem);
_baseFile.Set(ref baseFile.Ref());
return Result.Success;
}
}
public class FileHandleStorage : IStorage
{
private const long InvalidSize = -1;
private FileHandle _handle;
private bool _closeFile;
private long _size;
private SdkMutexType _mutex;
// LibHac addition
private FileSystemClient _fsClient;
public FileHandleStorage(FileSystemClient fsClient, FileHandle handle) : this(fsClient, handle, false) { }
public FileHandleStorage(FileSystemClient fsClient, FileHandle handle, bool closeFile)
{
_fsClient = fsClient;
_handle = handle;
_closeFile = closeFile;
_size = InvalidSize;
_mutex.Initialize();
}
public override void Dispose()
{
if (_closeFile)
{
_fsClient.CloseFile(_handle);
_closeFile = false;
_handle = default;
}
base.Dispose();
}
protected override Result DoRead(long offset, Span<byte> destination)
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
if (destination.Length == 0)
return Result.Success;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
if (!CheckAccessRange(offset, destination.Length, _size))
return ResultFs.OutOfRange.Log();
return _fsClient.ReadFile(_handle, offset, destination, ReadOption.None);
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source)
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
if (source.Length == 0)
return Result.Success;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
if (!CheckAccessRange(offset, source.Length, _size))
return ResultFs.OutOfRange.Log();
return _fsClient.WriteFile(_handle, offset, source, WriteOption.None);
}
protected override Result DoFlush()
{
return _fsClient.FlushFile(_handle);
}
protected override Result DoGetSize(out long size)
{
UnsafeHelpers.SkipParamInit(out size);
Result rc = UpdateSize();
if (rc.IsFailure()) return rc.Miss();
size = _size;
return Result.Success;
}
protected override Result DoSetSize(long size)
{
_size = InvalidSize;
return _fsClient.SetFileSize(_handle, size);
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan<byte> inBuffer)
{
if (operationId != OperationId.QueryRange)
return ResultFs.UnsupportedOperateRangeForFileHandleStorage.Log();
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
return ResultFs.InvalidSize.Log();
Result rc = _fsClient.QueryRange(out SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer), _handle, offset, size);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
private Result UpdateSize()
{
if (_size != InvalidSize)
return Result.Success;
Result rc = _fsClient.GetFileSize(out long size, _handle);
if (rc.IsFailure()) return rc.Miss();
_size = size;
return Result.Success;
}
}
}

View File

@ -81,7 +81,7 @@ namespace LibHac.Fs
/// ensure a write buffer is allocated and copy the input path to it. <see cref="SetShallowBuffer"/> will
/// directly use the input buffer without copying. If this method is used, the caller must ensure the path
/// is normalized before passing it to <see cref="SetShallowBuffer"/>.</para>
/// <br/>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <para>Based on FS 12.1.0 (nnSdk 12.3.1)</para></remarks>
[DebuggerDisplay("{" + nameof(ToString) + "(),nq}")]
public ref struct Path
{
@ -1084,6 +1084,16 @@ namespace LibHac.Fs
public static class PathFunctions
{
/// <summary>
/// Initializes a <see cref="Path"/> with the provided basic path.
/// The provided path must be a normalized basic path starting with a directory separator
/// and not containing any sort of prefix such as a mount name.
/// </summary>
/// <param name="path">The <see cref="Path"/> to initialize.</param>
/// <param name="pathBuffer">The string used to initialize the <see cref="Path"/>.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.InvalidCharacter"/>: The path contains an invalid character.<br/>
/// <see cref="ResultFs.InvalidPathFormat"/>: The path is in an invalid format or is not normalized.</returns>
public static Result SetUpFixedPath(ref Path path, ReadOnlySpan<byte> pathBuffer)
{
Result rc = PathNormalizer.IsNormalized(out bool isNormalized, out _, pathBuffer);
@ -1101,6 +1111,14 @@ namespace LibHac.Fs
// Only a small number of format strings are used with these functions, so we can hard code them all easily.
// /%s
/// <summary>
/// Initializes a <see cref="Path"/> using the format string <c>/%s</c>
/// </summary>
/// <param name="path">The <see cref="Path"/> to be initialized.</param>
/// <param name="pathBuffer">The buffer that will contain the built string.</param>
/// <param name="entryName">The first entry in the generated path.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.InvalidArgument"/>: <paramref name="pathBuffer"/> was too small to contain the built path.</returns>
internal static Result SetUpFixedPathSingleEntry(ref Path path, Span<byte> pathBuffer,
ReadOnlySpan<byte> entryName)
{
@ -1114,6 +1132,15 @@ namespace LibHac.Fs
}
// /%s/%s
/// <summary>
/// Initializes a <see cref="Path"/> using the format string <c>/%s/%s</c>
/// </summary>
/// <param name="path">The <see cref="Path"/> to be initialized.</param>
/// <param name="pathBuffer">The buffer that will contain the built string.</param>
/// <param name="entryName1">The first entry in the generated path.</param>
/// <param name="entryName2">The second entry in the generated path.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.InvalidArgument"/>: <paramref name="pathBuffer"/> was too small to contain the built path.</returns>
internal static Result SetUpFixedPathDoubleEntry(ref Path path, Span<byte> pathBuffer,
ReadOnlySpan<byte> entryName1, ReadOnlySpan<byte> entryName2)
{
@ -1128,6 +1155,14 @@ namespace LibHac.Fs
}
// /%016llx
/// <summary>
/// Initializes a <see cref="Path"/> using the format string <c>/%016llx</c>
/// </summary>
/// <param name="path">The <see cref="Path"/> to be initialized.</param>
/// <param name="pathBuffer">The buffer that will contain the built string.</param>
/// <param name="saveDataId">The save data ID to insert into the path.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.InvalidArgument"/>: <paramref name="pathBuffer"/> was too small to contain the built path.</returns>
internal static Result SetUpFixedPathSaveId(ref Path path, Span<byte> pathBuffer, ulong saveDataId)
{
var sb = new U8StringBuilder(pathBuffer);
@ -1140,6 +1175,14 @@ namespace LibHac.Fs
}
// /%08x.meta
/// <summary>
/// Initializes a <see cref="Path"/> using the format string <c>/%08x.meta</c>
/// </summary>
/// <param name="path">The <see cref="Path"/> to be initialized.</param>
/// <param name="pathBuffer">The buffer that will contain the built string.</param>
/// <param name="metaType">The <see cref="SaveDataMetaType"/> to insert into the path.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.InvalidArgument"/>: <paramref name="pathBuffer"/> was too small to contain the built path.</returns>
internal static Result SetUpFixedPathSaveMetaName(ref Path path, Span<byte> pathBuffer, uint metaType)
{
ReadOnlySpan<byte> metaExtension = new[] { (byte)'.', (byte)'m', (byte)'e', (byte)'t', (byte)'a' }; // ".meta"
@ -1154,6 +1197,14 @@ namespace LibHac.Fs
}
// /saveMeta/%016llx
/// <summary>
/// Initializes a <see cref="Path"/> using the format string <c>/saveMeta/%016llx</c>
/// </summary>
/// <param name="path">The <see cref="Path"/> to be initialized.</param>
/// <param name="pathBuffer">The buffer that will contain the built string.</param>
/// <param name="saveDataId">The save data ID to insert into the path.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.InvalidArgument"/>: <paramref name="pathBuffer"/> was too small to contain the built path.</returns>
internal static Result SetUpFixedPathSaveMetaDir(ref Path path, Span<byte> pathBuffer, ulong saveDataId)
{
ReadOnlySpan<byte> metaDirectoryName = new[]

View File

@ -14,7 +14,7 @@ namespace LibHac.Fs
/// <summary>
/// Contains functions for working with path formatting and normalization.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
public static class PathFormatter
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@ -11,7 +11,7 @@ namespace LibHac.Fs
/// <summary>
/// Contains functions for doing with basic path normalization.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
public static class PathNormalizer
{
private enum PathState

View File

@ -8,6 +8,10 @@ using static LibHac.Fs.StringTraits;
// ReSharper disable once CheckNamespace
namespace LibHac.Fs
{
/// <summary>
/// Contains various utility functions for working with paths.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
public static class PathUtility
{
public static void Replace(Span<byte> buffer, byte currentChar, byte newChar)

View File

@ -10,7 +10,7 @@ namespace LibHac.Fs
/// <summary>
/// Contains functions for working with Windows paths.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
public static class WindowsPath
{
private const int WindowsDriveLength = 2;

View File

@ -1,98 +1,98 @@
using System;
using LibHac.Common;
using LibHac.Fs.Fsa;
//using System;
//using LibHac.Common;
//using LibHac.Fs.Fsa;
namespace LibHac.Fs
{
public class FileHandleStorage : IStorage
{
private const long InvalidSize = -1;
private readonly object _locker = new object();
//namespace LibHac.Fs
//{
// public class FileHandleStorage : IStorage
// {
// private const long InvalidSize = -1;
// private readonly object _locker = new object();
private FileSystemClient FsClient { get; }
private FileHandle Handle { get; }
private long FileSize { get; set; } = InvalidSize;
private bool CloseHandle { get; }
// private FileSystemClient FsClient { get; }
// private FileHandle Handle { get; }
// private long FileSize { get; set; } = InvalidSize;
// private bool CloseHandle { get; }
public FileHandleStorage(FileSystemClient fsClient, FileHandle handle) : this(fsClient, handle, false) { }
// public FileHandleStorage(FileSystemClient fsClient, FileHandle handle) : this(fsClient, handle, false) { }
public FileHandleStorage(FileSystemClient fsClient, FileHandle handle, bool closeHandleOnDispose)
{
FsClient = fsClient;
Handle = handle;
CloseHandle = closeHandleOnDispose;
}
// public FileHandleStorage(FileSystemClient fsClient, FileHandle handle, bool closeHandleOnDispose)
// {
// FsClient = fsClient;
// Handle = handle;
// CloseHandle = closeHandleOnDispose;
// }
protected override Result DoRead(long offset, Span<byte> destination)
{
lock (_locker)
{
if (destination.Length == 0) return Result.Success;
// protected override Result DoRead(long offset, Span<byte> destination)
// {
// lock (_locker)
// {
// if (destination.Length == 0) return Result.Success;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc;
// Result rc = UpdateSize();
// if (rc.IsFailure()) return rc;
if (!IsRangeValid(offset, destination.Length, FileSize)) return ResultFs.OutOfRange.Log();
// if (!CheckAccessRange(offset, destination.Length, FileSize)) return ResultFs.OutOfRange.Log();
return FsClient.ReadFile(Handle, offset, destination);
}
}
// return FsClient.ReadFile(Handle, offset, destination);
// }
// }
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source)
{
lock (_locker)
{
if (source.Length == 0) return Result.Success;
// protected override Result DoWrite(long offset, ReadOnlySpan<byte> source)
// {
// lock (_locker)
// {
// if (source.Length == 0) return Result.Success;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc;
// Result rc = UpdateSize();
// if (rc.IsFailure()) return rc;
if (!IsRangeValid(offset, source.Length, FileSize)) return ResultFs.OutOfRange.Log();
// if (!CheckAccessRange(offset, source.Length, FileSize)) return ResultFs.OutOfRange.Log();
return FsClient.WriteFile(Handle, offset, source, WriteOption.None);
}
}
// return FsClient.WriteFile(Handle, offset, source, WriteOption.None);
// }
// }
protected override Result DoFlush()
{
return FsClient.FlushFile(Handle);
}
// protected override Result DoFlush()
// {
// return FsClient.FlushFile(Handle);
// }
protected override Result DoSetSize(long size)
{
FileSize = InvalidSize;
// protected override Result DoSetSize(long size)
// {
// FileSize = InvalidSize;
return FsClient.SetFileSize(Handle, size);
}
// return FsClient.SetFileSize(Handle, size);
// }
protected override Result DoGetSize(out long size)
{
UnsafeHelpers.SkipParamInit(out size);
// protected override Result DoGetSize(out long size)
// {
// UnsafeHelpers.SkipParamInit(out size);
Result rc = UpdateSize();
if (rc.IsFailure()) return rc;
// Result rc = UpdateSize();
// if (rc.IsFailure()) return rc;
size = FileSize;
return Result.Success;
}
// size = FileSize;
// return Result.Success;
// }
private Result UpdateSize()
{
if (FileSize != InvalidSize) return Result.Success;
// private Result UpdateSize()
// {
// if (FileSize != InvalidSize) return Result.Success;
Result rc = FsClient.GetFileSize(out long fileSize, Handle);
if (rc.IsFailure()) return rc;
// Result rc = FsClient.GetFileSize(out long fileSize, Handle);
// if (rc.IsFailure()) return rc;
FileSize = fileSize;
return Result.Success;
}
// FileSize = fileSize;
// return Result.Success;
// }
protected override void Dispose(bool disposing)
{
if (CloseHandle)
{
FsClient.CloseFile(Handle);
}
}
}
}
// protected override void Dispose(bool disposing)
// {
// if (CloseHandle)
// {
// FsClient.CloseFile(Handle);
// }
// }
// }
//}

View File

@ -1,130 +0,0 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Fs.Fsa;
namespace LibHac.Fs
{
public class FileStorage2 : IStorage
{
protected const long SizeNotInitialized = -1;
private IFile BaseFile { get; set; }
protected long FileSize { get; set; }
public FileStorage2(IFile baseFile)
{
BaseFile = baseFile;
FileSize = SizeNotInitialized;
}
protected FileStorage2() { }
protected void SetFile(IFile file)
{
Debug.Assert(file != null);
Debug.Assert(BaseFile == null);
BaseFile = file;
}
private Result UpdateSize()
{
if (FileSize != SizeNotInitialized)
return Result.Success;
Result rc = BaseFile.GetSize(out long fileSize);
if (rc.IsFailure()) return rc;
FileSize = fileSize;
return Result.Success;
}
protected override Result DoRead(long offset, Span<byte> destination)
{
if (destination.Length == 0)
return Result.Success;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc;
if (!IsRangeValid(offset, destination.Length, FileSize))
return ResultFs.OutOfRange.Log();
return BaseFile.Read(out _, offset, destination, ReadOption.None);
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source)
{
if (source.Length == 0)
return Result.Success;
Result rc = UpdateSize();
if (rc.IsFailure()) return rc;
if (!IsRangeValid(offset, source.Length, FileSize))
return ResultFs.OutOfRange.Log();
return BaseFile.Write(offset, source, WriteOption.None);
}
protected override Result DoFlush()
{
return BaseFile.Flush();
}
protected override Result DoGetSize(out long size)
{
UnsafeHelpers.SkipParamInit(out size);
Result rc = UpdateSize();
if (rc.IsFailure()) return rc;
size = FileSize;
return Result.Success;
}
protected override Result DoSetSize(long size)
{
FileSize = SizeNotInitialized;
return BaseFile.SetSize(size);
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan<byte> inBuffer)
{
switch (operationId)
{
case OperationId.InvalidateCache:
case OperationId.QueryRange:
if (size == 0)
{
if (operationId == OperationId.QueryRange)
{
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
{
return ResultFs.InvalidSize.Log();
}
Unsafe.As<byte, QueryRangeInfo>(ref outBuffer[0]) = new QueryRangeInfo();
}
return Result.Success;
}
Result rc = UpdateSize();
if (rc.IsFailure()) return rc;
if (size < 0 || offset < 0)
{
return ResultFs.OutOfRange.Log();
}
return BaseFile.OperateRange(outBuffer, operationId, offset, size, inBuffer);
default:
return ResultFs.UnsupportedOperateRangeForFileStorage.Log();
}
}
}
}

View File

@ -1,41 +1,41 @@
using LibHac.Common;
using LibHac.Fs.Fsa;
//using LibHac.Common;
//using LibHac.Fs.Fsa;
namespace LibHac.Fs
{
public class FileStorageBasedFileSystem : FileStorage2
{
private ReferenceCountedDisposable<IFileSystem> _baseFileSystem;
private UniqueRef<IFile> _baseFile;
//namespace LibHac.Fs
//{
// public class FileStorageBasedFileSystem : FileStorage2
// {
// private ReferenceCountedDisposable<IFileSystem> _baseFileSystem;
// private UniqueRef<IFile> _baseFile;
public FileStorageBasedFileSystem()
{
FileSize = SizeNotInitialized;
}
// public FileStorageBasedFileSystem()
// {
// FileSize = SizeNotInitialized;
// }
public Result Initialize(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, in Path path,
OpenMode mode)
{
using var baseFile = new UniqueRef<IFile>();
Result rc = baseFileSystem.Target.OpenFile(ref baseFile.Ref(), in path, mode);
if (rc.IsFailure()) return rc;
// public Result Initialize(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, in Path path,
// OpenMode mode)
// {
// using var baseFile = new UniqueRef<IFile>();
// Result rc = baseFileSystem.Get.OpenFile(ref baseFile.Ref(), in path, mode);
// if (rc.IsFailure()) return rc;
SetFile(baseFile.Get);
_baseFileSystem = Shared.Move(ref baseFileSystem);
_baseFile.Set(ref _baseFile.Ref());
// SetFile(baseFile.Get);
// _baseFileSystem = Shared.Move(ref baseFileSystem);
// _baseFile.Set(ref _baseFile.Ref());
return Result.Success;
}
// return Result.Success;
// }
protected override void Dispose(bool disposing)
{
if (disposing)
{
_baseFile.Destroy();
_baseFileSystem?.Dispose();
}
// protected override void Dispose(bool disposing)
// {
// if (disposing)
// {
// _baseFile.Destroy();
// _baseFileSystem?.Dispose();
// }
base.Dispose(disposing);
}
}
}
// base.Dispose(disposing);
// }
// }
//}

View File

@ -19,12 +19,12 @@ namespace LibHac.Fs.Impl
private const string InvalidFsEntryObjectMessage = "Invalid file or directory object.";
private MountName _mountName;
private IFileSystem _fileSystem;
private UniqueRef<IFileSystem> _fileSystem;
private LinkedList<FileAccessor> _openFiles;
private LinkedList<DirectoryAccessor> _openDirectories;
private SdkMutexType _openListLock;
private ICommonMountNameGenerator _mountNameGenerator;
private ISaveDataAttributeGetter _saveDataAttributeGetter;
private UniqueRef<ICommonMountNameGenerator> _mountNameGenerator;
private UniqueRef<ISaveDataAttributeGetter> _saveDataAttributeGetter;
private bool _isAccessLogEnabled;
private bool _isDataCacheAttachable;
private bool _isPathCacheAttachable;
@ -36,17 +36,17 @@ namespace LibHac.Fs.Impl
internal HorizonClient Hos { get; }
public FileSystemAccessor(HorizonClient hosClient, U8Span name, IMultiCommitTarget multiCommitTarget,
IFileSystem fileSystem, ICommonMountNameGenerator mountNameGenerator,
ISaveDataAttributeGetter saveAttributeGetter)
ref UniqueRef<IFileSystem> fileSystem, ref UniqueRef<ICommonMountNameGenerator> mountNameGenerator,
ref UniqueRef<ISaveDataAttributeGetter> saveAttributeGetter)
{
Hos = hosClient;
_fileSystem = fileSystem;
_fileSystem = new UniqueRef<IFileSystem>(ref fileSystem);
_openFiles = new LinkedList<FileAccessor>();
_openDirectories = new LinkedList<DirectoryAccessor>();
_openListLock.Initialize();
_mountNameGenerator = mountNameGenerator;
_saveDataAttributeGetter = saveAttributeGetter;
_mountNameGenerator = new UniqueRef<ICommonMountNameGenerator>(ref mountNameGenerator);
_saveDataAttributeGetter = new UniqueRef<ISaveDataAttributeGetter>(ref saveAttributeGetter);
_multiCommitTarget = multiCommitTarget;
if (name.IsEmpty())
@ -94,14 +94,9 @@ namespace LibHac.Fs.Impl
}
}
ISaveDataAttributeGetter saveDataAttributeGetter = Shared.Move(ref _saveDataAttributeGetter);
saveDataAttributeGetter?.Dispose();
ICommonMountNameGenerator mountNameGenerator = Shared.Move(ref _mountNameGenerator);
mountNameGenerator?.Dispose();
IFileSystem fileSystem = Shared.Move(ref _fileSystem);
fileSystem?.Dispose();
_saveDataAttributeGetter.Destroy();
_mountNameGenerator.Destroy();
_fileSystem.Destroy();
}
private static void Remove<T>(LinkedList<T> list, T item)
@ -132,7 +127,7 @@ namespace LibHac.Fs.Impl
}
public Optional<Ncm.DataId> GetDataId() => _dataId;
public void SetDataId(Ncm.DataId dataId) => _dataId.Set(dataId);
public void SetDataId(Optional<Ncm.DataId> dataId) => _dataId = dataId;
public Result SetUpPath(ref Path path, U8Span pathBuffer)
{
@ -177,7 +172,7 @@ namespace LibHac.Fs.Impl
}
else
{
rc = _fileSystem.CreateFile(in pathNormalized, size, option);
rc = _fileSystem.Get.CreateFile(in pathNormalized, size, option);
if (rc.IsFailure()) return rc;
}
@ -190,7 +185,7 @@ namespace LibHac.Fs.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
if (rc.IsFailure()) return rc;
rc = _fileSystem.DeleteFile(in pathNormalized);
rc = _fileSystem.Get.DeleteFile(in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -202,7 +197,7 @@ namespace LibHac.Fs.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
if (rc.IsFailure()) return rc;
rc = _fileSystem.CreateDirectory(in pathNormalized);
rc = _fileSystem.Get.CreateDirectory(in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -214,7 +209,7 @@ namespace LibHac.Fs.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
if (rc.IsFailure()) return rc;
rc = _fileSystem.CreateDirectory(in pathNormalized);
rc = _fileSystem.Get.CreateDirectory(in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -226,7 +221,7 @@ namespace LibHac.Fs.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
if (rc.IsFailure()) return rc;
rc = _fileSystem.DeleteDirectoryRecursively(in pathNormalized);
rc = _fileSystem.Get.DeleteDirectoryRecursively(in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -238,7 +233,7 @@ namespace LibHac.Fs.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
if (rc.IsFailure()) return rc;
rc = _fileSystem.CleanDirectoryRecursively(in pathNormalized);
rc = _fileSystem.Get.CleanDirectoryRecursively(in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -260,7 +255,7 @@ namespace LibHac.Fs.Impl
}
else
{
rc = _fileSystem.RenameFile(in currentPathNormalized, in newPathNormalized);
rc = _fileSystem.Get.RenameFile(in currentPathNormalized, in newPathNormalized);
if (rc.IsFailure()) return rc;
}
@ -283,7 +278,7 @@ namespace LibHac.Fs.Impl
}
else
{
rc = _fileSystem.RenameDirectory(in currentPathNormalized, in newPathNormalized);
rc = _fileSystem.Get.RenameDirectory(in currentPathNormalized, in newPathNormalized);
if (rc.IsFailure()) return rc;
}
return Result.Success;
@ -297,7 +292,7 @@ namespace LibHac.Fs.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
if (rc.IsFailure()) return rc;
rc = _fileSystem.GetEntryType(out entryType, in pathNormalized);
rc = _fileSystem.Get.GetEntryType(out entryType, in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -311,7 +306,7 @@ namespace LibHac.Fs.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
if (rc.IsFailure()) return rc;
rc = _fileSystem.GetFreeSpaceSize(out freeSpace, in pathNormalized);
rc = _fileSystem.Get.GetFreeSpaceSize(out freeSpace, in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -325,7 +320,7 @@ namespace LibHac.Fs.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
if (rc.IsFailure()) return rc;
rc = _fileSystem.GetTotalSpaceSize(out totalSpace, in pathNormalized);
rc = _fileSystem.Get.GetTotalSpaceSize(out totalSpace, in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -338,7 +333,7 @@ namespace LibHac.Fs.Impl
if (rc.IsFailure()) return rc;
using var file = new UniqueRef<IFile>();
rc = _fileSystem.OpenFile(ref file.Ref(), in pathNormalized, mode);
rc = _fileSystem.Get.OpenFile(ref file.Ref(), in pathNormalized, mode);
if (rc.IsFailure()) return rc;
var accessor = new FileAccessor(Hos, ref file.Ref(), this, mode);
@ -371,7 +366,7 @@ namespace LibHac.Fs.Impl
if (rc.IsFailure()) return rc;
using var directory = new UniqueRef<IDirectory>();
rc = _fileSystem.OpenDirectory(ref directory.Ref(), in pathNormalized, mode);
rc = _fileSystem.Get.OpenDirectory(ref directory.Ref(), in pathNormalized, mode);
if (rc.IsFailure()) return rc;
var accessor = new DirectoryAccessor(ref directory.Ref(), this);
@ -408,7 +403,7 @@ namespace LibHac.Fs.Impl
return ResultFs.WriteModeFileNotClosed.Log();
}
return _fileSystem.Commit();
return _fileSystem.Get.Commit();
}
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, U8Span path)
@ -419,7 +414,7 @@ namespace LibHac.Fs.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
if (rc.IsFailure()) return rc;
rc = _fileSystem.GetFileTimeStampRaw(out timeStamp, in pathNormalized);
rc = _fileSystem.Get.GetFileTimeStampRaw(out timeStamp, in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -431,7 +426,7 @@ namespace LibHac.Fs.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), path);
if (rc.IsFailure()) return rc;
rc = _fileSystem.QueryEntry(outBuffer, inBuffer, queryId, in pathNormalized);
rc = _fileSystem.Get.QueryEntry(outBuffer, inBuffer, queryId, in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -444,44 +439,51 @@ namespace LibHac.Fs.Impl
public Result GetCommonMountName(Span<byte> nameBuffer)
{
if (_mountNameGenerator is null)
if (!_mountNameGenerator.HasValue)
return ResultFs.PreconditionViolation.Log();
return _mountNameGenerator.GenerateCommonMountName(nameBuffer);
return _mountNameGenerator.Get.GenerateCommonMountName(nameBuffer);
}
public Result GetSaveDataAttribute(out SaveDataAttribute attribute)
{
UnsafeHelpers.SkipParamInit(out attribute);
if (_saveDataAttributeGetter is null)
if (!_saveDataAttributeGetter.HasValue)
return ResultFs.PreconditionViolation.Log();
Result rc = _saveDataAttributeGetter.GetSaveDataAttribute(out attribute);
Result rc = _saveDataAttributeGetter.Get.GetSaveDataAttribute(out attribute);
if (rc.IsFailure()) return rc;
return Result.Success;
}
public ReferenceCountedDisposable<IFileSystemSf> GetMultiCommitTarget()
public SharedRef<IFileSystemSf> GetMultiCommitTarget()
{
return _multiCommitTarget?.GetMultiCommitTarget();
if (_multiCommitTarget is not null)
{
return _multiCommitTarget.GetMultiCommitTarget();
}
else
{
return new SharedRef<IFileSystemSf>();
}
}
public void PurgeFileDataCache(FileDataCacheAccessor cacheAccessor)
{
cacheAccessor.Purge(_fileSystem);
cacheAccessor.Purge(_fileSystem.Get);
}
internal void NotifyCloseFile(FileAccessor file)
{
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _openListLock);
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _openListLock);
Remove(_openFiles, file);
}
internal void NotifyCloseDirectory(DirectoryAccessor directory)
{
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _openListLock);
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _openListLock);
Remove(_openDirectories, directory);
}

View File

@ -1,9 +1,10 @@
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
using LibHac.Common;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
namespace LibHac.Fs.Fsa
{
public interface IMultiCommitTarget
{
ReferenceCountedDisposable<IFileSystemSf> GetMultiCommitTarget();
SharedRef<IFileSystemSf> GetMultiCommitTarget();
}
}

View File

@ -1,40 +1,77 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Ncm;
using LibHac.Os;
using LibHac.Util;
// ReSharper disable once CheckNamespace
namespace LibHac.Fs.Impl
{
internal class MountTable
/// <summary>
/// Holds a list of <see cref="FileSystemAccessor"/>s that are indexed by their name.
/// These may be retrieved or removed using their name as a key.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
internal class MountTable : IDisposable
{
private LinkedList<FileSystemAccessor> _fileSystemList;
private SdkMutexType _mutex;
// LibHac addition
private FileSystemClient _fsClient;
public MountTable(FileSystemClient fsClient)
{
_fileSystemList = new LinkedList<FileSystemAccessor>();
_mutex = new SdkMutexType();
_mutex.Initialize();
_fsClient = fsClient;
}
public Result Mount(FileSystemAccessor fileSystem)
// Note: The original class does not have a destructor
public void Dispose()
{
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _mutex);
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
if (!CanAcceptMountName(fileSystem.GetName()))
LinkedListNode<FileSystemAccessor> currentEntry = _fileSystemList.First;
while (currentEntry is not null)
{
FileSystemAccessor accessor = currentEntry.Value;
_fileSystemList.Remove(currentEntry);
accessor?.Dispose();
currentEntry = _fileSystemList.First;
}
_fileSystemList = null;
_fsClient = null;
}
private static bool Matches(FileSystemAccessor accessor, U8Span name)
{
return StringUtils.Compare(accessor.GetName(), name, Unsafe.SizeOf<MountName>()) == 0;
}
public Result Mount(ref UniqueRef<FileSystemAccessor> fileSystem)
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
if (!CanAcceptMountName(fileSystem.Get.GetName()))
return ResultFs.MountNameAlreadyExists.Log();
_fileSystemList.AddLast(fileSystem);
_fileSystemList.AddLast(fileSystem.Release());
return Result.Success;
}
public Result Find(out FileSystemAccessor accessor, U8Span name)
{
UnsafeHelpers.SkipParamInit(out accessor);
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _mutex);
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
for (LinkedListNode<FileSystemAccessor> currentNode = _fileSystemList.First;
currentNode is not null;
@ -50,23 +87,28 @@ namespace LibHac.Fs.Impl
public void Unmount(U8Span name)
{
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _mutex);
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
LinkedListNode<FileSystemAccessor> currentNode;
for (currentNode = _fileSystemList.First; currentNode is not null; currentNode = currentNode.Next)
for (LinkedListNode<FileSystemAccessor> currentNode = _fileSystemList.First;
currentNode is not null;
currentNode = currentNode.Next)
{
if (Matches(currentNode.Value, name))
break;
{
_fileSystemList.Remove(currentNode);
currentNode.Value.Dispose();
return;
}
}
if (currentNode is null)
Abort.DoAbort(ResultFs.NotMounted.Log(), $"{name.ToString()} is not mounted.");
_fsClient.Impl.LogErrorMessage(ResultFs.NotMounted.Value,
"Error: Unmount failed because the mount name was not mounted. The mount name is \"{0}\".\n",
name.ToString());
_fileSystemList.Remove(currentNode);
currentNode.Value.Dispose();
Abort.DoAbortUnlessSuccess(ResultFs.NotMounted.Value);
}
public bool CanAcceptMountName(U8Span name)
private bool CanAcceptMountName(U8Span name)
{
Assert.SdkAssert(_mutex.IsLockedByCurrentThread());
@ -81,9 +123,44 @@ namespace LibHac.Fs.Impl
return true;
}
private static bool Matches(FileSystemAccessor accessor, U8Span name)
public int GetDataIdCount()
{
return StringUtils.Compare(accessor.GetName(), name, Unsafe.SizeOf<MountName>()) == 0;
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
int count = 0;
for (LinkedListNode<FileSystemAccessor> currentNode = _fileSystemList.First;
currentNode is not null;
currentNode = currentNode.Next)
{
if (currentNode.Value.GetDataId().HasValue)
count++;
}
return count;
}
public Result ListDataId(out int dataIdCount, Span<DataId> dataIdBuffer)
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
int count = 0;
for (LinkedListNode<FileSystemAccessor> currentNode = _fileSystemList.First;
currentNode is not null && count < dataIdBuffer.Length;
currentNode = currentNode.Next)
{
Optional<DataId> dataId = currentNode.Value.GetDataId();
if (dataId.HasValue)
{
dataIdBuffer[count] = dataId.Value;
count++;
}
}
dataIdCount = count;
return Result.Success;
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using LibHac.Common;
using LibHac.Fs.Impl;
using LibHac.Util;
namespace LibHac.Fs.Fsa
{
@ -14,42 +15,94 @@ namespace LibHac.Fs.Fsa
Result GetSaveDataAttribute(out SaveDataAttribute attribute);
}
/// <summary>
/// Contains functions for registering and unregistering mounted <see cref="IFileSystem"/>s.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
public static class Registrar
{
public static Result Register(this FileSystemClient fs, U8Span name, IFileSystem fileSystem)
public static Result Register(this FileSystemClient fs, U8Span name, ref UniqueRef<IFileSystem> fileSystem)
{
var accessor = new FileSystemAccessor(fs.Hos, name, null, fileSystem, null, null);
fs.Impl.Register(accessor);
using var attributeGetter = new UniqueRef<ISaveDataAttributeGetter>();
using var mountNameGenerator = new UniqueRef<ICommonMountNameGenerator>();
using var accessor = new UniqueRef<FileSystemAccessor>(new FileSystemAccessor(fs.Hos, name, null,
ref fileSystem, ref mountNameGenerator.Ref(), ref attributeGetter.Ref()));
Result rc = fs.Impl.Register(ref accessor.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result Register(this FileSystemClient fs, U8Span name, IFileSystem fileSystem,
ICommonMountNameGenerator mountNameGenerator)
public static Result Register(this FileSystemClient fs, U8Span name, ref UniqueRef<IFileSystem> fileSystem,
ref UniqueRef<ICommonMountNameGenerator> mountNameGenerator)
{
var accessor = new FileSystemAccessor(fs.Hos, name, null, fileSystem, mountNameGenerator, null);
fs.Impl.Register(accessor);
using var attributeGetter = new UniqueRef<ISaveDataAttributeGetter>();
using var accessor = new UniqueRef<FileSystemAccessor>(new FileSystemAccessor(fs.Hos, name, null,
ref fileSystem, ref mountNameGenerator, ref attributeGetter.Ref()));
Result rc = fs.Impl.Register(ref accessor.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result Register(this FileSystemClient fs, U8Span name, IMultiCommitTarget multiCommitTarget,
IFileSystem fileSystem, ICommonMountNameGenerator mountNameGenerator, bool useDataCache, bool usePathCache)
ref UniqueRef<IFileSystem> fileSystem, ref UniqueRef<ICommonMountNameGenerator> mountNameGenerator,
bool useDataCache, bool usePathCache)
{
return fs.Register(name, multiCommitTarget, fileSystem, mountNameGenerator, null, useDataCache,
usePathCache);
using var attributeGetter = new UniqueRef<ISaveDataAttributeGetter>();
Result rc = Register(fs, name, multiCommitTarget, ref fileSystem, ref mountNameGenerator,
ref attributeGetter.Ref(), useDataCache, usePathCache, new Optional<Ncm.DataId>());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result Register(this FileSystemClient fs, U8Span name, IMultiCommitTarget multiCommitTarget,
IFileSystem fileSystem, ICommonMountNameGenerator mountNameGenerator,
ISaveDataAttributeGetter saveAttributeGetter, bool useDataCache, bool usePathCache)
ref UniqueRef<IFileSystem> fileSystem, ref UniqueRef<ICommonMountNameGenerator> mountNameGenerator,
bool useDataCache, bool usePathCache, Optional<Ncm.DataId> dataId)
{
var accessor = new FileSystemAccessor(fs.Hos, name, multiCommitTarget, fileSystem, mountNameGenerator,
saveAttributeGetter);
using var attributeGetter = new UniqueRef<ISaveDataAttributeGetter>();
accessor.SetFileDataCacheAttachable(useDataCache);
accessor.SetPathBasedFileDataCacheAttachable(usePathCache);
fs.Impl.Register(accessor);
Result rc = Register(fs, name, multiCommitTarget, ref fileSystem, ref mountNameGenerator,
ref attributeGetter.Ref(), useDataCache, usePathCache, dataId);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result Register(this FileSystemClient fs, U8Span name, IMultiCommitTarget multiCommitTarget,
ref UniqueRef<IFileSystem> fileSystem, ref UniqueRef<ICommonMountNameGenerator> mountNameGenerator,
ref UniqueRef<ISaveDataAttributeGetter> saveAttributeGetter, bool useDataCache, bool usePathCache)
{
Result rc = Register(fs, name, multiCommitTarget, ref fileSystem, ref mountNameGenerator,
ref saveAttributeGetter, useDataCache, usePathCache, new Optional<Ncm.DataId>());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result Register(this FileSystemClient fs, U8Span name, IMultiCommitTarget multiCommitTarget,
ref UniqueRef<IFileSystem> fileSystem, ref UniqueRef<ICommonMountNameGenerator> mountNameGenerator,
ref UniqueRef<ISaveDataAttributeGetter> saveAttributeGetter, bool useDataCache, bool usePathCache,
Optional<Ncm.DataId> dataId)
{
using var accessor = new UniqueRef<FileSystemAccessor>(new FileSystemAccessor(fs.Hos, name,
multiCommitTarget, ref fileSystem, ref mountNameGenerator, ref saveAttributeGetter));
if (!accessor.HasValue)
return ResultFs.AllocationMemoryFailedInRegisterB.Log();
accessor.Get.SetFileDataCacheAttachable(useDataCache);
accessor.Get.SetPathBasedFileDataCacheAttachable(usePathCache);
accessor.Get.SetDataId(dataId);
Result rc = fs.Impl.Register(ref accessor.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
@ -60,4 +113,3 @@ namespace LibHac.Fs.Fsa
}
}
}

View File

@ -638,38 +638,29 @@ namespace LibHac.Fs.Fsa
if (mountNames.Length == 0)
return Result.Success;
ReferenceCountedDisposable<IMultiCommitManager> commitManager = null;
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var commitManager = new SharedRef<IMultiCommitManager>();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.OpenMultiCommitManager(out commitManager);
Result rc = fileSystemProxy.Get.OpenMultiCommitManager(ref commitManager.Ref());
if (rc.IsFailure()) return rc;
for (int i = 0; i < mountNames.Length; i++)
{
rc = fs.Impl.Find(out FileSystemAccessor accessor, mountNames[i]);
if (rc.IsFailure()) return rc;
for (int i = 0; i < mountNames.Length; i++)
{
rc = fs.Impl.Find(out FileSystemAccessor accessor, mountNames[i]);
if (rc.IsFailure()) return rc;
using SharedRef<IFileSystemSf> fileSystem = accessor.GetMultiCommitTarget();
if (!fileSystem.HasValue)
return ResultFs.UnsupportedCommitTarget.Log();
fileSystem = accessor.GetMultiCommitTarget();
if (fileSystem is null)
return ResultFs.UnsupportedCommitTarget.Log();
rc = commitManager.Target.Add(fileSystem);
if (rc.IsFailure()) return rc;
}
rc = commitManager.Target.Commit();
rc = commitManager.Get.Add(ref fileSystem.Ref());
if (rc.IsFailure()) return rc;
}
return Result.Success;
}
finally
{
commitManager?.Dispose();
fileSystem?.Dispose();
}
rc = commitManager.Get.Commit();
if (rc.IsFailure()) return rc;
return Result.Success;
}
public static Result Commit(this FileSystemClient fs, U8Span mountName, CommitOption option)

View File

@ -1,5 +1,7 @@
using LibHac.Common;
using System;
using LibHac.Common;
using LibHac.Fs.Impl;
using LibHac.Ncm;
namespace LibHac.Fs.Fsa
{
@ -13,11 +15,15 @@ namespace LibHac.Fs.Fsa
}
}
/// <summary>
/// Contains functions for adding, removing and retrieving <see cref="FileSystemAccessor"/>s from the mount table.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
internal static class UserMountTable
{
public static Result Register(this FileSystemClientImpl fs, FileSystemAccessor fileSystem)
public static Result Register(this FileSystemClientImpl fs, ref UniqueRef<FileSystemAccessor> fileSystem)
{
return fs.Globals.UserMountTable.MountTable.Mount(fileSystem);
return fs.Globals.UserMountTable.MountTable.Mount(ref fileSystem);
}
public static Result Find(this FileSystemClientImpl fs, out FileSystemAccessor fileSystem, U8Span name)
@ -29,5 +35,16 @@ namespace LibHac.Fs.Fsa
{
fs.Globals.UserMountTable.MountTable.Unmount(name);
}
public static int GetMountedDataIdCount(this FileSystemClientImpl fs)
{
return fs.Globals.UserMountTable.MountTable.GetDataIdCount();
}
public static Result ListMountedDataId(this FileSystemClientImpl fs, out int dataIdCount,
Span<DataId> dataIdBuffer)
{
return fs.Globals.UserMountTable.MountTable.ListDataId(out dataIdCount, dataIdBuffer);
}
}
}

View File

@ -1,7 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using LibHac.Common;
namespace LibHac.Fs
{
@ -16,10 +14,6 @@ namespace LibHac.Fs
/// </remarks>
public abstract class IStorage : IDisposable
{
// 0 = not disposed; 1 = disposed
private int _disposedState;
private bool IsDisposed => _disposedState != 0;
/// <summary>
/// Reads a sequence of bytes from the current <see cref="IStorage"/>.
/// </summary>
@ -30,9 +24,6 @@ namespace LibHac.Fs
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Result Read(long offset, Span<byte> destination)
{
if (IsDisposed)
return ResultFs.PreconditionViolation.Log();
return DoRead(offset, destination);
}
@ -45,9 +36,6 @@ namespace LibHac.Fs
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Result Write(long offset, ReadOnlySpan<byte> source)
{
if (IsDisposed)
return ResultFs.PreconditionViolation.Log();
return DoWrite(offset, source);
}
@ -58,9 +46,6 @@ namespace LibHac.Fs
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Result Flush()
{
if (IsDisposed)
return ResultFs.PreconditionViolation.Log();
return DoFlush();
}
@ -71,9 +56,6 @@ namespace LibHac.Fs
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Result SetSize(long size)
{
if (IsDisposed)
return ResultFs.PreconditionViolation.Log();
return DoSetSize(size);
}
@ -85,11 +67,6 @@ namespace LibHac.Fs
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Result GetSize(out long size)
{
UnsafeHelpers.SkipParamInit(out size);
if (IsDisposed)
return ResultFs.PreconditionViolation.Log();
return DoGetSize(out size);
}
@ -106,14 +83,11 @@ namespace LibHac.Fs
public Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
ReadOnlySpan<byte> inBuffer)
{
if (IsDisposed)
return ResultFs.PreconditionViolation.Log();
return DoOperateRange(outBuffer, operationId, offset, size, inBuffer);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsRangeValid(long offset, long size, long totalSize)
public static bool CheckAccessRange(long offset, long size, long totalSize)
{
return offset >= 0 &&
size >= 0 &&
@ -122,13 +96,14 @@ namespace LibHac.Fs
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsOffsetAndSizeValid(long offset, long size)
public static bool CheckOffsetAndSize(long offset, long size)
{
return offset >= 0 &&
size >= 0 &&
offset <= offset + size;
}
// Todo: Remove Do* methods
protected abstract Result DoRead(long offset, Span<byte> destination);
protected abstract Result DoWrite(long offset, ReadOnlySpan<byte> source);
protected abstract Result DoFlush();
@ -141,16 +116,6 @@ namespace LibHac.Fs
return ResultFs.NotImplemented.Log();
}
public void Dispose()
{
// Make sure Dispose is only called once
if (Interlocked.CompareExchange(ref _disposedState, 1, 0) == 0)
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
protected virtual void Dispose(bool disposing) { }
public virtual void Dispose() { }
}
}

View File

@ -10,49 +10,39 @@ namespace LibHac.Fs.Impl
/// 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.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
internal class StorageServiceObjectAdapter : IStorage
{
private ReferenceCountedDisposable<IStorageSf> BaseStorage { get; }
private SharedRef<IStorageSf> _baseStorage;
public StorageServiceObjectAdapter(ReferenceCountedDisposable<IStorageSf> baseStorage)
public StorageServiceObjectAdapter(ref SharedRef<IStorageSf> baseStorage)
{
BaseStorage = baseStorage.AddReference();
}
protected StorageServiceObjectAdapter(ref ReferenceCountedDisposable<IStorageSf> baseStorage)
{
BaseStorage = Shared.Move(ref baseStorage);
}
public static ReferenceCountedDisposable<IStorage> CreateShared(
ref ReferenceCountedDisposable<IStorageSf> baseStorage)
{
return new ReferenceCountedDisposable<IStorage>(new StorageServiceObjectAdapter(ref baseStorage));
_baseStorage = SharedRef<IStorageSf>.CreateMove(ref baseStorage);
}
protected override Result DoRead(long offset, Span<byte> destination)
{
return BaseStorage.Target.Read(offset, new OutBuffer(destination), destination.Length);
return _baseStorage.Get.Read(offset, new OutBuffer(destination), destination.Length);
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source)
{
return BaseStorage.Target.Write(offset, new InBuffer(source), source.Length);
return _baseStorage.Get.Write(offset, new InBuffer(source), source.Length);
}
protected override Result DoFlush()
{
return BaseStorage.Target.Flush();
return _baseStorage.Get.Flush();
}
protected override Result DoSetSize(long size)
{
return BaseStorage.Target.SetSize(size);
return _baseStorage.Get.SetSize(size);
}
protected override Result DoGetSize(out long size)
{
return BaseStorage.Target.GetSize(out size);
return _baseStorage.Get.GetSize(out size);
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
@ -61,27 +51,23 @@ namespace LibHac.Fs.Impl
switch (operationId)
{
case OperationId.InvalidateCache:
return BaseStorage.Target.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size);
return _baseStorage.Get.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size);
case OperationId.QueryRange:
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
return ResultFs.InvalidSize.Log();
ref QueryRangeInfo info = ref SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer);
return BaseStorage.Target.OperateRange(out info, (int)OperationId.QueryRange, offset, size);
return _baseStorage.Get.OperateRange(out info, (int)OperationId.QueryRange, offset, size);
default:
return ResultFs.UnsupportedOperateRangeForFileServiceObjectAdapter.Log();
return ResultFs.UnsupportedOperateRangeForStorageServiceObjectAdapter.Log();
}
}
protected override void Dispose(bool disposing)
public override void Dispose()
{
if (disposing)
{
BaseStorage?.Dispose();
}
base.Dispose(disposing);
_baseStorage.Destroy();
base.Dispose();
}
}
}

View File

@ -16,7 +16,7 @@ namespace LibHac.Fs
if (destination.Length == 0)
return Result.Success;
if (!IsRangeValid(offset, destination.Length, StorageBuffer.Length))
if (!CheckAccessRange(offset, destination.Length, StorageBuffer.Length))
return ResultFs.OutOfRange.Log();
StorageBuffer.AsSpan((int)offset, destination.Length).CopyTo(destination);
@ -29,7 +29,7 @@ namespace LibHac.Fs
if (source.Length == 0)
return Result.Success;
if (!IsRangeValid(offset, source.Length, StorageBuffer.Length))
if (!CheckAccessRange(offset, source.Length, StorageBuffer.Length))
return ResultFs.OutOfRange.Log();
source.CopyTo(StorageBuffer.AsSpan((int)offset));

View File

@ -6,10 +6,15 @@ using LibHac.Fs.Impl;
using LibHac.FsSrv.Sf;
using LibHac.Os;
using static LibHac.Fs.Impl.AccessLogStrings;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
namespace LibHac.Fs.Shim
{
/// <summary>
/// Contains functions for mounting application packages.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
[SkipLocalsInit]
public static class Application
{
@ -35,6 +40,7 @@ namespace LibHac.Fs.Shim
{
rc = Mount(fs, mountName, path);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -48,25 +54,26 @@ namespace LibHac.Fs.Shim
Result rc = fs.Impl.CheckMountName(mountName);
if (rc.IsFailure()) return rc;
rc = FspPath.FromSpan(out FspPath sfPath, path);
rc = PathUtility.ConvertToFspPath(out FspPath sfPath, path);
if (rc.IsFailure()) return rc;
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var fileSystem = new SharedRef<IFileSystemSf>();
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
{
rc = fsProxy.Target.OpenFileSystemWithId(out fileSystem, in sfPath, Ncm.ProgramId.InvalidId.Value,
FileSystemProxyType.Package);
if (rc.IsFailure()) return rc;
rc = fileSystemProxy.Get.OpenFileSystemWithId(ref fileSystem.Ref(), in sfPath,
Ncm.ProgramId.InvalidId.Value, FileSystemProxyType.Package);
if (rc.IsFailure()) return rc;
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
return fs.Register(mountName, fileSystemAdapter);
}
finally
{
fileSystem?.Dispose();
}
using var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInApplicationA.Log();
rc = fs.Register(mountName, ref fileSystemAdapter.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
}

View File

@ -6,10 +6,15 @@ using LibHac.Fs.Impl;
using LibHac.FsSrv.Sf;
using LibHac.Os;
using static LibHac.Fs.Impl.AccessLogStrings;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
namespace LibHac.Fs.Shim
{
/// <summary>
/// Contains functions for mounting BCAT save data.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
[SkipLocalsInit]
public static class BcatSaveData
{
@ -36,6 +41,7 @@ namespace LibHac.Fs.Shim
{
rc = Mount(fs, mountName, applicationId);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -49,25 +55,27 @@ namespace LibHac.Fs.Shim
Result rc = fs.Impl.CheckMountName(mountName);
if (rc.IsFailure()) return rc;
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, applicationId, SaveDataType.Bcat,
Fs.SaveData.InvalidUserId, 0);
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
{
rc = fsProxy.Target.OpenSaveDataFileSystem(out fileSystem, SaveDataSpaceId.User, in attribute);
if (rc.IsFailure()) return rc;
using var fileSystem = new SharedRef<IFileSystemSf>();
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
return fs.Register(mountName, fileSystemAdapter);
}
finally
{
fileSystem?.Dispose();
}
rc = fileSystemProxy.Get.OpenSaveDataFileSystem(ref fileSystem.Ref(), SaveDataSpaceId.User, in attribute);
if (rc.IsFailure()) return rc;
using var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInBcatSaveDataA.Log();
rc = fs.Register(mountName, ref fileSystemAdapter.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
}

View File

@ -1,49 +1,53 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs.Fsa;
using LibHac.Fs.Impl;
using LibHac.FsSrv.Sf;
using LibHac.FsSystem;
using LibHac.Os;
using LibHac.FsSystem;
using LibHac.Util;
using static LibHac.Fs.Impl.CommonMountNames;
using static LibHac.Fs.Impl.AccessLogStrings;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
namespace LibHac.Fs.Shim
{
/// <summary>
/// Contains functions for mounting built-in-storage partition file systems
/// and opening the raw partitions as <see cref="IStorage"/>s.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
[SkipLocalsInit]
public static class Bis
{
private class BisCommonMountNameGenerator : ICommonMountNameGenerator
{
private BisPartitionId PartitionId { get; }
private BisPartitionId _partitionId;
public BisCommonMountNameGenerator(BisPartitionId partitionId)
{
PartitionId = partitionId;
_partitionId = partitionId;
}
public void Dispose() { }
public Result GenerateCommonMountName(Span<byte> nameBuffer)
{
ReadOnlySpan<byte> mountName = GetBisMountName(PartitionId);
ReadOnlySpan<byte> mountName = GetBisMountName(_partitionId);
// Add 2 for the mount name separator and null terminator
// ReSharper disable once RedundantAssignment
int requiredNameBufferSize = StringUtils.GetLength(mountName, PathTools.MountNameLengthMax) + 2;
Debug.Assert(nameBuffer.Length >= requiredNameBufferSize);
Assert.SdkRequiresGreaterEqual(nameBuffer.Length, requiredNameBufferSize);
var sb = new U8StringBuilder(nameBuffer);
sb.Append(mountName).Append(StringTraits.DriveSeparator);
Debug.Assert(sb.Length == requiredNameBufferSize - 1);
Assert.SdkEqual(sb.Length, requiredNameBufferSize - 1);
return Result.Success;
}
@ -86,28 +90,34 @@ namespace LibHac.Fs.Shim
static Result Mount(FileSystemClientImpl fs, U8Span mountName, BisPartitionId partitionId)
{
Result rc = fs.CheckMountNameAcceptingReservedMountName(mountName);
if (rc.IsFailure()) return rc;
if (rc.IsFailure()) return rc.Miss();
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
// Nintendo doesn't use the provided rootPath
FspPath.CreateEmpty(out FspPath sfPath);
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
{
rc = fsProxy.Target.OpenBisFileSystem(out fileSystem, in sfPath, partitionId);
if (rc.IsFailure()) return rc;
using var fileSystem = new SharedRef<IFileSystemSf>();
var nameGenerator = new BisCommonMountNameGenerator(partitionId);
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
rc = fileSystemProxy.Get.OpenBisFileSystem(ref fileSystem.Ref(), in sfPath, partitionId);
if (rc.IsFailure()) return rc.Miss();
return fs.Fs.Register(mountName, fileSystemAdapter, nameGenerator);
}
finally
{
fileSystem?.Dispose();
}
using var mountNameGenerator =
new UniqueRef<ICommonMountNameGenerator>(new BisCommonMountNameGenerator(partitionId));
if (!mountNameGenerator.HasValue)
return ResultFs.AllocationMemoryFailedInBisA.Log();
using var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInBisB.Log();
rc = fs.Fs.Register(mountName, ref fileSystemAdapter.Ref(), ref mountNameGenerator.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
@ -155,75 +165,34 @@ namespace LibHac.Fs.Shim
return ReadOnlySpan<byte>.Empty;
}
public static Result SetBisRootForHost(this FileSystemClient fs, BisPartitionId partitionId, U8Span rootPath)
{
Unsafe.SkipInit(out FsPath pathBuffer);
Result rc;
int pathLen = StringUtils.GetLength(rootPath, PathTools.MaxPathLength + 1);
if (pathLen > PathTools.MaxPathLength)
{
fs.Impl.LogResultErrorMessage(ResultFs.TooLongPath.Value);
return ResultFs.TooLongPath.Log();
}
if (pathLen > 0)
{
byte endingSeparator = rootPath[pathLen - 1] == StringTraits.DirectorySeparator
? StringTraits.NullTerminator
: StringTraits.DirectorySeparator;
var sb = new U8StringBuilder(pathBuffer.Str);
sb.Append(rootPath).Append(endingSeparator);
if (sb.Overflowed)
return ResultFs.TooLongPath.Log();
}
else
{
pathBuffer.Str[0] = StringTraits.NullTerminator;
}
rc = PathUtility.ConvertToFspPath(out FspPath sfPath, pathBuffer.Str);
if (rc.IsFailure()) return rc;
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
rc = fsProxy.Target.SetBisRootForHost(partitionId, in sfPath);
fs.Impl.LogResultErrorMessage(rc);
return rc;
}
public static Result OpenBisPartition(this FileSystemClient fs, out IStorage partitionStorage,
public static Result OpenBisPartition(this FileSystemClient fs, ref UniqueRef<IStorage> outPartitionStorage,
BisPartitionId partitionId)
{
UnsafeHelpers.SkipParamInit(out partitionStorage);
using var storage = new SharedRef<IStorageSf>();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
ReferenceCountedDisposable<IStorageSf> storage = null;
try
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.OpenBisStorage(out storage, partitionId);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
Result rc = fileSystemProxy.Get.OpenBisStorage(ref storage.Ref(), partitionId);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
var storageAdapter = new StorageServiceObjectAdapter(storage);
var storageAdapter = new UniqueRef<IStorage>(new StorageServiceObjectAdapter(ref storage.Ref()));
partitionStorage = storageAdapter;
return Result.Success;
}
finally
{
storage?.Dispose();
}
if (!storageAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInBisC.Log();
outPartitionStorage.Set(ref storageAdapter.Ref());
return Result.Success;
}
public static Result InvalidateBisCache(this FileSystemClient fs)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.InvalidateBisCache();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fileSystemProxy.Get.InvalidateBisCache();
fs.Impl.AbortIfNeeded(rc);
return rc;
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
}

View File

@ -7,10 +7,15 @@ using LibHac.FsSrv.Sf;
using LibHac.Ncm;
using LibHac.Os;
using static LibHac.Fs.Impl.AccessLogStrings;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
namespace LibHac.Fs.Shim
{
/// <summary>
/// Contains functions for mounting code file systems.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
[SkipLocalsInit]
public static class Code
{
@ -37,6 +42,7 @@ namespace LibHac.Fs.Shim
{
rc = Mount(fs, out verificationData, mountName, path, programId);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -56,25 +62,30 @@ namespace LibHac.Fs.Shim
if (path.IsNull())
return ResultFs.NullptrArgument.Log();
rc = FspPath.FromSpan(out FspPath fsPath, path);
rc = PathUtility.ConvertToFspPath(out FspPath fsPath, path);
if (rc.IsFailure()) return rc;
using ReferenceCountedDisposable<IFileSystemProxyForLoader> fsProxy =
using SharedRef<IFileSystemProxyForLoader> fileSystemProxy =
fs.Impl.GetFileSystemProxyForLoaderServiceObject();
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
{
rc = fsProxy.Target.OpenCodeFileSystem(out fileSystem, out verificationData, in fsPath, programId);
if (rc.IsFailure()) return rc;
// SetCurrentProcess
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
return fs.Register(mountName, fileSystemAdapter);
}
finally
{
fileSystem?.Dispose();
}
using var fileSystem = new SharedRef<IFileSystemSf>();
rc = fileSystemProxy.Get.OpenCodeFileSystem(ref fileSystem.Ref(), out verificationData, in fsPath,
programId);
if (rc.IsFailure()) return rc;
var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInCodeA.Log();
rc = fs.Register(mountName, ref fileSystemAdapter.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
}

View File

@ -8,10 +8,15 @@ using LibHac.FsSrv.Sf;
using LibHac.Ncm;
using LibHac.Os;
using static LibHac.Fs.Impl.AccessLogStrings;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
namespace LibHac.Fs.Shim
{
/// <summary>
/// Contains functions for mounting content file systems.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
[SkipLocalsInit]
public static class Content
{
@ -40,24 +45,25 @@ namespace LibHac.Fs.Shim
if (path.IsNull())
return ResultFs.NullptrArgument.Log();
rc = FspPath.FromSpan(out FspPath fsPath, path);
rc = PathUtility.ConvertToFspPath(out FspPath fsPath, path);
if (rc.IsFailure()) return rc;
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var fileSystem = new SharedRef<IFileSystemSf>();
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
{
rc = fsProxy.Target.OpenFileSystemWithId(out fileSystem, in fsPath, id, fsType);
if (rc.IsFailure()) return rc;
rc = fileSystemProxy.Get.OpenFileSystemWithId(ref fileSystem.Ref(), in fsPath, id, fsType);
if (rc.IsFailure()) return rc;
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
return fs.Register(mountName, fileSystemAdapter);
}
finally
{
fileSystem?.Dispose();
}
using var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInContentA.Log();
rc = fs.Register(mountName, ref fileSystemAdapter.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result MountContent(this FileSystemClient fs, U8Span mountName, U8Span path,
@ -85,6 +91,7 @@ namespace LibHac.Fs.Shim
{
rc = PreMount(contentType);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -108,8 +115,9 @@ namespace LibHac.Fs.Shim
}
else
{
rc = MountContentImpl(fs, mountName, path, 0, contentType);
rc = MountContentImpl(fs, mountName, path, programId, contentType);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -155,6 +163,7 @@ namespace LibHac.Fs.Shim
{
rc = MountContentImpl(fs, mountName, path, programId.Value, contentType);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -190,6 +199,7 @@ namespace LibHac.Fs.Shim
{
rc = MountContentImpl(fs, mountName, path, dataId.Value, contentType);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -224,6 +234,7 @@ namespace LibHac.Fs.Shim
{
rc = Mount(fs, mountName, programId, contentType);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -239,21 +250,22 @@ namespace LibHac.Fs.Shim
FileSystemProxyType fsType = ConvertToFileSystemProxyType(contentType);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var fileSystem = new SharedRef<IFileSystemSf>();
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
{
rc = fsProxy.Target.OpenFileSystemWithPatch(out fileSystem, programId, fsType);
if (rc.IsFailure()) return rc;
rc = fileSystemProxy.Get.OpenFileSystemWithPatch(ref fileSystem.Ref(), programId, fsType);
if (rc.IsFailure()) return rc;
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
return fs.Register(mountName, fileSystemAdapter);
}
finally
{
fileSystem?.Dispose();
}
using var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInContentA.Log();
rc = fs.Register(mountName, ref fileSystemAdapter.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
}

View File

@ -8,38 +8,42 @@ using LibHac.FsSrv.Sf;
using LibHac.Os;
using LibHac.Util;
using static LibHac.Fs.Impl.AccessLogStrings;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
namespace LibHac.Fs.Shim
{
/// <summary>
/// Contains functions for mounting the directories where content is stored.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
[SkipLocalsInit]
public static class ContentStorage
{
private class ContentStorageCommonMountNameGenerator : ICommonMountNameGenerator
{
private ContentStorageId StorageId { get; }
private ContentStorageId _storageId;
public ContentStorageCommonMountNameGenerator(ContentStorageId storageId)
{
StorageId = storageId;
_storageId = storageId;
}
public void Dispose() { }
public Result GenerateCommonMountName(Span<byte> nameBuffer)
{
// Determine how much space we need.
int neededSize =
StringUtils.GetLength(GetContentStorageMountName(StorageId), PathTool.MountNameLengthMax) + 2;
ReadOnlySpan<byte> mountName = GetContentStorageMountName(_storageId);
Assert.SdkRequiresGreaterEqual(nameBuffer.Length, neededSize);
// Add 2 for the mount name separator and null terminator
int requiredNameBufferSize = StringUtils.GetLength(mountName, PathTool.MountNameLengthMax) + 2;
Assert.SdkRequiresGreaterEqual(nameBuffer.Length, requiredNameBufferSize);
// Generate the name.
var sb = new U8StringBuilder(nameBuffer);
sb.Append(GetContentStorageMountName(StorageId))
.Append(StringTraits.DriveSeparator);
sb.Append(mountName).Append(StringTraits.DriveSeparator);
Assert.SdkEqual(sb.Length, neededSize - 1);
Assert.SdkEqual(sb.Length, requiredNameBufferSize - 1);
return Result.Success;
}
@ -73,6 +77,7 @@ namespace LibHac.Fs.Shim
{
rc = Mount(fs, mountName, storageId);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -91,35 +96,41 @@ namespace LibHac.Fs.Shim
Result rc = fs.Impl.CheckMountNameAcceptingReservedMountName(mountName);
if (rc.IsFailure()) return rc;
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var fileSystem = new SharedRef<IFileSystemSf>();
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
for (int i = 0; i < maxRetries; i++)
{
for (int i = 0; i < maxRetries; i++)
{
rc = fsProxy.Target.OpenContentStorageFileSystem(out fileSystem, storageId);
rc = fileSystemProxy.Get.OpenContentStorageFileSystem(ref fileSystem.Ref(), storageId);
if (rc.IsSuccess())
break;
if (rc.IsSuccess())
break;
if (!ResultFs.SystemPartitionNotReady.Includes(rc))
return rc;
if (!ResultFs.SystemPartitionNotReady.Includes(rc))
return rc;
if (i == maxRetries - 1)
return rc;
if (i == maxRetries - 1)
return rc;
fs.Hos.Os.SleepThread(TimeSpan.FromMilliSeconds(retryInterval));
}
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
var mountNameGenerator = new ContentStorageCommonMountNameGenerator(storageId);
return fs.Register(mountName, fileSystemAdapter, mountNameGenerator);
}
finally
{
fileSystem?.Dispose();
fs.Hos.Os.SleepThread(TimeSpan.FromMilliSeconds(retryInterval));
}
using var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInContentStorageA.Log();
using var mountNameGenerator =
new UniqueRef<ICommonMountNameGenerator>(new ContentStorageCommonMountNameGenerator(storageId));
if (!mountNameGenerator.HasValue)
return ResultFs.AllocationMemoryFailedInContentStorageB.Log();
rc = fs.Register(mountName, ref fileSystemAdapter.Ref(), ref mountNameGenerator.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}

View File

@ -5,20 +5,25 @@ using LibHac.Diag;
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
{
/// <summary>
/// Contains functions for mounting custom storage file systems.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
[SkipLocalsInit]
public static class CustomStorage
{
public static U8Span GetCustomStorageDirectoryName(CustomStorageId storageId)
public static ReadOnlySpan<byte> GetCustomStorageDirectoryName(CustomStorageId storageId)
{
switch (storageId)
{
case CustomStorageId.System:
case CustomStorageId.SdCard:
return new U8Span(CustomStorageDirectoryName);
return CustomStorageDirectoryName;
default:
Abort.UnexpectedDefault();
return default;
@ -27,23 +32,31 @@ namespace LibHac.Fs.Shim
public static Result MountCustomStorage(this FileSystemClient fs, U8Span mountName, CustomStorageId storageId)
{
Result rc = fs.Impl.CheckMountName(mountName);
if (rc.IsFailure()) return rc;
Result rc = Mount(fs, mountName, storageId);
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
static Result Mount(FileSystemClient fs, U8Span mountName, CustomStorageId storageId)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fs.Impl.CheckMountName(mountName);
if (rc.IsFailure()) return rc.Miss();
rc = fsProxy.Target.OpenCustomStorageFileSystem(out fileSystem, storageId);
if (rc.IsFailure()) return rc;
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var fileSystem = new SharedRef<IFileSystemSf>();
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
return fs.Register(mountName, fileSystemAdapter);
}
finally
{
fileSystem?.Dispose();
rc = fileSystemProxy.Get.OpenCustomStorageFileSystem(ref fileSystem.Ref(), storageId);
if (rc.IsFailure()) return rc.Miss();
using var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
rc = fs.Register(mountName, ref fileSystemAdapter.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}

View File

@ -6,21 +6,20 @@ namespace LibHac.Fs.Shim
internal struct FileSystemProxyServiceObjectGlobals
{
public nint FileSystemProxyServiceObjectInitGuard;
public ReferenceCountedDisposable<IFileSystemProxy> FileSystemProxyServiceObject;
public SharedRef<IFileSystemProxy> FileSystemProxyServiceObject;
public nint FileSystemProxyForLoaderServiceObjectInitGuard;
public ReferenceCountedDisposable<IFileSystemProxyForLoader> FileSystemProxyForLoaderServiceObject;
public SharedRef<IFileSystemProxyForLoader> FileSystemProxyForLoaderServiceObject;
public nint ProgramRegistryServiceObjectInitGuard;
public ReferenceCountedDisposable<IProgramRegistry> ProgramRegistryServiceObject;
public SharedRef<IProgramRegistry> ProgramRegistryServiceObject;
public ReferenceCountedDisposable<IFileSystemProxy> DfcFileSystemProxyServiceObject;
public SharedRef<IFileSystemProxy> DfcFileSystemProxyServiceObject;
}
public static class FileSystemProxyServiceObject
{
public static ReferenceCountedDisposable<IFileSystemProxy> GetFileSystemProxyServiceObject(
this FileSystemClientImpl fs)
public static SharedRef<IFileSystemProxy> GetFileSystemProxyServiceObject(this FileSystemClientImpl fs)
{
ref FileSystemProxyServiceObjectGlobals g = ref fs.Globals.FileSystemProxyServiceObject;
using var guard = new InitializationGuard(ref g.FileSystemProxyServiceObjectInitGuard,
@ -28,33 +27,36 @@ namespace LibHac.Fs.Shim
if (!guard.IsInitialized)
{
g.FileSystemProxyServiceObject = GetFileSystemProxyServiceObjectImpl(fs);
using SharedRef<IFileSystemProxy> createdObject = GetFileSystemProxyServiceObjectImpl(fs);
g.FileSystemProxyServiceObject.SetByMove(ref createdObject.Ref());
}
return g.FileSystemProxyServiceObject.AddReference();
return SharedRef<IFileSystemProxy>.CreateCopy(ref g.FileSystemProxyServiceObject);
}
private static ReferenceCountedDisposable<IFileSystemProxy> GetFileSystemProxyServiceObjectImpl(
FileSystemClientImpl fs)
private static SharedRef<IFileSystemProxy> GetFileSystemProxyServiceObjectImpl(FileSystemClientImpl fs)
{
ReferenceCountedDisposable<IFileSystemProxy> dfcServiceObject =
fs.Globals.FileSystemProxyServiceObject.DfcFileSystemProxyServiceObject;
ref SharedRef<IFileSystemProxy> dfcServiceObject =
ref fs.Globals.FileSystemProxyServiceObject.DfcFileSystemProxyServiceObject;
if (dfcServiceObject is not null)
return dfcServiceObject.AddReference();
if (dfcServiceObject.HasValue)
{
return SharedRef<IFileSystemProxy>.CreateCopy(ref dfcServiceObject);
}
Result rc = fs.Hos.Sm.GetService(out ReferenceCountedDisposable<IFileSystemProxy> fsProxy, "fsp-srv");
using var fileSystemProxy = new SharedRef<IFileSystemProxy>();
Result rc = fs.Hos.Sm.GetService(ref fileSystemProxy.Ref(), "fsp-srv");
if (rc.IsFailure())
{
throw new HorizonResultException(rc, "Failed to get file system proxy service object.");
}
fsProxy.Target.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value).IgnoreResult();
return fsProxy;
fileSystemProxy.Get.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value).IgnoreResult();
return SharedRef<IFileSystemProxy>.CreateMove(ref fileSystemProxy.Ref());
}
public static ReferenceCountedDisposable<IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObject(
public static SharedRef<IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObject(
this FileSystemClientImpl fs)
{
ref FileSystemProxyServiceObjectGlobals g = ref fs.Globals.FileSystemProxyServiceObject;
@ -63,29 +65,29 @@ namespace LibHac.Fs.Shim
if (!guard.IsInitialized)
{
g.FileSystemProxyForLoaderServiceObject = GetFileSystemProxyForLoaderServiceObjectImpl(fs);
using SharedRef<IFileSystemProxyForLoader> createdObject = GetFileSystemProxyForLoaderServiceObjectImpl(fs);
g.FileSystemProxyForLoaderServiceObject.SetByMove(ref createdObject.Ref());
}
return g.FileSystemProxyForLoaderServiceObject.AddReference();
return SharedRef<IFileSystemProxyForLoader>.CreateCopy(ref g.FileSystemProxyForLoaderServiceObject);
}
private static ReferenceCountedDisposable<IFileSystemProxyForLoader>
GetFileSystemProxyForLoaderServiceObjectImpl(FileSystemClientImpl fs)
private static SharedRef<IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObjectImpl(
FileSystemClientImpl fs)
{
Result rc = fs.Hos.Sm.GetService(out ReferenceCountedDisposable<IFileSystemProxyForLoader> fsProxy,
"fsp-ldr");
using var fileSystemProxy = new SharedRef<IFileSystemProxyForLoader>();
Result rc = fs.Hos.Sm.GetService(ref fileSystemProxy.Ref(), "fsp-ldr");
if (rc.IsFailure())
{
throw new HorizonResultException(rc, "Failed to get file system proxy service object.");
}
fsProxy.Target.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value).IgnoreResult();
return fsProxy;
fileSystemProxy.Get.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value).IgnoreResult();
return SharedRef<IFileSystemProxyForLoader>.CreateMove(ref fileSystemProxy.Ref());
}
public static ReferenceCountedDisposable<IProgramRegistry> GetProgramRegistryServiceObject(
this FileSystemClientImpl fs)
public static SharedRef<IProgramRegistry> GetProgramRegistryServiceObject(this FileSystemClientImpl fs)
{
ref FileSystemProxyServiceObjectGlobals g = ref fs.Globals.FileSystemProxyServiceObject;
using var guard = new InitializationGuard(ref g.ProgramRegistryServiceObjectInitGuard,
@ -93,24 +95,25 @@ namespace LibHac.Fs.Shim
if (!guard.IsInitialized)
{
g.ProgramRegistryServiceObject = GetProgramRegistryServiceObjectImpl(fs);
using SharedRef<IProgramRegistry> createdObject = GetProgramRegistryServiceObjectImpl(fs);
g.ProgramRegistryServiceObject.SetByMove(ref createdObject.Ref());
}
return g.ProgramRegistryServiceObject.AddReference();
return SharedRef<IProgramRegistry>.CreateCopy(ref g.ProgramRegistryServiceObject);
}
private static ReferenceCountedDisposable<IProgramRegistry> GetProgramRegistryServiceObjectImpl(
FileSystemClientImpl fs)
private static SharedRef<IProgramRegistry> GetProgramRegistryServiceObjectImpl(FileSystemClientImpl fs)
{
Result rc = fs.Hos.Sm.GetService(out ReferenceCountedDisposable<IProgramRegistry> registry, "fsp-pr");
using var registry = new SharedRef<IProgramRegistry>();
Result rc = fs.Hos.Sm.GetService(ref registry.Ref(), "fsp-pr");
if (rc.IsFailure())
{
throw new HorizonResultException(rc, "Failed to get registry service object.");
}
registry.Target.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value).IgnoreResult();
return registry;
registry.Get.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value).IgnoreResult();
return SharedRef<IProgramRegistry>.CreateMove(ref registry.Ref());
}
/// <summary>
@ -121,9 +124,9 @@ namespace LibHac.Fs.Shim
/// <param name="fs">The <see cref="FileSystemClient"/> to use.</param>
/// <param name="serviceObject">The service object this <see cref="FileSystemClient"/> will use.</param>
public static void InitializeDfcFileSystemProxyServiceObject(this FileSystemClientImpl fs,
ReferenceCountedDisposable<IFileSystemProxy> serviceObject)
ref SharedRef<IFileSystemProxy> serviceObject)
{
fs.Globals.FileSystemProxyServiceObject.DfcFileSystemProxyServiceObject = serviceObject.AddReference();
fs.Globals.FileSystemProxyServiceObject.DfcFileSystemProxyServiceObject.SetByMove(ref serviceObject);
}
}
}

View File

@ -21,46 +21,45 @@ namespace LibHac.Fs.Impl
/// 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.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
internal class FileServiceObjectAdapter : IFile
{
private ReferenceCountedDisposable<IFileSf> BaseFile { get; }
private SharedRef<IFileSf> _baseFile;
public FileServiceObjectAdapter(ReferenceCountedDisposable<IFileSf> baseFile)
public FileServiceObjectAdapter(ref SharedRef<IFileSf> baseFile)
{
BaseFile = baseFile.AddReference();
_baseFile = SharedRef<IFileSf>.CreateMove(ref baseFile);
}
public override void Dispose()
{
BaseFile?.Dispose();
_baseFile.Destroy();
base.Dispose();
}
protected override Result DoRead(out long bytesRead, long offset, Span<byte> destination, in ReadOption option)
{
return BaseFile.Target.Read(out bytesRead, offset, new OutBuffer(destination), destination.Length, option);
return _baseFile.Get.Read(out bytesRead, offset, new OutBuffer(destination), destination.Length, option);
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source, in WriteOption option)
{
return BaseFile.Target.Write(offset, new InBuffer(source), source.Length, option);
return _baseFile.Get.Write(offset, new InBuffer(source), source.Length, option);
}
protected override Result DoFlush()
{
return BaseFile.Target.Flush();
return _baseFile.Get.Flush();
}
protected override Result DoSetSize(long size)
{
return BaseFile.Target.SetSize(size);
return _baseFile.Get.SetSize(size);
}
protected override Result DoGetSize(out long size)
{
return BaseFile.Target.GetSize(out size);
return _baseFile.Get.GetSize(out size);
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
@ -69,16 +68,16 @@ namespace LibHac.Fs.Impl
switch (operationId)
{
case OperationId.InvalidateCache:
return BaseFile.Target.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size);
return _baseFile.Get.OperateRange(out _, (int)OperationId.InvalidateCache, offset, size);
case OperationId.QueryRange:
if (outBuffer.Length != Unsafe.SizeOf<QueryRangeInfo>())
return ResultFs.InvalidSize.Log();
ref QueryRangeInfo info = ref SpanHelpers.AsStruct<QueryRangeInfo>(outBuffer);
return BaseFile.Target.OperateRange(out info, (int)OperationId.QueryRange, offset, size);
return _baseFile.Get.OperateRange(out info, (int)OperationId.QueryRange, offset, size);
default:
return BaseFile.Target.OperateRangeWithBuffer(new OutBuffer(outBuffer), new InBuffer(inBuffer),
return _baseFile.Get.OperateRangeWithBuffer(new OutBuffer(outBuffer), new InBuffer(inBuffer),
(int)operationId, offset, size);
}
}
@ -88,32 +87,31 @@ namespace LibHac.Fs.Impl
/// 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.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
internal class DirectoryServiceObjectAdapter : IDirectory
{
private ReferenceCountedDisposable<IDirectorySf> BaseDirectory { get; }
private SharedRef<IDirectorySf> _baseDirectory;
public DirectoryServiceObjectAdapter(ReferenceCountedDisposable<IDirectorySf> baseDirectory)
public DirectoryServiceObjectAdapter(ref SharedRef<IDirectorySf> baseDirectory)
{
BaseDirectory = baseDirectory.AddReference();
_baseDirectory = SharedRef<IDirectorySf>.CreateMove(ref baseDirectory);
}
public override void Dispose()
{
BaseDirectory?.Dispose();
_baseDirectory.Destroy();
base.Dispose();
}
protected override Result DoRead(out long entriesRead, Span<DirectoryEntry> entryBuffer)
{
Span<byte> buffer = MemoryMarshal.Cast<DirectoryEntry, byte>(entryBuffer);
return BaseDirectory.Target.Read(out entriesRead, new OutBuffer(buffer));
return _baseDirectory.Get.Read(out entriesRead, new OutBuffer(buffer));
}
protected override Result DoGetEntryCount(out long entryCount)
{
return BaseDirectory.Target.GetEntryCount(out entryCount);
return _baseDirectory.Get.GetEntryCount(out entryCount);
}
}
@ -121,10 +119,10 @@ namespace LibHac.Fs.Impl
/// 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.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
internal class FileSystemServiceObjectAdapter : IFileSystem, IMultiCommitTarget
{
private ReferenceCountedDisposable<IFileSystemSf> BaseFs { get; }
private SharedRef<IFileSystemSf> _baseFs;
private static Result GetPathForServiceObject(out PathSf sfPath, in Path path)
{
@ -139,14 +137,14 @@ namespace LibHac.Fs.Impl
return Result.Success;
}
public FileSystemServiceObjectAdapter(ReferenceCountedDisposable<IFileSystemSf> baseFileSystem)
public FileSystemServiceObjectAdapter(ref SharedRef<IFileSystemSf> baseFileSystem)
{
BaseFs = baseFileSystem.AddReference();
_baseFs = SharedRef<IFileSystemSf>.CreateMove(ref baseFileSystem);
}
public override void Dispose()
{
BaseFs?.Dispose();
_baseFs.Destroy();
base.Dispose();
}
@ -155,7 +153,7 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
return BaseFs.Target.CreateFile(in sfPath, size, (int)option);
return _baseFs.Get.CreateFile(in sfPath, size, (int)option);
}
protected override Result DoDeleteFile(in Path path)
@ -163,7 +161,7 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
return BaseFs.Target.DeleteFile(in sfPath);
return _baseFs.Get.DeleteFile(in sfPath);
}
protected override Result DoCreateDirectory(in Path path)
@ -171,7 +169,7 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
return BaseFs.Target.CreateDirectory(in sfPath);
return _baseFs.Get.CreateDirectory(in sfPath);
}
protected override Result DoDeleteDirectory(in Path path)
@ -179,7 +177,7 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
return BaseFs.Target.DeleteDirectory(in sfPath);
return _baseFs.Get.DeleteDirectory(in sfPath);
}
protected override Result DoDeleteDirectoryRecursively(in Path path)
@ -187,7 +185,7 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
return BaseFs.Target.DeleteDirectoryRecursively(in sfPath);
return _baseFs.Get.DeleteDirectoryRecursively(in sfPath);
}
protected override Result DoCleanDirectoryRecursively(in Path path)
@ -195,7 +193,7 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
return BaseFs.Target.CleanDirectoryRecursively(in sfPath);
return _baseFs.Get.CleanDirectoryRecursively(in sfPath);
}
protected override Result DoRenameFile(in Path currentPath, in Path newPath)
@ -206,7 +204,7 @@ namespace LibHac.Fs.Impl
rc = GetPathForServiceObject(out PathSf newSfPath, in newPath);
if (rc.IsFailure()) return rc;
return BaseFs.Target.RenameFile(in currentSfPath, in newSfPath);
return _baseFs.Get.RenameFile(in currentSfPath, in newSfPath);
}
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath)
@ -217,7 +215,7 @@ namespace LibHac.Fs.Impl
rc = GetPathForServiceObject(out PathSf newSfPath, in newPath);
if (rc.IsFailure()) return rc;
return BaseFs.Target.RenameDirectory(in currentSfPath, in newSfPath);
return _baseFs.Get.RenameDirectory(in currentSfPath, in newSfPath);
}
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
@ -229,7 +227,7 @@ namespace LibHac.Fs.Impl
ref uint sfEntryType = ref Unsafe.As<DirectoryEntryType, uint>(ref entryType);
return BaseFs.Target.GetEntryType(out sfEntryType, in sfPath);
return _baseFs.Get.GetEntryType(out sfEntryType, in sfPath);
}
protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path)
@ -239,7 +237,7 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
return BaseFs.Target.GetFreeSpaceSize(out freeSpace, in sfPath);
return _baseFs.Get.GetFreeSpaceSize(out freeSpace, in sfPath);
}
protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path)
@ -249,7 +247,7 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
return BaseFs.Target.GetTotalSpaceSize(out totalSpace, in sfPath);
return _baseFs.Get.GetTotalSpaceSize(out totalSpace, in sfPath);
}
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
@ -257,19 +255,13 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<IFileSf> sfFile = null;
try
{
rc = BaseFs.Target.OpenFile(out sfFile, in sfPath, (uint)mode);
if (rc.IsFailure()) return rc;
using var fileServiceObject = new SharedRef<IFileSf>();
outFile.Reset(new FileServiceObjectAdapter(sfFile));
return Result.Success;
}
finally
{
sfFile?.Dispose();
}
rc = _baseFs.Get.OpenFile(ref fileServiceObject.Ref(), in sfPath, (uint)mode);
if (rc.IsFailure()) return rc;
outFile.Reset(new FileServiceObjectAdapter(ref fileServiceObject.Ref()));
return Result.Success;
}
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
@ -278,24 +270,18 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<IDirectorySf> sfDir = null;
try
{
rc = BaseFs.Target.OpenDirectory(out sfDir, in sfPath, (uint)mode);
if (rc.IsFailure()) return rc;
using var directoryServiceObject = new SharedRef<IDirectorySf>();
outDirectory.Reset(new DirectoryServiceObjectAdapter(sfDir));
return Result.Success;
}
finally
{
sfDir?.Dispose();
}
rc = _baseFs.Get.OpenDirectory(ref directoryServiceObject.Ref(), in sfPath, (uint)mode);
if (rc.IsFailure()) return rc;
outDirectory.Reset(new DirectoryServiceObjectAdapter(ref directoryServiceObject.Ref()));
return Result.Success;
}
protected override Result DoCommit()
{
return BaseFs.Target.Commit();
return _baseFs.Get.Commit();
}
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path)
@ -305,7 +291,7 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
return BaseFs.Target.GetFileTimeStampRaw(out timeStamp, in sfPath);
return _baseFs.Get.GetFileTimeStampRaw(out timeStamp, in sfPath);
}
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
@ -314,15 +300,15 @@ namespace LibHac.Fs.Impl
Result rc = GetPathForServiceObject(out PathSf sfPath, in path);
if (rc.IsFailure()) return rc;
return BaseFs.Target.QueryEntry(new OutBuffer(outBuffer), new InBuffer(inBuffer), (int)queryId, in sfPath);
return _baseFs.Get.QueryEntry(new OutBuffer(outBuffer), new InBuffer(inBuffer), (int)queryId, in sfPath);
}
public ReferenceCountedDisposable<IFileSystemSf> GetFileSystem()
public SharedRef<IFileSystemSf> GetFileSystem()
{
return BaseFs.AddReference();
return SharedRef<IFileSystemSf>.CreateCopy(ref _baseFs);
}
public ReferenceCountedDisposable<IFileSystemSf> GetMultiCommitTarget()
public SharedRef<IFileSystemSf> GetMultiCommitTarget()
{
return GetFileSystem();
}

View File

@ -9,6 +9,7 @@ using LibHac.FsSrv.Sf;
using LibHac.Os;
using LibHac.Util;
using static LibHac.Fs.Impl.AccessLogStrings;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
using IStorageSf = LibHac.FsSrv.Sf.IStorage;
@ -48,12 +49,12 @@ namespace LibHac.Fs.Shim
int handleDigitCount = Unsafe.SizeOf<GameCardHandle>() * 2;
// Determine how much space we need.
int neededSize =
int requiredNameBufferSize =
StringUtils.GetLength(CommonMountNames.GameCardFileSystemMountName, PathTool.MountNameLengthMax) +
StringUtils.GetLength(GetGameCardMountNameSuffix(PartitionId), PathTool.MountNameLengthMax) +
handleDigitCount + 2;
Assert.SdkRequiresGreaterEqual(nameBuffer.Length, neededSize);
Assert.SdkRequiresGreaterEqual(nameBuffer.Length, requiredNameBufferSize);
// Generate the name.
var sb = new U8StringBuilder(nameBuffer);
@ -62,7 +63,7 @@ namespace LibHac.Fs.Shim
.AppendFormat(Handle.Value, 'x', (byte)handleDigitCount)
.Append(StringTraits.DriveSeparator);
Assert.SdkEqual(sb.Length, neededSize - 1);
Assert.SdkEqual(sb.Length, requiredNameBufferSize - 1);
return Result.Success;
}
@ -72,23 +73,16 @@ namespace LibHac.Fs.Shim
{
UnsafeHelpers.SkipParamInit(out handle);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var deviceOperator = new SharedRef<IDeviceOperator>();
ReferenceCountedDisposable<IDeviceOperator> deviceOperator = null;
try
{
Result rc = fsProxy.Target.OpenDeviceOperator(out deviceOperator);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
Result rc = fileSystemProxy.Get.OpenDeviceOperator(ref deviceOperator.Ref());
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
rc = deviceOperator.Target.GetGameCardHandle(out handle);
fs.Impl.AbortIfNeeded(rc);
return rc;
}
finally
{
deviceOperator?.Dispose();
}
rc = deviceOperator.Get.GetGameCardHandle(out handle);
fs.Impl.AbortIfNeeded(rc);
return rc;
}
public static Result MountGameCardPartition(this FileSystemClient fs, U8Span mountName, GameCardHandle handle,
@ -116,6 +110,7 @@ namespace LibHac.Fs.Shim
{
rc = Mount(fs, mountName, handle, partitionId);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -130,69 +125,61 @@ namespace LibHac.Fs.Shim
Result rc = fs.Impl.CheckMountNameAcceptingReservedMountName(mountName);
if (rc.IsFailure()) return rc;
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var fileSystem = new SharedRef<IFileSystemSf>();
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
{
rc = fsProxy.Target.OpenGameCardFileSystem(out fileSystem, handle, partitionId);
if (rc.IsFailure()) return rc;
rc = fileSystemProxy.Get.OpenGameCardFileSystem(ref fileSystem.Ref(), handle, partitionId);
if (rc.IsFailure()) return rc;
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
var mountNameGenerator = new GameCardCommonMountNameGenerator(handle, partitionId);
return fs.Register(mountName, fileSystemAdapter, mountNameGenerator);
}
finally
{
fileSystem?.Dispose();
}
using var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInGameCardC.Log();
using var mountNameGenerator =
new UniqueRef<ICommonMountNameGenerator>(new GameCardCommonMountNameGenerator(handle, partitionId));
if (!mountNameGenerator.HasValue)
return ResultFs.AllocationMemoryFailedInGameCardD.Log();
return fs.Register(mountName, ref fileSystemAdapter.Ref(), ref mountNameGenerator.Ref());
}
}
public static bool IsGameCardInserted(this FileSystemClient fs)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var deviceOperator = new SharedRef<IDeviceOperator>();
ReferenceCountedDisposable<IDeviceOperator> deviceOperator = null;
try
{
Result rc = fsProxy.Target.OpenDeviceOperator(out deviceOperator);
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
Result rc = fileSystemProxy.Get.OpenDeviceOperator(ref deviceOperator.Ref());
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
rc = deviceOperator.Target.IsGameCardInserted(out bool isInserted);
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
rc = deviceOperator.Get.IsGameCardInserted(out bool isInserted);
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
return isInserted;
}
finally
{
deviceOperator?.Dispose();
}
return isInserted;
}
public static Result OpenGameCardPartition(this FileSystemClient fs, out IStorage storage,
public static Result OpenGameCardPartition(this FileSystemClient fs, ref UniqueRef<IStorage> outStorage,
GameCardHandle handle, GameCardPartitionRaw partitionType)
{
UnsafeHelpers.SkipParamInit(out storage);
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var storage = new SharedRef<IStorageSf>();
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fileSystemProxy.Get.OpenGameCardStorage(ref storage.Ref(), handle, partitionType);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<IStorageSf> sfStorage = null;
try
{
Result rc = fsProxy.Target.OpenGameCardStorage(out sfStorage, handle, partitionType);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
using var storageAdapter = new UniqueRef<IStorage>(new StorageServiceObjectAdapter(ref storage.Ref()));
storage = new StorageServiceObjectAdapter(sfStorage);
return Result.Success;
}
finally
{
sfStorage?.Dispose();
}
if (!storageAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInGameCardB.Log();
outStorage.Set(ref storageAdapter.Ref());
return Result.Success;
}
}
}

View File

@ -26,44 +26,41 @@ namespace LibHac.Fs.Shim
private static ReadOnlySpan<byte> HostRootFileSystemPath => // "@Host:/"
new[] { (byte)'@', (byte)'H', (byte)'o', (byte)'s', (byte)'t', (byte)':', (byte)'/' };
private const int HostRootFileSystemPathLength = 8;
private const int HostRootFileSystemPathLength = 7;
/// <summary>
/// Opens a host file system via <see cref="IFileSystemProxy"/>.
/// </summary>
/// <param name="fs">The <see cref="FileSystemClient"/> to use.</param>
/// <param name="fileSystem">If successful, the opened host file system.</param>
/// <param name="outFileSystem">If successful, the opened host file system.</param>
/// <param name="path">The path on the host computer to open. e.g. /C:\Windows\System32/</param>
/// <param name="option">Options for opening the host file system.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
private static Result OpenHostFileSystemImpl(FileSystemClient fs, out IFileSystem fileSystem, in FspPath path,
MountHostOption option)
private static Result OpenHostFileSystemImpl(FileSystemClient fs, ref UniqueRef<IFileSystem> outFileSystem,
in FspPath path, MountHostOption option)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var fileSystem = new SharedRef<IFileSystemSf>();
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
ReferenceCountedDisposable<IFileSystemSf> hostFs = null;
try
if (option.Flags != MountHostOptionFlag.None)
{
if (option.Flags != MountHostOptionFlag.None)
{
Result rc = fsProxy.Target.OpenHostFileSystemWithOption(out hostFs, in path, option);
if (rc.IsFailure()) return rc;
}
else
{
Result rc = fsProxy.Target.OpenHostFileSystem(out hostFs, in path);
if (rc.IsFailure()) return rc;
}
fileSystem = new FileSystemServiceObjectAdapter(hostFs);
return Result.Success;
Result rc = fileSystemProxy.Get.OpenHostFileSystemWithOption(ref fileSystem.Ref(), in path, option);
if (rc.IsFailure()) return rc;
}
finally
else
{
hostFs?.Dispose();
Result rc = fileSystemProxy.Get.OpenHostFileSystem(ref fileSystem.Ref(), in path);
if (rc.IsFailure()) return rc;
}
using var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem.Ref()));
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInHostA.Log();
outFileSystem.Set(ref fileSystemAdapter.Ref());
return Result.Success;
}
private class HostCommonMountNameGenerator : ICommonMountNameGenerator
@ -72,13 +69,7 @@ namespace LibHac.Fs.Shim
public HostCommonMountNameGenerator(U8Span path)
{
StringUtils.Copy(_path.Str, path);
int pathLength = StringUtils.GetLength(_path.Str);
if (pathLength != 0 && _path.Str[pathLength - 1] == DirectorySeparator)
{
_path.Str[pathLength - 1] = NullTerminator;
}
StringUtils.Strlcpy(_path.Str, path, FsPath.MaxLength + 1);
}
public void Dispose() { }
@ -86,7 +77,7 @@ namespace LibHac.Fs.Shim
public Result GenerateCommonMountName(Span<byte> nameBuffer)
{
int requiredNameBufferSize =
StringUtils.GetLength(_path.Str, FsPath.MaxLength) + HostRootFileSystemPathLength;
StringUtils.GetLength(_path.Str, FsPath.MaxLength + 1) + HostRootFileSystemPathLength;
if (nameBuffer.Length < requiredNameBufferSize)
return ResultFs.TooLongPath.Log();
@ -123,16 +114,14 @@ namespace LibHac.Fs.Shim
/// Verifies parameters and opens a host file system.
/// </summary>
/// <param name="fs">The <see cref="FileSystemClient"/> to use.</param>
/// <param name="fileSystem">If successful, the opened host file system.</param>
/// <param name="outFileSystem">If successful, the opened host file system.</param>
/// <param name="mountName">The mount name to be verified.</param>
/// <param name="path">The path on the host computer to open. e.g. C:\Windows\System32</param>
/// <param name="option">Options for opening the host file system.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
private static Result OpenHostFileSystem(FileSystemClient fs, out IFileSystem fileSystem, U8Span mountName,
U8Span path, MountHostOption option)
private static Result OpenHostFileSystem(FileSystemClient fs, ref UniqueRef<IFileSystem> outFileSystem,
U8Span mountName, U8Span path, MountHostOption option)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
if (mountName.IsNull())
return ResultFs.NullptrArgument.Log();
@ -145,44 +134,22 @@ namespace LibHac.Fs.Shim
if (fs.Impl.IsUsedReservedMountName(mountName))
return ResultFs.InvalidMountName.Log();
bool needsTrailingSeparator = false;
int pathLength = StringUtils.GetLength(path, PathTools.MaxPathLength + 1);
Result rc = PathUtility.ConvertToFspPath(out FspPath sfPath, path);
if (rc.IsFailure()) return rc.Miss();
if (pathLength != 0 && path[pathLength - 1] == DirectorySeparator)
if (sfPath.Str[0] == NullTerminator)
{
needsTrailingSeparator = true;
pathLength++;
SpanHelpers.AsByteSpan(ref sfPath)[0] = Dot;
SpanHelpers.AsByteSpan(ref sfPath)[1] = NullTerminator;
}
if (pathLength + 1 > PathTools.MaxPathLength)
return ResultFs.TooLongPath.Log();
using var fileSystem = new UniqueRef<IFileSystem>();
Unsafe.SkipInit(out FsPath fullPath);
rc = OpenHostFileSystemImpl(fs, ref fileSystem.Ref(), in sfPath, option);
if (rc.IsFailure()) return rc.Miss();
var sb = new U8StringBuilder(fullPath.Str);
sb.Append(DirectorySeparator).Append(path);
if (needsTrailingSeparator)
{
sb.Append(DirectorySeparator);
}
if (sb.Overflowed)
return ResultFs.TooLongPath.Log();
// If the input path begins with "//", change any leading '/' characters to '\'
if (fullPath.Str[1] == DirectorySeparator && fullPath.Str[2] == DirectorySeparator)
{
for (int i = 1; fullPath.Str[i] == DirectorySeparator; i++)
{
fullPath.Str[i] = AltDirectorySeparator;
}
}
Result rc = FspPath.FromSpan(out FspPath sfPath, fullPath.Str);
if (rc.IsFailure()) return rc;
return OpenHostFileSystemImpl(fs, out fileSystem, in sfPath, option);
outFileSystem.Set(ref fileSystem.Ref());
return Result.Success;
}
/// <summary>
@ -190,22 +157,24 @@ namespace LibHac.Fs.Shim
/// <paramref name="path"/>, and verifies the <paramref name="mountName"/>.
/// </summary>
/// <param name="fs">The <see cref="FileSystemClient"/> to use.</param>
/// <param name="nameGenerator">If successful, the created <see cref="ICommonMountNameGenerator"/>.</param>
/// <param name="outMountNameGenerator">If successful, the created <see cref="ICommonMountNameGenerator"/>.</param>
/// <param name="mountName">The mount name at which the file system will be mounted.</param>
/// <param name="path">The path that will be opened on the host computer. e.g. C:\Windows\System32</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
private static Result PreMountHost(FileSystemClient fs, out HostCommonMountNameGenerator nameGenerator,
U8Span mountName, U8Span path)
private static Result PreMountHost(FileSystemClient fs,
ref UniqueRef<HostCommonMountNameGenerator> outMountNameGenerator, U8Span mountName, U8Span path)
{
UnsafeHelpers.SkipParamInit(out nameGenerator);
Result rc = fs.Impl.CheckMountName(mountName);
if (rc.IsFailure()) return rc;
if (path.IsNull())
return ResultFs.NullptrArgument.Log();
nameGenerator = new HostCommonMountNameGenerator(path);
outMountNameGenerator.Reset(new HostCommonMountNameGenerator(path));
if (!outMountNameGenerator.HasValue)
return ResultFs.AllocationMemoryFailedInHostB.Log();
return Result.Success;
}
@ -221,12 +190,12 @@ namespace LibHac.Fs.Shim
Result rc;
Span<byte> logBuffer = stackalloc byte[0x300];
HostCommonMountNameGenerator mountNameGenerator;
using var mountNameGenerator = new UniqueRef<HostCommonMountNameGenerator>();
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = PreMountHost(fs, out mountNameGenerator, mountName, path);
rc = PreMountHost(fs, ref mountNameGenerator.Ref(), mountName, path);
Tick end = fs.Hos.Os.GetSystemTick();
var sb = new U8StringBuilder(logBuffer, true);
@ -239,40 +208,43 @@ namespace LibHac.Fs.Shim
}
else
{
rc = PreMountHost(fs, out mountNameGenerator, mountName, path);
rc = PreMountHost(fs, ref mountNameGenerator.Ref(), mountName, path);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
IFileSystem fileSystem;
using var fileSystem = new UniqueRef<IFileSystem>();
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = OpenHostFileSystem(fs, out fileSystem, mountName, path, MountHostOption.None);
rc = OpenHostFileSystem(fs, ref fileSystem.Ref(), mountName, path, MountHostOption.None);
Tick end = fs.Hos.Os.GetSystemTick();
fs.Impl.OutputAccessLogUnlessResultSuccess(rc, start, end, null, new U8Span(logBuffer));
}
else
{
rc = OpenHostFileSystem(fs, out fileSystem, mountName, path, MountHostOption.None);
rc = OpenHostFileSystem(fs, ref fileSystem.Ref(), mountName, path, MountHostOption.None);
}
// No AbortIfNeeded here
if (rc.IsFailure()) return rc;
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = fs.Register(mountName, fileSystem, mountNameGenerator);
rc = PostMount(fs, mountName, ref fileSystem.Ref(), ref mountNameGenerator.Ref());
Tick end = fs.Hos.Os.GetSystemTick();
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(logBuffer));
}
else
{
rc = fs.Register(mountName, fileSystem, mountNameGenerator);
rc = PostMount(fs, mountName, ref fileSystem.Ref(), ref mountNameGenerator.Ref());
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -280,6 +252,18 @@ namespace LibHac.Fs.Shim
fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return Result.Success;
static Result PostMount(FileSystemClient fs, U8Span mountName, ref UniqueRef<IFileSystem> fileSystem,
ref UniqueRef<HostCommonMountNameGenerator> mountNameGenerator)
{
using UniqueRef<ICommonMountNameGenerator> baseMountNameGenerator =
UniqueRef<ICommonMountNameGenerator>.Create(ref mountNameGenerator);
Result rc = fs.Register(mountName, ref fileSystem, ref baseMountNameGenerator.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
/// <summary>
@ -295,12 +279,12 @@ namespace LibHac.Fs.Shim
Result rc;
Span<byte> logBuffer = stackalloc byte[0x300];
HostCommonMountNameGenerator mountNameGenerator;
using var mountNameGenerator = new UniqueRef<HostCommonMountNameGenerator>();
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = PreMountHost(fs, out mountNameGenerator, mountName, path);
rc = PreMountHost(fs, ref mountNameGenerator.Ref(), mountName, path);
Tick end = fs.Hos.Os.GetSystemTick();
var idString = new IdString();
@ -316,40 +300,43 @@ namespace LibHac.Fs.Shim
}
else
{
rc = PreMountHost(fs, out mountNameGenerator, mountName, path);
rc = PreMountHost(fs, ref mountNameGenerator.Ref(), mountName, path);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
IFileSystem fileSystem;
using var fileSystem = new UniqueRef<IFileSystem>();
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = OpenHostFileSystem(fs, out fileSystem, mountName, path, option);
rc = OpenHostFileSystem(fs, ref fileSystem.Ref(), mountName, path, option);
Tick end = fs.Hos.Os.GetSystemTick();
fs.Impl.OutputAccessLogUnlessResultSuccess(rc, start, end, null, new U8Span(logBuffer));
}
else
{
rc = OpenHostFileSystem(fs, out fileSystem, mountName, path, MountHostOption.None);
rc = OpenHostFileSystem(fs, ref fileSystem.Ref(), mountName, path, option);
}
// No AbortIfNeeded here
if (rc.IsFailure()) return rc;
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = fs.Register(mountName, fileSystem, mountNameGenerator);
rc = PostMount(fs, mountName, ref fileSystem.Ref(), ref mountNameGenerator.Ref());
Tick end = fs.Hos.Os.GetSystemTick();
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(logBuffer));
}
else
{
rc = fs.Register(mountName, fileSystem, mountNameGenerator);
rc = PostMount(fs, mountName, ref fileSystem.Ref(), ref mountNameGenerator.Ref());
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -357,6 +344,18 @@ namespace LibHac.Fs.Shim
fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return Result.Success;
static Result PostMount(FileSystemClient fs, U8Span mountName, ref UniqueRef<IFileSystem> fileSystem,
ref UniqueRef<HostCommonMountNameGenerator> mountNameGenerator)
{
using UniqueRef<ICommonMountNameGenerator> baseMountNameGenerator =
UniqueRef<ICommonMountNameGenerator>.Create(ref mountNameGenerator);
Result rc = fs.Register(mountName, ref fileSystem, ref baseMountNameGenerator.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
/// <summary>
@ -369,13 +368,13 @@ namespace LibHac.Fs.Shim
Result rc;
Span<byte> logBuffer = stackalloc byte[0x30];
IFileSystem fileSystem;
using var fileSystem = new UniqueRef<IFileSystem>();
FspPath.CreateEmpty(out FspPath sfPath);
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = OpenHostFileSystemImpl(fs, out fileSystem, in sfPath, MountHostOption.None);
rc = OpenHostFileSystemImpl(fs, ref fileSystem.Ref(), in sfPath, MountHostOption.None);
Tick end = fs.Hos.Os.GetSystemTick();
var sb = new U8StringBuilder(logBuffer, true);
@ -386,23 +385,25 @@ namespace LibHac.Fs.Shim
}
else
{
rc = OpenHostFileSystemImpl(fs, out fileSystem, in sfPath, MountHostOption.None);
rc = OpenHostFileSystemImpl(fs, ref fileSystem.Ref(), in sfPath, MountHostOption.None);
}
// No AbortIfNeeded here
if (rc.IsFailure()) return rc;
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = MountHostFs(fs, fileSystem);
rc = PostMount(fs, ref fileSystem.Ref());
Tick end = fs.Hos.Os.GetSystemTick();
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(logBuffer));
}
else
{
rc = MountHostFs(fs, fileSystem);
rc = PostMount(fs, ref fileSystem.Ref());
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -411,10 +412,19 @@ namespace LibHac.Fs.Shim
return Result.Success;
static Result MountHostFs(FileSystemClient fs, IFileSystem fileSystem)
static Result PostMount(FileSystemClient fs, ref UniqueRef<IFileSystem> fileSystem)
{
return fs.Register(new U8Span(HostRootFileSystemMountName), fileSystem,
new HostRootCommonMountNameGenerator());
using var mountNameGenerator =
new UniqueRef<ICommonMountNameGenerator>(new HostRootCommonMountNameGenerator());
if (!mountNameGenerator.HasValue)
return ResultFs.AllocationMemoryFailedInHostC.Log();
Result rc = fs.Register(new U8Span(HostRootFileSystemMountName), ref fileSystem,
ref mountNameGenerator.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
@ -429,13 +439,13 @@ namespace LibHac.Fs.Shim
Result rc;
Span<byte> logBuffer = stackalloc byte[0x60];
IFileSystem fileSystem;
using var fileSystem = new UniqueRef<IFileSystem>();
FspPath.CreateEmpty(out FspPath sfPath);
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = OpenHostFileSystemImpl(fs, out fileSystem, in sfPath, option);
rc = OpenHostFileSystemImpl(fs, ref fileSystem.Ref(), in sfPath, option);
Tick end = fs.Hos.Os.GetSystemTick();
var idString = new IdString();
@ -450,23 +460,25 @@ namespace LibHac.Fs.Shim
}
else
{
rc = OpenHostFileSystemImpl(fs, out fileSystem, in sfPath, option);
rc = OpenHostFileSystemImpl(fs, ref fileSystem.Ref(), in sfPath, option);
}
// No AbortIfNeeded here
if (rc.IsFailure()) return rc;
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = MountHostFs(fs, fileSystem);
rc = PostMount(fs, ref fileSystem.Ref());
Tick end = fs.Hos.Os.GetSystemTick();
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(logBuffer));
}
else
{
rc = MountHostFs(fs, fileSystem);
rc = PostMount(fs, ref fileSystem.Ref());
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
@ -475,10 +487,19 @@ namespace LibHac.Fs.Shim
return Result.Success;
static Result MountHostFs(FileSystemClient fs, IFileSystem fileSystem)
static Result PostMount(FileSystemClient fs, ref UniqueRef<IFileSystem> fileSystem)
{
return fs.Register(new U8Span(HostRootFileSystemMountName), fileSystem,
new HostRootCommonMountNameGenerator());
using var mountNameGenerator =
new UniqueRef<ICommonMountNameGenerator>(new HostRootCommonMountNameGenerator());
if (!mountNameGenerator.HasValue)
return ResultFs.AllocationMemoryFailedInHostC.Log();
Result rc = fs.Register(new U8Span(HostRootFileSystemMountName), ref fileSystem,
ref mountNameGenerator.Ref());
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
@ -508,6 +529,7 @@ namespace LibHac.Fs.Shim
{
rc = fs.Impl.Unmount(mountName);
}
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
}

View File

@ -1,4 +1,5 @@
using LibHac.FsSrv.Sf;
using LibHac.Common;
using LibHac.FsSrv.Sf;
using LibHac.Os;
namespace LibHac.Fs.Shim
@ -7,10 +8,10 @@ namespace LibHac.Fs.Shim
{
public static Result IsArchivedProgram(this FileSystemClient fs, out bool isArchived, ProcessId processId)
{
using ReferenceCountedDisposable<IFileSystemProxyForLoader> fsProxy =
using SharedRef<IFileSystemProxyForLoader> fileSystemProxy =
fs.Impl.GetFileSystemProxyForLoaderServiceObject();
Result rc = fsProxy.Target.IsArchivedProgram(out isArchived, processId.Value);
Result rc = fileSystemProxy.Get.IsArchivedProgram(out isArchived, processId.Value);
fs.Impl.AbortIfNeeded(rc);
return rc;
}

View File

@ -1,4 +1,5 @@
using LibHac.FsSrv.Sf;
using LibHac.Common;
using LibHac.FsSrv.Sf;
namespace LibHac.Fs.Shim
{
@ -7,9 +8,9 @@ namespace LibHac.Fs.Shim
public static Result SetCurrentPosixTime(this FileSystemClient fs, Time.PosixTime currentPosixTime,
int timeDifferenceSeconds)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.SetCurrentPosixTimeWithTimeDifference(currentPosixTime.Value,
Result rc = fileSystemProxy.Get.SetCurrentPosixTimeWithTimeDifference(currentPosixTime.Value,
timeDifferenceSeconds);
fs.Impl.AbortIfNeeded(rc);
return rc;

View File

@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.FsSrv.Sf;
using LibHac.Sf;
@ -20,11 +21,11 @@ namespace LibHac.Fs.Shim
if (mapInfo.IsEmpty)
return Result.Success;
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
var mapInfoBuffer = new InBuffer(MemoryMarshal.Cast<ProgramIndexMapInfo, byte>(mapInfo));
Result rc = fsProxy.Target.RegisterProgramIndexMapInfo(mapInfoBuffer, mapInfo.Length);
Result rc = fileSystemProxy.Get.RegisterProgramIndexMapInfo(mapInfoBuffer, mapInfo.Length);
fs.Impl.AbortIfNeeded(rc);
return rc;
}

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.FsSrv;
using LibHac.FsSrv.Sf;
using LibHac.Ncm;
@ -12,28 +13,33 @@ namespace LibHac.Fs.Shim
public static Result RegisterProgram(this FileSystemClient fs, ulong processId, ProgramId programId,
StorageId storageId, ReadOnlySpan<byte> accessControlData, ReadOnlySpan<byte> accessControlDescriptor)
{
using ReferenceCountedDisposable<IProgramRegistry> registry = fs.Impl.GetProgramRegistryServiceObject();
using SharedRef<IProgramRegistry> programRegistry = fs.Impl.GetProgramRegistryServiceObject();
Result rc = registry.Target.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value);
Result rc = programRegistry.Get.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
if (rc.IsFailure()) return rc.Miss();
rc = registry.Target.RegisterProgram(processId, programId, storageId, new InBuffer(accessControlData),
rc = programRegistry.Get.RegisterProgram(processId, programId, storageId, new InBuffer(accessControlData),
new InBuffer(accessControlDescriptor));
fs.Impl.AbortIfNeeded(rc);
return rc;
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
/// <inheritdoc cref="ProgramRegistryImpl.UnregisterProgram"/>
public static Result UnregisterProgram(this FileSystemClient fs, ulong processId)
{
using ReferenceCountedDisposable<IProgramRegistry> registry = fs.Impl.GetProgramRegistryServiceObject();
using SharedRef<IProgramRegistry> programRegistry = fs.Impl.GetProgramRegistryServiceObject();
Result rc = registry.Target.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value);
if (rc.IsFailure()) return rc;
Result rc = programRegistry.Get.SetCurrentProcess(fs.Hos.Os.GetCurrentProcessId().Value);
if (rc.IsFailure()) return rc.Miss();
return registry.Target.UnregisterProgram(processId);
rc = programRegistry.Get.UnregisterProgram(processId);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
}

View File

@ -2,63 +2,88 @@
using LibHac.FsSrv.Sf;
using LibHac.Ncm;
using LibHac.Spl;
using FsRightsId = LibHac.Fs.RightsId;
namespace LibHac.Fs.Shim
{
public static class RightsId
public static class RightsIdShim
{
public static Result GetRightsId(this FileSystemClient fs, out FsRightsId rightsId, ProgramId programId,
public static Result GetRightsId(this FileSystemClient fs, out RightsId rightsId, ProgramId programId,
StorageId storageId)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return fsProxy.Target.GetRightsId(out rightsId, programId, storageId);
Result rc = fileSystemProxy.Get.GetRightsId(out rightsId, programId, storageId);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result GetRightsId(this FileSystemClient fs, out FsRightsId rightsId, U8Span path)
public static Result GetRightsId(this FileSystemClient fs, out RightsId rightsId, U8Span path)
{
UnsafeHelpers.SkipParamInit(out rightsId);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = PathUtility.ConvertToFspPath(out FspPath sfPath, path);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc.Miss();
Result rc = FspPath.FromSpan(out FspPath sfPath, path);
if (rc.IsFailure()) return rc;
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return fsProxy.Target.GetRightsIdByPath(out rightsId, in sfPath);
rc = fileSystemProxy.Get.GetRightsIdByPath(out rightsId, in sfPath);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result GetRightsId(this FileSystemClient fs, out FsRightsId rightsId, out byte keyGeneration, U8Span path)
public static Result GetRightsId(this FileSystemClient fs, out RightsId rightsId, out byte keyGeneration, U8Span path)
{
UnsafeHelpers.SkipParamInit(out rightsId, out keyGeneration);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = PathUtility.ConvertToFspPath(out FspPath sfPath, path);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc.Miss();
Result rc = FspPath.FromSpan(out FspPath sfPath, path);
if (rc.IsFailure()) return rc;
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return fsProxy.Target.GetRightsIdAndKeyGenerationByPath(out rightsId, out keyGeneration, in sfPath);
rc = fileSystemProxy.Get.GetRightsIdAndKeyGenerationByPath(out rightsId, out keyGeneration, in sfPath);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result RegisterExternalKey(this FileSystemClient fs, in FsRightsId rightsId, in AccessKey key)
public static Result RegisterExternalKey(this FileSystemClient fs, in RightsId rightsId, in AccessKey key)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return fsProxy.Target.RegisterExternalKey(in rightsId, in key);
Result rc = fileSystemProxy.Get.RegisterExternalKey(in rightsId, in key);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result UnregisterExternalKey(this FileSystemClient fs, ref FsRightsId rightsId)
public static Result UnregisterExternalKey(this FileSystemClient fs, ref RightsId rightsId)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return fsProxy.Target.UnregisterExternalKey(in rightsId);
Result rc = fileSystemProxy.Get.UnregisterExternalKey(in rightsId);
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result UnregisterAllExternalKey(this FileSystemClient fs)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return fsProxy.Target.UnregisterAllExternalKey();
Result rc = fileSystemProxy.Get.UnregisterAllExternalKey();
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
}

View File

@ -7,6 +7,7 @@ using LibHac.FsSrv.Sf;
using LibHac.Ncm;
using LibHac.Os;
using static LibHac.Fs.Impl.AccessLogStrings;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
namespace LibHac.Fs.Shim
@ -20,33 +21,39 @@ namespace LibHac.Fs.Shim
Result rc = fs.CheckMountName(mountName);
if (rc.IsFailure()) return rc;
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, programId, type, userId, 0, index);
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
{
if (openReadOnly)
{
rc = fsProxy.Target.OpenReadOnlySaveDataFileSystem(out fileSystem, spaceId, in attribute);
if (rc.IsFailure()) return rc;
}
else
{
rc = fsProxy.Target.OpenSaveDataFileSystem(out fileSystem, spaceId, in attribute);
if (rc.IsFailure()) return rc;
}
using var fileSystem = new SharedRef<IFileSystemSf>();
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
return fs.Fs.Register(mountName, fileSystemAdapter, fileSystemAdapter, null, false, true);
}
finally
if (openReadOnly)
{
fileSystem?.Dispose();
rc = fileSystemProxy.Get.OpenReadOnlySaveDataFileSystem(ref fileSystem.Ref(), spaceId, in attribute);
if (rc.IsFailure()) return rc;
}
else
{
rc = fileSystemProxy.Get.OpenSaveDataFileSystem(ref fileSystem.Ref(), spaceId, in attribute);
if (rc.IsFailure()) return rc;
}
// Note: Nintendo does pass in the same object both as a unique_ptr and as a raw pointer.
// Both of these are tied to the lifetime of the created FileSystemServiceObjectAdapter so it shouldn't be an issue.
var fileSystemAdapterRaw = new FileSystemServiceObjectAdapter(ref fileSystem.Ref());
using var fileSystemAdapter = new UniqueRef<IFileSystem>(fileSystemAdapterRaw);
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedNew.Log();
using var mountNameGenerator = new UniqueRef<ICommonMountNameGenerator>();
rc = fs.Fs.Register(mountName, fileSystemAdapterRaw, ref fileSystemAdapter.Ref(),
ref mountNameGenerator.Ref(), false, true);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result MountSaveData(this FileSystemClient fs, U8Span mountName, Ncm.ApplicationId applicationId,

View File

@ -1,6 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs.Fsa;
@ -15,27 +14,34 @@ using static LibHac.Fs.Impl.AccessLogStrings;
namespace LibHac.Fs.Shim
{
public readonly struct SaveDataIterator : IDisposable
public class SaveDataIterator : IDisposable
{
private FileSystemClient FsClient { get; }
private ReferenceCountedDisposable<ISaveDataInfoReader> Reader { get; }
private readonly FileSystemClient _fsClient;
private SharedRef<ISaveDataInfoReader> _reader;
internal SaveDataIterator(FileSystemClient fsClient, ref ReferenceCountedDisposable<ISaveDataInfoReader> reader)
internal SaveDataIterator(FileSystemClient fsClient, ref SharedRef<ISaveDataInfoReader> reader)
{
FsClient = fsClient;
Reader = Shared.Move(ref reader);
_reader = SharedRef<ISaveDataInfoReader>.CreateMove(ref reader);
_fsClient = fsClient;
}
public void Dispose()
{
_reader.Destroy();
}
private Result ReadSaveDataInfoImpl(out long readCount, Span<SaveDataInfo> buffer)
{
var outBuffer = new OutBuffer(MemoryMarshal.Cast<SaveDataInfo, byte>(buffer));
return Reader.Target.Read(out readCount, outBuffer);
Result rc = _reader.Get.Read(out readCount, OutBuffer.FromSpan(buffer));
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public Result ReadSaveDataInfo(out long readCount, Span<SaveDataInfo> buffer)
{
Result rc;
FileSystemClient fs = FsClient;
FileSystemClient fs = _fsClient;
Span<byte> logBuffer = stackalloc byte[0x50];
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System) && fs.Impl.IsEnabledHandleAccessLog(null))
@ -55,12 +61,9 @@ namespace LibHac.Fs.Shim
}
fs.Impl.AbortIfNeeded(rc);
return rc;
}
if (rc.IsFailure()) return rc.Miss();
public void Dispose()
{
Reader?.Dispose();
return Result.Success;
}
}
@ -72,9 +75,9 @@ namespace LibHac.Fs.Shim
{
UnsafeHelpers.SkipParamInit(out extraData);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.ReadSaveDataFileSystemExtraData(OutBuffer.FromStruct(ref extraData), saveDataId);
Result rc = fileSystemProxy.Get.ReadSaveDataFileSystemExtraData(OutBuffer.FromStruct(ref extraData), saveDataId);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -85,9 +88,9 @@ namespace LibHac.Fs.Shim
{
UnsafeHelpers.SkipParamInit(out extraData);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(
Result rc = fileSystemProxy.Get.ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(
OutBuffer.FromStruct(ref extraData), spaceId, saveDataId);
if (rc.IsFailure()) return rc;
@ -99,9 +102,9 @@ namespace LibHac.Fs.Shim
{
UnsafeHelpers.SkipParamInit(out extraData);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.ReadSaveDataFileSystemExtraDataBySaveDataAttribute(
Result rc = fileSystemProxy.Get.ReadSaveDataFileSystemExtraDataBySaveDataAttribute(
OutBuffer.FromStruct(ref extraData), spaceId, in attribute);
if (rc.IsFailure()) return rc;
@ -114,9 +117,9 @@ namespace LibHac.Fs.Shim
{
UnsafeHelpers.SkipParamInit(out extraData);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
Result rc = fileSystemProxy.Get.ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
OutBuffer.FromStruct(ref extraData), spaceId, in attribute, InBuffer.FromStruct(in extraDataMask));
if (rc.IsFailure()) return rc;
@ -137,12 +140,14 @@ namespace LibHac.Fs.Shim
public static Result WriteSaveDataFileSystemExtraData(this FileSystemClientImpl fs, SaveDataSpaceId spaceId,
ulong saveDataId, in SaveDataExtraData extraData)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.WriteSaveDataFileSystemExtraData(saveDataId, spaceId,
Result rc = fileSystemProxy.Get.WriteSaveDataFileSystemExtraData(saveDataId, spaceId,
InBuffer.FromStruct(in extraData));
fs.AbortIfNeeded(rc);
return rc;
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
/// <summary>
@ -166,12 +171,14 @@ namespace LibHac.Fs.Shim
public static Result WriteSaveDataFileSystemExtraData(this FileSystemClientImpl fs, SaveDataSpaceId spaceId,
ulong saveDataId, in SaveDataExtraData extraData, in SaveDataExtraData extraDataMask)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.WriteSaveDataFileSystemExtraDataWithMask(saveDataId, spaceId,
Result rc = fileSystemProxy.Get.WriteSaveDataFileSystemExtraDataWithMask(saveDataId, spaceId,
InBuffer.FromStruct(in extraData), InBuffer.FromStruct(in extraDataMask));
fs.AbortIfNeeded(rc);
return rc;
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
/// <summary>
@ -198,12 +205,14 @@ namespace LibHac.Fs.Shim
public static Result WriteSaveDataFileSystemExtraData(this FileSystemClientImpl fs, SaveDataSpaceId spaceId,
in SaveDataAttribute attribute, in SaveDataExtraData extraData, in SaveDataExtraData extraDataMask)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(in attribute,
Result rc = fileSystemProxy.Get.WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(in attribute,
spaceId, InBuffer.FromStruct(in extraData), InBuffer.FromStruct(in extraDataMask));
fs.AbortIfNeeded(rc);
return rc;
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result FindSaveDataWithFilter(this FileSystemClientImpl fs, out SaveDataInfo saveInfo,
@ -211,12 +220,12 @@ namespace LibHac.Fs.Shim
{
UnsafeHelpers.SkipParamInit(out saveInfo);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Unsafe.SkipInit(out SaveDataInfo tempInfo);
OutBuffer saveInfoBuffer = OutBuffer.FromStruct(ref tempInfo);
Result rc = fsProxy.Target.FindSaveDataWithFilter(out long count, saveInfoBuffer, spaceId, in filter);
Result rc = fileSystemProxy.Get.FindSaveDataWithFilter(out long count, saveInfoBuffer, spaceId, in filter);
if (rc.IsFailure()) return rc;
if (count == 0)
@ -229,7 +238,7 @@ namespace LibHac.Fs.Shim
public static Result CreateSaveData(this FileSystemClientImpl fs, Ncm.ApplicationId applicationId,
UserId userId, ulong ownerId, long size, long journalSize, SaveDataFlags flags)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, applicationId, SaveDataType.Account,
userId, 0);
@ -242,13 +251,16 @@ namespace LibHac.Fs.Shim
var metaPolicy = new SaveDataMetaPolicy(SaveDataType.Account);
metaPolicy.GenerateMetaInfo(out SaveDataMetaInfo metaInfo);
return fsProxy.Target.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo);
rc = fileSystemProxy.Get.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result CreateBcatSaveData(this FileSystemClientImpl fs, Ncm.ApplicationId applicationId,
long size)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, applicationId, SaveDataType.Bcat,
Fs.SaveData.InvalidUserId, 0);
@ -265,13 +277,16 @@ namespace LibHac.Fs.Shim
Size = 0
};
return fsProxy.Target.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo);
rc = fileSystemProxy.Get.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result CreateDeviceSaveData(this FileSystemClientImpl fs, Ncm.ApplicationId applicationId,
ulong ownerId, long size, long journalSize, SaveDataFlags flags)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, applicationId, SaveDataType.Device,
Fs.SaveData.InvalidUserId, 0);
@ -284,13 +299,16 @@ namespace LibHac.Fs.Shim
var metaPolicy = new SaveDataMetaPolicy(SaveDataType.Device);
metaPolicy.GenerateMetaInfo(out SaveDataMetaInfo metaInfo);
return fsProxy.Target.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo);
rc = fileSystemProxy.Get.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result CreateCacheStorage(this FileSystemClientImpl fs, Ncm.ApplicationId applicationId,
SaveDataSpaceId spaceId, ulong ownerId, ushort index, long size, long journalSize, SaveDataFlags flags)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, applicationId, SaveDataType.Cache,
Fs.SaveData.InvalidUserId, 0, index);
@ -306,27 +324,30 @@ namespace LibHac.Fs.Shim
Size = 0
};
return fsProxy.Target.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo);
rc = fileSystemProxy.Get.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result CreateSaveData(this FileSystemClientImpl fs, in SaveDataAttribute attribute,
in SaveDataCreationInfo creationInfo, in SaveDataMetaInfo metaInfo, in HashSalt hashSalt)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
return fsProxy.Target.CreateSaveDataFileSystemWithHashSalt(in attribute, in creationInfo,
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
return fileSystemProxy.Get.CreateSaveDataFileSystemWithHashSalt(in attribute, in creationInfo,
in metaInfo, in hashSalt);
}
public static Result DeleteSaveData(this FileSystemClientImpl fs, ulong saveDataId)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
return fsProxy.Target.DeleteSaveDataFileSystem(saveDataId);
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
return fileSystemProxy.Get.DeleteSaveDataFileSystem(saveDataId);
}
public static Result DeleteSaveData(this FileSystemClientImpl fs, SaveDataSpaceId spaceId, ulong saveDataId)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
return fsProxy.Target.DeleteSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId);
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
return fileSystemProxy.Get.DeleteSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId);
}
public static Result DeleteSaveData(this FileSystemClient fs, ulong saveDataId)
@ -413,13 +434,13 @@ namespace LibHac.Fs.Shim
static Result Delete(FileSystemClient fs, SaveDataSpaceId spaceId, ulong saveDataId, UserId userId)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, Fs.SaveData.InvalidProgramId,
SaveDataType.System, userId, saveDataId);
if (rc.IsFailure()) return rc;
return fsProxy.Target.DeleteSaveDataFileSystemBySaveDataAttribute(spaceId, in attribute);
return fileSystemProxy.Get.DeleteSaveDataFileSystemBySaveDataAttribute(spaceId, in attribute);
}
}
@ -449,70 +470,62 @@ namespace LibHac.Fs.Shim
static Result Delete(FileSystemClient fs, ApplicationId applicationId)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, new ProgramId(applicationId.Value),
SaveDataType.Device, Fs.SaveData.InvalidUserId, 0);
if (rc.IsFailure()) return rc;
return fsProxy.Target.DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId.User, in attribute);
return fileSystemProxy.Get.DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId.User, in attribute);
}
}
public static Result RegisterSaveDataAtomicDeletion(this FileSystemClient fs,
ReadOnlySpan<ulong> saveDataIdList)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
var listBytes = new InBuffer(MemoryMarshal.Cast<ulong, byte>(saveDataIdList));
Result rc = fsProxy.Target.RegisterSaveDataFileSystemAtomicDeletion(listBytes);
Result rc = fileSystemProxy.Get.RegisterSaveDataFileSystemAtomicDeletion(InBuffer.FromSpan(saveDataIdList));
fs.Impl.AbortIfNeeded(rc);
return rc;
}
public static Result OpenSaveDataIterator(this FileSystemClientImpl fs, out SaveDataIterator iterator,
SaveDataSpaceId spaceId)
{
UnsafeHelpers.SkipParamInit(out iterator);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
ReferenceCountedDisposable<ISaveDataInfoReader> reader = null;
try
{
Result rc = fsProxy.Target.OpenSaveDataInfoReaderBySaveDataSpaceId(out reader, spaceId);
if (rc.IsFailure()) return rc;
iterator = new SaveDataIterator(fs.Fs, ref reader);
}
finally
{
reader?.Dispose();
}
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result OpenSaveDataIterator(this FileSystemClientImpl fs, out SaveDataIterator iterator,
SaveDataSpaceId spaceId, in SaveDataFilter filter)
public static Result OpenSaveDataIterator(this FileSystemClientImpl fs,
ref UniqueRef<SaveDataIterator> outIterator, SaveDataSpaceId spaceId)
{
UnsafeHelpers.SkipParamInit(out iterator);
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
using var reader = new SharedRef<ISaveDataInfoReader>();
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fileSystemProxy.Get.OpenSaveDataInfoReaderBySaveDataSpaceId(ref reader.Ref(), spaceId);
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<ISaveDataInfoReader> reader = null;
try
{
Result rc = fsProxy.Target.OpenSaveDataInfoReaderWithFilter(out reader, spaceId, in filter);
if (rc.IsFailure()) return rc;
var iterator = new UniqueRef<SaveDataIterator>(new SaveDataIterator(fs.Fs, ref reader.Ref()));
iterator = new SaveDataIterator(fs.Fs, ref reader);
}
finally
{
reader?.Dispose();
}
if (!iterator.HasValue)
return ResultFs.AllocationMemoryFailedInSaveDataManagementA.Log();
outIterator.Set(ref iterator);
return Result.Success;
}
public static Result OpenSaveDataIterator(this FileSystemClientImpl fs,
ref UniqueRef<SaveDataIterator> outIterator, SaveDataSpaceId spaceId, in SaveDataFilter filter)
{
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
using var reader = new SharedRef<ISaveDataInfoReader>();
Result rc = fileSystemProxy.Get.OpenSaveDataInfoReaderWithFilter(ref reader.Ref(), spaceId, in filter);
if (rc.IsFailure()) return rc;
var iterator = new UniqueRef<SaveDataIterator>(new SaveDataIterator(fs.Fs, ref reader.Ref()));
if (!iterator.HasValue)
return ResultFs.AllocationMemoryFailedInSaveDataManagementA.Log();
outIterator.Set(ref iterator);
return Result.Success;
}
@ -520,10 +533,13 @@ namespace LibHac.Fs.Shim
public static Result ReadSaveDataIteratorSaveDataInfo(out long readCount, Span<SaveDataInfo> buffer,
in SaveDataIterator iterator)
{
return iterator.ReadSaveDataInfo(out readCount, buffer);
Result rc = iterator.ReadSaveDataInfo(out readCount, buffer);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public static Result OpenSaveDataIterator(this FileSystemClient fs, out SaveDataIterator iterator,
public static Result OpenSaveDataIterator(this FileSystemClient fs, ref UniqueRef<SaveDataIterator> outIterator,
SaveDataSpaceId spaceId)
{
Result rc;
@ -532,7 +548,7 @@ namespace LibHac.Fs.Shim
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System) && fs.Impl.IsEnabledHandleAccessLog(null))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = fs.Impl.OpenSaveDataIterator(out iterator, spaceId);
rc = fs.Impl.OpenSaveDataIterator(ref outIterator, spaceId);
Tick end = fs.Hos.Os.GetSystemTick();
var idString = new IdString();
@ -543,14 +559,14 @@ namespace LibHac.Fs.Shim
}
else
{
rc = fs.Impl.OpenSaveDataIterator(out iterator, spaceId);
rc = fs.Impl.OpenSaveDataIterator(ref outIterator, spaceId);
}
fs.Impl.AbortIfNeeded(rc);
return rc;
}
public static Result OpenSaveDataIterator(this FileSystemClient fs, out SaveDataIterator iterator,
public static Result OpenSaveDataIterator(this FileSystemClient fs, ref UniqueRef<SaveDataIterator> outIterator,
SaveDataSpaceId spaceId, in SaveDataFilter filter)
{
Result rc;
@ -559,7 +575,7 @@ namespace LibHac.Fs.Shim
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System) && fs.Impl.IsEnabledHandleAccessLog(null))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = fs.Impl.OpenSaveDataIterator(out iterator, spaceId, in filter);
rc = fs.Impl.OpenSaveDataIterator(ref outIterator, spaceId, in filter);
Tick end = fs.Hos.Os.GetSystemTick();
var idString = new IdString();
@ -570,7 +586,7 @@ namespace LibHac.Fs.Shim
}
else
{
rc = fs.Impl.OpenSaveDataIterator(out iterator, spaceId, in filter);
rc = fs.Impl.OpenSaveDataIterator(ref outIterator, spaceId, in filter);
}
fs.Impl.AbortIfNeeded(rc);
@ -668,7 +684,7 @@ namespace LibHac.Fs.Shim
static Result CreateSave(FileSystemClient fs, Ncm.ApplicationId applicationId, UserId userId,
ulong ownerId, long size, long journalSize, in HashSalt hashSalt, SaveDataFlags flags)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, applicationId, SaveDataType.Account,
userId, 0);
@ -681,7 +697,7 @@ namespace LibHac.Fs.Shim
var metaPolicy = new SaveDataMetaPolicy(SaveDataType.Account);
metaPolicy.GenerateMetaInfo(out SaveDataMetaInfo metaInfo);
return fsProxy.Target.CreateSaveDataFileSystemWithHashSalt(in attribute, in creationInfo, in metaInfo,
return fileSystemProxy.Get.CreateSaveDataFileSystemWithHashSalt(in attribute, in creationInfo, in metaInfo,
in hashSalt);
}
}
@ -745,7 +761,7 @@ namespace LibHac.Fs.Shim
public static Result CreateTemporaryStorage(this FileSystemClientImpl fs, Ncm.ApplicationId applicationId,
ulong ownerId, long size, SaveDataFlags flags)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, applicationId, SaveDataType.Temporary,
Fs.SaveData.InvalidUserId, 0);
@ -761,7 +777,7 @@ namespace LibHac.Fs.Shim
Size = 0
};
return fsProxy.Target.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo);
return fileSystemProxy.Get.CreateSaveDataFileSystem(in attribute, in creationInfo, in metaInfo);
}
public static Result CreateTemporaryStorage(this FileSystemClient fs, Ncm.ApplicationId applicationId,
@ -872,7 +888,7 @@ namespace LibHac.Fs.Shim
static Result CreateSave(FileSystemClient fs, SaveDataSpaceId spaceId, ulong saveDataId, UserId userId,
ulong ownerId, long size, long journalSize, SaveDataFlags flags)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, Fs.SaveData.InvalidProgramId,
SaveDataType.System, userId, saveDataId);
@ -882,7 +898,7 @@ namespace LibHac.Fs.Shim
spaceId);
if (rc.IsFailure()) return rc;
return fsProxy.Target.CreateSaveDataFileSystemBySystemSaveDataId(in attribute, in creationInfo);
return fileSystemProxy.Get.CreateSaveDataFileSystemBySystemSaveDataId(in attribute, in creationInfo);
}
}
@ -921,9 +937,9 @@ namespace LibHac.Fs.Shim
public static Result ExtendSaveData(this FileSystemClientImpl fs, SaveDataSpaceId spaceId, ulong saveDataId,
long saveDataSize, long journalSize)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
return fsProxy.Target.ExtendSaveDataFileSystem(spaceId, saveDataId, saveDataSize, journalSize);
return fileSystemProxy.Get.ExtendSaveDataFileSystem(spaceId, saveDataId, saveDataSize, journalSize);
}
public static Result ExtendSaveData(this FileSystemClient fs, ulong saveDataId, long saveDataSize,
@ -995,13 +1011,13 @@ namespace LibHac.Fs.Shim
{
UnsafeHelpers.SkipParamInit(out totalSize);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.QuerySaveDataTotalSize(out long tempTotalSize, size, journalSize);
if (rc.IsSuccess())
totalSize = tempTotalSize;
Result rc = fileSystemProxy.Get.QuerySaveDataTotalSize(out long tempTotalSize, size, journalSize);
if (rc.IsFailure()) return rc.Miss();
return rc;
totalSize = tempTotalSize;
return Result.Success;
}
public static Result QuerySaveDataTotalSize(this FileSystemClient fs, out long totalSize, long size,
@ -1295,9 +1311,9 @@ namespace LibHac.Fs.Shim
var idString = new IdString();
var sb = new U8StringBuilder(logBuffer, true);
sb.Append(LogSaveDataSpaceId).Append(idString.ToString(spaceId))
.Append(LogSaveDataId).AppendFormat(saveDataId, 'X')
sb.Append(LogSaveDataId).AppendFormat(saveDataId, 'X')
.Append(LogUserId).AppendFormat(userId.Id.High, 'X', 16).AppendFormat(userId.Id.Low, 'X', 16)
.Append(LogSaveDataSpaceId).Append(idString.ToString(spaceId))
.Append(LogSaveDataFlags).AppendFormat((int)flags, 'X', 8);
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
@ -1636,9 +1652,9 @@ namespace LibHac.Fs.Shim
{
UnsafeHelpers.SkipParamInit(out commitId);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return fsProxy.Target.GetSaveDataCommitId(out commitId, spaceId, saveDataId);
return fileSystemProxy.Get.GetSaveDataCommitId(out commitId, spaceId, saveDataId);
}
}
@ -1688,9 +1704,9 @@ namespace LibHac.Fs.Shim
{
UnsafeHelpers.SkipParamInit(out size);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
return fsProxy.Target.QuerySaveDataInternalStorageTotalSize(out size, spaceId, saveDataId);
return fileSystemProxy.Get.QuerySaveDataInternalStorageTotalSize(out size, spaceId, saveDataId);
}
public static Result QuerySaveDataInternalStorageTotalSize(this FileSystemClient fs, out long size,
@ -1733,9 +1749,9 @@ namespace LibHac.Fs.Shim
{
UnsafeHelpers.SkipParamInit(out isValid);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.VerifySaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId,
Result rc = fileSystemProxy.Get.VerifySaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId,
new OutBuffer(workBuffer));
if (ResultFs.DataCorrupted.Includes(rc))
@ -1763,9 +1779,9 @@ namespace LibHac.Fs.Shim
public static Result CorruptSaveDataForDebug(this FileSystemClient fs, SaveDataSpaceId spaceId,
ulong saveDataId)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.CorruptSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId);
Result rc = fileSystemProxy.Get.CorruptSaveDataFileSystemBySaveDataSpaceId(spaceId, saveDataId);
fs.Impl.AbortIfNeeded(rc);
return rc;
@ -1774,9 +1790,9 @@ namespace LibHac.Fs.Shim
public static Result CorruptSaveDataForDebug(this FileSystemClient fs, SaveDataSpaceId spaceId,
ulong saveDataId, long offset)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.CorruptSaveDataFileSystemByOffset(spaceId, saveDataId, offset);
Result rc = fileSystemProxy.Get.CorruptSaveDataFileSystemByOffset(spaceId, saveDataId, offset);
fs.Impl.AbortIfNeeded(rc);
return rc;
@ -1784,9 +1800,9 @@ namespace LibHac.Fs.Shim
public static void DisableAutoSaveDataCreation(this FileSystemClient fs)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.DisableAutoSaveDataCreation();
Result rc = fileSystemProxy.Get.DisableAutoSaveDataCreation();
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
@ -1821,9 +1837,9 @@ namespace LibHac.Fs.Shim
if (index < 0)
return ResultFs.InvalidArgument.Log();
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return fsProxy.Target.DeleteCacheStorage((ushort)index);
return fileSystemProxy.Get.DeleteCacheStorage((ushort)index);
}
}
@ -1863,18 +1879,18 @@ namespace LibHac.Fs.Shim
return ResultFs.InvalidArgument.Log();
// Note: Nintendo gets the service object in the outer function and captures it for the inner function
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return fsProxy.Target.GetCacheStorageSize(out saveSize, out journalSize, (ushort)index);
return fileSystemProxy.Get.GetCacheStorageSize(out saveSize, out journalSize, (ushort)index);
}
}
public static Result UpdateSaveDataMacForDebug(this FileSystemClient fs, SaveDataSpaceId spaceId,
ulong saveDataId)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return fsProxy.Target.UpdateSaveDataMacForDebug(spaceId, saveDataId);
return fileSystemProxy.Get.UpdateSaveDataMacForDebug(spaceId, saveDataId);
}
public static Result ListApplicationAccessibleSaveDataOwnerId(this FileSystemClient fs, out int readCount,
@ -1886,12 +1902,12 @@ namespace LibHac.Fs.Shim
return Result.Success;
}
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
var programId = new ProgramId(applicationId.Value + (uint)programIndex);
var idOutBuffer = new OutBuffer(MemoryMarshal.Cast<Ncm.ApplicationId, byte>(idBuffer));
OutBuffer idOutBuffer = OutBuffer.FromSpan(idBuffer);
Result rc = fsProxy.Target.ListAccessibleSaveDataOwnerId(out readCount, idOutBuffer, programId, startIndex,
Result rc = fileSystemProxy.Get.ListAccessibleSaveDataOwnerId(out readCount, idOutBuffer, programId, startIndex,
idBuffer.Length);
fs.Impl.AbortIfNeeded(rc);
return rc;
@ -1913,7 +1929,7 @@ namespace LibHac.Fs.Shim
Tick end = fs.Hos.Os.GetSystemTick();
var sb = new U8StringBuilder(logBuffer, true);
sb.Append(LogName).Append(mountName).Append((byte)'"');
sb.Append(LogName).Append(mountName).Append(LogQuote);
fs.Impl.OutputAccessLogUnlessResultSuccess(rc, start, end, null, new U8Span(sb.Buffer));
}
@ -1936,7 +1952,7 @@ namespace LibHac.Fs.Shim
AccessLogImpl.DereferenceOutValue(in isRestoreFlagSet, rc));
var sb = new U8StringBuilder(logBuffer, true);
sb.Append(LogName).Append(mountName).Append((byte)'"')
sb.Append(LogName).Append(mountName).Append(LogQuote)
.Append(LogRestoreFlag).Append(isSetString);
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
@ -1975,13 +1991,13 @@ namespace LibHac.Fs.Shim
}
}
public static Result GetDeviceSaveDataSize(this FileSystemClientImpl fs, out long saveSize,
public static Result GetDeviceSaveDataSize(this FileSystemClient fs, out long saveSize,
out long journalSize, ApplicationId applicationId)
{
Result rc;
Span<byte> logBuffer = stackalloc byte[0x70];
if (fs.IsEnabledAccessLog() && fs.IsEnabledHandleAccessLog(null))
if (fs.Impl.IsEnabledAccessLog() && fs.Impl.IsEnabledHandleAccessLog(null))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = GetSize(fs, out saveSize, out journalSize, applicationId);
@ -1993,17 +2009,17 @@ namespace LibHac.Fs.Shim
.Append(LogSaveDataJournalSize)
.AppendFormat(AccessLogImpl.DereferenceOutValue(in journalSize, rc), 'd');
fs.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
}
else
{
rc = GetSize(fs, out saveSize, out journalSize, applicationId);
}
fs.AbortIfNeeded(rc);
fs.Impl.AbortIfNeeded(rc);
return rc;
static Result GetSize(FileSystemClientImpl fs, out long saveSize, out long journalSize,
static Result GetSize(FileSystemClient fs, out long saveSize, out long journalSize,
ApplicationId applicationId)
{
UnsafeHelpers.SkipParamInit(out saveSize, out journalSize);
@ -2016,7 +2032,7 @@ namespace LibHac.Fs.Shim
SaveDataType.Device, Fs.SaveData.InvalidUserId, 0);
if (rc.IsFailure()) return rc;
rc = fs.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, SaveDataSpaceId.User,
rc = fs.Impl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, SaveDataSpaceId.User,
in attribute, in extraDataMask);
if (rc.IsFailure()) return rc;

View File

@ -7,6 +7,7 @@ using LibHac.Fs.Impl;
using LibHac.FsSrv.Sf;
using LibHac.Os;
using static LibHac.Fs.Impl.AccessLogStrings;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
namespace LibHac.Fs.Shim
@ -14,25 +15,22 @@ namespace LibHac.Fs.Shim
[SkipLocalsInit]
public static class SdCard
{
private static Result OpenSdCardFileSystem(FileSystemClient fs,
out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
private static Result OpenSdCardFileSystem(FileSystemClient fs, ref SharedRef<IFileSystemSf> outFileSystem)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
return OpenFileSystem(fs, fsProxy, out fileSystem);
return OpenFileSystem(fs, ref fileSystemProxy.Ref(), ref outFileSystem);
static Result OpenFileSystem(FileSystemClient fs, ReferenceCountedDisposable<IFileSystemProxy> fsProxy,
out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
static Result OpenFileSystem(FileSystemClient fs, ref SharedRef<IFileSystemProxy> fileSystemProxy,
ref SharedRef<IFileSystemSf> outFileSystem)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
// Retry a few times if the storage device isn't ready yet
const int maxRetries = 10;
const int retryInterval = 1000;
for (int i = 0; i < maxRetries; i++)
{
Result rc = fsProxy.Target.OpenSdCardFileSystem(out fileSystem);
Result rc = fileSystemProxy.Get.OpenSdCardFileSystem(ref outFileSystem);
if (rc.IsSuccess())
break;
@ -51,10 +49,15 @@ namespace LibHac.Fs.Shim
}
private static Result RegisterFileSystem(FileSystemClient fs, U8Span mountName,
ReferenceCountedDisposable<IFileSystemSf> fileSystem)
ref SharedRef<IFileSystemSf> fileSystem)
{
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
return fs.Register(mountName, fileSystemAdapter);
using var fileSystemAdapter =
new UniqueRef<IFileSystem>(new FileSystemServiceObjectAdapter(ref fileSystem));
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInSdCardA.Log();
return fs.Register(mountName, ref fileSystemAdapter.Ref());
}
public static Result MountSdCard(this FileSystemClient fs, U8Span mountName)
@ -79,79 +82,69 @@ namespace LibHac.Fs.Shim
{
rc = fs.Impl.CheckMountName(mountName);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
// Open the SD card file system
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
using var fileSystem = new SharedRef<IFileSystemSf>();
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
{
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = OpenSdCardFileSystem(fs, out fileSystem);
Tick end = fs.Hos.Os.GetSystemTick();
Tick start = fs.Hos.Os.GetSystemTick();
rc = OpenSdCardFileSystem(fs, ref fileSystem.Ref());
Tick end = fs.Hos.Os.GetSystemTick();
fs.Impl.OutputAccessLogUnlessResultSuccess(rc, start, end, null, new U8Span(logBuffer));
}
else
{
rc = OpenSdCardFileSystem(fs, out fileSystem);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
// Mount the file system
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = RegisterFileSystem(fs, mountName, fileSystem);
Tick end = fs.Hos.Os.GetSystemTick();
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(logBuffer));
}
else
{
rc = RegisterFileSystem(fs, mountName, fileSystem);
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return Result.Success;
fs.Impl.OutputAccessLogUnlessResultSuccess(rc, start, end, null, new U8Span(logBuffer));
}
finally
else
{
fileSystem?.Dispose();
rc = OpenSdCardFileSystem(fs, ref fileSystem.Ref());
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
// Mount the file system
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = RegisterFileSystem(fs, mountName, ref fileSystem.Ref());
Tick end = fs.Hos.Os.GetSystemTick();
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(logBuffer));
}
else
{
rc = RegisterFileSystem(fs, mountName, ref fileSystem.Ref());
}
fs.Impl.AbortIfNeeded(rc);
if (rc.IsFailure()) return rc;
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return Result.Success;
}
public static bool IsSdCardInserted(this FileSystemClient fs)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
using var deviceOperator = new SharedRef<IDeviceOperator>();
ReferenceCountedDisposable<IDeviceOperator> deviceOperator = null;
try
{
Result rc = fsProxy.Target.OpenDeviceOperator(out deviceOperator);
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
Result rc = fileSystemProxy.Get.OpenDeviceOperator(ref deviceOperator.Ref());
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
rc = CheckIfInserted(fs, deviceOperator, out bool isInserted);
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
rc = CheckIfInserted(fs, ref deviceOperator.Ref(), out bool isInserted);
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
return isInserted;
}
finally
{
deviceOperator?.Dispose();
}
return isInserted;
static Result CheckIfInserted(FileSystemClient fs,
ReferenceCountedDisposable<IDeviceOperator> deviceOperator, out bool isInserted)
static Result CheckIfInserted(FileSystemClient fs, ref SharedRef<IDeviceOperator> deviceOperator,
out bool isInserted)
{
UnsafeHelpers.SkipParamInit(out isInserted);
@ -161,7 +154,7 @@ namespace LibHac.Fs.Shim
for (int i = 0; i < maxRetries; i++)
{
Result rc = deviceOperator.Target.IsSdCardInserted(out isInserted);
Result rc = deviceOperator.Get.IsSdCardInserted(out isInserted);
if (rc.IsSuccess())
break;
@ -181,9 +174,9 @@ namespace LibHac.Fs.Shim
public static Result SetSdCardEncryptionSeed(this FileSystemClient fs, in EncryptionSeed seed)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.SetSdCardEncryptionSeed(in seed);
Result rc = fileSystemProxy.Get.SetSdCardEncryptionSeed(in seed);
fs.Impl.AbortIfNeeded(rc);
return rc;
}
@ -197,9 +190,9 @@ namespace LibHac.Fs.Shim
public static bool IsSdCardAccessible(this FileSystemClient fs)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.IsSdCardAccessible(out bool isAccessible);
Result rc = fileSystemProxy.Get.IsSdCardAccessible(out bool isAccessible);
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnless(rc.IsSuccess());
@ -208,9 +201,9 @@ namespace LibHac.Fs.Shim
public static Result SetSdCardAccessibility(this FileSystemClientImpl fs, bool isAccessible)
{
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = fsProxy.Target.SetSdCardAccessibility(isAccessible);
Result rc = fileSystemProxy.Get.SetSdCardAccessibility(isAccessible);
fs.AbortIfNeeded(rc);
return rc;
}

View File

@ -6,6 +6,7 @@ using LibHac.Fs.Impl;
using LibHac.FsSrv.Sf;
using LibHac.Os;
using static LibHac.Fs.Impl.AccessLogStrings;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
namespace LibHac.Fs.Shim
@ -65,32 +66,32 @@ namespace LibHac.Fs.Shim
Result rc = fs.Impl.CheckMountName(mountName);
if (rc.IsFailure()) return rc;
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = fs.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, Fs.SaveData.InvalidProgramId,
SaveDataType.System, userId, saveDataId);
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<IFileSystemSf> fileSystem = null;
try
using var fileSystem = new SharedRef<IFileSystemSf>();
rc = fileSystemProxy.Get.OpenSaveDataFileSystemBySystemSaveDataId(ref fileSystem.Ref(), spaceId, in attribute);
if (rc.IsFailure()) return rc;
var fileSystemAdapterRaw = new FileSystemServiceObjectAdapter(ref fileSystem.Ref());
using var fileSystemAdapter = new UniqueRef<IFileSystem>(fileSystemAdapterRaw);
if (!fileSystemAdapter.HasValue)
return ResultFs.AllocationMemoryFailedInSystemSaveDataA.Log();
if (spaceId == SaveDataSpaceId.System)
{
rc = fsProxy.Target.OpenSaveDataFileSystemBySystemSaveDataId(out fileSystem, spaceId, in attribute);
if (rc.IsFailure()) return rc;
var fileSystemAdapter = new FileSystemServiceObjectAdapter(fileSystem);
if (spaceId == SaveDataSpaceId.System)
{
return fs.Register(mountName, fileSystemAdapter, fileSystemAdapter, null, false, false);
}
else
{
return fs.Register(mountName, fileSystemAdapter);
}
using var mountNameGenerator = new UniqueRef<ICommonMountNameGenerator>();
return fs.Register(mountName, fileSystemAdapterRaw, ref fileSystemAdapter.Ref(),
ref mountNameGenerator.Ref(), false, false);
}
finally
else
{
fileSystem?.Dispose();
return fs.Register(mountName, ref fileSystemAdapter.Ref());
}
}
}

View File

@ -21,51 +21,35 @@ namespace LibHac.Fs
/// </remarks>
public class SubStorage : IStorage
{
private ReferenceCountedDisposable<IStorage> SharedBaseStorage { get; set; }
protected IStorage BaseStorage { get; private set; }
private long Offset { get; set; }
private long Size { get; set; }
private bool IsResizable { get; set; }
private SharedRef<IStorage> _sharedBaseStorage;
protected IStorage BaseStorage;
private long _offset;
private long _size;
private bool _isResizable;
/// <summary>
/// Creates an uninitialized <see cref="SubStorage"/>. It must be initialized with <see cref="InitializeFrom"/> before using.
/// Creates an uninitialized <see cref="SubStorage"/>. It must be initialized with <see cref="Set"/> before using.
/// </summary>
public SubStorage()
{
BaseStorage = null;
Offset = 0;
Size = 0;
IsResizable = false;
_offset = 0;
_size = 0;
_isResizable = false;
}
/// <summary>
/// Creates a copy of <paramref name="other"/>.
/// Initializes a new <see cref="SubStorage"/> as a copy of <paramref name="other"/>.
/// <paramref name="other"/> will not be disposed when the created <see cref="SubStorage"/> is disposed.
/// </summary>
/// <param name="other">The <see cref="SubStorage"/> to create a copy of. Caller retains ownership.</param>
/// <param name="other">The <see cref="SubStorage"/> to create a copy of.</param>
public SubStorage(SubStorage other)
{
BaseStorage = other.BaseStorage;
Offset = other.Offset;
Size = other.Size;
IsResizable = other.IsResizable;
}
/// <summary>
/// Initializes or reinitializes this <see cref="SubStorage"/> as a copy of <paramref name="other"/>.
/// Any shared references in <paramref name="other"/> will be copied.
/// </summary>
/// <param name="other">The <see cref="SubStorage"/> used to initialize this one.</param>
public void InitializeFrom(SubStorage other)
{
if (this != other)
{
SharedBaseStorage = other.SharedBaseStorage.AddReference();
BaseStorage = other.BaseStorage;
Offset = other.Offset;
Size = other.Size;
IsResizable = other.IsResizable;
}
_offset = other._offset;
_size = other._size;
_isResizable = other._isResizable;
_sharedBaseStorage = SharedRef<IStorage>.CreateCopy(ref other._sharedBaseStorage);
}
/// <summary>
@ -74,46 +58,27 @@ namespace LibHac.Fs
/// </summary>
/// <param name="baseStorage">The base <see cref="IStorage"/>. Caller retains ownership.</param>
/// <param name="offset">The offset in the base storage at which to begin the created SubStorage.</param>
/// <param name="size">The size of the SubStorage.</param>
/// <param name="size">The size of the created SubStorage.</param>
public SubStorage(IStorage baseStorage, long offset, long size)
{
BaseStorage = baseStorage;
Offset = offset;
Size = size;
IsResizable = false;
_offset = offset;
_size = size;
_isResizable = false;
Assert.SdkRequiresNotNull(baseStorage);
Assert.SdkRequiresLessEqual(0, Offset);
Assert.SdkRequiresLessEqual(0, Size);
}
/// <summary>
/// Creates a <see cref="SubStorage"/> from a subsection of another <see cref="IStorage"/>.
/// Holds a reference to <paramref name="sharedBaseStorage"/> until disposed.
/// </summary>
/// <param name="sharedBaseStorage">The base IStorage.</param>
/// <param name="offset">The offset in the base storage at which to begin the created SubStorage.</param>
/// <param name="size">The size of the SubStorage.</param>
public SubStorage(ReferenceCountedDisposable<IStorage> sharedBaseStorage, long offset, long size)
{
SharedBaseStorage = sharedBaseStorage.AddReference();
BaseStorage = SharedBaseStorage.Target;
Offset = offset;
Size = size;
IsResizable = false;
Assert.SdkRequiresNotNull(sharedBaseStorage);
Assert.SdkRequiresLessEqual(0, Offset);
Assert.SdkRequiresLessEqual(0, Size);
Assert.SdkRequiresLessEqual(0, offset);
Assert.SdkRequiresLessEqual(0, size);
}
/// <summary>
/// Creates a <see cref="SubStorage"/> from a subsection of another <see cref="SubStorage"/>.
/// <paramref name="other"/> will not be disposed when the created <see cref="SubStorage"/> is disposed.
/// Any shared references to the base <see cref="IStorage"/> will be copied over.
/// </summary>
/// <remarks>
/// The created SubStorage will directly use the base SubStorage of <paramref name="other"/> and will
/// adjust the <paramref name="offset"/> and <paramref name="size"/> accordingly.
/// The created SubStorage will directly use the base <see cref="IStorage"/> of <paramref name="other"/>
/// and will adjust the <paramref name="offset"/> and <paramref name="size"/> accordingly.
/// This avoids the overhead of going through two SubStorage layers.
/// </remarks>
/// <param name="other">The base SubStorage.</param>
@ -122,14 +87,58 @@ namespace LibHac.Fs
public SubStorage(SubStorage other, long offset, long size)
{
BaseStorage = other.BaseStorage;
Offset = other.Offset + offset;
Size = size;
IsResizable = false;
_offset = other._offset + offset;
_size = size;
_isResizable = false;
_sharedBaseStorage = SharedRef<IStorage>.CreateCopy(ref other._sharedBaseStorage);
Assert.SdkRequiresLessEqual(0, offset);
Assert.SdkRequiresLessEqual(0, size);
Assert.SdkRequires(other.IsValid());
Assert.SdkRequiresLessEqual(0, Offset);
Assert.SdkRequiresLessEqual(0, Size);
Assert.SdkRequiresGreaterEqual(other.Size, offset + size);
Assert.SdkRequiresGreaterEqual(other._size, offset + size);
}
/// <summary>
/// Creates a <see cref="SubStorage"/> from a subsection of another <see cref="IStorage"/>.
/// Holds a reference to <paramref name="baseStorage"/> until disposed.
/// </summary>
/// <param name="baseStorage">The base <see cref="IStorage"/>.</param>
/// <param name="offset">The offset in the base storage at which to begin the created SubStorage.</param>
/// <param name="size">The size of the created SubStorage.</param>
public SubStorage(ref SharedRef<IStorage> baseStorage, long offset, long size)
{
BaseStorage = _sharedBaseStorage.Get;
_offset = offset;
_size = size;
_isResizable = false;
_sharedBaseStorage = SharedRef<IStorage>.CreateCopy(ref baseStorage);
Assert.SdkRequiresNotNull(baseStorage.Get);
Assert.SdkRequiresLessEqual(0, _offset);
Assert.SdkRequiresLessEqual(0, _size);
}
public override void Dispose()
{
_sharedBaseStorage.Destroy();
base.Dispose();
}
/// <summary>
/// Sets this <see cref="SubStorage"/> to be a copy of <paramref name="other"/>.
/// Any shared references in <paramref name="other"/> will be copied.
/// </summary>
/// <param name="other">The <see cref="SubStorage"/> used to initialize this one.</param>
public void Set(SubStorage other)
{
if (this != other)
{
BaseStorage = other.BaseStorage;
_offset = other._offset;
_size = other._size;
_isResizable = other._isResizable;
_sharedBaseStorage.SetByCopy(ref other._sharedBaseStorage);
}
}
private bool IsValid() => BaseStorage != null;
@ -141,7 +150,7 @@ namespace LibHac.Fs
/// be resizable. <see langword="false"/> if not.</param>
public void SetResizable(bool isResizable)
{
IsResizable = isResizable;
_isResizable = isResizable;
}
protected override Result DoRead(long offset, Span<byte> destination)
@ -149,9 +158,10 @@ namespace LibHac.Fs
if (!IsValid()) return ResultFs.NotInitialized.Log();
if (destination.Length == 0) return Result.Success;
if (!IsRangeValid(offset, destination.Length, Size)) return ResultFs.OutOfRange.Log();
if (!CheckAccessRange(offset, destination.Length, _size))
return ResultFs.OutOfRange.Log();
return BaseStorage.Read(Offset + offset, destination);
return BaseStorage.Read(_offset + offset, destination);
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source)
@ -159,9 +169,10 @@ namespace LibHac.Fs
if (!IsValid()) return ResultFs.NotInitialized.Log();
if (source.Length == 0) return Result.Success;
if (!IsRangeValid(offset, source.Length, Size)) return ResultFs.OutOfRange.Log();
if (!CheckAccessRange(offset, source.Length, _size))
return ResultFs.OutOfRange.Log();
return BaseStorage.Write(Offset + offset, source);
return BaseStorage.Write(_offset + offset, source);
}
protected override Result DoFlush()
@ -174,22 +185,22 @@ namespace LibHac.Fs
protected override Result DoSetSize(long size)
{
if (!IsValid()) return ResultFs.NotInitialized.Log();
if (!IsResizable) return ResultFs.UnsupportedSetSizeForNotResizableSubStorage.Log();
if (!IsOffsetAndSizeValid(Offset, size)) return ResultFs.InvalidSize.Log();
if (!_isResizable) return ResultFs.UnsupportedSetSizeForNotResizableSubStorage.Log();
if (!CheckOffsetAndSize(_offset, size)) return ResultFs.InvalidSize.Log();
Result rc = BaseStorage.GetSize(out long currentSize);
if (rc.IsFailure()) return rc;
if (currentSize != Offset + Size)
if (currentSize != _offset + _size)
{
// SubStorage cannot be resized unless it is located at the end of the base storage.
return ResultFs.UnsupportedSetSizeForResizableSubStorage.Log();
}
rc = BaseStorage.SetSize(Offset + size);
rc = BaseStorage.SetSize(_offset + size);
if (rc.IsFailure()) return rc;
Size = size;
_size = size;
return Result.Success;
}
@ -199,30 +210,17 @@ namespace LibHac.Fs
if (!IsValid()) return ResultFs.NotInitialized.Log();
size = Size;
size = _size;
return Result.Success;
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan<byte> inBuffer)
{
if (!IsValid()) return ResultFs.NotInitialized.Log();
if (size == 0) return Result.Success;
if (!CheckOffsetAndSize(_offset, size)) return ResultFs.OutOfRange.Log();
if (!IsOffsetAndSizeValid(Offset, size)) return ResultFs.OutOfRange.Log();
return base.DoOperateRange(outBuffer, operationId, Offset + offset, size, inBuffer);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
SharedBaseStorage?.Dispose();
SharedBaseStorage = null;
}
base.Dispose(disposing);
return base.DoOperateRange(outBuffer, operationId, _offset + offset, size, inBuffer);
}
}
}

View File

@ -22,23 +22,21 @@ namespace LibHac.FsSrv
return _serviceImpl.GetProgramInfo(out programInfo, _processId);
}
public Result OpenAccessFailureDetectionEventNotifier(out ReferenceCountedDisposable<IEventNotifier> notifier,
public Result OpenAccessFailureDetectionEventNotifier(ref SharedRef<IEventNotifier> outNotifier,
ulong processId, bool notifyOnDeepRetry)
{
UnsafeHelpers.SkipParamInit(out notifier);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.OpenAccessFailureDetectionEventNotifier))
return ResultFs.PermissionDenied.Log();
using var tempNotifier = new UniqueRef<IEventNotifier>();
using var notifier = new UniqueRef<IEventNotifier>();
rc = _serviceImpl.CreateNotifier(ref tempNotifier.Ref(), processId, notifyOnDeepRetry);
rc = _serviceImpl.CreateNotifier(ref notifier.Ref(), processId, notifyOnDeepRetry);
if (rc.IsFailure()) return rc;
notifier = new ReferenceCountedDisposable<IEventNotifier>(tempNotifier.Release());
outNotifier.Set(ref notifier.Ref());
return Result.Success;
}

View File

@ -8,6 +8,7 @@ using LibHac.Sf;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
using IFileSystemSf = LibHac.FsSrv.Sf.IFileSystem;
using Path = LibHac.Fs.Path;
using Utility = LibHac.FsSrv.Impl.Utility;
namespace LibHac.FsSrv
{
@ -57,38 +58,36 @@ namespace LibHac.FsSrv
return Result.Success;
}
public Result OpenBaseFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
BaseFileSystemId fileSystemId)
public Result OpenBaseFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, BaseFileSystemId fileSystemId)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
Result rc = CheckCapabilityById(fileSystemId, _processId);
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<IFileSystem> fs = null;
// Open the file system
using var fileSystem = new SharedRef<IFileSystem>();
rc = _serviceImpl.OpenBaseFileSystem(ref fileSystem.Ref(), fileSystemId);
if (rc.IsFailure()) return rc;
try
{
// Open the file system
rc = _serviceImpl.OpenBaseFileSystem(out fs, fileSystemId);
if (rc.IsFailure()) return rc;
// Create an SF adapter for the file system
using SharedRef<IFileSystemSf> fileSystemAdapter =
FileSystemInterfaceAdapter.CreateShared(ref fileSystem.Ref(), false);
// Create an SF adapter for the file system
fileSystem = FileSystemInterfaceAdapter.CreateShared(ref fs, false);
outFileSystem.SetByMove(ref fileSystemAdapter.Ref());
return Result.Success;
}
finally
{
fs?.Dispose();
}
return Result.Success;
}
public Result OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystemSf> outFileSystem, in FspPath rootPath,
public Result FormatBaseFileSystem(BaseFileSystemId fileSystemId)
{
Result rc = CheckCapabilityById(fileSystemId, _processId);
if (rc.IsFailure()) return rc;
return _serviceImpl.FormatBaseFileSystem(fileSystemId);
}
public Result OpenBisFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, in FspPath rootPath,
BisPartitionId partitionId)
{
UnsafeHelpers.SkipParamInit(out outFileSystem);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
@ -126,32 +125,29 @@ namespace LibHac.FsSrv
rc = pathNormalized.Normalize(pathFlags);
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<IFileSystem> baseFileSystem = null;
ReferenceCountedDisposable<IFileSystem> fileSystem = null;
// Open the file system
using var fileSystem = new SharedRef<IFileSystem>();
rc = _serviceImpl.OpenBisFileSystem(ref fileSystem.Ref(), partitionId, false);
if (rc.IsFailure()) return rc;
try
{
// Open the file system
rc = _serviceImpl.OpenBisFileSystem(out baseFileSystem, partitionId, false);
if (rc.IsFailure()) return rc;
using var subDirFileSystem = new SharedRef<IFileSystem>();
rc = Utility.CreateSubDirectoryFileSystem(ref subDirFileSystem.Ref(), ref fileSystem.Ref(),
in pathNormalized);
if (rc.IsFailure()) return rc;
rc = Utility.CreateSubDirectoryFileSystem(out fileSystem, ref baseFileSystem, in pathNormalized);
if (rc.IsFailure()) return rc;
// Add all the file system wrappers
using var typeSetFileSystem =
new SharedRef<IFileSystem>(new StorageLayoutTypeSetFileSystem(ref subDirFileSystem.Ref(), storageFlag));
// Add all the file system wrappers
fileSystem = StorageLayoutTypeSetFileSystem.CreateShared(ref fileSystem, storageFlag);
fileSystem = AsynchronousAccessFileSystem.CreateShared(ref fileSystem);
using var asyncFileSystem =
new SharedRef<IFileSystem>(new AsynchronousAccessFileSystem(ref typeSetFileSystem.Ref()));
// Create an SF adapter for the file system
outFileSystem = FileSystemInterfaceAdapter.CreateShared(ref fileSystem, false);
using SharedRef<IFileSystemSf> fileSystemAdapter =
FileSystemInterfaceAdapter.CreateShared(ref asyncFileSystem.Ref(), false);
return Result.Success;
}
finally
{
baseFileSystem?.Dispose();
fileSystem?.Dispose();
}
outFileSystem.SetByMove(ref fileSystemAdapter.Ref());
return Result.Success;
}
public Result SetBisRootForHost(BisPartitionId partitionId, in FspPath path)
@ -187,39 +183,33 @@ namespace LibHac.FsSrv
return _serviceImpl.DeleteAllPaddingFiles();
}
public Result OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, GameCardHandle handle,
public Result OpenGameCardFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, GameCardHandle handle,
GameCardPartition partitionId)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.MountGameCard).CanRead)
return ResultFs.PermissionDenied.Log();
ReferenceCountedDisposable<IFileSystem> fs = null;
using var fileSystem = new SharedRef<IFileSystem>();
try
{
rc = _serviceImpl.OpenGameCardFileSystem(out fs, handle, partitionId);
if (rc.IsFailure()) return rc;
rc = _serviceImpl.OpenGameCardFileSystem(ref fileSystem.Ref(), handle, partitionId);
if (rc.IsFailure()) return rc;
// Create an SF adapter for the file system
fileSystem = FileSystemInterfaceAdapter.CreateShared(ref fs, false);
using var asyncFileSystem =
new SharedRef<IFileSystem>(new AsynchronousAccessFileSystem(ref fileSystem.Ref()));
return Result.Success;
}
finally
{
fs?.Dispose();
}
using SharedRef<IFileSystemSf> fileSystemAdapter =
FileSystemInterfaceAdapter.CreateShared(ref asyncFileSystem.Ref(), false);
outFileSystem.SetByMove(ref fileSystemAdapter.Ref());
return Result.Success;
}
public Result OpenSdCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
public Result OpenSdCardFileSystem(ref SharedRef<IFileSystemSf> outFileSystem)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
@ -228,22 +218,26 @@ namespace LibHac.FsSrv
if (!accessibility.CanRead || !accessibility.CanWrite)
return ResultFs.PermissionDenied.Log();
ReferenceCountedDisposable<IFileSystem> fs = null;
const StorageType storageFlag = StorageType.Bis;
using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag);
try
{
rc = _serviceImpl.OpenSdCardProxyFileSystem(out fs);
if (rc.IsFailure()) return rc;
using var fileSystem = new SharedRef<IFileSystem>();
rc = _serviceImpl.OpenSdCardProxyFileSystem(ref fileSystem.Ref());
if (rc.IsFailure()) return rc;
// Create an SF adapter for the file system
fileSystem = FileSystemInterfaceAdapter.CreateShared(ref fs, false);
// Add all the file system wrappers
using var typeSetFileSystem =
new SharedRef<IFileSystem>(new StorageLayoutTypeSetFileSystem(ref fileSystem.Ref(), storageFlag));
return Result.Success;
}
finally
{
fs?.Dispose();
}
using var asyncFileSystem =
new SharedRef<IFileSystem>(new AsynchronousAccessFileSystem(ref typeSetFileSystem.Ref()));
using SharedRef<IFileSystemSf> fileSystemAdapter =
FileSystemInterfaceAdapter.CreateShared(ref asyncFileSystem.Ref(), false);
outFileSystem.SetByMove(ref fileSystemAdapter.Ref());
return Result.Success;
}
public Result FormatSdCardFileSystem()
@ -273,11 +267,9 @@ namespace LibHac.FsSrv
return Result.Success;
}
public Result OpenImageDirectoryFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenImageDirectoryFileSystem(ref SharedRef<IFileSystemSf> outFileSystem,
ImageDirectoryId directoryId)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
// Caller must have the MountImageAndVideoStorage permission
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
@ -301,28 +293,22 @@ namespace LibHac.FsSrv
default:
return ResultFs.InvalidArgument.Log();
}
ReferenceCountedDisposable<IFileSystem> fs = null;
try
{
rc = _serviceImpl.OpenBaseFileSystem(out fs, fileSystemId);
if (rc.IsFailure()) return rc;
using var baseFileSystem = new SharedRef<IFileSystem>();
rc = _serviceImpl.OpenBaseFileSystem(ref baseFileSystem.Ref(), fileSystemId);
if (rc.IsFailure()) return rc;
// Create an SF adapter for the file system
fileSystem = FileSystemInterfaceAdapter.CreateShared(ref fs, false);
using SharedRef<IFileSystemSf> fileSystemAdapter =
FileSystemInterfaceAdapter.CreateShared(ref baseFileSystem.Ref(), false);
return Result.Success;
}
finally
{
fs?.Dispose();
}
outFileSystem.SetByMove(ref fileSystemAdapter.Ref());
return Result.Success;
}
public Result OpenBisWiper(out ReferenceCountedDisposable<IWiper> bisWiper, NativeHandle transferMemoryHandle, ulong transferMemorySize)
public Result OpenBisWiper(ref SharedRef<IWiper> outBisWiper, NativeHandle transferMemoryHandle,
ulong transferMemorySize)
{
UnsafeHelpers.SkipParamInit(out bisWiper);
// Caller must have the OpenBisWiper permission
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
@ -330,10 +316,12 @@ namespace LibHac.FsSrv
if (!programInfo.AccessControl.CanCall(OperationType.OpenBisWiper))
return ResultFs.PermissionDenied.Log();
rc = _serviceImpl.OpenBisWiper(out IWiper wiper, transferMemoryHandle, transferMemorySize);
using var bisWiper = new UniqueRef<IWiper>();
rc = _serviceImpl.OpenBisWiper(ref bisWiper.Ref(), transferMemoryHandle, transferMemorySize);
if (rc.IsFailure()) return rc;
bisWiper = new ReferenceCountedDisposable<IWiper>(wiper);
outBisWiper.Set(ref bisWiper.Ref());
return Result.Success;
}
}

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSrv.FsCreator;
using LibHac.FsSrv.Impl;
@ -12,7 +13,7 @@ namespace LibHac.FsSrv
{
private Configuration _config;
public delegate Result BisWiperCreator(out IWiper wiper, NativeHandle transferMemoryHandle,
public delegate Result BisWiperCreator(ref UniqueRef<IWiper> outWiper, NativeHandle transferMemoryHandle,
ulong transferMemorySize);
public BaseFileSystemServiceImpl(in Configuration configuration)
@ -34,23 +35,26 @@ namespace LibHac.FsSrv
public FileSystemServer FsServer;
}
public Result OpenBaseFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
BaseFileSystemId fileSystemId)
public Result OpenBaseFileSystem(ref SharedRef<IFileSystem> outFileSystem, BaseFileSystemId fileSystemId)
{
throw new NotImplementedException();
}
public Result OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
BisPartitionId partitionId)
public Result FormatBaseFileSystem(BaseFileSystemId fileSystemId)
{
return OpenBisFileSystem(out fileSystem, partitionId, false);
throw new NotImplementedException();
}
public Result OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
BisPartitionId partitionId, bool caseSensitive)
public Result OpenBisFileSystem(ref SharedRef<IFileSystem> outFileSystem, BisPartitionId partitionId)
{
Result rc = _config.BisFileSystemCreator.Create(out fileSystem, partitionId, caseSensitive);
if (rc.IsFailure()) return rc;
return OpenBisFileSystem(ref outFileSystem, partitionId, false);
}
public Result OpenBisFileSystem(ref SharedRef<IFileSystem> outFileSystem, BisPartitionId partitionId,
bool caseSensitive)
{
Result rc = _config.BisFileSystemCreator.Create(ref outFileSystem, partitionId, caseSensitive);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
@ -65,33 +69,31 @@ namespace LibHac.FsSrv
throw new NotImplementedException();
}
public Result OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, GameCardHandle handle,
public Result OpenGameCardFileSystem(ref SharedRef<IFileSystem> outFileSystem, GameCardHandle handle,
GameCardPartition partitionId)
{
Result rc;
int tries = 0;
const int maxTries = 2;
Result rc = Result.Success;
do
for (int i = 0; i < maxTries; i++)
{
rc = _config.GameCardFileSystemCreator.Create(out fileSystem, handle, partitionId);
rc = _config.GameCardFileSystemCreator.Create(ref outFileSystem, handle, partitionId);
if (!ResultFs.DataCorrupted.Includes(rc))
break;
tries++;
} while (tries < 2);
}
return rc;
}
public Result OpenSdCardProxyFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem)
public Result OpenSdCardProxyFileSystem(ref SharedRef<IFileSystem> outFileSystem)
{
return OpenSdCardProxyFileSystem(out fileSystem, false);
return OpenSdCardProxyFileSystem(ref outFileSystem, false);
}
public Result OpenSdCardProxyFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, bool openCaseSensitive)
public Result OpenSdCardProxyFileSystem(ref SharedRef<IFileSystem> outFileSystem, bool openCaseSensitive)
{
return _config.SdCardFileSystemCreator.Create(out fileSystem, openCaseSensitive);
return _config.SdCardFileSystemCreator.Create(ref outFileSystem, openCaseSensitive);
}
public Result FormatSdCardProxyFileSystem()
@ -110,9 +112,10 @@ namespace LibHac.FsSrv
return false;
}
public Result OpenBisWiper(out IWiper wiper, NativeHandle transferMemoryHandle, ulong transferMemorySize)
public Result OpenBisWiper(ref UniqueRef<IWiper> outBisWiper, NativeHandle transferMemoryHandle,
ulong transferMemorySize)
{
return _config.BisWiperCreator(out wiper, transferMemoryHandle, transferMemorySize);
return _config.BisWiperCreator(ref outBisWiper, transferMemoryHandle, transferMemorySize);
}
internal Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)

View File

@ -21,135 +21,9 @@ namespace LibHac.FsSrv
_processId = processId;
}
public Result OpenBisStorage(out ReferenceCountedDisposable<IStorageSf> storage, BisPartitionId id)
{
UnsafeHelpers.SkipParamInit(out storage);
var storageFlag = StorageType.Bis;
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(storageFlag);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
rc = GetAccessibilityForOpenBisPartition(out Accessibility accessibility, programInfo, id);
if (rc.IsFailure()) return rc;
bool canAccess = accessibility.CanRead && accessibility.CanWrite;
if (!canAccess)
return ResultFs.PermissionDenied.Log();
ReferenceCountedDisposable<IStorage> tempStorage = null;
try
{
rc = _serviceImpl.OpenBisStorage(out tempStorage, id);
if (rc.IsFailure()) return rc;
tempStorage = StorageLayoutTypeSetStorage.CreateShared(ref tempStorage, storageFlag);
// Todo: Async storage
storage = StorageInterfaceAdapter.CreateShared(ref tempStorage);
return Result.Success;
}
finally
{
tempStorage?.Dispose();
}
}
public Result InvalidateBisCache()
{
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.InvalidateBisCache))
return ResultFs.PermissionDenied.Log();
return _serviceImpl.InvalidateBisCache();
}
public Result OpenGameCardStorage(out ReferenceCountedDisposable<IStorageSf> storage, GameCardHandle handle,
GameCardPartitionRaw partitionId)
{
UnsafeHelpers.SkipParamInit(out storage);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
Accessibility accessibility =
programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.OpenGameCardStorage);
bool canAccess = accessibility.CanRead && accessibility.CanWrite;
if (!canAccess)
return ResultFs.PermissionDenied.Log();
ReferenceCountedDisposable<IStorage> tempStorage = null;
try
{
rc = _serviceImpl.OpenGameCardPartition(out tempStorage, handle, partitionId);
if (rc.IsFailure()) return rc;
// Todo: Async storage
storage = StorageInterfaceAdapter.CreateShared(ref tempStorage);
return Result.Success;
}
finally
{
tempStorage?.Dispose();
}
}
public Result OpenDeviceOperator(out ReferenceCountedDisposable<IDeviceOperator> deviceOperator)
{
deviceOperator = _serviceImpl.Config.DeviceOperator.AddReference();
return Result.Success;
}
public Result OpenSdCardDetectionEventNotifier(out ReferenceCountedDisposable<IEventNotifier> eventNotifier)
{
UnsafeHelpers.SkipParamInit(out eventNotifier);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.OpenSdCardDetectionEventNotifier))
return ResultFs.PermissionDenied.Log();
throw new NotImplementedException();
}
public Result OpenGameCardDetectionEventNotifier(out ReferenceCountedDisposable<IEventNotifier> eventNotifier)
{
UnsafeHelpers.SkipParamInit(out eventNotifier);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.OpenGameCardDetectionEventNotifier))
return ResultFs.PermissionDenied.Log();
throw new NotImplementedException();
}
public Result SimulateDeviceDetectionEvent(SdmmcPort port, SimulatingDeviceDetectionMode mode, bool signalEvent)
{
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.SimulateDevice))
return ResultFs.PermissionDenied.Log();
throw new NotImplementedException();
}
private Result GetProgramInfo(out ProgramInfo programInfo)
{
var registry = new ProgramRegistryImpl(_serviceImpl.Config.FsServer);
return registry.GetProgramInfo(out programInfo, _processId);
return _serviceImpl.GetProgramInfo(out programInfo, _processId);
}
private static Result GetAccessibilityForOpenBisPartition(out Accessibility accessibility, ProgramInfo programInfo,
@ -184,15 +58,131 @@ namespace LibHac.FsSrv
accessibility = programInfo.AccessControl.GetAccessibilityFor(type);
return Result.Success;
}
public Result OpenBisStorage(ref SharedRef<IStorageSf> outStorage, BisPartitionId id)
{
var storageFlag = StorageType.Bis;
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(storageFlag);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
rc = GetAccessibilityForOpenBisPartition(out Accessibility accessibility, programInfo, id);
if (rc.IsFailure()) return rc;
bool canAccess = accessibility.CanRead && accessibility.CanWrite;
if (!canAccess)
return ResultFs.PermissionDenied.Log();
using var storage = new SharedRef<IStorage>();
rc = _serviceImpl.OpenBisStorage(ref storage.Ref(), id);
if (rc.IsFailure()) return rc;
using var typeSetStorage =
new SharedRef<IStorage>(new StorageLayoutTypeSetStorage(ref storage.Ref(), storageFlag));
// Todo: Async storage
using var storageAdapter =
new SharedRef<IStorageSf>(new StorageInterfaceAdapter(ref typeSetStorage.Ref()));
outStorage.SetByMove(ref storageAdapter.Ref());
return Result.Success;
}
public Result InvalidateBisCache()
{
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.InvalidateBisCache))
return ResultFs.PermissionDenied.Log();
return _serviceImpl.InvalidateBisCache();
}
public Result OpenGameCardStorage(ref SharedRef<IStorageSf> outStorage, GameCardHandle handle,
GameCardPartitionRaw partitionId)
{
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
Accessibility accessibility =
programInfo.AccessControl.GetAccessibilityFor(AccessibilityType.OpenGameCardStorage);
bool canAccess = accessibility.CanRead && accessibility.CanWrite;
if (!canAccess)
return ResultFs.PermissionDenied.Log();
using var storage = new SharedRef<IStorage>();
rc = _serviceImpl.OpenGameCardPartition(ref storage.Ref(), handle, partitionId);
if (rc.IsFailure()) return rc;
// Todo: Async storage
using var storageAdapter =
new SharedRef<IStorageSf>(new StorageInterfaceAdapter(ref storage.Ref()));
outStorage.SetByMove(ref storageAdapter.Ref());
return Result.Success;
}
public Result OpenDeviceOperator(ref SharedRef<IDeviceOperator> outDeviceOperator)
{
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc.Miss();
rc = _serviceImpl.OpenDeviceOperator(ref outDeviceOperator, programInfo.AccessControl);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
public Result OpenSdCardDetectionEventNotifier(ref SharedRef<IEventNotifier> outEventNotifier)
{
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.OpenSdCardDetectionEventNotifier))
return ResultFs.PermissionDenied.Log();
throw new NotImplementedException();
}
public Result OpenGameCardDetectionEventNotifier(ref SharedRef<IEventNotifier> outEventNotifier)
{
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.OpenGameCardDetectionEventNotifier))
return ResultFs.PermissionDenied.Log();
throw new NotImplementedException();
}
public Result SimulateDeviceDetectionEvent(SdmmcPort port, SimulatingDeviceDetectionMode mode, bool signalEvent)
{
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
if (!programInfo.AccessControl.CanCall(OperationType.SimulateDevice))
return ResultFs.PermissionDenied.Log();
throw new NotImplementedException();
}
}
public class BaseStorageServiceImpl
{
internal Configuration Config;
private Configuration _config;
public BaseStorageServiceImpl(in Configuration configuration)
{
Config = configuration;
_config = configuration;
}
public struct Configuration
@ -203,34 +193,47 @@ namespace LibHac.FsSrv
// LibHac additions
public FileSystemServer FsServer;
// Todo: The DeviceOperator in FS uses mostly global state. Decide how to handle this.
public ReferenceCountedDisposable<IDeviceOperator> DeviceOperator;
public SharedRef<IDeviceOperator> DeviceOperator;
}
public Result OpenBisStorage(out ReferenceCountedDisposable<IStorage> storage, BisPartitionId partitionId)
internal Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
{
return Config.BisStorageCreator.Create(out storage, partitionId);
var registry = new ProgramRegistryImpl(_config.FsServer);
return registry.GetProgramInfo(out programInfo, processId);
}
public Result OpenBisStorage(ref SharedRef<IStorage> outStorage, BisPartitionId partitionId)
{
return _config.BisStorageCreator.Create(ref outStorage, partitionId);
}
public Result InvalidateBisCache()
{
return Config.BisStorageCreator.InvalidateCache();
return _config.BisStorageCreator.InvalidateCache();
}
public Result OpenGameCardPartition(out ReferenceCountedDisposable<IStorage> storage, GameCardHandle handle,
public Result OpenGameCardPartition(ref SharedRef<IStorage> outStorage, GameCardHandle handle,
GameCardPartitionRaw partitionId)
{
switch (partitionId)
{
case GameCardPartitionRaw.NormalReadOnly:
return Config.GameCardStorageCreator.CreateReadOnly(handle, out storage);
return _config.GameCardStorageCreator.CreateReadOnly(handle, ref outStorage);
case GameCardPartitionRaw.SecureReadOnly:
return Config.GameCardStorageCreator.CreateSecureReadOnly(handle, out storage);
return _config.GameCardStorageCreator.CreateSecureReadOnly(handle, ref outStorage);
case GameCardPartitionRaw.RootWriteOnly:
return Config.GameCardStorageCreator.CreateWriteOnly(handle, out storage);
return _config.GameCardStorageCreator.CreateWriteOnly(handle, ref outStorage);
default:
UnsafeHelpers.SkipParamInit(out storage);
return ResultFs.InvalidArgument.Log();
}
}
// LibHac addition
internal Result OpenDeviceOperator(ref SharedRef<IDeviceOperator> outDeviceOperator,
AccessControl accessControl)
{
outDeviceOperator.SetByCopy(ref _config.DeviceOperator);
return Result.Success;
}
}
}

View File

@ -1,4 +1,5 @@
using LibHac.Common.Keys;
using LibHac.Common;
using LibHac.Common.Keys;
using LibHac.FsSrv.FsCreator;
using LibHac.FsSrv.Sf;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
@ -21,6 +22,10 @@ namespace LibHac.FsSrv
var gcStorageCreator = new EmulatedGameCardStorageCreator(gameCard);
using var sharedRootFileSystem = new SharedRef<IFileSystem>(rootFileSystem);
using SharedRef<IFileSystem> sharedRootFileSystemCopy =
SharedRef<IFileSystem>.CreateCopy(ref sharedRootFileSystem.Ref());
creators.RomFileSystemCreator = new RomFileSystemCreator();
creators.PartitionFileSystemCreator = new PartitionFileSystemCreator();
creators.StorageOnNcaCreator = new StorageOnNcaCreator(keySet);
@ -30,8 +35,8 @@ namespace LibHac.FsSrv
creators.GameCardStorageCreator = gcStorageCreator;
creators.GameCardFileSystemCreator = new EmulatedGameCardFsCreator(gcStorageCreator, gameCard);
creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keySet);
creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(rootFileSystem);
creators.SdCardFileSystemCreator = new EmulatedSdCardFileSystemCreator(sdCard, rootFileSystem);
creators.BuiltInStorageFileSystemCreator = new EmulatedBisFileSystemCreator(ref sharedRootFileSystem.Ref());
creators.SdCardFileSystemCreator = new EmulatedSdCardFileSystemCreator(sdCard, ref sharedRootFileSystemCopy.Ref());
var deviceOperator = new EmulatedDeviceOperator(gameCard, sdCard);

View File

@ -11,116 +11,103 @@ namespace LibHac.FsSrv
{
public class FileSystemProxyCoreImpl
{
private FileSystemCreatorInterfaces FsCreators { get; }
private BaseFileSystemServiceImpl BaseFileSystemService { get; }
private EncryptionSeed SdEncryptionSeed { get; set; }
private FileSystemCreatorInterfaces _fsCreators;
private BaseFileSystemServiceImpl _baseFileSystemService;
private EncryptionSeed _sdEncryptionSeed;
public FileSystemProxyCoreImpl(FileSystemCreatorInterfaces fsCreators, BaseFileSystemServiceImpl baseFsService)
{
FsCreators = fsCreators;
BaseFileSystemService = baseFsService;
_fsCreators = fsCreators;
_baseFileSystemService = baseFsService;
}
public Result OpenCloudBackupWorkStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
public Result OpenCloudBackupWorkStorageFileSystem(ref SharedRef<IFileSystem> outFileSystem,
CloudBackupWorkStorageId storageId)
{
throw new NotImplementedException();
}
public Result OpenCustomStorageFileSystem(out ReferenceCountedDisposable<IFileSystem> outFileSystem,
CustomStorageId storageId)
public Result OpenCustomStorageFileSystem(ref SharedRef<IFileSystem> outFileSystem, CustomStorageId storageId)
{
UnsafeHelpers.SkipParamInit(out outFileSystem);
// Hack around error CS8350.
const int pathBufferLength = 0x40;
Span<byte> buffer = stackalloc byte[pathBufferLength];
ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
Span<byte> pathBuffer = MemoryMarshal.CreateSpan(ref bufferRef, pathBufferLength);
ReferenceCountedDisposable<IFileSystem> fileSystem = null;
ReferenceCountedDisposable<IFileSystem> tempFs = null;
try
using var fileSystem = new SharedRef<IFileSystem>();
if (storageId == CustomStorageId.System)
{
// Hack around error CS8350.
const int pathBufferLength = 0x40;
Span<byte> buffer = stackalloc byte[pathBufferLength];
ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
Span<byte> pathBuffer = MemoryMarshal.CreateSpan(ref bufferRef, pathBufferLength);
Result rc = _baseFileSystemService.OpenBisFileSystem(ref fileSystem.Ref(), BisPartitionId.User);
if (rc.IsFailure()) return rc;
if (storageId == CustomStorageId.System)
{
Result rc = BaseFileSystemService.OpenBisFileSystem(out fileSystem, BisPartitionId.User);
if (rc.IsFailure()) return rc;
using var path = new Path();
rc = PathFunctions.SetUpFixedPathSingleEntry(ref path.Ref(), pathBuffer,
CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.System));
if (rc.IsFailure()) return rc;
using var path = new Path();
rc = PathFunctions.SetUpFixedPathSingleEntry(ref path.Ref(), pathBuffer,
CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.System));
if (rc.IsFailure()) return rc;
tempFs = Shared.Move(ref fileSystem);
rc = Utility.WrapSubDirectory(out fileSystem, ref tempFs, in path, true);
if (rc.IsFailure()) return rc;
}
else if (storageId == CustomStorageId.SdCard)
{
Result rc = BaseFileSystemService.OpenSdCardProxyFileSystem(out fileSystem);
if (rc.IsFailure()) return rc;
using var path = new Path();
rc = PathFunctions.SetUpFixedPathDoubleEntry(ref path.Ref(), pathBuffer,
CommonPaths.SdCardNintendoRootDirectoryName,
CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.System));
if (rc.IsFailure()) return rc;
tempFs = Shared.Move(ref fileSystem);
rc = Utility.WrapSubDirectory(out fileSystem, ref tempFs, in path, true);
if (rc.IsFailure()) return rc;
tempFs = Shared.Move(ref fileSystem);
rc = FsCreators.EncryptedFileSystemCreator.Create(out fileSystem, ref tempFs,
IEncryptedFileSystemCreator.KeyId.CustomStorage, SdEncryptionSeed);
if (rc.IsFailure()) return rc;
}
else
{
return ResultFs.InvalidArgument.Log();
}
outFileSystem = Shared.Move(ref fileSystem);
return Result.Success;
using SharedRef<IFileSystem> tempFs = SharedRef<IFileSystem>.CreateMove(ref fileSystem.Ref());
rc = Utility.WrapSubDirectory(ref fileSystem.Ref(), ref tempFs.Ref(), in path, createIfMissing: true);
if (rc.IsFailure()) return rc;
}
finally
else if (storageId == CustomStorageId.SdCard)
{
fileSystem?.Dispose();
tempFs?.Dispose();
Result rc = _baseFileSystemService.OpenSdCardProxyFileSystem(ref fileSystem.Ref());
if (rc.IsFailure()) return rc;
using var path = new Path();
rc = PathFunctions.SetUpFixedPathDoubleEntry(ref path.Ref(), pathBuffer,
CommonPaths.SdCardNintendoRootDirectoryName,
CustomStorage.GetCustomStorageDirectoryName(CustomStorageId.System));
if (rc.IsFailure()) return rc;
using SharedRef<IFileSystem> tempFs = SharedRef<IFileSystem>.CreateMove(ref fileSystem.Ref());
rc = Utility.WrapSubDirectory(ref fileSystem.Ref(), ref tempFs.Ref(), in path, createIfMissing: true);
if (rc.IsFailure()) return rc;
tempFs.SetByMove(ref fileSystem.Ref());
rc = _fsCreators.EncryptedFileSystemCreator.Create(ref fileSystem.Ref(), ref tempFs.Ref(),
IEncryptedFileSystemCreator.KeyId.CustomStorage, in _sdEncryptionSeed);
if (rc.IsFailure()) return rc;
}
else
{
return ResultFs.InvalidArgument.Log();
}
outFileSystem.SetByMove(ref fileSystem.Ref());
return Result.Success;
}
private Result OpenHostFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, in Path path)
private Result OpenHostFileSystem(ref SharedRef<IFileSystem> outFileSystem, in Path path)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
using var pathHost = new Path();
Result rc = pathHost.Initialize(in path);
if (rc.IsFailure()) return rc;
rc = FsCreators.TargetManagerFileSystemCreator.NormalizeCaseOfPath(out bool isSupported, ref pathHost.Ref());
rc = _fsCreators.TargetManagerFileSystemCreator.NormalizeCaseOfPath(out bool isSupported, ref pathHost.Ref());
if (rc.IsFailure()) return rc;
rc = FsCreators.TargetManagerFileSystemCreator.Create(out fileSystem, in pathHost, isSupported, false,
Result.Success);
rc = _fsCreators.TargetManagerFileSystemCreator.Create(ref outFileSystem, in pathHost, isSupported,
ensureRootPathExists: false, Result.Success);
if (rc.IsFailure()) return rc;
return Result.Success;
}
public Result OpenHostFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem, in Path path,
public Result OpenHostFileSystem(ref SharedRef<IFileSystem> outFileSystem, in Path path,
bool openCaseSensitive)
{
if (!path.IsEmpty() && openCaseSensitive)
{
Result rc = OpenHostFileSystem(out fileSystem, in path);
Result rc = OpenHostFileSystem(ref outFileSystem, in path);
if (rc.IsFailure()) return rc;
}
else
{
Result rc = FsCreators.TargetManagerFileSystemCreator.Create(out fileSystem, in path, openCaseSensitive,
false, Result.Success);
Result rc = _fsCreators.TargetManagerFileSystemCreator.Create(ref outFileSystem, in path,
openCaseSensitive, ensureRootPathExists: false, Result.Success);
if (rc.IsFailure()) return rc;
}
@ -129,7 +116,7 @@ namespace LibHac.FsSrv
public Result SetSdCardEncryptionSeed(in EncryptionSeed seed)
{
SdEncryptionSeed = seed;
_sdEncryptionSeed = seed;
return Result.Success;
}
}

View File

@ -52,78 +52,83 @@ namespace LibHac.FsSrv
public Optional<FileSystemProxyCoreImpl> FileSystemProxyCoreImpl;
}
/// <summary>
/// Dispatches calls to the main file system service interface.
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
public class FileSystemProxyImpl : IFileSystemProxy, IFileSystemProxyForLoader
{
private FileSystemServer FsServer { get; }
private ref FileSystemProxyImplGlobals Globals => ref FsServer.Globals.FileSystemProxyImpl;
private FileSystemProxyCoreImpl _fsProxyCore;
private SharedRef<NcaFileSystemService> _ncaFsService;
private SharedRef<SaveDataFileSystemService> _saveFsService;
private ulong _currentProcess;
private FileSystemProxyCoreImpl FsProxyCore { get; }
private ReferenceCountedDisposable<NcaFileSystemService> NcaFsService { get; set; }
private ReferenceCountedDisposable<SaveDataFileSystemService> SaveFsService { get; set; }
private ulong CurrentProcess { get; set; }
// LibHac addition
private FileSystemServer _fsServer;
private ref FileSystemProxyImplGlobals Globals => ref _fsServer.Globals.FileSystemProxyImpl;
internal FileSystemProxyImpl(FileSystemServer server)
{
FsServer = server;
_fsServer = server;
FsProxyCore = Globals.FileSystemProxyCoreImpl.Value;
CurrentProcess = ulong.MaxValue;
_fsProxyCore = Globals.FileSystemProxyCoreImpl.Value;
_currentProcess = ulong.MaxValue;
}
public void Dispose()
{
NcaFsService?.Dispose();
SaveFsService?.Dispose();
_ncaFsService.Destroy();
_saveFsService.Destroy();
}
private Result GetProgramInfo(out ProgramInfo programInfo)
{
var registry = new ProgramRegistryImpl(FsServer);
return registry.GetProgramInfo(out programInfo, CurrentProcess);
var registry = new ProgramRegistryImpl(_fsServer);
return registry.GetProgramInfo(out programInfo, _currentProcess);
}
private Result GetNcaFileSystemService(out NcaFileSystemService ncaFsService)
{
if (NcaFsService is null)
if (!_ncaFsService.HasValue)
{
UnsafeHelpers.SkipParamInit(out ncaFsService);
return ResultFs.PreconditionViolation.Log();
}
ncaFsService = NcaFsService.Target;
ncaFsService = _ncaFsService.Get;
return Result.Success;
}
private Result GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService)
{
if (SaveFsService is null)
if (!_saveFsService.HasValue)
{
UnsafeHelpers.SkipParamInit(out saveFsService);
return ResultFs.PreconditionViolation.Log();
}
saveFsService = SaveFsService.Target;
saveFsService = _saveFsService.Get;
return Result.Success;
}
private BaseStorageService GetBaseStorageService()
{
return new BaseStorageService(Globals.BaseStorageServiceImpl, CurrentProcess);
return new BaseStorageService(Globals.BaseStorageServiceImpl, _currentProcess);
}
private BaseFileSystemService GetBaseFileSystemService()
{
return new BaseFileSystemService(Globals.BaseFileSystemServiceImpl, CurrentProcess);
return new BaseFileSystemService(Globals.BaseFileSystemServiceImpl, _currentProcess);
}
private AccessFailureManagementService GetAccessFailureManagementService()
{
return new AccessFailureManagementService(Globals.AccessFailureManagementServiceImpl, CurrentProcess);
return new AccessFailureManagementService(Globals.AccessFailureManagementServiceImpl, _currentProcess);
}
private TimeService GetTimeService()
{
return new TimeService(Globals.TimeServiceImpl, CurrentProcess);
return new TimeService(Globals.TimeServiceImpl, _currentProcess);
}
private StatusReportService GetStatusReportService()
@ -133,62 +138,50 @@ namespace LibHac.FsSrv
private ProgramIndexRegistryService GetProgramIndexRegistryService()
{
return new ProgramIndexRegistryService(Globals.ProgramRegistryServiceImpl, CurrentProcess);
return new ProgramIndexRegistryService(Globals.ProgramRegistryServiceImpl, _currentProcess);
}
private AccessLogService GetAccessLogService()
{
return new AccessLogService(Globals.AccessLogServiceImpl, CurrentProcess);
return new AccessLogService(Globals.AccessLogServiceImpl, _currentProcess);
}
public Result OpenFileSystemWithId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in FspPath path,
public Result OpenFileSystemWithId(ref SharedRef<IFileSystemSf> outFileSystem, in FspPath path,
ulong id, FileSystemProxyType fsType)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenFileSystemWithId(out fileSystem, in path, id, fsType);
return ncaFsService.OpenFileSystemWithId(ref outFileSystem, in path, id, fsType);
}
public Result OpenFileSystemWithPatch(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenFileSystemWithPatch(ref SharedRef<IFileSystemSf> outFileSystem,
ProgramId programId, FileSystemProxyType fsType)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenFileSystemWithPatch(out fileSystem, programId, fsType);
return ncaFsService.OpenFileSystemWithPatch(ref outFileSystem, programId, fsType);
}
public Result OpenCodeFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenCodeFileSystem(ref SharedRef<IFileSystemSf> fileSystem,
out CodeVerificationData verificationData, in FspPath path, ProgramId programId)
{
UnsafeHelpers.SkipParamInit(out verificationData);
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenCodeFileSystem(out fileSystem, out verificationData, in path, programId);
return ncaFsService.OpenCodeFileSystem(ref fileSystem, out verificationData, in path, programId);
}
public Result SetCurrentProcess(ulong processId)
{
CurrentProcess = processId;
_currentProcess = processId;
// Initialize the NCA file system service
NcaFsService = NcaFileSystemService.CreateShared(Globals.NcaFileSystemServiceImpl, processId);
SaveFsService = SaveDataFileSystemService.CreateShared(Globals.SaveDataFileSystemServiceImpl, processId);
_ncaFsService = NcaFileSystemService.CreateShared(Globals.NcaFileSystemServiceImpl, processId);
_saveFsService = SaveDataFileSystemService.CreateShared(Globals.SaveDataFileSystemServiceImpl, processId);
return Result.Success;
}
@ -203,99 +196,70 @@ namespace LibHac.FsSrv
return saveFsService.GetFreeSpaceSizeForSaveData(out freeSpaceSize, spaceId);
}
public Result OpenDataFileSystemByCurrentProcess(out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
public Result OpenDataFileSystemByCurrentProcess(ref SharedRef<IFileSystemSf> outFileSystem)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenDataFileSystemByCurrentProcess(out fileSystem);
return ncaFsService.OpenDataFileSystemByCurrentProcess(ref outFileSystem);
}
public Result OpenDataFileSystemByProgramId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenDataFileSystemByProgramId(ref SharedRef<IFileSystemSf> outFileSystem,
ProgramId programId)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenDataFileSystemByProgramId(out fileSystem, programId);
return ncaFsService.OpenDataFileSystemByProgramId(ref outFileSystem, programId);
}
public Result OpenDataStorageByCurrentProcess(out ReferenceCountedDisposable<IStorageSf> storage)
public Result OpenDataStorageByCurrentProcess(ref SharedRef<IStorageSf> outStorage)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out storage);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenDataStorageByCurrentProcess(out storage);
return ncaFsService.OpenDataStorageByCurrentProcess(ref outStorage);
}
public Result OpenDataStorageByProgramId(out ReferenceCountedDisposable<IStorageSf> storage,
public Result OpenDataStorageByProgramId(ref SharedRef<IStorageSf> outStorage,
ProgramId programId)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out storage);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenDataStorageByProgramId(out storage, programId);
return ncaFsService.OpenDataStorageByProgramId(ref outStorage, programId);
}
public Result OpenDataStorageByDataId(out ReferenceCountedDisposable<IStorageSf> storage, DataId dataId,
public Result OpenDataStorageByDataId(ref SharedRef<IStorageSf> outStorage, DataId dataId,
StorageId storageId)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out storage);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenDataStorageByDataId(out storage, dataId, storageId);
return ncaFsService.OpenDataStorageByDataId(ref outStorage, dataId, storageId);
}
public Result OpenPatchDataStorageByCurrentProcess(out ReferenceCountedDisposable<IStorageSf> storage)
public Result OpenPatchDataStorageByCurrentProcess(ref SharedRef<IStorageSf> outStorage)
{
UnsafeHelpers.SkipParamInit(out storage);
return ResultFs.TargetNotFound.Log();
}
public Result OpenDataFileSystemWithProgramIndex(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenDataFileSystemWithProgramIndex(ref SharedRef<IFileSystemSf> outFileSystem,
byte programIndex)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenDataFileSystemWithProgramIndex(out fileSystem, programIndex);
return ncaFsService.OpenDataFileSystemWithProgramIndex(ref outFileSystem, programIndex);
}
public Result OpenDataStorageWithProgramIndex(out ReferenceCountedDisposable<IStorageSf> storage,
public Result OpenDataStorageWithProgramIndex(ref SharedRef<IStorageSf> outStorage,
byte programIndex)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out storage);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenDataStorageWithProgramIndex(out storage, programIndex);
return ncaFsService.OpenDataStorageWithProgramIndex(ref outStorage, programIndex);
}
public Result RegisterSaveDataFileSystemAtomicDeletion(InBuffer saveDataIds)
@ -376,43 +340,31 @@ namespace LibHac.FsSrv
return saveFsService.ExtendSaveDataFileSystem(spaceId, saveDataId, dataSize, journalSize);
}
public Result OpenSaveDataFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
SaveDataSpaceId spaceId, in SaveDataAttribute attribute)
public Result OpenSaveDataFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, SaveDataSpaceId spaceId,
in SaveDataAttribute attribute)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataFileSystem(out fileSystem, spaceId, in attribute);
return saveFsService.OpenSaveDataFileSystem(ref outFileSystem, spaceId, in attribute);
}
public Result OpenReadOnlySaveDataFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenReadOnlySaveDataFileSystem(ref SharedRef<IFileSystemSf> outFileSystem,
SaveDataSpaceId spaceId, in SaveDataAttribute attribute)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return saveFsService.OpenReadOnlySaveDataFileSystem(out fileSystem, spaceId, in attribute);
return saveFsService.OpenReadOnlySaveDataFileSystem(ref outFileSystem, spaceId, in attribute);
}
public Result OpenSaveDataFileSystemBySystemSaveDataId(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenSaveDataFileSystemBySystemSaveDataId(ref SharedRef<IFileSystemSf> outFileSystem,
SaveDataSpaceId spaceId, in SaveDataAttribute attribute)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataFileSystemBySystemSaveDataId(out fileSystem, spaceId, in attribute);
return saveFsService.OpenSaveDataFileSystemBySystemSaveDataId(ref outFileSystem, spaceId, in attribute);
}
public Result ReadSaveDataFileSystemExtraData(OutBuffer extraDataBuffer, ulong saveDataId)
@ -481,27 +433,31 @@ namespace LibHac.FsSrv
maskBuffer);
}
public Result OpenImageDirectoryFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenImageDirectoryFileSystem(ref SharedRef<IFileSystemSf> outFileSystem,
ImageDirectoryId directoryId)
{
return GetBaseFileSystemService().OpenImageDirectoryFileSystem(out fileSystem, directoryId);
return GetBaseFileSystemService().OpenImageDirectoryFileSystem(ref outFileSystem, directoryId);
}
public Result OpenBaseFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
BaseFileSystemId fileSystemId)
public Result OpenBaseFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, BaseFileSystemId fileSystemId)
{
return GetBaseFileSystemService().OpenBaseFileSystem(out fileSystem, fileSystemId);
return GetBaseFileSystemService().OpenBaseFileSystem(ref outFileSystem, fileSystemId);
}
public Result OpenBisFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in FspPath rootPath,
public Result FormatBaseFileSystem(BaseFileSystemId fileSystemId)
{
return GetBaseFileSystemService().FormatBaseFileSystem(fileSystemId);
}
public Result OpenBisFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, in FspPath rootPath,
BisPartitionId partitionId)
{
return GetBaseFileSystemService().OpenBisFileSystem(out fileSystem, in rootPath, partitionId);
return GetBaseFileSystemService().OpenBisFileSystem(ref outFileSystem, in rootPath, partitionId);
}
public Result OpenBisStorage(out ReferenceCountedDisposable<IStorageSf> storage, BisPartitionId partitionId)
public Result OpenBisStorage(ref SharedRef<IStorageSf> outStorage, BisPartitionId partitionId)
{
return GetBaseStorageService().OpenBisStorage(out storage, partitionId);
return GetBaseStorageService().OpenBisStorage(ref outStorage, partitionId);
}
public Result InvalidateBisCache()
@ -509,16 +465,14 @@ namespace LibHac.FsSrv
return GetBaseStorageService().InvalidateBisCache();
}
public Result OpenHostFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem, in FspPath path)
public Result OpenHostFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, in FspPath path)
{
return OpenHostFileSystemWithOption(out fileSystem, in path, MountHostOption.None);
return OpenHostFileSystemWithOption(ref outFileSystem, in path, MountHostOption.None);
}
public Result OpenHostFileSystemWithOption(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenHostFileSystemWithOption(ref SharedRef<IFileSystemSf> outFileSystem,
in FspPath path, MountHostOption option)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
@ -527,52 +481,48 @@ namespace LibHac.FsSrv
if (!accessibility.CanRead || !accessibility.CanWrite)
return ResultFs.PermissionDenied.Log();
ReferenceCountedDisposable<IFileSystem> hostFileSystem = null;
try
using var hostFileSystem = new SharedRef<IFileSystem>();
using var pathNormalized = new Path();
if (path.Str.At(0) == DirectorySeparator && path.Str.At(1) != DirectorySeparator)
{
using var pathNormalized = new Path();
if (path.Str.At(0) == DirectorySeparator && path.Str.At(1) != DirectorySeparator)
{
rc = pathNormalized.Initialize(path.Str.Slice(1));
if (rc.IsFailure()) return rc;
}
else
{
rc = pathNormalized.InitializeWithReplaceUnc(path.Str);
if (rc.IsFailure()) return rc;
}
var flags = new PathFlags();
flags.AllowWindowsPath();
flags.AllowRelativePath();
flags.AllowEmptyPath();
rc = pathNormalized.Normalize(flags);
rc = pathNormalized.Initialize(path.Str.Slice(1));
if (rc.IsFailure()) return rc;
bool isCaseSensitive = option.Flags.HasFlag(MountHostOptionFlag.PseudoCaseSensitive);
rc = FsProxyCore.OpenHostFileSystem(out hostFileSystem, in pathNormalized, isCaseSensitive);
if (rc.IsFailure()) return rc;
var adapterFlags = new PathFlags();
if (path.Str.At(0) == NullTerminator)
adapterFlags.AllowWindowsPath();
fileSystem = FileSystemInterfaceAdapter.CreateShared(ref hostFileSystem, adapterFlags, false);
return Result.Success;
}
finally
else
{
hostFileSystem?.Dispose();
rc = pathNormalized.InitializeWithReplaceUnc(path.Str);
if (rc.IsFailure()) return rc;
}
var flags = new PathFlags();
flags.AllowWindowsPath();
flags.AllowRelativePath();
flags.AllowEmptyPath();
rc = pathNormalized.Normalize(flags);
if (rc.IsFailure()) return rc;
bool isCaseSensitive = option.Flags.HasFlag(MountHostOptionFlag.PseudoCaseSensitive);
rc = _fsProxyCore.OpenHostFileSystem(ref hostFileSystem.Ref(), in pathNormalized, isCaseSensitive);
if (rc.IsFailure()) return rc;
var adapterFlags = new PathFlags();
if (path.Str.At(0) == NullTerminator)
adapterFlags.AllowWindowsPath();
using SharedRef<IFileSystemSf> fileSystemAdapter =
FileSystemInterfaceAdapter.CreateShared(ref hostFileSystem.Ref(), adapterFlags, false);
outFileSystem.SetByMove(ref fileSystemAdapter.Ref());
return Result.Success;
}
public Result OpenSdCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
public Result OpenSdCardFileSystem(ref SharedRef<IFileSystemSf> outFileSystem)
{
return GetBaseFileSystemService().OpenSdCardFileSystem(out fileSystem);
return GetBaseFileSystemService().OpenSdCardFileSystem(ref outFileSystem);
}
public Result FormatSdCardFileSystem()
@ -590,25 +540,25 @@ namespace LibHac.FsSrv
return GetBaseFileSystemService().IsExFatSupported(out isSupported);
}
public Result OpenGameCardStorage(out ReferenceCountedDisposable<IStorageSf> storage, GameCardHandle handle,
public Result OpenGameCardStorage(ref SharedRef<IStorageSf> outStorage, GameCardHandle handle,
GameCardPartitionRaw partitionId)
{
return GetBaseStorageService().OpenGameCardStorage(out storage, handle, partitionId);
return GetBaseStorageService().OpenGameCardStorage(ref outStorage, handle, partitionId);
}
public Result OpenDeviceOperator(out ReferenceCountedDisposable<IDeviceOperator> deviceOperator)
public Result OpenDeviceOperator(ref SharedRef<IDeviceOperator> outDeviceOperator)
{
return GetBaseStorageService().OpenDeviceOperator(out deviceOperator);
return GetBaseStorageService().OpenDeviceOperator(ref outDeviceOperator);
}
public Result OpenSdCardDetectionEventNotifier(out ReferenceCountedDisposable<IEventNotifier> eventNotifier)
public Result OpenSdCardDetectionEventNotifier(ref SharedRef<IEventNotifier> outEventNotifier)
{
return GetBaseStorageService().OpenSdCardDetectionEventNotifier(out eventNotifier);
return GetBaseStorageService().OpenSdCardDetectionEventNotifier(ref outEventNotifier);
}
public Result OpenGameCardDetectionEventNotifier(out ReferenceCountedDisposable<IEventNotifier> eventNotifier)
public Result OpenGameCardDetectionEventNotifier(ref SharedRef<IEventNotifier> outEventNotifier)
{
return GetBaseStorageService().OpenGameCardDetectionEventNotifier(out eventNotifier);
return GetBaseStorageService().OpenGameCardDetectionEventNotifier(ref outEventNotifier);
}
public Result SimulateDeviceDetectionEvent(SdmmcPort port, SimulatingDeviceDetectionMode mode, bool signalEvent)
@ -616,16 +566,12 @@ namespace LibHac.FsSrv
return GetBaseStorageService().SimulateDeviceDetectionEvent(port, mode, signalEvent);
}
public Result OpenSystemDataUpdateEventNotifier(out ReferenceCountedDisposable<IEventNotifier> eventNotifier)
public Result OpenSystemDataUpdateEventNotifier(ref SharedRef<IEventNotifier> outEventNotifier)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out eventNotifier);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenSystemDataUpdateEventNotifier(out eventNotifier);
return ncaFsService.OpenSystemDataUpdateEventNotifier(ref outEventNotifier);
}
public Result NotifySystemDataUpdateEvent()
@ -636,42 +582,30 @@ namespace LibHac.FsSrv
return ncaFsService.NotifySystemDataUpdateEvent();
}
public Result OpenSaveDataInfoReader(out ReferenceCountedDisposable<ISaveDataInfoReader> infoReader)
public Result OpenSaveDataInfoReader(ref SharedRef<ISaveDataInfoReader> outInfoReader)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out infoReader);
return rc;
}
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataInfoReader(out infoReader);
return saveFsService.OpenSaveDataInfoReader(ref outInfoReader);
}
public Result OpenSaveDataInfoReaderBySaveDataSpaceId(
out ReferenceCountedDisposable<ISaveDataInfoReader> infoReader, SaveDataSpaceId spaceId)
ref SharedRef<ISaveDataInfoReader> outInfoReader, SaveDataSpaceId spaceId)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out infoReader);
return rc;
}
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataInfoReaderBySaveDataSpaceId(out infoReader, spaceId);
return saveFsService.OpenSaveDataInfoReaderBySaveDataSpaceId(ref outInfoReader, spaceId);
}
public Result OpenSaveDataInfoReaderWithFilter(out ReferenceCountedDisposable<ISaveDataInfoReader> infoReader,
public Result OpenSaveDataInfoReaderWithFilter(ref SharedRef<ISaveDataInfoReader> outInfoReader,
SaveDataSpaceId spaceId, in SaveDataFilter filter)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out infoReader);
return rc;
}
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataInfoReaderWithFilter(out infoReader, spaceId, in filter);
return saveFsService.OpenSaveDataInfoReaderWithFilter(ref outInfoReader, spaceId, in filter);
}
public Result FindSaveDataWithFilter(out long count, OutBuffer saveDataInfoBuffer, SaveDataSpaceId spaceId,
@ -685,17 +619,13 @@ namespace LibHac.FsSrv
return saveFsService.FindSaveDataWithFilter(out count, saveDataInfoBuffer, spaceId, in filter);
}
public Result OpenSaveDataInternalStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenSaveDataInternalStorageFileSystem(ref SharedRef<IFileSystemSf> outFileSystem,
SaveDataSpaceId spaceId, ulong saveDataId)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataInternalStorageFileSystem(out fileSystem, spaceId, saveDataId);
return saveFsService.OpenSaveDataInternalStorageFileSystem(ref outFileSystem, spaceId, saveDataId);
}
public Result QuerySaveDataInternalStorageTotalSize(out long size, SaveDataSpaceId spaceId, ulong saveDataId)
@ -718,30 +648,21 @@ namespace LibHac.FsSrv
return saveFsService.GetSaveDataCommitId(out commitId, spaceId, saveDataId);
}
public Result OpenSaveDataInfoReaderOnlyCacheStorage(
out ReferenceCountedDisposable<ISaveDataInfoReader> infoReader)
public Result OpenSaveDataInfoReaderOnlyCacheStorage(ref SharedRef<ISaveDataInfoReader> outInfoReader)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out infoReader);
return rc;
}
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataInfoReaderOnlyCacheStorage(out infoReader);
return saveFsService.OpenSaveDataInfoReaderOnlyCacheStorage(ref outInfoReader);
}
public Result OpenSaveDataMetaFile(out ReferenceCountedDisposable<IFileSf> file, SaveDataSpaceId spaceId,
public Result OpenSaveDataMetaFile(ref SharedRef<IFileSf> outFile, SaveDataSpaceId spaceId,
in SaveDataAttribute attribute, SaveDataMetaType type)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out file);
return rc;
}
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataMetaFile(out file, spaceId, in attribute, type);
return saveFsService.OpenSaveDataMetaFile(ref outFile, spaceId, in attribute, type);
}
public Result DeleteCacheStorage(ushort index)
@ -762,58 +683,48 @@ namespace LibHac.FsSrv
return saveFsService.GetCacheStorageSize(out dataSize, out journalSize, index);
}
public Result OpenSaveDataTransferManager(out ReferenceCountedDisposable<ISaveDataTransferManager> manager)
public Result OpenSaveDataTransferManager(ref SharedRef<ISaveDataTransferManager> outTransferManager)
{
UnsafeHelpers.SkipParamInit(out manager);
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataTransferManager(out manager);
return saveFsService.OpenSaveDataTransferManager(ref outTransferManager);
}
public Result OpenSaveDataTransferManagerVersion2(
out ReferenceCountedDisposable<ISaveDataTransferManagerWithDivision> manager)
ref SharedRef<ISaveDataTransferManagerWithDivision> outTransferManager)
{
UnsafeHelpers.SkipParamInit(out manager);
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataTransferManagerVersion2(out manager);
return saveFsService.OpenSaveDataTransferManagerVersion2(ref outTransferManager);
}
public Result OpenSaveDataTransferManagerForSaveDataRepair(
out ReferenceCountedDisposable<ISaveDataTransferManagerForSaveDataRepair> manager)
ref SharedRef<ISaveDataTransferManagerForSaveDataRepair> outTransferManager)
{
UnsafeHelpers.SkipParamInit(out manager);
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataTransferManagerForSaveDataRepair(out manager);
return saveFsService.OpenSaveDataTransferManagerForSaveDataRepair(ref outTransferManager);
}
public Result OpenSaveDataTransferManagerForRepair(
out ReferenceCountedDisposable<ISaveDataTransferManagerForRepair> manager)
ref SharedRef<ISaveDataTransferManagerForRepair> outTransferManager)
{
UnsafeHelpers.SkipParamInit(out manager);
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataTransferManagerForRepair(out manager);
return saveFsService.OpenSaveDataTransferManagerForRepair(ref outTransferManager);
}
public Result OpenSaveDataTransferProhibiter(
out ReferenceCountedDisposable<ISaveDataTransferProhibiter> prohibiter, Ncm.ApplicationId applicationId)
public Result OpenSaveDataTransferProhibiter(ref SharedRef<ISaveDataTransferProhibiter> outProhibiter,
Ncm.ApplicationId applicationId)
{
UnsafeHelpers.SkipParamInit(out prohibiter);
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataTransferProhibiter(out prohibiter, applicationId);
return saveFsService.OpenSaveDataTransferProhibiter(ref outProhibiter, applicationId);
}
public Result ListAccessibleSaveDataOwnerId(out int readCount, OutBuffer idBuffer, ProgramId programId,
@ -828,19 +739,14 @@ namespace LibHac.FsSrv
bufferIdCount);
}
public Result OpenSaveDataMover(out ReferenceCountedDisposable<ISaveDataMover> saveMover,
SaveDataSpaceId sourceSpaceId, SaveDataSpaceId destinationSpaceId, NativeHandle workBufferHandle,
ulong workBufferSize)
public Result OpenSaveDataMover(ref SharedRef<ISaveDataMover> outSaveDataMover, SaveDataSpaceId sourceSpaceId,
SaveDataSpaceId destinationSpaceId, NativeHandle workBufferHandle, ulong workBufferSize)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out saveMover);
return rc;
}
if (rc.IsFailure()) return rc;
return saveFsService.OpenSaveDataMover(out saveMover, sourceSpaceId, destinationSpaceId, workBufferHandle,
workBufferSize);
return saveFsService.OpenSaveDataMover(ref outSaveDataMover, sourceSpaceId, destinationSpaceId,
workBufferHandle, workBufferSize);
}
public Result SetSaveDataSize(long saveDataSize, long saveDataJournalSize)
@ -864,25 +770,20 @@ namespace LibHac.FsSrv
return saveFsService.UnsetSaveDataRootPath();
}
public Result OpenContentStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenContentStorageFileSystem(ref SharedRef<IFileSystemSf> outFileSystem,
ContentStorageId storageId)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc.Miss();
return ncaFsService.OpenContentStorageFileSystem(out fileSystem, storageId);
return ncaFsService.OpenContentStorageFileSystem(ref outFileSystem, storageId);
}
public Result OpenCloudBackupWorkStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
public Result OpenCloudBackupWorkStorageFileSystem(ref SharedRef<IFileSystemSf> outFileSystem,
CloudBackupWorkStorageId storageId)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
var storageFlag = StorageType.NonGameCard;
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(storageFlag);
using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
@ -893,30 +794,29 @@ namespace LibHac.FsSrv
if (!accessibility.CanRead || !accessibility.CanWrite)
return ResultFs.PermissionDenied.Log();
ReferenceCountedDisposable<IFileSystem> tempFs = null;
try
{
rc = FsProxyCore.OpenCloudBackupWorkStorageFileSystem(out tempFs, storageId);
if (rc.IsFailure()) return rc;
using var fileSystem = new SharedRef<IFileSystem>();
rc = _fsProxyCore.OpenCloudBackupWorkStorageFileSystem(ref fileSystem.Ref(), storageId);
if (rc.IsFailure()) return rc;
tempFs = StorageLayoutTypeSetFileSystem.CreateShared(ref tempFs, storageFlag);
tempFs = AsynchronousAccessFileSystem.CreateShared(ref tempFs);
fileSystem = FileSystemInterfaceAdapter.CreateShared(ref tempFs, false);
// Add all the wrappers for the file system
using var typeSetFileSystem =
new SharedRef<IFileSystem>(new StorageLayoutTypeSetFileSystem(ref fileSystem.Ref(), storageFlag));
return Result.Success;
}
finally
{
tempFs?.Dispose();
}
using var asyncFileSystem =
new SharedRef<IFileSystem>(new AsynchronousAccessFileSystem(ref typeSetFileSystem.Ref()));
using SharedRef<IFileSystemSf> fileSystemAdapter =
FileSystemInterfaceAdapter.CreateShared(ref asyncFileSystem.Ref(), false);
outFileSystem.SetByMove(ref fileSystemAdapter.Ref());
return Result.Success;
}
public Result OpenCustomStorageFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
CustomStorageId storageId)
public Result OpenCustomStorageFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, CustomStorageId storageId)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
var storageFlag = StorageType.NonGameCard;
using var scopedLayoutType = new ScopedStorageLayoutTypeSetter(storageFlag);
using var scopedContext = new ScopedStorageLayoutTypeSetter(storageFlag);
Result rc = GetProgramInfo(out ProgramInfo programInfo);
if (rc.IsFailure()) return rc;
@ -930,28 +830,29 @@ namespace LibHac.FsSrv
if (!accessibility.CanRead || !accessibility.CanWrite)
return ResultFs.PermissionDenied.Log();
ReferenceCountedDisposable<IFileSystem> customFs = null;
try
{
rc = FsProxyCore.OpenCustomStorageFileSystem(out customFs, storageId);
if (rc.IsFailure()) return rc;
using var fileSystem = new SharedRef<IFileSystem>();
rc = _fsProxyCore.OpenCustomStorageFileSystem(ref fileSystem.Ref(), storageId);
if (rc.IsFailure()) return rc;
customFs = StorageLayoutTypeSetFileSystem.CreateShared(ref customFs, storageFlag);
customFs = AsynchronousAccessFileSystem.CreateShared(ref customFs);
fileSystem = FileSystemInterfaceAdapter.CreateShared(ref customFs, false);
// Add all the file system wrappers
using var typeSetFileSystem =
new SharedRef<IFileSystem>(new StorageLayoutTypeSetFileSystem(ref fileSystem.Ref(), storageFlag));
return Result.Success;
}
finally
{
customFs?.Dispose();
}
using var asyncFileSystem =
new SharedRef<IFileSystem>(new AsynchronousAccessFileSystem(ref typeSetFileSystem.Ref()));
using SharedRef<IFileSystemSf> fileSystemAdapter =
FileSystemInterfaceAdapter.CreateShared(ref asyncFileSystem.Ref(), false);
outFileSystem.SetByMove(ref fileSystemAdapter.Ref());
return Result.Success;
}
public Result OpenGameCardFileSystem(out ReferenceCountedDisposable<IFileSystemSf> fileSystem,
GameCardHandle handle, GameCardPartition partitionId)
public Result OpenGameCardFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, GameCardHandle handle,
GameCardPartition partitionId)
{
return GetBaseFileSystemService().OpenGameCardFileSystem(out fileSystem, handle, partitionId);
return GetBaseFileSystemService().OpenGameCardFileSystem(ref outFileSystem, handle, partitionId);
}
public Result IsArchivedProgram(out bool isArchived, ulong processId)
@ -1036,7 +937,7 @@ namespace LibHac.FsSrv
if (!programInfo.AccessControl.CanCall(OperationType.SetEncryptionSeed))
return ResultFs.PermissionDenied.Log();
rc = FsProxyCore.SetSdCardEncryptionSeed(in seed);
rc = _fsProxyCore.SetSdCardEncryptionSeed(in seed);
if (rc.IsFailure()) return rc;
rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
@ -1161,16 +1062,12 @@ namespace LibHac.FsSrv
return ncaFsService.RegisterUpdatePartition();
}
public Result OpenRegisteredUpdatePartition(out ReferenceCountedDisposable<IFileSystemSf> fileSystem)
public Result OpenRegisteredUpdatePartition(ref SharedRef<IFileSystemSf> outFileSystem)
{
Result rc = GetNcaFileSystemService(out NcaFileSystemService ncaFsService);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
if (rc.IsFailure()) return rc;
return ncaFsService.OpenRegisteredUpdatePartition(out fileSystem);
return ncaFsService.OpenRegisteredUpdatePartition(ref outFileSystem);
}
public Result GetAndClearMemoryReportInfo(out MemoryReportInfo reportInfo)
@ -1209,11 +1106,11 @@ namespace LibHac.FsSrv
return saveFsService.IsSdCardAccessible(out isAccessible);
}
public Result OpenAccessFailureDetectionEventNotifier(out ReferenceCountedDisposable<IEventNotifier> notifier,
public Result OpenAccessFailureDetectionEventNotifier(ref SharedRef<IEventNotifier> outEventNotifier,
ulong processId, bool notifyOnDeepRetry)
{
return GetAccessFailureManagementService()
.OpenAccessFailureDetectionEventNotifier(out notifier, processId, notifyOnDeepRetry);
.OpenAccessFailureDetectionEventNotifier(ref outEventNotifier, processId, notifyOnDeepRetry);
}
public Result GetAccessFailureDetectionEvent(out NativeHandle eventHandle)
@ -1236,20 +1133,18 @@ namespace LibHac.FsSrv
return GetAccessFailureManagementService().AbandonAccessFailure(processId);
}
public Result OpenMultiCommitManager(out ReferenceCountedDisposable<IMultiCommitManager> commitManager)
public Result OpenMultiCommitManager(ref SharedRef<IMultiCommitManager> outCommitManager)
{
UnsafeHelpers.SkipParamInit(out commitManager);
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure()) return rc;
return saveFsService.OpenMultiCommitManager(out commitManager);
return saveFsService.OpenMultiCommitManager(ref outCommitManager);
}
public Result OpenBisWiper(out ReferenceCountedDisposable<IWiper> bisWiper, NativeHandle transferMemoryHandle,
public Result OpenBisWiper(ref SharedRef<IWiper> outBisWiper, NativeHandle transferMemoryHandle,
ulong transferMemorySize)
{
return GetBaseFileSystemService().OpenBisWiper(out bisWiper, transferMemoryHandle, transferMemorySize);
return GetBaseFileSystemService().OpenBisWiper(ref outBisWiper, transferMemoryHandle, transferMemorySize);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs.Impl;
using LibHac.Fs.Shim;
using LibHac.FsSrv.FsCreator;
@ -38,11 +39,11 @@ namespace LibHac.FsSrv
FileSystemProxyConfiguration fspConfig = InitializeFileSystemProxy(server, config);
using ReferenceCountedDisposable<IFileSystemProxy> fsProxy = server.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> fileSystemProxy = server.Impl.GetFileSystemProxyServiceObject();
ulong processId = client.Os.GetCurrentProcessId().Value;
fsProxy.Target.SetCurrentProcess(processId).IgnoreResult();
fileSystemProxy.Get.SetCurrentProcess(processId).IgnoreResult();
client.Fs.Impl.InitializeDfcFileSystemProxyServiceObject(fsProxy);
client.Fs.Impl.InitializeDfcFileSystemProxyServiceObject(ref fileSystemProxy.Ref());
InitializeFileSystemProxyServer(client, server);
@ -76,7 +77,10 @@ namespace LibHac.FsSrv
var saveDataIndexerManager = new SaveDataIndexerManager(server.Hos.Fs, Fs.SaveData.SaveIndexerId,
new ArrayPoolMemoryResource(), new SdHandleManager(), false);
var programRegistryService = new ProgramRegistryServiceImpl(server);
var programRegistryConfig = new ProgramRegistryServiceImpl.Configuration();
programRegistryConfig.FsServer = server;
var programRegistryService = new ProgramRegistryServiceImpl(in programRegistryConfig);
server.InitializeProgramRegistryImpl(programRegistryService);
@ -84,7 +88,7 @@ namespace LibHac.FsSrv
baseStorageConfig.BisStorageCreator = config.FsCreators.BuiltInStorageCreator;
baseStorageConfig.GameCardStorageCreator = config.FsCreators.GameCardStorageCreator;
baseStorageConfig.FsServer = server;
baseStorageConfig.DeviceOperator = new ReferenceCountedDisposable<IDeviceOperator>(config.DeviceOperator);
baseStorageConfig.DeviceOperator = new SharedRef<IDeviceOperator>(config.DeviceOperator);
var baseStorageService = new BaseStorageServiceImpl(in baseStorageConfig);
var timeService = new TimeServiceImpl(server);
@ -194,9 +198,10 @@ namespace LibHac.FsSrv
_server = server;
}
public Result GetServiceObject(out object serviceObject)
public Result GetServiceObject(ref SharedRef<IDisposable> serviceObject)
{
serviceObject = _server.Impl.GetFileSystemProxyServiceObject();
using SharedRef<IFileSystemProxy> derivedObject = _server.Impl.GetFileSystemProxyServiceObject();
serviceObject.SetByMove(ref derivedObject.Ref());
return Result.Success;
}
}
@ -210,9 +215,10 @@ namespace LibHac.FsSrv
_server = server;
}
public Result GetServiceObject(out object serviceObject)
public Result GetServiceObject(ref SharedRef<IDisposable> serviceObject)
{
serviceObject = _server.Impl.GetFileSystemProxyForLoaderServiceObject();
using SharedRef<IFileSystemProxyForLoader> derivedObject = _server.Impl.GetFileSystemProxyForLoaderServiceObject();
serviceObject.SetByMove(ref derivedObject.Ref());
return Result.Success;
}
}
@ -226,9 +232,10 @@ namespace LibHac.FsSrv
_server = server;
}
public Result GetServiceObject(out object serviceObject)
public Result GetServiceObject(ref SharedRef<IDisposable> serviceObject)
{
serviceObject = _server.Impl.GetProgramRegistryServiceObject();
using SharedRef<IProgramRegistry> derivedObject = _server.Impl.GetProgramRegistryServiceObject();
serviceObject.SetByMove(ref derivedObject.Ref());
return Result.Success;
}
}

View File

@ -39,10 +39,10 @@ namespace LibHac.FsSrv.FsCreator
/// Each partition will be located at their default paths in this IFileSystem.
/// </summary>
/// <param name="rootFileSystem">The <see cref="IFileSystem"/> to use as the root file system.</param>
public EmulatedBisFileSystemCreator(IFileSystem rootFileSystem)
public EmulatedBisFileSystemCreator(ref SharedRef<IFileSystem> rootFileSystem)
{
Config = new EmulatedBisFileSystemCreatorConfig();
Config.RootFileSystem = rootFileSystem;
Config.SetRootFileSystem(ref rootFileSystem).ThrowIfFailure();
}
/// <summary>
@ -55,20 +55,20 @@ namespace LibHac.FsSrv.FsCreator
}
// Todo: Make case sensitive
public Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem, BisPartitionId partitionId,
bool caseSensitive)
public Result Create(ref SharedRef<IFileSystem> outFileSystem, BisPartitionId partitionId, bool caseSensitive)
{
UnsafeHelpers.SkipParamInit(out fileSystem);
if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument.Log();
if (Config.TryGetFileSystem(out IFileSystem fs, partitionId))
using var fileSystem = new SharedRef<IFileSystem>();
if (Config.TryGetFileSystem(ref fileSystem.Ref(), partitionId))
{
fileSystem = new ReferenceCountedDisposable<IFileSystem>(fs);
outFileSystem.SetByMove(ref fileSystem.Ref());
return Result.Success;
}
if (Config.RootFileSystem == null)
using var rootFileSystem = new SharedRef<IFileSystem>();
if (!Config.TryGetRootFileSystem(ref rootFileSystem.Ref()))
{
return ResultFs.PreconditionViolation.Log();
}
@ -82,23 +82,12 @@ namespace LibHac.FsSrv.FsCreator
rc = bisRootPath.Normalize(pathFlags);
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<IFileSystem> partitionFileSystem = null;
ReferenceCountedDisposable<IFileSystem> sharedRootFs = null;
try
{
sharedRootFs = new ReferenceCountedDisposable<IFileSystem>(Config.RootFileSystem);
using var partitionFileSystem = new SharedRef<IFileSystem>();
rc = Utility.WrapSubDirectory(ref partitionFileSystem.Ref(), ref rootFileSystem.Ref(), in bisRootPath, true);
if (rc.IsFailure()) return rc;
rc = Utility.WrapSubDirectory(out partitionFileSystem, ref sharedRootFs, in bisRootPath, true);
if (rc.IsFailure()) return rc;
Shared.Move(out fileSystem, ref partitionFileSystem);
return Result.Success;
}
finally
{
partitionFileSystem?.Dispose();
sharedRootFs?.Dispose();
}
outFileSystem.SetByMove(ref partitionFileSystem.Ref());
return Result.Success;
}
public Result SetBisRoot(BisPartitionId partitionId, string rootPath)

View File

@ -13,17 +13,27 @@ namespace LibHac.FsSrv.FsCreator
{
private const int ValidPartitionCount = 4;
public IFileSystem RootFileSystem { get; set; }
private SharedRef<IFileSystem> _rootFileSystem;
private IFileSystem[] PartitionFileSystems { get; } = new IFileSystem[ValidPartitionCount];
private SharedRef<IFileSystem>[] PartitionFileSystems { get; } = new SharedRef<IFileSystem>[ValidPartitionCount];
private string[] PartitionPaths { get; } = new string[ValidPartitionCount];
public Result SetFileSystem(IFileSystem fileSystem, BisPartitionId partitionId)
public Result SetRootFileSystem(ref SharedRef<IFileSystem> fileSystem)
{
if (fileSystem == null) return ResultFs.NullptrArgument.Log();
if (!fileSystem.HasValue) return ResultFs.NullptrArgument.Log();
if (_rootFileSystem.HasValue) return ResultFs.PreconditionViolation.Log();
_rootFileSystem.SetByMove(ref fileSystem);
return Result.Success;
}
public Result SetFileSystem(ref UniqueRef<IFileSystem> fileSystem, BisPartitionId partitionId)
{
if (!fileSystem.HasValue) return ResultFs.NullptrArgument.Log();
if (!IsValidPartitionId(partitionId)) return ResultFs.InvalidArgument.Log();
PartitionFileSystems[GetArrayIndex(partitionId)] = fileSystem;
PartitionFileSystems[GetArrayIndex(partitionId)].Set(ref fileSystem);
return Result.Success;
}
@ -38,17 +48,21 @@ namespace LibHac.FsSrv.FsCreator
return Result.Success;
}
public bool TryGetFileSystem(out IFileSystem fileSystem, BisPartitionId partitionId)
public bool TryGetRootFileSystem(ref SharedRef<IFileSystem> outFileSystem)
{
outFileSystem.SetByCopy(ref _rootFileSystem);
return outFileSystem.HasValue;
}
public bool TryGetFileSystem(ref SharedRef<IFileSystem> outFileSystem, BisPartitionId partitionId)
{
if (!IsValidPartitionId(partitionId))
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return false;
}
fileSystem = PartitionFileSystems[GetArrayIndex(partitionId)];
outFileSystem.SetByCopy(ref PartitionFileSystems[GetArrayIndex(partitionId)]);
return fileSystem != null;
return outFileSystem.HasValue;
}
public bool TryGetPartitionPath(out string path, BisPartitionId partitionId)

View File

@ -6,41 +6,22 @@ namespace LibHac.FsSrv.FsCreator
{
public class EmulatedGameCardFsCreator : IGameCardFileSystemCreator
{
// ReSharper disable once UnusedAutoPropertyAccessor.Local
private EmulatedGameCardStorageCreator StorageCreator { get; }
private EmulatedGameCard GameCard { get; }
// ReSharper disable once NotAccessedField.Local
private EmulatedGameCardStorageCreator _storageCreator;
private EmulatedGameCard _gameCard;
public EmulatedGameCardFsCreator(EmulatedGameCardStorageCreator storageCreator, EmulatedGameCard gameCard)
{
StorageCreator = storageCreator;
GameCard = gameCard;
_storageCreator = storageCreator;
_gameCard = gameCard;
}
public Result Create(out IFileSystem fileSystem, GameCardHandle handle, GameCardPartition partitionType)
public Result Create(ref SharedRef<IFileSystem> outFileSystem, GameCardHandle handle,
GameCardPartition partitionType)
{
// Use the old xci code temporarily
UnsafeHelpers.SkipParamInit(out fileSystem);
Result rc = GameCard.GetXci(out Xci xci, handle);
if (rc.IsFailure()) return rc;
if (!xci.HasPartition((XciPartitionType)partitionType))
{
return ResultFs.PartitionNotFound.Log();
}
fileSystem = xci.OpenPartition((XciPartitionType)partitionType);
return Result.Success;
}
public Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem, GameCardHandle handle, GameCardPartition partitionType)
{
// Use the old xci code temporarily
UnsafeHelpers.SkipParamInit(out fileSystem);
Result rc = GameCard.GetXci(out Xci xci, handle);
Result rc = _gameCard.GetXci(out Xci xci, handle);
if (rc.IsFailure()) return rc;
if (!xci.HasPartition((XciPartitionType)partitionType))
@ -49,7 +30,7 @@ namespace LibHac.FsSrv.FsCreator
}
XciPartition fs = xci.OpenPartition((XciPartitionType)partitionType);
fileSystem = new ReferenceCountedDisposable<IFileSystem>(fs);
outFileSystem.Reset(fs);
return Result.Success;
}
}

View File

@ -13,29 +13,24 @@ namespace LibHac.FsSrv.FsCreator
GameCard = gameCard;
}
public Result CreateReadOnly(GameCardHandle handle, out ReferenceCountedDisposable<IStorage> storage)
public Result CreateReadOnly(GameCardHandle handle, ref SharedRef<IStorage> outStorage)
{
UnsafeHelpers.SkipParamInit(out storage);
if (GameCard.IsGameCardHandleInvalid(handle))
{
return ResultFs.InvalidGameCardHandleOnOpenNormalPartition.Log();
}
var baseStorage = new ReferenceCountedDisposable<IStorage>(new ReadOnlyGameCardStorage(GameCard, handle));
using var baseStorage = new SharedRef<IStorage>(new ReadOnlyGameCardStorage(GameCard, handle));
Result rc = GameCard.GetCardInfo(out GameCardInfo cardInfo, handle);
if (rc.IsFailure()) return rc;
storage = new ReferenceCountedDisposable<IStorage>(
new SubStorage(baseStorage, 0, cardInfo.SecureAreaOffset));
outStorage.Reset(new SubStorage(ref baseStorage.Ref(), 0, cardInfo.SecureAreaOffset));
return Result.Success;
}
public Result CreateSecureReadOnly(GameCardHandle handle, out ReferenceCountedDisposable<IStorage> storage)
public Result CreateSecureReadOnly(GameCardHandle handle, ref SharedRef<IStorage> outStorage)
{
UnsafeHelpers.SkipParamInit(out storage);
if (GameCard.IsGameCardHandleInvalid(handle))
{
return ResultFs.InvalidGameCardHandleOnOpenSecurePartition.Log();
@ -50,19 +45,17 @@ namespace LibHac.FsSrv.FsCreator
rc = GameCard.GetGameCardImageHash(imageHash);
if (rc.IsFailure()) return rc;
var baseStorage =
new ReferenceCountedDisposable<IStorage>(new ReadOnlyGameCardStorage(GameCard, handle, deviceId,
imageHash));
using var baseStorage =
new SharedRef<IStorage>(new ReadOnlyGameCardStorage(GameCard, handle, deviceId, imageHash));
rc = GameCard.GetCardInfo(out GameCardInfo cardInfo, handle);
if (rc.IsFailure()) return rc;
storage = new ReferenceCountedDisposable<IStorage>(new SubStorage(baseStorage, cardInfo.SecureAreaOffset,
cardInfo.SecureAreaSize));
outStorage.Reset(new SubStorage(ref baseStorage.Ref(), cardInfo.SecureAreaOffset, cardInfo.SecureAreaSize));
return Result.Success;
}
public Result CreateWriteOnly(GameCardHandle handle, out ReferenceCountedDisposable<IStorage> storage)
public Result CreateWriteOnly(GameCardHandle handle, ref SharedRef<IStorage> outStorage)
{
throw new NotImplementedException();
}

View File

@ -11,62 +11,50 @@ namespace LibHac.FsSrv.FsCreator
{
private const string DefaultPath = "/sdcard";
private EmulatedSdCard SdCard { get; }
private ReferenceCountedDisposable<IFileSystem> _rootFileSystem;
private string Path { get; }
private EmulatedSdCard _sdCard;
private SharedRef<IFileSystem> _rootFileSystem;
private SharedRef<IFileSystem> _sdCardFileSystem;
private string _path;
private ReferenceCountedDisposable<IFileSystem> _sdCardFileSystem;
public EmulatedSdCardFileSystemCreator(EmulatedSdCard sdCard, IFileSystem rootFileSystem)
public EmulatedSdCardFileSystemCreator(EmulatedSdCard sdCard, ref SharedRef<IFileSystem> rootFileSystem)
{
SdCard = sdCard;
_rootFileSystem = new ReferenceCountedDisposable<IFileSystem>(rootFileSystem);
_sdCard = sdCard;
_rootFileSystem = SharedRef<IFileSystem>.CreateMove(ref rootFileSystem);
}
public EmulatedSdCardFileSystemCreator(EmulatedSdCard sdCard, IFileSystem rootFileSystem, string path)
public EmulatedSdCardFileSystemCreator(EmulatedSdCard sdCard, ref SharedRef<IFileSystem> rootFileSystem, string path)
{
SdCard = sdCard;
_rootFileSystem = new ReferenceCountedDisposable<IFileSystem>(rootFileSystem);
Path = path;
_sdCard = sdCard;
_rootFileSystem = SharedRef<IFileSystem>.CreateMove(ref rootFileSystem);
_path = path;
}
public void Dispose()
{
if (_rootFileSystem is not null)
{
_rootFileSystem.Dispose();
_rootFileSystem = null;
}
if (_sdCardFileSystem is not null)
{
_sdCardFileSystem.Dispose();
_sdCardFileSystem = null;
}
_rootFileSystem.Destroy();
_sdCardFileSystem.Destroy();
}
public Result Create(out ReferenceCountedDisposable<IFileSystem> outFileSystem, bool isCaseSensitive)
public Result Create(ref SharedRef<IFileSystem> outFileSystem, bool openCaseSensitive)
{
UnsafeHelpers.SkipParamInit(out outFileSystem);
if (!SdCard.IsSdCardInserted())
if (!_sdCard.IsSdCardInserted())
{
return ResultFs.PortSdCardNoDevice.Log();
}
if (_sdCardFileSystem is not null)
if (_sdCardFileSystem.HasValue)
{
outFileSystem = _sdCardFileSystem.AddReference();
outFileSystem.SetByCopy(ref _sdCardFileSystem);
return Result.Success;
}
if (_rootFileSystem is null)
if (!_rootFileSystem.HasValue)
{
return ResultFs.PreconditionViolation.Log();
}
string path = Path ?? DefaultPath;
string path = _path ?? DefaultPath;
using var sdCardPath = new Path();
Result rc = sdCardPath.Initialize(StringUtils.StringToUtf8(path));
@ -79,21 +67,13 @@ namespace LibHac.FsSrv.FsCreator
// Todo: Add ProxyFileSystem?
ReferenceCountedDisposable<IFileSystem> tempFs = null;
try
{
tempFs = _rootFileSystem.AddReference();
rc = Utility.WrapSubDirectory(out _sdCardFileSystem, ref tempFs, in sdCardPath, true);
if (rc.IsFailure()) return rc;
using SharedRef<IFileSystem> fileSystem = SharedRef<IFileSystem>.CreateCopy(ref _rootFileSystem);
rc = Utility.WrapSubDirectory(ref _sdCardFileSystem, ref fileSystem.Ref(), in sdCardPath, true);
if (rc.IsFailure()) return rc;
outFileSystem = _sdCardFileSystem.AddReference();
outFileSystem.SetByCopy(ref _sdCardFileSystem);
return Result.Success;
}
finally
{
tempFs?.Dispose();
}
return Result.Success;
}
public Result Format(bool removeFromFatFsCache)

View File

@ -16,12 +16,8 @@ namespace LibHac.FsSrv.FsCreator
KeySet = keySet;
}
public Result Create(out ReferenceCountedDisposable<IFileSystem> encryptedFileSystem,
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, KeyId idIndex,
in EncryptionSeed encryptionSeed)
public Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem, ref SharedRef<IFileSystem> baseFileSystem, KeyId idIndex, in EncryptionSeed encryptionSeed)
{
UnsafeHelpers.SkipParamInit(out encryptedFileSystem);
if (idIndex < KeyId.Save || idIndex > KeyId.CustomStorage)
{
return ResultFs.InvalidArgument.Log();
@ -30,10 +26,10 @@ namespace LibHac.FsSrv.FsCreator
// todo: "proper" key generation instead of a lazy hack
KeySet.SetSdSeed(encryptionSeed.Value);
// Todo: pass ReferenceCountedDisposable to AesXtsFileSystem
var fs = new AesXtsFileSystem(baseFileSystem, KeySet.SdCardEncryptionKeys[(int)idIndex].DataRo.ToArray(),
0x4000);
encryptedFileSystem = new ReferenceCountedDisposable<IFileSystem>(fs);
using var encryptedFileSystem = new SharedRef<AesXtsFileSystem>(new AesXtsFileSystem(ref baseFileSystem,
KeySet.SdCardEncryptionKeys[(int)idIndex].DataRo.ToArray(), 0x4000));
outEncryptedFileSystem.SetByMove(ref encryptedFileSystem.Ref());
return Result.Success;
}

View File

@ -1,10 +1,11 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSrv.FsCreator
{
public interface IBuiltInStorageCreator
{
Result Create(out ReferenceCountedDisposable<IStorage> storage, BisPartitionId partitionId);
Result Create(ref SharedRef<IStorage> outStorage, BisPartitionId partitionId);
Result InvalidateCache();
}
}

View File

@ -1,10 +1,11 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
namespace LibHac.FsSrv.FsCreator
{
public interface IBuiltInStorageFileSystemCreator
{
Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem, BisPartitionId partitionId, bool caseSensitive);
Result Create(ref SharedRef<IFileSystem> outFileSystem, BisPartitionId partitionId, bool caseSensitive);
}
}

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
namespace LibHac.FsSrv.FsCreator
@ -12,15 +13,7 @@ namespace LibHac.FsSrv.FsCreator
CustomStorage = 2
}
Result Create(out ReferenceCountedDisposable<IFileSystem> encryptedFileSystem,
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, KeyId idIndex,
in EncryptionSeed encryptionSeed);
}
public enum EncryptedFsKeyId
{
Save = 0,
Content = 1,
CustomStorage = 2
Result Create(ref SharedRef<IFileSystem> outEncryptedFileSystem, ref SharedRef<IFileSystem> baseFileSystem,
KeyId idIndex, in EncryptionSeed encryptionSeed);
}
}

View File

@ -1,4 +1,5 @@
using LibHac.Fat;
using LibHac.Common;
using LibHac.Fat;
using LibHac.Fs;
using LibHac.Fs.Fsa;
@ -6,11 +7,10 @@ namespace LibHac.FsSrv.FsCreator
{
public interface IFatFileSystemCreator
{
Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem,
ReferenceCountedDisposable<IStorage> baseStorage, FatAttribute attribute, int driveId,
Result invalidFatFormatResult, Result usableSpaceNotEnoughResult);
Result Create(ref SharedRef<IFileSystem> outFileSystem, ref SharedRef<IStorage> baseStorage,
FatAttribute attribute, int driveId, Result invalidFatFormatResult, Result usableSpaceNotEnoughResult);
Result Format(ReferenceCountedDisposable<IStorage> partitionStorage, FatAttribute attribute,
FatFormatParam formatParam, int driveId, Result invalidFatFormatResult, Result usableSpaceNotEnoughResult);
Result Format(ref SharedRef<IStorage> partitionStorage, FatAttribute attribute, FatFormatParam formatParam,
int driveId, Result invalidFatFormatResult, Result usableSpaceNotEnoughResult);
}
}

View File

@ -1,11 +1,11 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
namespace LibHac.FsSrv.FsCreator
{
public interface IGameCardFileSystemCreator
{
Result Create(out IFileSystem fileSystem, GameCardHandle handle, GameCardPartition partitionType);
Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem, GameCardHandle handle, GameCardPartition partitionType);
Result Create(ref SharedRef<IFileSystem> outFileSystem, GameCardHandle handle, GameCardPartition partitionType);
}
}

View File

@ -1,11 +1,12 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSrv.FsCreator
{
public interface IGameCardStorageCreator
{
Result CreateReadOnly(GameCardHandle handle, out ReferenceCountedDisposable<IStorage> storage);
Result CreateSecureReadOnly(GameCardHandle handle, out ReferenceCountedDisposable<IStorage> storage);
Result CreateWriteOnly(GameCardHandle handle, out ReferenceCountedDisposable<IStorage> storage);
Result CreateReadOnly(GameCardHandle handle, ref SharedRef<IStorage> outStorage);
Result CreateSecureReadOnly(GameCardHandle handle, ref SharedRef<IStorage> outStorage);
Result CreateWriteOnly(GameCardHandle handle, ref SharedRef<IStorage> outStorage);
}
}

View File

@ -1,12 +1,11 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
namespace LibHac.FsSrv.FsCreator
{
public interface IPartitionFileSystemCreator
{
// Todo: Remove non-shared overload
Result Create(out IFileSystem fileSystem, IStorage pFsStorage);
Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem, ReferenceCountedDisposable<IStorage> pFsStorage);
Result Create(ref SharedRef<IFileSystem> outFileSystem, ref SharedRef<IStorage> baseStorage);
}
}

View File

@ -1,10 +1,11 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
namespace LibHac.FsSrv.FsCreator
{
public interface IRomFileSystemCreator
{
Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem, ReferenceCountedDisposable<IStorage> romFsStorage);
Result Create(ref SharedRef<IFileSystem> outFileSystem, ref SharedRef<IStorage> romFsStorage);
}
}

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.FsSystem;
@ -9,15 +10,15 @@ namespace LibHac.FsSrv.FsCreator
{
Result CreateFile(out IFile file, IFileSystem sourceFileSystem, ulong saveDataId, OpenMode openMode);
Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem,
out ReferenceCountedDisposable<ISaveDataExtraDataAccessor> extraDataAccessor,
ISaveDataFileSystemCacheManager cacheManager, ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
Result Create(ref SharedRef<IFileSystem> outFileSystem,
ref SharedRef<ISaveDataExtraDataAccessor> outExtraDataAccessor,
ISaveDataFileSystemCacheManager cacheManager, ref SharedRef<IFileSystem> baseFileSystem,
SaveDataSpaceId spaceId, ulong saveDataId, bool allowDirectorySaveData, bool useDeviceUniqueMac,
bool isJournalingSupported, bool isMultiCommitSupported, bool openReadOnly, bool openShared,
ISaveDataCommitTimeStampGetter timeStampGetter);
Result CreateExtraDataAccessor(out ReferenceCountedDisposable<ISaveDataExtraDataAccessor> extraDataAccessor,
ReferenceCountedDisposable<IFileSystem> sourceFileSystem);
Result CreateExtraDataAccessor(ref SharedRef<ISaveDataExtraDataAccessor> outExtraDataAccessor,
ref SharedRef<IFileSystem> baseFileSystem);
void SetSdCardEncryptionSeed(ReadOnlySpan<byte> seed);
}

View File

@ -1,10 +1,11 @@
using LibHac.Fs.Fsa;
using LibHac.Common;
using LibHac.Fs.Fsa;
namespace LibHac.FsSrv.FsCreator
{
public interface ISdCardProxyFileSystemCreator
{
Result Create(out ReferenceCountedDisposable<IFileSystem> outFileSystem, bool isCaseSensitive);
Result Create(ref SharedRef<IFileSystem> outFileSystem, bool openCaseSensitive);
/// <summary>
/// Formats the SD card.

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.FsSystem.NcaUtils;
@ -6,8 +7,8 @@ namespace LibHac.FsSrv.FsCreator
{
public interface IStorageOnNcaCreator
{
Result Create(out ReferenceCountedDisposable<IStorage> storage, out NcaFsHeader fsHeader, Nca nca, int fsIndex, bool isCodeFs);
Result CreateWithPatch(out ReferenceCountedDisposable<IStorage> storage, out NcaFsHeader fsHeader, Nca baseNca, Nca patchNca, int fsIndex, bool isCodeFs);
Result Create(ref SharedRef<IStorage> outStorage, out NcaFsHeader fsHeader, Nca nca, int fsIndex, bool isCodeFs);
Result CreateWithPatch(ref SharedRef<IStorage> outStorage, out NcaFsHeader fsHeader, Nca baseNca, Nca patchNca, int fsIndex, bool isCodeFs);
Result OpenNca(out Nca nca, IStorage ncaStorage);
Result VerifyAcidSignature(IFileSystem codeFileSystem, Nca nca);
}

View File

@ -1,10 +1,11 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
namespace LibHac.FsSrv.FsCreator
{
public interface ISubDirectoryFileSystemCreator
{
Result Create(out ReferenceCountedDisposable<IFileSystem> subDirFileSystem, ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, in Path path);
Result Create(ref SharedRef<IFileSystem> outSubDirFileSystem, ref SharedRef<IFileSystem> baseFileSystem, in Path path);
}
}

View File

@ -1,11 +1,12 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
namespace LibHac.FsSrv.FsCreator
{
public interface ITargetManagerFileSystemCreator
{
Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem, in Path rootPath, bool openCaseSensitive, bool ensureRootPathExists, Result pathNotFoundResult);
Result Create(ref SharedRef<IFileSystem> outFileSystem, in Path rootPath, bool openCaseSensitive, bool ensureRootPathExists, Result pathNotFoundResult);
Result NormalizeCaseOfPath(out bool isSupported, ref Path path);
}
}

View File

@ -8,33 +8,15 @@ namespace LibHac.FsSrv.FsCreator
{
public class PartitionFileSystemCreator : IPartitionFileSystemCreator
{
public Result Create(out IFileSystem fileSystem, IStorage pFsStorage)
public Result Create(ref SharedRef<IFileSystem> outFileSystem, ref SharedRef<IStorage> baseStorage)
{
var partitionFs = new PartitionFileSystemCore<StandardEntry>();
using var partitionFs =
new SharedRef<PartitionFileSystemCore<StandardEntry>>(new PartitionFileSystemCore<StandardEntry>());
Result rc = partitionFs.Initialize(pFsStorage);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
Result rc = partitionFs.Get.Initialize(ref baseStorage);
if (rc.IsFailure()) return rc.Miss();
fileSystem = partitionFs;
return Result.Success;
}
public Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem, ReferenceCountedDisposable<IStorage> pFsStorage)
{
var partitionFs = new PartitionFileSystemCore<StandardEntry>();
Result rc = partitionFs.Initialize(pFsStorage);
if (rc.IsFailure())
{
UnsafeHelpers.SkipParamInit(out fileSystem);
return rc;
}
fileSystem = new ReferenceCountedDisposable<IFileSystem>(partitionFs);
outFileSystem.SetByMove(ref partitionFs.Ref());
return Result.Success;
}
}

View File

@ -1,4 +1,5 @@
using LibHac.Fs;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.FsSystem.RomFs;
@ -7,10 +8,9 @@ namespace LibHac.FsSrv.FsCreator
public class RomFileSystemCreator : IRomFileSystemCreator
{
// todo: Implement properly
public Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem, ReferenceCountedDisposable<IStorage> romFsStorage)
public Result Create(ref SharedRef<IFileSystem> outFileSystem, ref SharedRef<IStorage> romFsStorage)
{
// Todo: Properly use shared references
fileSystem = new ReferenceCountedDisposable<IFileSystem>(new RomFsFileSystem(romFsStorage.AddReference().Target));
outFileSystem.Reset(new RomFsFileSystem(ref romFsStorage));
return Result.Success;
}
}

View File

@ -36,9 +36,9 @@ namespace LibHac.FsSrv.FsCreator
throw new NotImplementedException();
}
public Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem,
out ReferenceCountedDisposable<ISaveDataExtraDataAccessor> extraDataAccessor,
ISaveDataFileSystemCacheManager cacheManager, ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
public Result Create(ref SharedRef<IFileSystem> outFileSystem,
ref SharedRef<ISaveDataExtraDataAccessor> outExtraDataAccessor,
ISaveDataFileSystemCacheManager cacheManager, ref SharedRef<IFileSystem> baseFileSystem,
SaveDataSpaceId spaceId, ulong saveDataId, bool allowDirectorySaveData, bool useDeviceUniqueMac,
bool isJournalingSupported, bool isMultiCommitSupported, bool openReadOnly, bool openShared,
ISaveDataCommitTimeStampGetter timeStampGetter)
@ -48,15 +48,13 @@ namespace LibHac.FsSrv.FsCreator
ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
Span<byte> saveImageNameBuffer = MemoryMarshal.CreateSpan(ref bufferRef, 0x12);
UnsafeHelpers.SkipParamInit(out fileSystem, out extraDataAccessor);
Assert.SdkRequiresNotNull(cacheManager);
using var saveImageName = new Path();
Result rc = PathFunctions.SetUpFixedPathSaveId(ref saveImageName.Ref(), saveImageNameBuffer, saveDataId);
if (rc.IsFailure()) return rc;
rc = baseFileSystem.Target.GetEntryType(out DirectoryEntryType type, in saveImageName);
rc = baseFileSystem.Get.GetEntryType(out DirectoryEntryType type, in saveImageName);
if (rc.IsFailure())
{
@ -68,40 +66,36 @@ namespace LibHac.FsSrv.FsCreator
if (!allowDirectorySaveData)
return ResultFs.InvalidSaveDataEntryType.Log();
SubdirectoryFileSystem subDirFs = null;
ReferenceCountedDisposable<DirectorySaveDataFileSystem> saveFs = null;
try
{
subDirFs = new SubdirectoryFileSystem(ref baseFileSystem);
using var baseFs =
new UniqueRef<SubdirectoryFileSystem>(new SubdirectoryFileSystem(ref baseFileSystem));
rc = subDirFs.Initialize(in saveImageName);
if (rc.IsFailure()) return rc;
if (!baseFs.HasValue)
return ResultFs.AllocationMemoryFailedInSaveDataFileSystemCreatorA.Log();
saveFs = DirectorySaveDataFileSystem.CreateShared(Shared.Move(ref subDirFs), _fsServer.Hos.Fs);
rc = baseFs.Get.Initialize(in saveImageName);
if (rc.IsFailure()) return rc;
rc = saveFs.Target.Initialize(timeStampGetter, _randomGenerator, isJournalingSupported,
isMultiCommitSupported, !openReadOnly);
if (rc.IsFailure()) return rc;
using UniqueRef<IFileSystem> tempFs = UniqueRef<IFileSystem>.Create(ref baseFs.Ref());
using var saveDirFs = new SharedRef<DirectorySaveDataFileSystem>(
new DirectorySaveDataFileSystem(ref tempFs.Ref(), _fsServer.Hos.Fs));
fileSystem = saveFs.AddReference<IFileSystem>();
extraDataAccessor = saveFs.AddReference<ISaveDataExtraDataAccessor>();
rc = saveDirFs.Get.Initialize(timeStampGetter, _randomGenerator, isJournalingSupported,
isMultiCommitSupported, !openReadOnly);
if (rc.IsFailure()) return rc;
return Result.Success;
}
finally
{
subDirFs?.Dispose();
saveFs?.Dispose();
}
outFileSystem.SetByCopy(ref saveDirFs.Ref());
outExtraDataAccessor.SetByCopy(ref saveDirFs.Ref());
return Result.Success;
}
ReferenceCountedDisposable<IStorage> fileStorage = null;
try
else
{
using var fileStorage = new SharedRef<IStorage>();
Optional<OpenType> openType =
openShared ? new Optional<OpenType>(OpenType.Normal) : new Optional<OpenType>();
rc = _fsServer.OpenSaveDataStorage(out fileStorage, ref baseFileSystem, spaceId, saveDataId,
rc = _fsServer.OpenSaveDataStorage(ref fileStorage.Ref(), ref baseFileSystem, spaceId, saveDataId,
OpenMode.ReadWrite, openType);
if (rc.IsFailure()) return rc;
@ -110,23 +104,17 @@ namespace LibHac.FsSrv.FsCreator
throw new NotImplementedException();
}
// Todo: Properly handle shared storage
fileSystem = new ReferenceCountedDisposable<IFileSystem>(new SaveDataFileSystem(_keySet,
fileStorage.Target, IntegrityCheckLevel.ErrorOnInvalid, false));
using var saveFs = new SharedRef<SaveDataFileSystem>(new SaveDataFileSystem(_keySet, fileStorage.Get,
IntegrityCheckLevel.ErrorOnInvalid, false));
// Todo: ISaveDataExtraDataAccessor
return Result.Success;
}
finally
{
fileStorage?.Dispose();
}
}
public Result CreateExtraDataAccessor(
out ReferenceCountedDisposable<ISaveDataExtraDataAccessor> extraDataAccessor,
ReferenceCountedDisposable<IFileSystem> sourceFileSystem)
public Result CreateExtraDataAccessor(ref SharedRef<ISaveDataExtraDataAccessor> outExtraDataAccessor,
ref SharedRef<IFileSystem> baseFileSystem)
{
throw new NotImplementedException();
}

View File

@ -21,10 +21,10 @@ namespace LibHac.FsSrv.FsCreator
}
// todo: Implement NcaReader and other Nca classes
public Result Create(out ReferenceCountedDisposable<IStorage> storage, out NcaFsHeader fsHeader, Nca nca,
public Result Create(ref SharedRef<IStorage> outStorage, out NcaFsHeader fsHeader, Nca nca,
int fsIndex, bool isCodeFs)
{
UnsafeHelpers.SkipParamInit(out storage, out fsHeader);
UnsafeHelpers.SkipParamInit(out fsHeader);
Result rc = OpenStorage(out IStorage storageTemp, nca, fsIndex);
if (rc.IsFailure()) return rc;
@ -41,13 +41,13 @@ namespace LibHac.FsSrv.FsCreator
}
}
storage = new ReferenceCountedDisposable<IStorage>(storageTemp);
outStorage.Reset(storageTemp);
fsHeader = nca.GetFsHeader(fsIndex);
return Result.Success;
}
public Result CreateWithPatch(out ReferenceCountedDisposable<IStorage> storage, out NcaFsHeader fsHeader,
public Result CreateWithPatch(ref SharedRef<IStorage> outStorage, out NcaFsHeader fsHeader,
Nca baseNca, Nca patchNca, int fsIndex, bool isCodeFs)
{
throw new NotImplementedException();

View File

@ -7,34 +7,26 @@ namespace LibHac.FsSrv.FsCreator
{
public class SubDirectoryFileSystemCreator : ISubDirectoryFileSystemCreator
{
public Result Create(out ReferenceCountedDisposable<IFileSystem> subDirFileSystem,
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, in Path path)
public Result Create(ref SharedRef<IFileSystem> outSubDirFileSystem, ref SharedRef<IFileSystem> baseFileSystem,
in Path path)
{
UnsafeHelpers.SkipParamInit(out subDirFileSystem);
using var directory = new UniqueRef<IDirectory>();
Result rc = baseFileSystem.Target.OpenDirectory(ref directory.Ref(), in path, OpenDirectoryMode.Directory);
Result rc = baseFileSystem.Get.OpenDirectory(ref directory.Ref(), in path, OpenDirectoryMode.Directory);
if (rc.IsFailure()) return rc;
directory.Reset();
ReferenceCountedDisposable<SubdirectoryFileSystem> subFs = null;
try
{
subFs = new ReferenceCountedDisposable<SubdirectoryFileSystem>(
new SubdirectoryFileSystem(ref baseFileSystem));
using var subFs = new SharedRef<SubdirectoryFileSystem>(new SubdirectoryFileSystem(ref baseFileSystem));
rc = subFs.Target.Initialize(in path);
if (rc.IsFailure()) return rc;
if (!subFs.HasValue)
return ResultFs.AllocationMemoryFailedInSubDirectoryFileSystemCreatorA.Log();
subDirFileSystem = subFs.AddReference<IFileSystem>();
return Result.Success;
}
finally
{
subFs?.Dispose();
}
rc = subFs.Get.Initialize(in path);
if (rc.IsFailure()) return rc;
outSubDirFileSystem.SetByMove(ref subFs.Ref());
return Result.Success;
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
@ -6,7 +7,8 @@ namespace LibHac.FsSrv.FsCreator
{
public class TargetManagerFileSystemCreator : ITargetManagerFileSystemCreator
{
public Result Create(out ReferenceCountedDisposable<IFileSystem> fileSystem, in Path rootPath, bool openCaseSensitive, bool ensureRootPathExists, Result pathNotFoundResult)
public Result Create(ref SharedRef<IFileSystem> outFileSystem, in Path rootPath, bool openCaseSensitive,
bool ensureRootPathExists, Result pathNotFoundResult)
{
throw new NotImplementedException();
}

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs;
namespace LibHac.FsSrv
@ -141,8 +142,8 @@ namespace LibHac.FsSrv
/// <summary>
/// Returns an <see cref="SaveDataInfoReaderImpl"/> that iterates through the <see cref="SaveDataIndexer"/>.
/// </summary>
/// <param name="infoReader">If the method returns successfully, contains the created <see cref="SaveDataInfoReaderImpl"/>.</param>
/// <param name="outInfoReader">If the method returns successfully, contains the created <see cref="SaveDataInfoReaderImpl"/>.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result OpenSaveDataInfoReader(out ReferenceCountedDisposable<SaveDataInfoReaderImpl> infoReader);
Result OpenSaveDataInfoReader(ref SharedRef<SaveDataInfoReaderImpl> outInfoReader);
}
}

View File

@ -7,16 +7,10 @@ namespace LibHac.FsSrv.Impl
{
public class AsynchronousAccessFileSystem : ForwardingFileSystem
{
protected AsynchronousAccessFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem) : base(
public AsynchronousAccessFileSystem(ref SharedRef<IFileSystem> baseFileSystem) : base(
ref baseFileSystem)
{ }
public static ReferenceCountedDisposable<IFileSystem> CreateShared(
ref ReferenceCountedDisposable<IFileSystem> fileSystem)
{
return new ReferenceCountedDisposable<IFileSystem>(new AsynchronousAccessFileSystem(ref fileSystem));
}
// ReSharper disable once RedundantOverriddenMember
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
{

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.FsSrv.Sf;
using LibHac.Sf;
@ -20,9 +21,9 @@ namespace LibHac.FsSrv.Impl
throw new NotImplementedException();
}
public static Result CreateWiper(out IWiper wiper, NativeHandle memoryHandle, ulong memorySize)
public static Result CreateWiper(ref UniqueRef<IWiper> outWiper, NativeHandle memoryHandle, ulong memorySize)
{
wiper = new BisWiper(memoryHandle, memorySize);
outWiper.Reset(new BisWiper(memoryHandle, memorySize));
return Result.Success;
}

View File

@ -7,41 +7,30 @@ namespace LibHac.FsSrv.Impl
{
public class DeepRetryFileSystem : ForwardingFileSystem
{
// ReSharper disable once UnusedAutoPropertyAccessor.Local
private ReferenceCountedDisposable<DeepRetryFileSystem>.WeakReference SelfReference { get; set; }
private ReferenceCountedDisposable<IRomFileSystemAccessFailureManager> AccessFailureManager { get; set; }
// ReSharper disable once NotAccessedField.Local
private WeakRef<DeepRetryFileSystem> _selfReference;
private SharedRef<IRomFileSystemAccessFailureManager> _accessFailureManager;
protected DeepRetryFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
ref ReferenceCountedDisposable<IRomFileSystemAccessFailureManager> accessFailureManager) : base(
ref baseFileSystem)
protected DeepRetryFileSystem(ref SharedRef<IFileSystem> baseFileSystem,
ref SharedRef<IRomFileSystemAccessFailureManager> accessFailureManager) : base(ref baseFileSystem)
{
AccessFailureManager = Shared.Move(ref accessFailureManager);
_accessFailureManager = Shared.Move(ref accessFailureManager);
}
public static ReferenceCountedDisposable<IFileSystem> CreateShared(
ref ReferenceCountedDisposable<IFileSystem> fileSystem,
ref ReferenceCountedDisposable<IRomFileSystemAccessFailureManager> accessFailureManager)
public static SharedRef<IFileSystem> CreateShared(ref SharedRef<IFileSystem> baseFileSystem,
ref SharedRef<IRomFileSystemAccessFailureManager> accessFailureManager)
{
ReferenceCountedDisposable<DeepRetryFileSystem> sharedRetryFileSystem = null;
try
{
var retryFileSystem = new DeepRetryFileSystem(ref fileSystem, ref accessFailureManager);
sharedRetryFileSystem = new ReferenceCountedDisposable<DeepRetryFileSystem>(retryFileSystem);
using var retryFileSystem = new SharedRef<DeepRetryFileSystem>(
new DeepRetryFileSystem(ref baseFileSystem, ref accessFailureManager));
retryFileSystem.SelfReference =
new ReferenceCountedDisposable<DeepRetryFileSystem>.WeakReference(sharedRetryFileSystem);
retryFileSystem.Get._selfReference = new WeakRef<DeepRetryFileSystem>(ref retryFileSystem.Ref());
return sharedRetryFileSystem.AddReference<IFileSystem>();
}
finally
{
sharedRetryFileSystem?.Dispose();
}
return SharedRef<IFileSystem>.CreateMove(ref retryFileSystem.Ref());
}
public override void Dispose()
{
AccessFailureManager?.Dispose();
_accessFailureManager.Destroy();
base.Dispose();
}

View File

@ -4,23 +4,25 @@ using LibHac.Fs;
namespace LibHac.FsSrv.Impl
{
/// <summary>
/// An <see cref="IStorage"/> for simulating device failures
/// </summary>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
internal class DeviceEventSimulationStorage : IStorage
{
private ReferenceCountedDisposable<IStorage> _baseStorage;
private SharedRef<IStorage> _baseStorage;
private IDeviceEventSimulator _eventSimulator;
private DeviceEventSimulationStorage(ref ReferenceCountedDisposable<IStorage> baseStorage,
IDeviceEventSimulator eventSimulator)
public DeviceEventSimulationStorage(ref SharedRef<IStorage> baseStorage, IDeviceEventSimulator eventSimulator)
{
_baseStorage = Shared.Move(ref baseStorage);
_baseStorage = SharedRef<IStorage>.CreateMove(ref baseStorage);
_eventSimulator = eventSimulator;
}
public static ReferenceCountedDisposable<IStorage> CreateShared(
ref ReferenceCountedDisposable<IStorage> baseStorage, IDeviceEventSimulator eventSimulator)
public override void Dispose()
{
var storage = new DeviceEventSimulationStorage(ref baseStorage, eventSimulator);
return new ReferenceCountedDisposable<IStorage>(storage);
_baseStorage.Destroy();
base.Dispose();
}
protected override Result DoRead(long offset, Span<byte> destination)
@ -28,7 +30,7 @@ namespace LibHac.FsSrv.Impl
Result rc = _eventSimulator.CheckSimulatedAccessFailureEvent(SimulatingDeviceTargetOperation.Read);
if (rc.IsFailure()) return rc;
return _baseStorage.Target.Read(offset, destination);
return _baseStorage.Get.Read(offset, destination);
}
protected override Result DoWrite(long offset, ReadOnlySpan<byte> source)
@ -36,28 +38,28 @@ namespace LibHac.FsSrv.Impl
Result rc = _eventSimulator.CheckSimulatedAccessFailureEvent(SimulatingDeviceTargetOperation.Write);
if (rc.IsFailure()) return rc;
return _baseStorage.Target.Write(offset, source);
return _baseStorage.Get.Write(offset, source);
}
protected override Result DoFlush()
{
return _baseStorage.Target.Flush();
return _baseStorage.Get.Flush();
}
protected override Result DoSetSize(long size)
{
return _baseStorage.Target.SetSize(size);
return _baseStorage.Get.SetSize(size);
}
protected override Result DoGetSize(out long size)
{
return _baseStorage.Target.GetSize(out size);
return _baseStorage.Get.GetSize(out size);
}
protected override Result DoOperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
ReadOnlySpan<byte> inBuffer)
{
return _baseStorage.Target.OperateRange(outBuffer, operationId, offset, size, inBuffer);
return _baseStorage.Get.OperateRange(outBuffer, operationId, offset, size, inBuffer);
}
}
}

View File

@ -20,25 +20,25 @@ namespace LibHac.FsSrv.Impl
/// <summary>
/// Wraps an <see cref="IFile"/> to allow interfacing with it via the <see cref="IFileSf"/> interface over IPC.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
public class FileInterfaceAdapter : IFileSf
{
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> _parentFs;
private SharedRef<FileSystemInterfaceAdapter> _parentFs;
private UniqueRef<IFile> _baseFile;
private bool _allowAllOperations;
public FileInterfaceAdapter(ref UniqueRef<IFile> baseFile,
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem, bool allowAllOperations)
ref SharedRef<FileSystemInterfaceAdapter> parentFileSystem, bool allowAllOperations)
{
_parentFs = SharedRef<FileSystemInterfaceAdapter>.CreateMove(ref parentFileSystem);
_baseFile = new UniqueRef<IFile>(ref baseFile);
_parentFs = Shared.Move(ref parentFileSystem);
_allowAllOperations = allowAllOperations;
}
public void Dispose()
{
_baseFile.Destroy();
_parentFs?.Dispose();
_parentFs.Destroy();
}
public Result Read(out long bytesRead, long offset, OutBuffer destination, long size, ReadOption option)
@ -175,23 +175,23 @@ namespace LibHac.FsSrv.Impl
/// <summary>
/// Wraps an <see cref="IDirectory"/> to allow interfacing with it via the <see cref="IDirectorySf"/> interface over IPC.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
public class DirectoryInterfaceAdapter : IDirectorySf
{
private ReferenceCountedDisposable<FileSystemInterfaceAdapter> _parentFs;
private SharedRef<FileSystemInterfaceAdapter> _parentFs;
private UniqueRef<IDirectory> _baseDirectory;
public DirectoryInterfaceAdapter(ref UniqueRef<IDirectory> baseDirectory,
ref ReferenceCountedDisposable<FileSystemInterfaceAdapter> parentFileSystem)
ref SharedRef<FileSystemInterfaceAdapter> parentFileSystem)
{
_parentFs = SharedRef<FileSystemInterfaceAdapter>.CreateMove(ref parentFileSystem);
_baseDirectory = new UniqueRef<IDirectory>(ref baseDirectory);
_parentFs = Shared.Move(ref parentFileSystem);
}
public void Dispose()
{
_baseDirectory.Destroy();
_parentFs?.Dispose();
_parentFs.Destroy();
}
public Result Read(out long entriesRead, OutBuffer entryBuffer)
@ -235,10 +235,10 @@ namespace LibHac.FsSrv.Impl
/// Wraps an <see cref="IFileSystem"/> to allow interfacing with it via the <see cref="IFileSystemSf"/> interface over IPC.
/// All incoming paths are normalized before they are passed to the base <see cref="IFileSystem"/>.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
public class FileSystemInterfaceAdapter : IFileSystemSf
{
private ReferenceCountedDisposable<IFileSystem> _baseFileSystem;
private SharedRef<IFileSystem> _baseFileSystem;
private PathFlags _pathFlags;
// This field is always false in FS 12.0.0. Not sure what it's actually used for.
@ -246,67 +246,47 @@ namespace LibHac.FsSrv.Impl
// In FS, FileSystemInterfaceAdapter is derived from ISharedObject, so that's used for ref-counting when
// creating files and directories. We don't have an ISharedObject, so a self-reference is used instead.
private ReferenceCountedDisposable<FileSystemInterfaceAdapter>.WeakReference _selfReference;
private WeakRef<FileSystemInterfaceAdapter> _selfReference;
private FileSystemInterfaceAdapter(ref ReferenceCountedDisposable<IFileSystem> fileSystem,
private FileSystemInterfaceAdapter(ref SharedRef<IFileSystem> fileSystem,
bool allowAllOperations)
{
_baseFileSystem = Shared.Move(ref fileSystem);
_baseFileSystem = SharedRef<IFileSystem>.CreateMove(ref fileSystem);
_allowAllOperations = allowAllOperations;
}
private FileSystemInterfaceAdapter(ref ReferenceCountedDisposable<IFileSystem> fileSystem, PathFlags flags,
private FileSystemInterfaceAdapter(ref SharedRef<IFileSystem> fileSystem, PathFlags flags,
bool allowAllOperations)
{
_baseFileSystem = Shared.Move(ref fileSystem);
_baseFileSystem = SharedRef<IFileSystem>.CreateMove(ref fileSystem);
_pathFlags = flags;
_allowAllOperations = allowAllOperations;
}
public static ReferenceCountedDisposable<IFileSystemSf> CreateShared(
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, bool allowAllOperations)
public static SharedRef<IFileSystemSf> CreateShared(ref SharedRef<IFileSystem> baseFileSystem, bool allowAllOperations)
{
ReferenceCountedDisposable<FileSystemInterfaceAdapter> sharedAdapter = null;
try
{
var adapter = new FileSystemInterfaceAdapter(ref baseFileSystem, allowAllOperations);
sharedAdapter = new ReferenceCountedDisposable<FileSystemInterfaceAdapter>(adapter);
var adapter = new FileSystemInterfaceAdapter(ref baseFileSystem, allowAllOperations);
using var sharedAdapter = new SharedRef<FileSystemInterfaceAdapter>(adapter);
adapter._selfReference =
new ReferenceCountedDisposable<FileSystemInterfaceAdapter>.WeakReference(sharedAdapter);
adapter._selfReference = new WeakRef<FileSystemInterfaceAdapter>(ref sharedAdapter.Ref());
return sharedAdapter.AddReference<IFileSystemSf>();
}
finally
{
sharedAdapter?.Dispose();
}
return SharedRef<IFileSystemSf>.CreateMove(ref sharedAdapter.Ref());
}
public static ReferenceCountedDisposable<IFileSystemSf> CreateShared(
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem, PathFlags flags, bool allowAllOperations)
public static SharedRef<IFileSystemSf> CreateShared(
ref SharedRef<IFileSystem> baseFileSystem, PathFlags flags, bool allowAllOperations)
{
ReferenceCountedDisposable<FileSystemInterfaceAdapter> sharedAdapter = null;
try
{
var adapter = new FileSystemInterfaceAdapter(ref baseFileSystem, flags, allowAllOperations);
sharedAdapter = new ReferenceCountedDisposable<FileSystemInterfaceAdapter>(adapter);
var adapter = new FileSystemInterfaceAdapter(ref baseFileSystem, flags, allowAllOperations);
using var sharedAdapter = new SharedRef<FileSystemInterfaceAdapter>(adapter);
adapter._selfReference =
new ReferenceCountedDisposable<FileSystemInterfaceAdapter>.WeakReference(sharedAdapter);
adapter._selfReference = new WeakRef<FileSystemInterfaceAdapter>(ref sharedAdapter.Ref());
return sharedAdapter.AddReference<IFileSystemSf>();
}
finally
{
sharedAdapter?.Dispose();
}
return SharedRef<IFileSystemSf>.CreateMove(ref sharedAdapter.Ref());
}
public void Dispose()
{
ReferenceCountedDisposable<IFileSystem> tempFs = Shared.Move(ref _baseFileSystem);
tempFs?.Dispose();
_baseFileSystem.Destroy();
}
private static ReadOnlySpan<byte> RootDir => new[] { (byte)'/' };
@ -341,7 +321,7 @@ namespace LibHac.FsSrv.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
if (rc.IsFailure()) return rc;
rc = _baseFileSystem.Target.CreateFile(in pathNormalized, size, (CreateFileOptions)option);
rc = _baseFileSystem.Get.CreateFile(in pathNormalized, size, (CreateFileOptions)option);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -353,7 +333,7 @@ namespace LibHac.FsSrv.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
if (rc.IsFailure()) return rc;
rc = _baseFileSystem.Target.DeleteFile(in pathNormalized);
rc = _baseFileSystem.Get.DeleteFile(in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -368,7 +348,7 @@ namespace LibHac.FsSrv.Impl
if (pathNormalized == RootDir)
return ResultFs.PathAlreadyExists.Log();
rc = _baseFileSystem.Target.CreateDirectory(in pathNormalized);
rc = _baseFileSystem.Get.CreateDirectory(in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -383,7 +363,7 @@ namespace LibHac.FsSrv.Impl
if (pathNormalized == RootDir)
return ResultFs.DirectoryNotDeletable.Log();
rc = _baseFileSystem.Target.DeleteDirectory(in pathNormalized);
rc = _baseFileSystem.Get.DeleteDirectory(in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -398,7 +378,7 @@ namespace LibHac.FsSrv.Impl
if (pathNormalized == RootDir)
return ResultFs.DirectoryNotDeletable.Log();
rc = _baseFileSystem.Target.DeleteDirectoryRecursively(in pathNormalized);
rc = _baseFileSystem.Get.DeleteDirectoryRecursively(in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -410,7 +390,7 @@ namespace LibHac.FsSrv.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
if (rc.IsFailure()) return rc;
rc = _baseFileSystem.Target.CleanDirectoryRecursively(in pathNormalized);
rc = _baseFileSystem.Get.CleanDirectoryRecursively(in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -426,7 +406,7 @@ namespace LibHac.FsSrv.Impl
rc = SetUpPath(ref newPathNormalized.Ref(), in newPath);
if (rc.IsFailure()) return rc;
rc = _baseFileSystem.Target.RenameFile(in currentPathNormalized, in newPathNormalized);
rc = _baseFileSystem.Get.RenameFile(in currentPathNormalized, in newPathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -445,7 +425,7 @@ namespace LibHac.FsSrv.Impl
if (PathUtility.IsSubPath(currentPathNormalized.GetString(), newPathNormalized.GetString()))
return ResultFs.DirectoryNotRenamable.Log();
rc = _baseFileSystem.Target.RenameDirectory(in currentPathNormalized, in newPathNormalized);
rc = _baseFileSystem.Get.RenameDirectory(in currentPathNormalized, in newPathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
@ -459,7 +439,7 @@ namespace LibHac.FsSrv.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
if (rc.IsFailure()) return rc;
rc = _baseFileSystem.Target.GetEntryType(out DirectoryEntryType type, in pathNormalized);
rc = _baseFileSystem.Get.GetEntryType(out DirectoryEntryType type, in pathNormalized);
if (rc.IsFailure()) return rc;
entryType = (uint)type;
@ -474,7 +454,7 @@ namespace LibHac.FsSrv.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
if (rc.IsFailure()) return rc;
rc = _baseFileSystem.Target.GetFreeSpaceSize(out long space, in pathNormalized);
rc = _baseFileSystem.Get.GetFreeSpaceSize(out long space, in pathNormalized);
if (rc.IsFailure()) return rc;
freeSpace = space;
@ -489,17 +469,16 @@ namespace LibHac.FsSrv.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
if (rc.IsFailure()) return rc;
rc = _baseFileSystem.Target.GetTotalSpaceSize(out long space, in pathNormalized);
rc = _baseFileSystem.Get.GetTotalSpaceSize(out long space, in pathNormalized);
if (rc.IsFailure()) return rc;
totalSpace = space;
return Result.Success;
}
public Result OpenFile(out ReferenceCountedDisposable<IFileSf> outFile, in PathSf path, uint mode)
public Result OpenFile(ref SharedRef<IFileSf> outFile, in PathSf path, uint mode)
{
const int maxTryCount = 2;
UnsafeHelpers.SkipParamInit(out outFile);
using var pathNormalized = new Path();
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
@ -509,7 +488,7 @@ namespace LibHac.FsSrv.Impl
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
{
rc = _baseFileSystem.Target.OpenFile(ref file.Ref(), in pathNormalized, (OpenMode)mode);
rc = _baseFileSystem.Get.OpenFile(ref file.Ref(), in pathNormalized, (OpenMode)mode);
// Retry on ResultDataCorrupted
if (!ResultFs.DataCorrupted.Includes(rc))
@ -518,17 +497,18 @@ namespace LibHac.FsSrv.Impl
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.AddReference();
var adapter = new FileInterfaceAdapter(ref file.Ref(), ref selfReference, _allowAllOperations);
outFile = new ReferenceCountedDisposable<IFileSf>(adapter);
using SharedRef<FileSystemInterfaceAdapter> selfReference =
SharedRef<FileSystemInterfaceAdapter>.Create(ref _selfReference);
var adapter = new FileInterfaceAdapter(ref file.Ref(), ref selfReference.Ref(), _allowAllOperations);
outFile.Reset(adapter);
return Result.Success;
}
public Result OpenDirectory(out ReferenceCountedDisposable<IDirectorySf> outDirectory, in PathSf path, uint mode)
public Result OpenDirectory(ref SharedRef<IDirectorySf> outDirectory, in PathSf path, uint mode)
{
const int maxTryCount = 2;
UnsafeHelpers.SkipParamInit(out outDirectory);
using var pathNormalized = new Path();
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
@ -538,7 +518,7 @@ namespace LibHac.FsSrv.Impl
for (int tryNum = 0; tryNum < maxTryCount; tryNum++)
{
rc = _baseFileSystem.Target.OpenDirectory(ref directory.Ref(), in pathNormalized,
rc = _baseFileSystem.Get.OpenDirectory(ref directory.Ref(), in pathNormalized,
(OpenDirectoryMode)mode);
// Retry on ResultDataCorrupted
@ -548,16 +528,18 @@ namespace LibHac.FsSrv.Impl
if (rc.IsFailure()) return rc;
ReferenceCountedDisposable<FileSystemInterfaceAdapter> selfReference = _selfReference.AddReference();
var adapter = new DirectoryInterfaceAdapter(ref directory.Ref(), ref selfReference);
outDirectory = new ReferenceCountedDisposable<IDirectorySf>(adapter);
using SharedRef<FileSystemInterfaceAdapter> selfReference =
SharedRef<FileSystemInterfaceAdapter>.Create(ref _selfReference);
var adapter = new DirectoryInterfaceAdapter(ref directory.Ref(), ref selfReference.Ref());
outDirectory.Reset(adapter);
return Result.Success;
}
public Result Commit()
{
return _baseFileSystem.Target.Commit();
return _baseFileSystem.Get.Commit();
}
public Result GetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in PathSf path)
@ -568,7 +550,7 @@ namespace LibHac.FsSrv.Impl
Result rc = SetUpPath(ref pathNormalized.Ref(), in path);
if (rc.IsFailure()) return rc;
rc = _baseFileSystem.Target.GetFileTimeStampRaw(out FileTimeStampRaw tempTimeStamp, in pathNormalized);
rc = _baseFileSystem.Get.GetFileTimeStampRaw(out FileTimeStampRaw tempTimeStamp, in pathNormalized);
if (rc.IsFailure()) return rc;
timeStamp = tempTimeStamp;
@ -599,16 +581,16 @@ namespace LibHac.FsSrv.Impl
rc = SetUpPath(ref pathNormalized.Ref(), in path);
if (rc.IsFailure()) return rc;
rc = _baseFileSystem.Target.QueryEntry(outBuffer.Buffer, inBuffer.Buffer, (QueryId)queryId,
rc = _baseFileSystem.Get.QueryEntry(outBuffer.Buffer, inBuffer.Buffer, (QueryId)queryId,
in pathNormalized);
if (rc.IsFailure()) return rc;
return Result.Success;
}
public Result GetImpl(out ReferenceCountedDisposable<IFileSystem> fileSystem)
public Result GetImpl(ref SharedRef<IFileSystem> fileSystem)
{
fileSystem = _baseFileSystem.AddReference();
fileSystem.SetByCopy(ref _baseFileSystem);
return Result.Success;
}
}

View File

@ -8,34 +8,32 @@ namespace LibHac.FsSrv.Impl
{
public static class FileSystemProxyServiceObject
{
public static ReferenceCountedDisposable<IFileSystemProxy> GetFileSystemProxyServiceObject(
this FileSystemServerImpl fsSrv)
public static SharedRef<IFileSystemProxy> GetFileSystemProxyServiceObject(this FileSystemServerImpl fsSrv)
{
return new ReferenceCountedDisposable<IFileSystemProxy>(new FileSystemProxyImpl(fsSrv.FsSrv));
return new SharedRef<IFileSystemProxy>(new FileSystemProxyImpl(fsSrv.FsSrv));
}
public static ReferenceCountedDisposable<IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObject(
public static SharedRef<IFileSystemProxyForLoader> GetFileSystemProxyForLoaderServiceObject(
this FileSystemServerImpl fsSrv)
{
return new ReferenceCountedDisposable<IFileSystemProxyForLoader>(new FileSystemProxyImpl(fsSrv.FsSrv));
return new SharedRef<IFileSystemProxyForLoader>(new FileSystemProxyImpl(fsSrv.FsSrv));
}
public static ReferenceCountedDisposable<IFileSystemProxyForLoader>
GetInvalidFileSystemProxyForLoaderServiceObject(this FileSystemServerImpl fsSrv)
{
return new ReferenceCountedDisposable<IFileSystemProxyForLoader>(new InvalidFileSystemProxyImplForLoader());
}
public static ReferenceCountedDisposable<IProgramRegistry> GetProgramRegistryServiceObject(
public static SharedRef<IFileSystemProxyForLoader> GetInvalidFileSystemProxyForLoaderServiceObject(
this FileSystemServerImpl fsSrv)
{
return new ReferenceCountedDisposable<IProgramRegistry>(new ProgramRegistryImpl(fsSrv.FsSrv));
return new SharedRef<IFileSystemProxyForLoader>(new InvalidFileSystemProxyImplForLoader());
}
public static ReferenceCountedDisposable<IProgramRegistry> GetInvalidProgramRegistryServiceObject(
public static SharedRef<IProgramRegistry> GetProgramRegistryServiceObject(this FileSystemServerImpl fsSrv)
{
return new SharedRef<IProgramRegistry>(new ProgramRegistryImpl(fsSrv.FsSrv));
}
public static SharedRef<IProgramRegistry> GetInvalidProgramRegistryServiceObject(
this FileSystemServerImpl fsSrv)
{
return new ReferenceCountedDisposable<IProgramRegistry>(new InvalidProgramRegistryImpl());
return new SharedRef<IProgramRegistry>(new InvalidProgramRegistryImpl());
}
private class InvalidFileSystemProxyImplForLoader : IFileSystemProxyForLoader
@ -49,10 +47,10 @@ namespace LibHac.FsSrv.Impl
return ResultFs.PortAcceptableCountLimited.Log();
}
public Result OpenCodeFileSystem(out ReferenceCountedDisposable<IFileSystem> fileSystem,
public Result OpenCodeFileSystem(ref SharedRef<IFileSystem> fileSystem,
out CodeVerificationData verificationData, in FspPath path, ProgramId programId)
{
UnsafeHelpers.SkipParamInit(out fileSystem, out verificationData);
UnsafeHelpers.SkipParamInit(out verificationData);
return ResultFs.PortAcceptableCountLimited.Log();
}

View File

@ -69,7 +69,7 @@ namespace LibHac.FsSrv.Impl
public void SetDeviceEvent(SimulatingDeviceTargetOperation operation,
SimulatingDeviceAccessFailureEventType failureType, Result failureResult, bool isRecurringEvent)
{
using ScopedLock<SdkRecursiveMutex> lk = ScopedLock.Lock(ref _mutex);
using ScopedLock<SdkRecursiveMutex> scopedLock = ScopedLock.Lock(ref _mutex);
if (failureResult.IsFailure())
_failureResult = failureResult;
@ -82,7 +82,7 @@ namespace LibHac.FsSrv.Impl
public void ClearDeviceEvent()
{
using ScopedLock<SdkRecursiveMutex> lk = ScopedLock.Lock(ref _mutex);
using ScopedLock<SdkRecursiveMutex> scopedLock = ScopedLock.Lock(ref _mutex);
_isEventSet = false;
_simulatedFailureType = SimulatingDeviceAccessFailureEventType.None;
@ -93,7 +93,7 @@ namespace LibHac.FsSrv.Impl
public void SetDetectionSimulationMode(SimulatingDeviceDetectionMode mode)
{
using ScopedLock<SdkRecursiveMutex> lk = ScopedLock.Lock(ref _mutex);
using ScopedLock<SdkRecursiveMutex> scopedLock = ScopedLock.Lock(ref _mutex);
_isDetectionSimulationEnabled = mode != SimulatingDeviceDetectionMode.NoSimulation;
_detectionSimulationMode = mode;
@ -109,7 +109,7 @@ namespace LibHac.FsSrv.Impl
if (_isEventSet)
return Result.Success;
using ScopedLock<SdkRecursiveMutex> lk = ScopedLock.Lock(ref _mutex);
using ScopedLock<SdkRecursiveMutex> scopedLock = ScopedLock.Lock(ref _mutex);
if ((_simulatedOperation & operation) == 0)
return Result.Success;

View File

@ -87,63 +87,62 @@ namespace LibHac.FsSrv.Impl
// ReSharper disable once InconsistentNaming
public abstract class IResultConvertFileSystem : IFileSystem
{
protected ReferenceCountedDisposable<IFileSystem> BaseFileSystem;
protected SharedRef<IFileSystem> BaseFileSystem;
protected IResultConvertFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem)
protected IResultConvertFileSystem(ref SharedRef<IFileSystem> baseFileSystem)
{
BaseFileSystem = Shared.Move(ref baseFileSystem);
BaseFileSystem = SharedRef<IFileSystem>.CreateMove(ref baseFileSystem);
}
public override void Dispose()
{
BaseFileSystem?.Dispose();
BaseFileSystem = null;
BaseFileSystem.Destroy();
base.Dispose();
}
protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option)
{
return ConvertResult(BaseFileSystem.Target.CreateFile(path, size, option));
return ConvertResult(BaseFileSystem.Get.CreateFile(path, size, option));
}
protected override Result DoDeleteFile(in Path path)
{
return ConvertResult(BaseFileSystem.Target.DeleteFile(path));
return ConvertResult(BaseFileSystem.Get.DeleteFile(path));
}
protected override Result DoCreateDirectory(in Path path)
{
return ConvertResult(BaseFileSystem.Target.CreateDirectory(path));
return ConvertResult(BaseFileSystem.Get.CreateDirectory(path));
}
protected override Result DoDeleteDirectory(in Path path)
{
return ConvertResult(BaseFileSystem.Target.DeleteDirectory(path));
return ConvertResult(BaseFileSystem.Get.DeleteDirectory(path));
}
protected override Result DoDeleteDirectoryRecursively(in Path path)
{
return ConvertResult(BaseFileSystem.Target.DeleteDirectoryRecursively(path));
return ConvertResult(BaseFileSystem.Get.DeleteDirectoryRecursively(path));
}
protected override Result DoCleanDirectoryRecursively(in Path path)
{
return ConvertResult(BaseFileSystem.Target.CleanDirectoryRecursively(path));
return ConvertResult(BaseFileSystem.Get.CleanDirectoryRecursively(path));
}
protected override Result DoRenameFile(in Path currentPath, in Path newPath)
{
return ConvertResult(BaseFileSystem.Target.RenameFile(currentPath, newPath));
return ConvertResult(BaseFileSystem.Get.RenameFile(currentPath, newPath));
}
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath)
{
return ConvertResult(BaseFileSystem.Target.RenameDirectory(currentPath, newPath));
return ConvertResult(BaseFileSystem.Get.RenameDirectory(currentPath, newPath));
}
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
{
return ConvertResult(BaseFileSystem.Target.GetEntryType(out entryType, path));
return ConvertResult(BaseFileSystem.Get.GetEntryType(out entryType, path));
}
protected abstract override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode);
@ -153,43 +152,43 @@ namespace LibHac.FsSrv.Impl
protected override Result DoCommit()
{
return ConvertResult(BaseFileSystem.Target.Commit());
return ConvertResult(BaseFileSystem.Get.Commit());
}
protected override Result DoCommitProvisionally(long counter)
{
return ConvertResult(BaseFileSystem.Target.CommitProvisionally(counter));
return ConvertResult(BaseFileSystem.Get.CommitProvisionally(counter));
}
protected override Result DoRollback()
{
return ConvertResult(BaseFileSystem.Target.Rollback());
return ConvertResult(BaseFileSystem.Get.Rollback());
}
protected override Result DoFlush()
{
return ConvertResult(BaseFileSystem.Target.Flush());
return ConvertResult(BaseFileSystem.Get.Flush());
}
protected override Result DoGetFileTimeStampRaw(out FileTimeStampRaw timeStamp, in Path path)
{
return ConvertResult(BaseFileSystem.Target.GetFileTimeStampRaw(out timeStamp, path));
return ConvertResult(BaseFileSystem.Get.GetFileTimeStampRaw(out timeStamp, path));
}
protected override Result DoQueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId,
in Path path)
{
return ConvertResult(BaseFileSystem.Target.QueryEntry(outBuffer, inBuffer, queryId, path));
return ConvertResult(BaseFileSystem.Get.QueryEntry(outBuffer, inBuffer, queryId, path));
}
protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path)
{
return ConvertResult(BaseFileSystem.Target.GetFreeSpaceSize(out freeSpace, path));
return ConvertResult(BaseFileSystem.Get.GetFreeSpaceSize(out freeSpace, path));
}
protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path)
{
return ConvertResult(BaseFileSystem.Target.GetTotalSpaceSize(out totalSpace, path));
return ConvertResult(BaseFileSystem.Get.GetTotalSpaceSize(out totalSpace, path));
}
protected abstract Result ConvertResult(Result result);

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
using LibHac.Ncm;
@ -7,9 +8,7 @@ namespace LibHac.FsSrv.Impl
{
public interface IRomFileSystemAccessFailureManager : IDisposable
{
Result OpenDataStorageCore(out ReferenceCountedDisposable<IStorage> storage, out Hash ncaHeaderDigest, ulong id,
StorageId storageId);
Result OpenDataStorageCore(ref SharedRef<IStorage> outStorage, out Hash ncaHeaderDigest, ulong id, StorageId storageId);
Result HandleResolubleAccessFailure(out bool wasDeferred, Result resultForNoFailureDetected);
void IncrementRomFsRemountForDataCorruptionCount();
void IncrementRomFsUnrecoverableDataCorruptionByRemountCount();

View File

@ -1,4 +1,5 @@
using System;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
@ -9,6 +10,6 @@ namespace LibHac.FsSrv.Impl
Result RecoverMultiCommit();
Result IsProvisionallyCommittedSaveData(out bool isProvisionallyCommitted, in SaveDataInfo saveInfo);
Result RecoverProvisionallyCommittedSaveData(in SaveDataInfo saveInfo, bool doRollback);
Result OpenMultiCommitContext(out ReferenceCountedDisposable<IFileSystem> contextFileSystem);
Result OpenMultiCommitContext(ref SharedRef<IFileSystem> contextFileSystem);
}
}

View File

@ -18,9 +18,9 @@ namespace LibHac.FsSrv.Impl
Result WriteSaveDataFileSystemExtraDataCore(SaveDataSpaceId spaceId, ulong saveDataId, in SaveDataExtraData extraData, SaveDataType type, bool updateTimeStamp);
Result FinalizeSaveDataCreation(ulong saveDataId, SaveDataSpaceId spaceId);
Result CancelSaveDataCreation(ulong saveDataId, SaveDataSpaceId spaceId);
Result OpenSaveDataFile(out ReferenceCountedDisposable<IFileSf> file, SaveDataSpaceId spaceId, in SaveDataAttribute attribute, SaveDataMetaType metaType);
Result OpenSaveDataMetaFileRaw(out ReferenceCountedDisposable<IFile> file, SaveDataSpaceId spaceId, ulong saveDataId, SaveDataMetaType metaType, OpenMode mode);
Result OpenSaveDataInternalStorageFileSystemCore(out ReferenceCountedDisposable<IFileSystem> fileSystem, SaveDataSpaceId spaceId, ulong saveDataId, bool useSecondMacKey);
Result OpenSaveDataFile(ref SharedRef<IFileSf> file, SaveDataSpaceId spaceId, in SaveDataAttribute attribute, SaveDataMetaType metaType);
Result OpenSaveDataMetaFileRaw(ref SharedRef<IFile> file, SaveDataSpaceId spaceId, ulong saveDataId, SaveDataMetaType metaType, OpenMode mode);
Result OpenSaveDataInternalStorageFileSystemCore(ref SharedRef<IFileSystem> fileSystem, SaveDataSpaceId spaceId, ulong saveDataId, bool useSecondMacKey);
Result ExtendSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, long dataSize, long journalSize);
Result DeleteSaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId);
Result SwapSaveDataKeyAndState(SaveDataSpaceId spaceId, ulong saveDataId1, ulong saveDataId2);

View File

@ -1,10 +1,12 @@
using System;
using LibHac.Common;
using LibHac.Common.FixedArrays;
using LibHac.Diag;
using LibHac.Fs;
using LibHac.Lr;
using LibHac.Ncm;
using LibHac.Os;
using LibHac.Util;
namespace LibHac.FsSrv.Impl
{
@ -37,34 +39,39 @@ namespace LibHac.FsSrv.Impl
/// <summary>
/// Manages resolving the location of NCAs via the <c>lr</c> service.
/// </summary>
/// <remarks>Based on FS 12.0.3 (nnSdk 12.3.1)</remarks>
/// <remarks>Based on FS 12.1.0 (nnSdk 12.3.1)</remarks>
internal class LocationResolverSet : IDisposable
{
private const int LocationResolverCount = 5;
// Todo: Use Optional<T>
private LocationResolver[] _resolvers;
private AddOnContentLocationResolver _aocResolver;
private Array5<Optional<LocationResolver>> _resolvers;
private Optional<AddOnContentLocationResolver> _aocResolver;
private SdkMutexType _mutex;
// LibHac addition
private FileSystemServer _fsServer;
private HorizonClient Hos => _fsServer.Hos;
public LocationResolverSet(FileSystemServer fsServer)
{
_resolvers = new LocationResolver[LocationResolverCount];
_mutex.Initialize();
_fsServer = fsServer;
}
public void Dispose()
{
foreach (LocationResolver resolver in _resolvers)
for (int i = 0; i < Array5<SharedRef<LocationResolver>>.Length; i++)
{
resolver?.Dispose();
if (_resolvers[i].HasValue)
{
_resolvers[i].Value.Dispose();
_resolvers[i].Clear();
}
}
_aocResolver?.Dispose();
if (_aocResolver.HasValue)
{
_aocResolver.Value.Dispose();
_aocResolver.Clear();
}
}
private static Result SetUpFsPath(ref Fs.Path outPath, in Lr.Path lrPath)
@ -90,48 +97,43 @@ namespace LibHac.FsSrv.Impl
_fsServer.InitializeLocationResolverSet();
if (!IsValidStorageId(storageId))
return ResultLr.LocationResolverNotFound.Log();
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _mutex);
int index = GetResolverIndexFromStorageId(storageId);
if (index == -1)
return ResultLr.ApplicationNotFound.Log();
if (index < 0)
return ResultLr.LocationResolverNotFound.Log();
ref LocationResolver lr = ref _resolvers[index];
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
// Open the location resolver if it hasn't been already
if (lr is null && Hos.Lr.OpenLocationResolver(out lr, storageId).IsFailure())
return ResultLr.LocationResolverNotFound.Log();
if (!_resolvers[index].HasValue)
{
_resolvers[index].Set(null);
Result rc = Hos.Lr.OpenLocationResolver(out _resolvers[index].Value, storageId);
resolver = lr;
if (rc.IsFailure())
{
_resolvers[index].Clear();
return ResultLr.ApplicationNotFound.Log();
}
}
resolver = _resolvers[index].Value;
return Result.Success;
}
private Result GetRegisteredLocationResolver(out RegisteredLocationResolver resolver)
{
Result rc = Hos.Lr.OpenRegisteredLocationResolver(out RegisteredLocationResolver lr);
_fsServer.InitializeLocationResolverSet();
if (rc.IsFailure())
{
lr?.Dispose();
UnsafeHelpers.SkipParamInit(out resolver);
return rc;
}
resolver = lr;
return Result.Success;
return Hos.Lr.OpenRegisteredLocationResolver(out resolver);
}
private Result GetAddOnContentLocationResolver(out AddOnContentLocationResolver resolver)
{
_fsServer.InitializeLocationResolverSet();
using ScopedLock<SdkMutexType> lk = ScopedLock.Lock(ref _mutex);
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
if (_aocResolver is null)
if (!_aocResolver.HasValue)
{
Result rc = Hos.Lr.OpenAddOnContentLocationResolver(out AddOnContentLocationResolver lr);
if (rc.IsFailure())
@ -143,7 +145,7 @@ namespace LibHac.FsSrv.Impl
_aocResolver = lr;
}
resolver = _aocResolver;
resolver = _aocResolver.Value;
return Result.Success;
}
@ -230,8 +232,6 @@ namespace LibHac.FsSrv.Impl
public Result ResolveRegisteredProgramPath(ref Fs.Path outPath, ulong id)
{
_fsServer.InitializeLocationResolverSet();
RegisteredLocationResolver resolver = null;
try
{
@ -251,8 +251,6 @@ namespace LibHac.FsSrv.Impl
public Result ResolveRegisteredHtmlDocumentPath(ref Fs.Path outPath, ulong id)
{
_fsServer.InitializeLocationResolverSet();
RegisteredLocationResolver resolver = null;
try
{

View File

@ -40,9 +40,8 @@ namespace LibHac.FsSrv.Impl
/// Even though multi-commits are supposed to be atomic, issues can arise from errors during the process of fully committing the save data.
/// Save data image files are designed so that minimal changes are made when fully committing a provisionally committed save.
/// However if any commit fails for any reason, all other saves in the multi-commit will still be committed.
/// This can especially cause issues with directory save data where finishing a commit is much more involved.<br/>
/// <br/>
/// Based on FS 12.0.3 (nnSdk 12.3.1)
/// This can especially cause issues with directory save data where finishing a commit is much more involved.
/// <para>Based on FS 12.1.0 (nnSdk 12.3.1)</para>
/// </remarks>
internal class MultiCommitManager : IMultiCommitManager
{
@ -60,40 +59,39 @@ namespace LibHac.FsSrv.Impl
private static ReadOnlySpan<byte> CommitContextFileName =>
new[] { (byte)'/', (byte)'c', (byte)'o', (byte)'m', (byte)'m', (byte)'i', (byte)'t', (byte)'i', (byte)'n', (byte)'f', (byte)'o' };
private ReferenceCountedDisposable<ISaveDataMultiCommitCoreInterface> _multiCommitInterface;
private readonly ReferenceCountedDisposable<IFileSystem>[] _fileSystems;
private SharedRef<ISaveDataMultiCommitCoreInterface> _multiCommitInterface;
private readonly SharedRef<IFileSystem>[] _fileSystems;
private int _fileSystemCount;
private long _counter;
// Extra field used in LibHac
// LibHac additions
private readonly FileSystemServer _fsServer;
private ref MultiCommitManagerGlobals Globals => ref _fsServer.Globals.MultiCommitManager;
public MultiCommitManager(FileSystemServer fsServer, ref ReferenceCountedDisposable<ISaveDataMultiCommitCoreInterface> multiCommitInterface)
public MultiCommitManager(FileSystemServer fsServer, ref SharedRef<ISaveDataMultiCommitCoreInterface> multiCommitInterface)
{
_fsServer = fsServer;
_multiCommitInterface = Shared.Move(ref multiCommitInterface);
_fileSystems = new ReferenceCountedDisposable<IFileSystem>[MaxFileSystemCount];
_multiCommitInterface = SharedRef<ISaveDataMultiCommitCoreInterface>.CreateMove(ref multiCommitInterface);
_fileSystems = new SharedRef<IFileSystem>[MaxFileSystemCount];
_fileSystemCount = 0;
_counter = 0;
}
public static ReferenceCountedDisposable<IMultiCommitManager> CreateShared(FileSystemServer fsServer,
ref ReferenceCountedDisposable<ISaveDataMultiCommitCoreInterface> multiCommitInterface)
public static SharedRef<IMultiCommitManager> CreateShared(FileSystemServer fsServer,
ref SharedRef<ISaveDataMultiCommitCoreInterface> multiCommitInterface)
{
var manager = new MultiCommitManager(fsServer, ref multiCommitInterface);
return new ReferenceCountedDisposable<IMultiCommitManager>(manager);
return new SharedRef<IMultiCommitManager>(new MultiCommitManager(fsServer, ref multiCommitInterface));
}
public void Dispose()
{
foreach (ReferenceCountedDisposable<IFileSystem> fs in _fileSystems)
for (int i = 0; i < _fileSystems.Length; i++)
{
fs?.Dispose();
_fileSystems[i].Destroy();
}
_multiCommitInterface?.Dispose();
_multiCommitInterface.Destroy();
}
/// <summary>
@ -102,26 +100,19 @@ namespace LibHac.FsSrv.Impl
/// <returns>The <see cref="Result"/> of the operation.</returns>
private Result EnsureSaveDataForContext()
{
ReferenceCountedDisposable<IFileSystem> contextFs = null;
try
using var contextFileSystem = new SharedRef<IFileSystem>();
Result rc = _multiCommitInterface.Get.OpenMultiCommitContext(ref contextFileSystem.Ref());
if (rc.IsFailure())
{
Result rc = _multiCommitInterface.Target.OpenMultiCommitContext(out contextFs);
if (!ResultFs.TargetNotFound.Includes(rc))
return rc;
if (rc.IsFailure())
{
if (!ResultFs.TargetNotFound.Includes(rc))
return rc;
rc = _fsServer.Hos.Fs.CreateSystemSaveData(SaveDataId, SaveDataSize, SaveJournalSize, SaveDataFlags.None);
if (rc.IsFailure()) return rc;
}
return Result.Success;
}
finally
{
contextFs?.Dispose();
rc = _fsServer.Hos.Fs.CreateSystemSaveData(SaveDataId, SaveDataSize, SaveJournalSize, SaveDataFlags.None);
if (rc.IsFailure()) return rc;
}
return Result.Success;
}
/// <summary>
@ -132,33 +123,26 @@ namespace LibHac.FsSrv.Impl
/// <see cref="ResultFs.MultiCommitFileSystemLimit"/>: The maximum number of file systems have been added.
/// <see cref="MaxFileSystemCount"/> file systems may be added to a single multi-commit.<br/>
/// <see cref="ResultFs.MultiCommitFileSystemAlreadyAdded"/>: The provided file system has already been added.</returns>
public Result Add(ReferenceCountedDisposable<IFileSystemSf> fileSystem)
public Result Add(ref SharedRef<IFileSystemSf> fileSystem)
{
if (_fileSystemCount >= MaxFileSystemCount)
return ResultFs.MultiCommitFileSystemLimit.Log();
ReferenceCountedDisposable<IFileSystem> fsaFileSystem = null;
try
using var fsaFileSystem = new SharedRef<IFileSystem>();
Result rc = fileSystem.Get.GetImpl(ref fsaFileSystem.Ref());
if (rc.IsFailure()) return rc;
// Check that the file system hasn't already been added
for (int i = 0; i < _fileSystemCount; i++)
{
Result rc = fileSystem.Target.GetImpl(out fsaFileSystem);
if (rc.IsFailure()) return rc;
// Check that the file system hasn't already been added
for (int i = 0; i < _fileSystemCount; i++)
{
if (ReferenceEquals(fsaFileSystem.Target, _fileSystems[i].Target))
return ResultFs.MultiCommitFileSystemAlreadyAdded.Log();
}
_fileSystems[_fileSystemCount] = Shared.Move(ref fsaFileSystem);
_fileSystemCount++;
return Result.Success;
}
finally
{
fsaFileSystem?.Dispose();
if (ReferenceEquals(fsaFileSystem.Get, _fileSystems[i].Get))
return ResultFs.MultiCommitFileSystemAlreadyAdded.Log();
}
_fileSystems[_fileSystemCount].SetByMove(ref fsaFileSystem.Ref());
_fileSystemCount++;
return Result.Success;
}
/// <summary>
@ -198,21 +182,14 @@ namespace LibHac.FsSrv.Impl
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref Globals.MultiCommitMutex);
ReferenceCountedDisposable<IFileSystem> contextFs = null;
try
{
Result rc = EnsureSaveDataForContext();
if (rc.IsFailure()) return rc;
using var contextFileSystem = new SharedRef<IFileSystem>();
Result rc = EnsureSaveDataForContext();
if (rc.IsFailure()) return rc;
rc = _multiCommitInterface.Target.OpenMultiCommitContext(out contextFs);
if (rc.IsFailure()) return rc;
rc = _multiCommitInterface.Get.OpenMultiCommitContext(ref contextFileSystem.Ref());
if (rc.IsFailure()) return rc;
return Commit(contextFs.Target);
}
finally
{
contextFs?.Dispose();
}
return Commit(contextFileSystem.Get);
}
/// <summary>
@ -227,9 +204,9 @@ namespace LibHac.FsSrv.Impl
for (i = 0; i < _fileSystemCount; i++)
{
Assert.SdkNotNull(_fileSystems[i]);
Assert.SdkNotNull(_fileSystems[i].Get);
rc = _fileSystems[i].Target.CommitProvisionally(counter);
rc = _fileSystems[i].Get.CommitProvisionally(counter);
if (rc.IsFailure())
break;
@ -240,9 +217,9 @@ namespace LibHac.FsSrv.Impl
// Rollback all provisional commits including the failed commit
for (int j = 0; j <= i; j++)
{
Assert.SdkNotNull(_fileSystems[j]);
Assert.SdkNotNull(_fileSystems[j].Get);
_fileSystems[j].Target.Rollback().IgnoreResult();
_fileSystems[j].Get.Rollback().IgnoreResult();
}
}
@ -261,17 +238,19 @@ namespace LibHac.FsSrv.Impl
for (int i = 0; i < _fileSystemCount; i++)
{
Assert.SdkNotNull(_fileSystems[i]);
Assert.SdkNotNull(_fileSystems[i].Get);
Result rc = _fileSystems[i].Target.Commit();
Result resultLast = _fileSystems[i].Get.Commit();
// If the commit failed, set the overall result if it hasn't been set yet.
if (result.IsSuccess() && rc.IsFailure())
if (result.IsSuccess() && resultLast.IsFailure())
{
result = rc;
result = resultLast;
}
}
if (result.IsFailure()) return result.Miss();
return Result.Success;
}
@ -319,14 +298,14 @@ namespace LibHac.FsSrv.Impl
int saveCount = 0;
Span<SaveDataInfo> savesToRecover = stackalloc SaveDataInfo[MaxFileSystemCount];
ReferenceCountedDisposable<SaveDataInfoReaderImpl> infoReader = null;
try
{
using var reader = new SharedRef<SaveDataInfoReaderImpl>();
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
rc = saveService.OpenSaveDataIndexerAccessor(ref accessor.Ref(), out _, SaveDataSpaceId.User);
if (rc.IsFailure()) return rc;
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out infoReader);
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(ref reader.Ref());
if (rc.IsFailure()) return rc;
// Iterate through all the saves to find any provisionally committed save data
@ -334,7 +313,7 @@ namespace LibHac.FsSrv.Impl
{
Unsafe.SkipInit(out SaveDataInfo info);
rc = infoReader.Target.Read(out long readCount, OutBuffer.FromStruct(ref info));
rc = reader.Get.Read(out long readCount, OutBuffer.FromStruct(ref info));
if (rc.IsFailure()) return rc;
// Break once we're done iterating all save data
@ -344,8 +323,10 @@ namespace LibHac.FsSrv.Impl
rc = multiCommitInterface.IsProvisionallyCommittedSaveData(out bool isProvisionallyCommitted,
in info);
// Note: Some saves could be missed if there are more than MaxFileSystemCount
// provisionally committed saves. Not sure why Nintendo doesn't catch this.
// Note: Multi-commits are only recovered at boot time, so some saves could be missed if there
// are more than MaxFileSystemCount provisionally committed saves.
// In theory this shouldn't happen because a multi-commit should only be interrupted if the
// entire OS is brought down.
if (rc.IsSuccess() && isProvisionallyCommitted && saveCount < MaxFileSystemCount)
{
savesToRecover[saveCount] = info;
@ -353,10 +334,6 @@ namespace LibHac.FsSrv.Impl
}
}
}
finally
{
infoReader?.Dispose();
}
// Recover the saves by finishing their commits.
// All file systems will try to be recovered, even if one fails.
@ -402,14 +379,14 @@ namespace LibHac.FsSrv.Impl
int saveCount = 0;
Span<SaveDataInfo> savesToRecover = stackalloc SaveDataInfo[MaxFileSystemCount];
ReferenceCountedDisposable<SaveDataInfoReaderImpl> infoReader = null;
try
{
using var reader = new SharedRef<SaveDataInfoReaderImpl>();
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
rc = saveService.OpenSaveDataIndexerAccessor(ref accessor.Ref(), out _, SaveDataSpaceId.User);
if (rc.IsFailure()) return rc;
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(out infoReader);
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(ref reader.Ref());
if (rc.IsFailure()) return rc;
// Iterate through all the saves to find any provisionally committed save data
@ -417,7 +394,7 @@ namespace LibHac.FsSrv.Impl
{
Unsafe.SkipInit(out SaveDataInfo info);
rc = infoReader.Target.Read(out long readCount, OutBuffer.FromStruct(ref info));
rc = reader.Get.Read(out long readCount, OutBuffer.FromStruct(ref info));
if (rc.IsFailure()) return rc;
// Break once we're done iterating all save data
@ -427,8 +404,10 @@ namespace LibHac.FsSrv.Impl
rc = multiCommitInterface.IsProvisionallyCommittedSaveData(out bool isProvisionallyCommitted,
in info);
// Note: Some saves could be missed if there are more than MaxFileSystemCount
// provisionally committed saves. Not sure why Nintendo doesn't catch this.
// Note: Multi-commits are only recovered at boot time, so some saves could be missed if there
// are more than MaxFileSystemCount provisionally committed saves.
// In theory this shouldn't happen because a multi-commit should only be interrupted if the
// entire OS is brought down.
if (rc.IsSuccess() && isProvisionallyCommitted && saveCount < MaxFileSystemCount)
{
savesToRecover[saveCount] = info;
@ -436,10 +415,6 @@ namespace LibHac.FsSrv.Impl
}
}
}
finally
{
infoReader?.Dispose();
}
// Recover the saves by rolling them back to the previous commit.
// All file systems will try to be recovered, even if one fails.
@ -448,7 +423,7 @@ namespace LibHac.FsSrv.Impl
{
rc = multiCommitInterface.RecoverProvisionallyCommittedSaveData(in savesToRecover[i], true);
if (recoveryResult.IsSuccess() && rc.IsFailure())
if (rc.IsFailure() && !recoveryResult.IsFailure())
{
recoveryResult = rc;
}
@ -481,53 +456,46 @@ namespace LibHac.FsSrv.Impl
public static Result Recover(FileSystemServer fsServer, ISaveDataMultiCommitCoreInterface multiCommitInterface,
SaveDataFileSystemServiceImpl saveService)
{
ref MultiCommitManagerGlobals globals = ref fsServer.Globals.MultiCommitManager;
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref globals.MultiCommitMutex);
using ScopedLock<SdkMutexType> scopedLock =
ScopedLock.Lock(ref fsServer.Globals.MultiCommitManager.MultiCommitMutex);
bool needsRecovery = true;
ReferenceCountedDisposable<IFileSystem> fileSystem = null;
using var fileSystem = new SharedRef<IFileSystem>();
try
// Check if a multi-commit was interrupted by checking if there's a commit context file.
Result rc = multiCommitInterface.OpenMultiCommitContext(ref fileSystem.Ref());
if (rc.IsFailure())
{
// Check if a multi-commit was interrupted by checking if there's a commit context file.
Result rc = multiCommitInterface.OpenMultiCommitContext(out fileSystem);
if (!ResultFs.PathNotFound.Includes(rc) && !ResultFs.TargetNotFound.Includes(rc))
return rc;
// Unable to open the multi-commit context file system, so there's nothing to recover
needsRecovery = false;
}
if (needsRecovery)
{
using var contextFilePath = new Fs.Path();
rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
if (rc.IsFailure()) return rc;
using var file = new UniqueRef<IFile>();
rc = fileSystem.Get.OpenFile(ref file.Ref(), in contextFilePath, OpenMode.Read);
if (rc.IsFailure())
{
if (!ResultFs.PathNotFound.Includes(rc) && !ResultFs.TargetNotFound.Includes(rc))
return rc;
// Unable to open the multi-commit context file system, so there's nothing to recover
needsRecovery = false;
// Unable to open the context file. No multi-commit to recover.
if (ResultFs.PathNotFound.Includes(rc))
needsRecovery = false;
}
if (needsRecovery)
{
using var contextFilePath = new Fs.Path();
rc = PathFunctions.SetUpFixedPath(ref contextFilePath.Ref(), CommitContextFileName);
if (rc.IsFailure()) return rc;
using var file = new UniqueRef<IFile>();
rc = fileSystem.Target.OpenFile(ref file.Ref(), in contextFilePath, OpenMode.Read);
if (rc.IsFailure())
{
// Unable to open the context file. No multi-commit to recover.
if (ResultFs.PathNotFound.Includes(rc))
needsRecovery = false;
}
}
if (!needsRecovery)
return Result.Success;
// There was a context file. Recover the unfinished commit.
return Recover(multiCommitInterface, fileSystem.Target, saveService);
}
finally
{
fileSystem?.Dispose();
}
if (!needsRecovery)
return Result.Success;
// There was a context file. Recover the unfinished commit.
return Recover(multiCommitInterface, fileSystem.Get, saveService);
}
[StructLayout(LayoutKind.Explicit, Size = 0x18)]

View File

@ -7,43 +7,42 @@ namespace LibHac.FsSrv.Impl
{
internal class OpenCountFileSystem : ForwardingFileSystem
{
private ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> _entryCountSemaphore;
private SharedRef<IEntryOpenCountSemaphoreManager> _entryCountSemaphore;
private UniqueRef<IUniqueLock> _mountCountSemaphore;
public OpenCountFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore) : base(
ref baseFileSystem)
public OpenCountFileSystem(ref SharedRef<IFileSystem> baseFileSystem,
ref SharedRef<IEntryOpenCountSemaphoreManager> entryCountSemaphore) : base(ref baseFileSystem)
{
Shared.Move(out _entryCountSemaphore, ref entryCountSemaphore);
_entryCountSemaphore = SharedRef<IEntryOpenCountSemaphoreManager>.CreateMove(ref entryCountSemaphore);
}
public OpenCountFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore,
public OpenCountFileSystem(ref SharedRef<IFileSystem> baseFileSystem,
ref SharedRef<IEntryOpenCountSemaphoreManager> entryCountSemaphore,
ref UniqueRef<IUniqueLock> mountCountSemaphore) : base(ref baseFileSystem)
{
Shared.Move(out _entryCountSemaphore, ref entryCountSemaphore);
_entryCountSemaphore = SharedRef<IEntryOpenCountSemaphoreManager>.CreateMove(ref entryCountSemaphore);
_mountCountSemaphore = new UniqueRef<IUniqueLock>(ref mountCountSemaphore);
}
public static ReferenceCountedDisposable<IFileSystem> CreateShared(
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore,
public static SharedRef<IFileSystem> CreateShared(
ref SharedRef<IFileSystem> baseFileSystem,
ref SharedRef<IEntryOpenCountSemaphoreManager> entryCountSemaphore,
ref UniqueRef<IUniqueLock> mountCountSemaphore)
{
var filesystem =
new OpenCountFileSystem(ref baseFileSystem, ref entryCountSemaphore, ref mountCountSemaphore);
return new ReferenceCountedDisposable<IFileSystem>(filesystem);
return new SharedRef<IFileSystem>(filesystem);
}
public static ReferenceCountedDisposable<IFileSystem> CreateShared(
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem,
ref ReferenceCountedDisposable<IEntryOpenCountSemaphoreManager> entryCountSemaphore)
public static SharedRef<IFileSystem> CreateShared(
ref SharedRef<IFileSystem> baseFileSystem,
ref SharedRef<IEntryOpenCountSemaphoreManager> entryCountSemaphore)
{
var filesystem =
new OpenCountFileSystem(ref baseFileSystem, ref entryCountSemaphore);
return new ReferenceCountedDisposable<IFileSystem>(filesystem);
return new SharedRef<IFileSystem>(filesystem);
}
// ReSharper disable once RedundantOverriddenMember
@ -63,7 +62,7 @@ namespace LibHac.FsSrv.Impl
public override void Dispose()
{
_entryCountSemaphore?.Dispose();
_entryCountSemaphore.Destroy();
_mountCountSemaphore.Destroy();
base.Dispose();
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using LibHac.Common;
using LibHac.Fs;
using LibHac.FsSystem;
@ -11,32 +12,37 @@ namespace LibHac.FsSrv.Impl
/// </summary>
public class SaveDataExtraDataAccessorCacheManager : ISaveDataExtraDataAccessorCacheObserver
{
private struct Cache
private struct Cache : IDisposable
{
private ReferenceCountedDisposable<ISaveDataExtraDataAccessor>.WeakReference _accessor;
private WeakRef<ISaveDataExtraDataAccessor> _accessor;
private readonly SaveDataSpaceId _spaceId;
private readonly ulong _saveDataId;
public Cache(ReferenceCountedDisposable<ISaveDataExtraDataAccessor> accessor, SaveDataSpaceId spaceId,
public Cache(ref SharedRef<ISaveDataExtraDataAccessor> accessor, SaveDataSpaceId spaceId,
ulong saveDataId)
{
_accessor = new ReferenceCountedDisposable<ISaveDataExtraDataAccessor>.WeakReference(accessor);
_accessor = new WeakRef<ISaveDataExtraDataAccessor>(ref accessor);
_spaceId = spaceId;
_saveDataId = saveDataId;
}
public void Dispose()
{
_accessor.Destroy();
}
public bool Contains(SaveDataSpaceId spaceId, ulong saveDataId)
{
return _spaceId == spaceId && _saveDataId == saveDataId;
}
public ReferenceCountedDisposable<ISaveDataExtraDataAccessor> Lock()
public SharedRef<ISaveDataExtraDataAccessor> Lock()
{
return _accessor.TryAddReference();
return _accessor.Lock();
}
}
private readonly LinkedList<Cache> _accessorList;
private LinkedList<Cache> _accessorList;
private SdkRecursiveMutexType _mutex;
public SaveDataExtraDataAccessorCacheManager()
@ -47,17 +53,33 @@ namespace LibHac.FsSrv.Impl
public void Dispose()
{
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
LinkedListNode<Cache> currentEntry = _accessorList.First;
while (currentEntry is not null)
{
ref Cache entry = ref currentEntry.ValueRef;
_accessorList.Remove(entry);
entry.Dispose();
currentEntry = _accessorList.First;
}
_accessorList.Clear();
}
public Result Register(ReferenceCountedDisposable<ISaveDataExtraDataAccessor> accessor,
public Result Register(ref SharedRef<ISaveDataExtraDataAccessor> accessor,
SaveDataSpaceId spaceId, ulong saveDataId)
{
var cache = new Cache(accessor, spaceId, saveDataId);
var cache = new Cache(ref accessor, spaceId, saveDataId);
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
using (ScopedLock.Lock(ref _mutex))
{
UnregisterImpl(spaceId, saveDataId);
_accessorList.AddLast(cache);
}
_accessorList.AddLast(cache);
return Result.Success;
}
@ -84,11 +106,9 @@ namespace LibHac.FsSrv.Impl
}
}
public Result GetCache(out ReferenceCountedDisposable<ISaveDataExtraDataAccessor> accessor,
SaveDataSpaceId spaceId, ulong saveDataId)
public Result GetCache(ref SharedRef<ISaveDataExtraDataAccessor> outAccessor, SaveDataSpaceId spaceId,
ulong saveDataId)
{
UnsafeHelpers.SkipParamInit(out accessor);
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
LinkedListNode<Cache> currentNode = _accessorList.First;
@ -104,31 +124,18 @@ namespace LibHac.FsSrv.Impl
currentNode = currentNode.Next;
}
ReferenceCountedDisposable<ISaveDataExtraDataAccessor> tempAccessor = null;
try
{
tempAccessor = currentNode.ValueRef.Lock();
using SharedRef<ISaveDataExtraDataAccessor> accessor = currentNode.ValueRef.Lock();
// Return early if the accessor was already disposed
if (tempAccessor is null)
{
// Note: Nintendo doesn't remove the accessor from the list in this case
_accessorList.Remove(currentNode);
return ResultFs.TargetNotFound.Log();
}
if (!accessor.HasValue)
return ResultFs.TargetNotFound.Log();
accessor = SaveDataExtraDataResultConvertAccessor.CreateShared(ref tempAccessor);
return Result.Success;
}
finally
{
tempAccessor?.Dispose();
}
outAccessor.Reset(new SaveDataExtraDataResultConvertAccessor(ref accessor.Ref()));
return Result.Success;
}
public ScopedLock<SdkRecursiveMutexType> GetScopedLock()
public UniqueLockRef<SdkRecursiveMutexType> GetScopedLock()
{
return new ScopedLock<SdkRecursiveMutexType>(ref _mutex);
return new UniqueLockRef<SdkRecursiveMutexType>(ref _mutex);
}
}
}

View File

@ -164,22 +164,15 @@ namespace LibHac.FsSrv.Impl
/// </summary>
public class SaveDataResultConvertFileSystem : IResultConvertFileSystem
{
public SaveDataResultConvertFileSystem(ref ReferenceCountedDisposable<IFileSystem> baseFileSystem)
public SaveDataResultConvertFileSystem(ref SharedRef<IFileSystem> baseFileSystem)
: base(ref baseFileSystem)
{
}
public static ReferenceCountedDisposable<IFileSystem> CreateShared(
ref ReferenceCountedDisposable<IFileSystem> baseFileSystem)
{
var resultConvertFileSystem = new SaveDataResultConvertFileSystem(ref baseFileSystem);
return new ReferenceCountedDisposable<IFileSystem>(resultConvertFileSystem);
}
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
{
using var file = new UniqueRef<IFile>();
Result rc = ConvertResult(BaseFileSystem.Target.OpenFile(ref file.Ref(), path, mode));
Result rc = ConvertResult(BaseFileSystem.Get.OpenFile(ref file.Ref(), path, mode));
if (rc.IsFailure()) return rc;
outFile.Reset(new SaveDataResultConvertFile(ref file.Ref()));
@ -190,7 +183,7 @@ namespace LibHac.FsSrv.Impl
OpenDirectoryMode mode)
{
using var directory = new UniqueRef<IDirectory>();
Result rc = ConvertResult(BaseFileSystem.Target.OpenDirectory(ref directory.Ref(), path, mode));
Result rc = ConvertResult(BaseFileSystem.Get.OpenDirectory(ref directory.Ref(), path, mode));
if (rc.IsFailure()) return rc;
outDirectory.Reset(new SaveDataResultConvertDirectory(ref directory.Ref()));
@ -209,49 +202,40 @@ namespace LibHac.FsSrv.Impl
/// </summary>
public class SaveDataExtraDataResultConvertAccessor : ISaveDataExtraDataAccessor
{
private ReferenceCountedDisposable<ISaveDataExtraDataAccessor> _accessor;
private SharedRef<ISaveDataExtraDataAccessor> _accessor;
public SaveDataExtraDataResultConvertAccessor(
ref ReferenceCountedDisposable<ISaveDataExtraDataAccessor> accessor)
public SaveDataExtraDataResultConvertAccessor(ref SharedRef<ISaveDataExtraDataAccessor> accessor)
{
_accessor = Shared.Move(ref accessor);
}
public static ReferenceCountedDisposable<ISaveDataExtraDataAccessor> CreateShared(
ref ReferenceCountedDisposable<ISaveDataExtraDataAccessor> accessor)
{
var resultConvertAccessor = new SaveDataExtraDataResultConvertAccessor(ref accessor);
return new ReferenceCountedDisposable<ISaveDataExtraDataAccessor>(resultConvertAccessor);
_accessor = SharedRef<ISaveDataExtraDataAccessor>.CreateMove(ref accessor);
}
public void Dispose()
{
_accessor?.Dispose();
_accessor = null;
_accessor.Destroy();
}
public Result WriteExtraData(in SaveDataExtraData extraData)
{
Result rc = _accessor.Target.WriteExtraData(in extraData);
Result rc = _accessor.Get.WriteExtraData(in extraData);
return SaveDataResultConvert.ConvertSaveFsDriverPublicResult(rc);
}
public Result CommitExtraData(bool updateTimeStamp)
{
Result rc = _accessor.Target.CommitExtraData(updateTimeStamp);
Result rc = _accessor.Get.CommitExtraData(updateTimeStamp);
return SaveDataResultConvert.ConvertSaveFsDriverPublicResult(rc);
}
public Result ReadExtraData(out SaveDataExtraData extraData)
{
Result rc = _accessor.Target.ReadExtraData(out extraData);
Result rc = _accessor.Get.ReadExtraData(out extraData);
return SaveDataResultConvert.ConvertSaveFsDriverPublicResult(rc);
}
public void RegisterCacheObserver(ISaveDataExtraDataAccessorCacheObserver observer, SaveDataSpaceId spaceId,
ulong saveDataId)
{
_accessor.Target.RegisterCacheObserver(observer, spaceId, saveDataId);
_accessor.Get.RegisterCacheObserver(observer, spaceId, saveDataId);
}
}
}

Some files were not shown because too many files have changed in this diff Show More