mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add SaveDataExtraDataAccessorCacheManager
This commit is contained in:
parent
44229f5986
commit
d06731f464
2 changed files with 313 additions and 0 deletions
134
src/LibHac/FsSrv/Impl/SaveDataExtraDataAccessorCacheManager.cs
Normal file
134
src/LibHac/FsSrv/Impl/SaveDataExtraDataAccessorCacheManager.cs
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.FsSystem;
|
||||||
|
using LibHac.Os;
|
||||||
|
|
||||||
|
namespace LibHac.FsSrv.Impl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the <see cref="ISaveDataExtraDataAccessor"/>s for opened save data file systems.
|
||||||
|
/// </summary>
|
||||||
|
public class SaveDataExtraDataAccessorCacheManager : ISaveDataExtraDataAccessorCacheObserver
|
||||||
|
{
|
||||||
|
private struct Cache
|
||||||
|
{
|
||||||
|
private ReferenceCountedDisposable<ISaveDataExtraDataAccessor>.WeakReference _accessor;
|
||||||
|
private readonly SaveDataSpaceId _spaceId;
|
||||||
|
private readonly ulong _saveDataId;
|
||||||
|
|
||||||
|
public Cache(ReferenceCountedDisposable<ISaveDataExtraDataAccessor> accessor, SaveDataSpaceId spaceId,
|
||||||
|
ulong saveDataId)
|
||||||
|
{
|
||||||
|
_accessor = new ReferenceCountedDisposable<ISaveDataExtraDataAccessor>.WeakReference(accessor);
|
||||||
|
_spaceId = spaceId;
|
||||||
|
_saveDataId = saveDataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||||
|
{
|
||||||
|
return _spaceId == spaceId && _saveDataId == saveDataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReferenceCountedDisposable<ISaveDataExtraDataAccessor> Lock()
|
||||||
|
{
|
||||||
|
return _accessor.TryAddReference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly LinkedList<Cache> _accessorList;
|
||||||
|
private SdkRecursiveMutex _mutex;
|
||||||
|
|
||||||
|
public SaveDataExtraDataAccessorCacheManager()
|
||||||
|
{
|
||||||
|
_accessorList = new LinkedList<Cache>();
|
||||||
|
_mutex = new SdkRecursiveMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_accessorList.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Register(ReferenceCountedDisposable<ISaveDataExtraDataAccessor> accessor,
|
||||||
|
SaveDataSpaceId spaceId, ulong saveDataId)
|
||||||
|
{
|
||||||
|
var cache = new Cache(accessor, spaceId, saveDataId);
|
||||||
|
|
||||||
|
using ScopedLock<SdkRecursiveMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||||
|
|
||||||
|
_accessorList.AddLast(cache);
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unregister(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||||
|
{
|
||||||
|
using ScopedLock<SdkRecursiveMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||||
|
|
||||||
|
UnregisterImpl(spaceId, saveDataId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnregisterImpl(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||||
|
{
|
||||||
|
LinkedListNode<Cache> currentNode = _accessorList.First;
|
||||||
|
|
||||||
|
while (currentNode is not null)
|
||||||
|
{
|
||||||
|
if (currentNode.ValueRef.Contains(spaceId, saveDataId))
|
||||||
|
{
|
||||||
|
_accessorList.Remove(currentNode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentNode = currentNode.Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetCache(out ReferenceCountedDisposable<ISaveDataExtraDataAccessor> accessor,
|
||||||
|
SaveDataSpaceId spaceId, ulong saveDataId)
|
||||||
|
{
|
||||||
|
UnsafeHelpers.SkipParamInit(out accessor);
|
||||||
|
|
||||||
|
using ScopedLock<SdkRecursiveMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||||
|
|
||||||
|
LinkedListNode<Cache> currentNode = _accessorList.First;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (currentNode is null)
|
||||||
|
return ResultFs.TargetNotFound.Log();
|
||||||
|
|
||||||
|
if (currentNode.ValueRef.Contains(spaceId, saveDataId))
|
||||||
|
break;
|
||||||
|
|
||||||
|
currentNode = currentNode.Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReferenceCountedDisposable<ISaveDataExtraDataAccessor> tempAccessor = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tempAccessor = 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
accessor = SaveDataExtraDataResultConvertAccessor.CreateShared(ref tempAccessor);
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
tempAccessor?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScopedLock<SdkRecursiveMutex> GetScopedLock()
|
||||||
|
{
|
||||||
|
return new ScopedLock<SdkRecursiveMutex>(ref _mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
179
src/LibHac/FsSrv/Impl/SaveDataResultConvertFileSystem.cs
Normal file
179
src/LibHac/FsSrv/Impl/SaveDataResultConvertFileSystem.cs
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Diag;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.FsSystem;
|
||||||
|
|
||||||
|
namespace LibHac.FsSrv.Impl
|
||||||
|
{
|
||||||
|
public static class SaveDataResultConvert
|
||||||
|
{
|
||||||
|
private static Result ConvertCorruptedResult(Result result)
|
||||||
|
{
|
||||||
|
if (ResultFs.IntegrityVerificationStorageCorrupted.Includes(result))
|
||||||
|
{
|
||||||
|
if (ResultFs.IncorrectIntegrityVerificationMagic.Includes(result))
|
||||||
|
return ResultFs.IncorrectSaveDataIntegrityVerificationMagic.Value;
|
||||||
|
|
||||||
|
if (ResultFs.InvalidZeroHash.Includes(result))
|
||||||
|
return ResultFs.InvalidSaveDataZeroHash.Value;
|
||||||
|
|
||||||
|
if (ResultFs.NonRealDataVerificationFailed.Includes(result))
|
||||||
|
return ResultFs.SaveDataNonRealDataVerificationFailed.Value;
|
||||||
|
|
||||||
|
if (ResultFs.ClearedRealDataVerificationFailed.Includes(result))
|
||||||
|
return ResultFs.ClearedSaveDataRealDataVerificationFailed.Value;
|
||||||
|
|
||||||
|
if (ResultFs.UnclearedRealDataVerificationFailed.Includes(result))
|
||||||
|
return ResultFs.UnclearedSaveDataRealDataVerificationFailed.Value;
|
||||||
|
|
||||||
|
Assert.SdkAssert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ResultFs.HostFileSystemCorrupted.Includes(result))
|
||||||
|
{
|
||||||
|
if (ResultFs.HostEntryCorrupted.Includes(result))
|
||||||
|
return ResultFs.SaveDataHostEntryCorrupted.Value;
|
||||||
|
|
||||||
|
if (ResultFs.HostFileDataCorrupted.Includes(result))
|
||||||
|
return ResultFs.SaveDataHostFileDataCorrupted.Value;
|
||||||
|
|
||||||
|
if (ResultFs.HostFileCorrupted.Includes(result))
|
||||||
|
return ResultFs.SaveDataHostFileCorrupted.Value;
|
||||||
|
|
||||||
|
if (ResultFs.InvalidHostHandle.Includes(result))
|
||||||
|
return ResultFs.InvalidSaveDataHostHandle.Value;
|
||||||
|
|
||||||
|
Assert.SdkAssert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ResultFs.DatabaseCorrupted.Includes(result))
|
||||||
|
{
|
||||||
|
if (ResultFs.InvalidAllocationTableBlock.Includes(result))
|
||||||
|
return ResultFs.InvalidSaveDataAllocationTableBlock.Value;
|
||||||
|
|
||||||
|
if (ResultFs.InvalidKeyValueListElementIndex.Includes(result))
|
||||||
|
return ResultFs.InvalidSaveDataKeyValueListElementIndex.Value;
|
||||||
|
|
||||||
|
if (ResultFs.AllocationTableIteratedRangeEntry.Includes(result))
|
||||||
|
return ResultFs.SaveDataAllocationTableIteratedRangeEntry.Value;
|
||||||
|
|
||||||
|
if (ResultFs.InvalidAllocationTableOffset.Includes(result))
|
||||||
|
return ResultFs.InvalidSaveDataAllocationTableOffset.Value;
|
||||||
|
|
||||||
|
if (ResultFs.InvalidAllocationTableBlockCount.Includes(result))
|
||||||
|
return ResultFs.InvalidSaveDataAllocationTableBlockCount.Value;
|
||||||
|
|
||||||
|
if (ResultFs.InvalidKeyValueListEntryIndex.Includes(result))
|
||||||
|
return ResultFs.InvalidSaveDataKeyValueListEntryIndex.Value;
|
||||||
|
|
||||||
|
if (ResultFs.InvalidBitmapIndex.Includes(result))
|
||||||
|
return ResultFs.InvalidSaveDataBitmapIndex.Value;
|
||||||
|
|
||||||
|
Assert.SdkAssert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ResultFs.ZeroBitmapFileCorrupted.Includes(result))
|
||||||
|
{
|
||||||
|
if (ResultFs.IncompleteBlockInZeroBitmapHashStorageFile.Includes(result))
|
||||||
|
return ResultFs.IncompleteBlockInZeroBitmapHashStorageFileSaveData.Value;
|
||||||
|
|
||||||
|
Assert.SdkAssert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result ConvertSaveFsDriverPublicResult(Result result)
|
||||||
|
{
|
||||||
|
if (result.IsSuccess())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (ResultFs.UnsupportedVersion.Includes(result))
|
||||||
|
return ResultFs.UnsupportedSaveDataVersion.Value;
|
||||||
|
|
||||||
|
if (ResultFs.IntegrityVerificationStorageCorrupted.Includes(result) ||
|
||||||
|
ResultFs.BuiltInStorageCorrupted.Includes(result) ||
|
||||||
|
ResultFs.HostFileSystemCorrupted.Includes(result) ||
|
||||||
|
ResultFs.DatabaseCorrupted.Includes(result) ||
|
||||||
|
ResultFs.ZeroBitmapFileCorrupted.Includes(result))
|
||||||
|
{
|
||||||
|
return ConvertCorruptedResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ResultFs.FatFileSystemCorrupted.Includes(result))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (ResultFs.NotFound.Includes(result))
|
||||||
|
return ResultFs.PathNotFound.Value;
|
||||||
|
|
||||||
|
if (ResultFs.AllocationTableFull.Includes(result))
|
||||||
|
return ResultFs.UsableSpaceNotEnough.Value;
|
||||||
|
|
||||||
|
if (ResultFs.AlreadyExists.Includes(result))
|
||||||
|
return ResultFs.PathAlreadyExists.Value;
|
||||||
|
|
||||||
|
if (ResultFs.InvalidOffset.Includes(result))
|
||||||
|
return ResultFs.OutOfRange.Value;
|
||||||
|
|
||||||
|
if (ResultFs.IncompatiblePath.Includes(result) ||
|
||||||
|
ResultFs.FileNotFound.Includes(result))
|
||||||
|
{
|
||||||
|
return ResultFs.PathNotFound.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wraps an <see cref="ISaveDataExtraDataAccessor"/>, converting its returned <see cref="Result"/>s
|
||||||
|
/// to save-data-specific <see cref="Result"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public class SaveDataExtraDataResultConvertAccessor : ISaveDataExtraDataAccessor
|
||||||
|
{
|
||||||
|
private ReferenceCountedDisposable<ISaveDataExtraDataAccessor> _accessor;
|
||||||
|
|
||||||
|
public SaveDataExtraDataResultConvertAccessor(
|
||||||
|
ref ReferenceCountedDisposable<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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_accessor?.Dispose();
|
||||||
|
_accessor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result WriteExtraData(in SaveDataExtraData extraData)
|
||||||
|
{
|
||||||
|
Result rc = _accessor.Target.WriteExtraData(in extraData);
|
||||||
|
return SaveDataResultConvert.ConvertSaveFsDriverPublicResult(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result CommitExtraData(bool updateTimeStamp)
|
||||||
|
{
|
||||||
|
Result rc = _accessor.Target.CommitExtraData(updateTimeStamp);
|
||||||
|
return SaveDataResultConvert.ConvertSaveFsDriverPublicResult(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result ReadExtraData(out SaveDataExtraData extraData)
|
||||||
|
{
|
||||||
|
Result rc = _accessor.Target.ReadExtraData(out extraData);
|
||||||
|
return SaveDataResultConvert.ConvertSaveFsDriverPublicResult(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterCacheObserver(ISaveDataExtraDataAccessorCacheObserver observer, SaveDataSpaceId spaceId,
|
||||||
|
ulong saveDataId)
|
||||||
|
{
|
||||||
|
_accessor.Target.RegisterCacheObserver(observer, spaceId, saveDataId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue