mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Fixup save data indexer classes and update them for 13.1.0
- SaveDataIndexer - SaveDataIndexerLite - SaveDataIndexerLiteInfoReader - SaveDataIndexerManager - SaveDataIndexerAccessor
This commit is contained in:
parent
ecb85269eb
commit
085511660d
9 changed files with 1038 additions and 914 deletions
|
@ -4,9 +4,9 @@ namespace LibHac.Fs;
|
|||
|
||||
public static class SaveData
|
||||
{
|
||||
public const ulong SaveIndexerId = 0x8000000000000000;
|
||||
public static readonly ulong SaveIndexerId = 0x8000000000000000;
|
||||
public static ProgramId InvalidProgramId => ProgramId.InvalidId;
|
||||
public static ProgramId AutoResolveCallerProgramId => new ProgramId(ulong.MaxValue - 1);
|
||||
public static UserId InvalidUserId => UserId.InvalidId;
|
||||
|
||||
public static readonly ulong InvalidSystemSaveDataId = 0;
|
||||
}
|
||||
|
|
|
@ -304,7 +304,7 @@ internal class MultiCommitManager : IMultiCommitManager
|
|||
rc = saveService.OpenSaveDataIndexerAccessor(ref accessor.Ref(), out _, SaveDataSpaceId.User);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(ref reader.Ref());
|
||||
rc = accessor.Get.GetInterface().OpenSaveDataInfoReader(ref reader.Ref());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Iterate through all the saves to find any provisionally committed save data
|
||||
|
@ -385,7 +385,7 @@ internal class MultiCommitManager : IMultiCommitManager
|
|||
rc = saveService.OpenSaveDataIndexerAccessor(ref accessor.Ref(), out _, SaveDataSpaceId.User);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(ref reader.Ref());
|
||||
rc = accessor.Get.GetInterface().OpenSaveDataInfoReader(ref reader.Ref());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Iterate through all the saves to find any provisionally committed save data
|
||||
|
|
|
@ -484,7 +484,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
rc = accessor.Get.GetInterface().GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (value.SpaceId != ConvertToRealSpaceId(spaceId))
|
||||
|
@ -534,14 +534,14 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
}
|
||||
else
|
||||
{
|
||||
rc = accessor.Get.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
rc = accessor.Get.GetInterface().GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
actualSpaceId = value.SpaceId;
|
||||
}
|
||||
|
||||
// Check if the caller has permission to delete this save.
|
||||
rc = accessor.Get.Indexer.GetKey(out SaveDataAttribute key, saveDataId);
|
||||
rc = accessor.Get.GetInterface().GetKey(out SaveDataAttribute key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Result GetExtraData(out SaveDataExtraData data) =>
|
||||
|
@ -552,10 +552,10 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Pre-delete checks successful. Put the save in the Processing state until deletion is finished.
|
||||
rc = accessor.Get.Indexer.SetState(saveDataId, SaveDataState.Processing);
|
||||
rc = accessor.Get.GetInterface().SetState(saveDataId, SaveDataState.Processing);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.Commit();
|
||||
rc = accessor.Get.GetInterface().Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
|
@ -567,10 +567,10 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
// The indexer doesn't track itself, so skip if deleting its save data.
|
||||
if (saveDataId != SaveData.SaveIndexerId)
|
||||
{
|
||||
rc = accessor.Get.Indexer.Delete(saveDataId);
|
||||
rc = accessor.Get.GetInterface().Delete(saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.Commit();
|
||||
rc = accessor.Get.GetInterface().Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
|
@ -725,7 +725,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
// If a static save data ID is specified that ID is always used
|
||||
saveDataId = attribute.StaticSaveDataId;
|
||||
|
||||
rc = accessor.Get.Indexer.PutStaticSaveDataIdIndex(in indexerKey);
|
||||
rc = accessor.Get.GetInterface().PutStaticSaveDataIdIndex(in indexerKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -734,14 +734,14 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
// end up in a situation where it can't create a required system save.
|
||||
if (!SaveDataProperties.CanUseIndexerReservedArea(attribute.Type))
|
||||
{
|
||||
if (accessor.Get.Indexer.IsRemainedReservedOnly())
|
||||
if (accessor.Get.GetInterface().IsRemainedReservedOnly())
|
||||
{
|
||||
return ResultKvdb.OutOfKeyResource.Log();
|
||||
}
|
||||
}
|
||||
|
||||
// If a static save data ID is no specified we're assigned a new save ID
|
||||
rc = accessor.Get.Indexer.Publish(out saveDataId, in indexerKey);
|
||||
rc = accessor.Get.GetInterface().Publish(out saveDataId, in indexerKey);
|
||||
}
|
||||
|
||||
if (rc.IsFailure())
|
||||
|
@ -757,19 +757,19 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
creating = true;
|
||||
|
||||
// Set the state, space ID and size on the new save indexer entry.
|
||||
rc = accessor.Get.Indexer.SetState(saveDataId, SaveDataState.Processing);
|
||||
rc = accessor.Get.GetInterface().SetState(saveDataId, SaveDataState.Processing);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.SetSpaceId(saveDataId, ConvertToRealSpaceId(creationInfo.SpaceId));
|
||||
rc = accessor.Get.GetInterface().SetSpaceId(saveDataId, ConvertToRealSpaceId(creationInfo.SpaceId));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = QuerySaveDataTotalSize(out long saveDataSize, creationInfo.Size, creationInfo.JournalSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.SetSize(saveDataId, saveDataSize);
|
||||
rc = accessor.Get.GetInterface().SetSize(saveDataId, saveDataSize);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.Commit();
|
||||
rc = accessor.Get.GetInterface().Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
|
@ -826,10 +826,10 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
if (attribute.StaticSaveDataId != SaveData.SaveIndexerId)
|
||||
{
|
||||
// Mark the save data as being successfully created
|
||||
rc = accessor.Get.Indexer.SetState(saveDataId, SaveDataState.Normal);
|
||||
rc = accessor.Get.GetInterface().SetState(saveDataId, SaveDataState.Normal);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.Commit();
|
||||
rc = accessor.Get.GetInterface().Commit();
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
|
@ -845,12 +845,12 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
|
||||
if (accessorInitialized && saveDataId != SaveData.SaveIndexerId)
|
||||
{
|
||||
rc = accessor.Get.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
rc = accessor.Get.GetInterface().GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
|
||||
if (rc.IsSuccess() && value.SpaceId == creationInfo.SpaceId)
|
||||
{
|
||||
accessor.Get.Indexer.Delete(saveDataId).IgnoreResult();
|
||||
accessor.Get.Indexer.Commit().IgnoreResult();
|
||||
accessor.Get.GetInterface().Delete(saveDataId).IgnoreResult();
|
||||
accessor.Get.GetInterface().Commit().IgnoreResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -867,7 +867,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.Get(out SaveDataIndexerValue value, in attribute);
|
||||
rc = accessor.Get.GetInterface().Get(out SaveDataIndexerValue value, in attribute);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
SaveDataIndexer.GenerateSaveDataInfo(out info, in attribute, in value);
|
||||
|
@ -1007,7 +1007,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.Get(out SaveDataIndexerValue indexerValue, in attribute);
|
||||
rc = accessor.Get.GetInterface().Get(out SaveDataIndexerValue indexerValue, in attribute);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (indexerValue.SpaceId != ConvertToRealSpaceId(spaceId))
|
||||
|
@ -1062,7 +1062,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
if (rc.IsFailure()) return rc;
|
||||
|
||||
// Check the space ID of the save data
|
||||
rc = accessor.Get.Indexer.Get(out SaveDataIndexerValue value, in key);
|
||||
rc = accessor.Get.GetInterface().Get(out SaveDataIndexerValue value, in key);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (value.SpaceId != ConvertToRealSpaceId(spaceId))
|
||||
|
@ -1070,8 +1070,8 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
}
|
||||
|
||||
// Remove the indexer entry. Nintendo ignores these results
|
||||
accessor.Get.Indexer.Delete(tempSaveDataId).IgnoreResult();
|
||||
accessor.Get.Indexer.Commit().IgnoreResult();
|
||||
accessor.Get.GetInterface().Delete(tempSaveDataId).IgnoreResult();
|
||||
accessor.Get.GetInterface().Commit().IgnoreResult();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
@ -1275,7 +1275,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.GetKey(out SaveDataAttribute key, saveDataId);
|
||||
rc = accessor.Get.GetInterface().GetKey(out SaveDataAttribute key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||
|
@ -1311,12 +1311,12 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
rc = accessor.Get.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
rc = accessor.Get.GetInterface().GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
resolvedSpaceId = value.SpaceId;
|
||||
|
||||
rc = accessor.Get.Indexer.GetKey(out key, saveDataId);
|
||||
rc = accessor.Get.GetInterface().GetKey(out key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
else
|
||||
|
@ -1326,12 +1326,12 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
rc = accessor.Get.GetInterface().GetValue(out SaveDataIndexerValue value, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
resolvedSpaceId = value.SpaceId;
|
||||
|
||||
rc = accessor.Get.Indexer.GetKey(out key, saveDataId);
|
||||
rc = accessor.Get.GetInterface().GetKey(out key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
|
@ -1462,7 +1462,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.GetKey(out SaveDataAttribute key, saveDataId);
|
||||
rc = accessor.Get.GetInterface().GetKey(out SaveDataAttribute key, saveDataId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
Result ReadExtraData(out SaveDataExtraData data) => _serviceImpl.ReadSaveDataFileSystemExtraData(out data,
|
||||
|
@ -1554,7 +1554,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), SaveDataSpaceId.System);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(ref reader.Ref());
|
||||
rc = accessor.Get.GetInterface().OpenSaveDataInfoReader(ref reader.Ref());
|
||||
if (rc.IsFailure()) return rc;
|
||||
}
|
||||
|
||||
|
@ -1583,7 +1583,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
|
||||
using var reader = new SharedRef<SaveDataInfoReaderImpl>();
|
||||
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(ref reader.Ref());
|
||||
rc = accessor.Get.GetInterface().OpenSaveDataInfoReader(ref reader.Ref());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var filter = new SaveDataInfoFilter(ConvertToRealSpaceId(spaceId), programId: default,
|
||||
|
@ -1620,7 +1620,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
|
||||
using var reader = new SharedRef<SaveDataInfoReaderImpl>();
|
||||
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(ref reader.Ref());
|
||||
rc = accessor.Get.GetInterface().OpenSaveDataInfoReader(ref reader.Ref());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
var infoFilter = new SaveDataInfoFilter(ConvertToRealSpaceId(spaceId), in filter);
|
||||
|
@ -1644,7 +1644,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(ref reader.Ref());
|
||||
rc = accessor.Get.GetInterface().OpenSaveDataInfoReader(ref reader.Ref());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
using var filterReader =
|
||||
|
@ -1762,7 +1762,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
|||
rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), spaceId);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
rc = accessor.Get.Indexer.OpenSaveDataInfoReader(ref reader.Ref());
|
||||
rc = accessor.Get.GetInterface().OpenSaveDataInfoReader(ref reader.Ref());
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
ProgramId resolvedProgramId = ResolveDefaultSaveDataReferenceProgramId(programInfo.ProgramId);
|
||||
|
|
|
@ -803,7 +803,7 @@ public class SaveDataFileSystemServiceImpl
|
|||
Result rc = OpenSaveDataIndexerAccessor(ref accessor.Ref(), out bool _, SaveDataSpaceId.User);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
count = accessor.Get.Indexer.GetIndexCount();
|
||||
count = accessor.Get.GetInterface().GetIndexCount();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,11 +1,66 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Os;
|
||||
using LibHac.Sf;
|
||||
using LibHac.Util;
|
||||
|
||||
namespace LibHac.FsSrv;
|
||||
|
||||
/// <summary>
|
||||
/// Iterates through all the save data indexed in a <see cref="SaveDataIndexerLite"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
internal class SaveDataIndexerLiteInfoReader : SaveDataInfoReaderImpl
|
||||
{
|
||||
private bool _finishedIterating;
|
||||
private SaveDataInfo _info;
|
||||
|
||||
public SaveDataIndexerLiteInfoReader()
|
||||
{
|
||||
_finishedIterating = true;
|
||||
_info = default;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public SaveDataIndexerLiteInfoReader(in SaveDataAttribute key, in SaveDataIndexerValue value)
|
||||
{
|
||||
_finishedIterating = false;
|
||||
_info = default;
|
||||
|
||||
// Don't set the State, Index, or Rank of the returned SaveDataInfo
|
||||
_info.SaveDataId = value.SaveDataId;
|
||||
_info.SpaceId = value.SpaceId;
|
||||
_info.Size = value.Size;
|
||||
_info.StaticSaveDataId = key.StaticSaveDataId;
|
||||
_info.ProgramId = key.ProgramId;
|
||||
_info.Type = key.Type;
|
||||
_info.UserId = key.UserId;
|
||||
}
|
||||
|
||||
public Result Read(out long readCount, OutBuffer saveDataInfoBuffer)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out readCount);
|
||||
|
||||
if (_finishedIterating || saveDataInfoBuffer.Size == 0)
|
||||
{
|
||||
readCount = 0;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
if (saveDataInfoBuffer.Size < Unsafe.SizeOf<SaveDataInfo>())
|
||||
return ResultFs.InvalidSize.Log();
|
||||
|
||||
Unsafe.As<byte, SaveDataInfo>(ref MemoryMarshal.GetReference(saveDataInfoBuffer.Buffer)) = _info;
|
||||
readCount = 1;
|
||||
_finishedIterating = true;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indexes metadata for temporary save data, holding a key-value pair of types
|
||||
/// <see cref="SaveDataAttribute"/> and <see cref="SaveDataIndexerValue"/> respectively.
|
||||
|
@ -13,65 +68,70 @@ namespace LibHac.FsSrv;
|
|||
/// <remarks>
|
||||
/// Only one temporary save data may exist at a time. When a new
|
||||
/// save data is added to the index, the existing key-value pair is replaced.
|
||||
/// <br/>Based on FS 10.0.0 (nnSdk 10.4.0)
|
||||
/// <para>Based on FS 13.1.0 (nnSdk 13.4.0)</para>
|
||||
/// </remarks>
|
||||
public class SaveDataIndexerLite : ISaveDataIndexer
|
||||
{
|
||||
private object Locker { get; } = new object();
|
||||
private ulong CurrentSaveDataId { get; set; } = 0x4000000000000000;
|
||||
|
||||
// Todo: Use Optional<T>
|
||||
private bool IsKeyValueSet { get; set; }
|
||||
|
||||
private SaveDataAttribute _key;
|
||||
private SdkMutex _mutex;
|
||||
private ulong _nextSaveDataId;
|
||||
private Optional<SaveDataAttribute> _key;
|
||||
private SaveDataIndexerValue _value;
|
||||
|
||||
public SaveDataIndexerLite()
|
||||
{
|
||||
_mutex = new SdkMutex();
|
||||
_nextSaveDataId = 0x4000000000000000;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public Result Commit()
|
||||
{
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Rollback()
|
||||
{
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Reset()
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
IsKeyValueSet = false;
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
_key.Clear();
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public Result Publish(out ulong saveDataId, in SaveDataAttribute key)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out saveDataId);
|
||||
|
||||
lock (Locker)
|
||||
{
|
||||
if (IsKeyValueSet && _key == key)
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (_key.HasValue && key == _key.ValueRo)
|
||||
return ResultFs.AlreadyExists.Log();
|
||||
|
||||
_key = key;
|
||||
IsKeyValueSet = true;
|
||||
_key.Set(in key);
|
||||
|
||||
_value = new SaveDataIndexerValue { SaveDataId = CurrentSaveDataId };
|
||||
saveDataId = CurrentSaveDataId;
|
||||
CurrentSaveDataId++;
|
||||
saveDataId = _nextSaveDataId;
|
||||
_value = new SaveDataIndexerValue { SaveDataId = _nextSaveDataId };
|
||||
_nextSaveDataId++;
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public Result Get(out SaveDataIndexerValue value, in SaveDataAttribute key)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out value);
|
||||
|
||||
lock (Locker)
|
||||
{
|
||||
if (IsKeyValueSet && _key == key)
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (_key.HasValue && key == _key.ValueRo)
|
||||
{
|
||||
value = _value;
|
||||
return Result.Success;
|
||||
|
@ -79,22 +139,19 @@ public class SaveDataIndexerLite : ISaveDataIndexer
|
|||
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public Result PutStaticSaveDataIdIndex(in SaveDataAttribute key)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
if (IsKeyValueSet && _key == key)
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (_key.HasValue && key == _key.ValueRo)
|
||||
return ResultFs.AlreadyExists.Log();
|
||||
|
||||
_key = key;
|
||||
IsKeyValueSet = true;
|
||||
_key.Set(in key);
|
||||
_value = default;
|
||||
|
||||
_value = new SaveDataIndexerValue();
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRemainedReservedOnly()
|
||||
{
|
||||
|
@ -103,23 +160,22 @@ public class SaveDataIndexerLite : ISaveDataIndexer
|
|||
|
||||
public Result Delete(ulong saveDataId)
|
||||
{
|
||||
lock (Locker)
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (_key.HasValue && saveDataId == _value.SaveDataId)
|
||||
{
|
||||
if (IsKeyValueSet && _value.SaveDataId == saveDataId)
|
||||
{
|
||||
IsKeyValueSet = false;
|
||||
_key.Clear();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public Result SetSpaceId(ulong saveDataId, SaveDataSpaceId spaceId)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
if (IsKeyValueSet && _value.SaveDataId == saveDataId)
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (_key.HasValue && saveDataId == _value.SaveDataId)
|
||||
{
|
||||
_value.SpaceId = spaceId;
|
||||
return Result.Success;
|
||||
|
@ -127,14 +183,13 @@ public class SaveDataIndexerLite : ISaveDataIndexer
|
|||
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public Result SetSize(ulong saveDataId, long size)
|
||||
{
|
||||
// Nintendo doesn't lock in this function for some reason
|
||||
lock (Locker)
|
||||
{
|
||||
if (IsKeyValueSet && _value.SaveDataId == saveDataId)
|
||||
// Note: Nintendo doesn't lock in this function for some reason
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (_key.HasValue && saveDataId == _value.SaveDataId)
|
||||
{
|
||||
_value.Size = size;
|
||||
return Result.Success;
|
||||
|
@ -142,14 +197,13 @@ public class SaveDataIndexerLite : ISaveDataIndexer
|
|||
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public Result SetState(ulong saveDataId, SaveDataState state)
|
||||
{
|
||||
// Nintendo doesn't lock in this function for some reason
|
||||
lock (Locker)
|
||||
{
|
||||
if (IsKeyValueSet && _value.SaveDataId == saveDataId)
|
||||
// Note: Nintendo doesn't lock in this function for some reason
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (_key.HasValue && saveDataId == _value.SaveDataId)
|
||||
{
|
||||
_value.State = state;
|
||||
return Result.Success;
|
||||
|
@ -157,31 +211,29 @@ public class SaveDataIndexerLite : ISaveDataIndexer
|
|||
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public Result GetKey(out SaveDataAttribute key, ulong saveDataId)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out key);
|
||||
|
||||
lock (Locker)
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (_key.HasValue && saveDataId == _value.SaveDataId)
|
||||
{
|
||||
if (IsKeyValueSet && _value.SaveDataId == saveDataId)
|
||||
{
|
||||
key = _key;
|
||||
key = _key.ValueRo;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public Result GetValue(out SaveDataIndexerValue value, ulong saveDataId)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out value);
|
||||
|
||||
lock (Locker)
|
||||
{
|
||||
if (IsKeyValueSet && _value.SaveDataId == saveDataId)
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (_key.HasValue && saveDataId == _value.SaveDataId)
|
||||
{
|
||||
value = _value;
|
||||
return Result.Success;
|
||||
|
@ -189,13 +241,12 @@ public class SaveDataIndexerLite : ISaveDataIndexer
|
|||
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public Result SetValue(in SaveDataAttribute key, in SaveDataIndexerValue value)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
if (IsKeyValueSet && _key == key)
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (_key.HasValue && _key.ValueRo == key)
|
||||
{
|
||||
_value = value;
|
||||
return Result.Success;
|
||||
|
@ -203,7 +254,6 @@ public class SaveDataIndexerLite : ISaveDataIndexer
|
|||
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
}
|
||||
|
||||
public int GetIndexCount()
|
||||
{
|
||||
|
@ -212,58 +262,17 @@ public class SaveDataIndexerLite : ISaveDataIndexer
|
|||
|
||||
public Result OpenSaveDataInfoReader(ref SharedRef<SaveDataInfoReaderImpl> outInfoReader)
|
||||
{
|
||||
SaveDataIndexerLiteInfoReader reader;
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
if (IsKeyValueSet)
|
||||
if (_key.HasValue)
|
||||
{
|
||||
reader = new SaveDataIndexerLiteInfoReader(in _key, in _value);
|
||||
outInfoReader.Reset(new SaveDataIndexerLiteInfoReader(in _key.Value, in _value));
|
||||
}
|
||||
else
|
||||
{
|
||||
reader = new SaveDataIndexerLiteInfoReader();
|
||||
}
|
||||
|
||||
outInfoReader.Reset(reader);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private class SaveDataIndexerLiteInfoReader : SaveDataInfoReaderImpl
|
||||
{
|
||||
private bool _finishedIterating;
|
||||
private SaveDataInfo _info;
|
||||
|
||||
public SaveDataIndexerLiteInfoReader()
|
||||
{
|
||||
_finishedIterating = true;
|
||||
}
|
||||
|
||||
public SaveDataIndexerLiteInfoReader(in SaveDataAttribute key, in SaveDataIndexerValue value)
|
||||
{
|
||||
SaveDataIndexer.GenerateSaveDataInfo(out _info, in key, in value);
|
||||
}
|
||||
|
||||
public Result Read(out long readCount, OutBuffer saveDataInfoBuffer)
|
||||
{
|
||||
Span<SaveDataInfo> outInfo = MemoryMarshal.Cast<byte, SaveDataInfo>(saveDataInfoBuffer.Buffer);
|
||||
|
||||
// Note: Nintendo doesn't check if the buffer is large enough here
|
||||
if (_finishedIterating || outInfo.IsEmpty)
|
||||
{
|
||||
readCount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
outInfo[0] = _info;
|
||||
readCount = 1;
|
||||
_finishedIterating = true;
|
||||
outInfoReader.Reset(new SaveDataIndexerLiteInfoReader());
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
|
@ -3,6 +3,7 @@ using LibHac.Common;
|
|||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSrv.Storage;
|
||||
using LibHac.Os;
|
||||
using LibHac.Util;
|
||||
|
||||
namespace LibHac.FsSrv;
|
||||
|
@ -11,35 +12,106 @@ namespace LibHac.FsSrv;
|
|||
/// Initializes and holds <see cref="ISaveDataIndexer"/>s for each save data space.
|
||||
/// Creates accessors for individual SaveDataIndexers.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 10.0.0 (nnSdk 10.4.0)</remarks>
|
||||
internal class SaveDataIndexerManager : ISaveDataIndexerManager
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
internal class SaveDataIndexerManager : ISaveDataIndexerManager, IDisposable
|
||||
{
|
||||
private FileSystemClient FsClient { get; }
|
||||
private MemoryResource MemoryResource { get; }
|
||||
private ulong SaveDataId { get; }
|
||||
|
||||
private IndexerHolder _bisIndexer = new IndexerHolder(new object());
|
||||
private IndexerHolder _tempIndexer = new IndexerHolder(new object());
|
||||
|
||||
private IndexerHolder _sdCardIndexer = new IndexerHolder(new object());
|
||||
private MemoryResource _memoryResource;
|
||||
private readonly ulong _indexerSaveDataId;
|
||||
private SdkMutex _bisIndexerMutex;
|
||||
private Optional<SaveDataIndexer> _bisIndexer;
|
||||
private SdkMutex _tempIndexerMutex;
|
||||
private SaveDataIndexerLite _tempIndexer;
|
||||
private SdkMutex _sdIndexerMutex;
|
||||
private Optional<SaveDataIndexer> _sdIndexer;
|
||||
private StorageDeviceHandle _sdCardHandle;
|
||||
private IDeviceHandleManager _sdCardHandleManager;
|
||||
private IDeviceHandleManager _sdHandleManager;
|
||||
private SdkMutex _properBisIndexerMutex;
|
||||
private Optional<SaveDataIndexer> _properBisIndexer;
|
||||
private SdkMutex _safeIndexerMutex;
|
||||
private Optional<SaveDataIndexer> _safeIndexer;
|
||||
private readonly bool _isBisUserRedirectionEnabled;
|
||||
|
||||
private IndexerHolder _safeIndexer = new IndexerHolder(new object());
|
||||
private IndexerHolder _properSystemIndexer = new IndexerHolder(new object());
|
||||
|
||||
private bool IsBisUserRedirectionEnabled { get; }
|
||||
// LibHac addition
|
||||
private FileSystemClient _fsClient;
|
||||
|
||||
public SaveDataIndexerManager(FileSystemClient fsClient, ulong saveDataId, MemoryResource memoryResource,
|
||||
IDeviceHandleManager sdCardHandleManager, bool isBisUserRedirectionEnabled)
|
||||
{
|
||||
FsClient = fsClient;
|
||||
SaveDataId = saveDataId;
|
||||
MemoryResource = memoryResource;
|
||||
_sdCardHandleManager = sdCardHandleManager;
|
||||
IsBisUserRedirectionEnabled = isBisUserRedirectionEnabled;
|
||||
_memoryResource = memoryResource;
|
||||
_indexerSaveDataId = saveDataId;
|
||||
|
||||
_tempIndexer.Indexer = new SaveDataIndexerLite();
|
||||
_bisIndexerMutex = new SdkMutex();
|
||||
_tempIndexerMutex = new SdkMutex();
|
||||
_tempIndexer = new SaveDataIndexerLite();
|
||||
_sdIndexerMutex = new SdkMutex();
|
||||
_sdHandleManager = sdCardHandleManager;
|
||||
_properBisIndexerMutex = new SdkMutex();
|
||||
_safeIndexerMutex = new SdkMutex();
|
||||
|
||||
_isBisUserRedirectionEnabled = isBisUserRedirectionEnabled;
|
||||
|
||||
_fsClient = fsClient;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
InvalidateIndexerImpl(ref _bisIndexer);
|
||||
_tempIndexer.Dispose();
|
||||
InvalidateIndexerImpl(ref _sdIndexer);
|
||||
InvalidateIndexerImpl(ref _properBisIndexer);
|
||||
InvalidateIndexerImpl(ref _safeIndexer);
|
||||
}
|
||||
|
||||
public void InvalidateAllIndexers()
|
||||
{
|
||||
InvalidateIndexerImpl(ref _bisIndexer);
|
||||
InvalidateIndexerImpl(ref _sdIndexer);
|
||||
InvalidateIndexerImpl(ref _properBisIndexer);
|
||||
InvalidateIndexerImpl(ref _safeIndexer);
|
||||
}
|
||||
|
||||
public void InvalidateIndexer(SaveDataSpaceId spaceId)
|
||||
{
|
||||
switch (spaceId)
|
||||
{
|
||||
case SaveDataSpaceId.SdSystem:
|
||||
case SaveDataSpaceId.SdUser:
|
||||
{
|
||||
// Note: Nintendo doesn't lock when doing this operation
|
||||
using ScopedLock<SdkMutex> scopedLock = ScopedLock.Lock(ref _sdIndexerMutex);
|
||||
InvalidateIndexerImpl(ref _sdIndexer);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Abort.UnexpectedDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Todo: Figure out how to add generic disposal to Optional<T>
|
||||
private static void InvalidateIndexerImpl(ref Optional<SaveDataIndexer> indexer)
|
||||
{
|
||||
if (indexer.HasValue)
|
||||
indexer.Value.Dispose();
|
||||
|
||||
indexer.Clear();
|
||||
}
|
||||
|
||||
public void ResetIndexer(SaveDataSpaceId spaceId)
|
||||
{
|
||||
switch (spaceId)
|
||||
{
|
||||
case SaveDataSpaceId.Temporary:
|
||||
// ReSharper disable once RedundantAssignment
|
||||
Result rc = _tempIndexer.Reset();
|
||||
Assert.SdkAssert(rc.IsSuccess());
|
||||
break;
|
||||
|
||||
default:
|
||||
Abort.UnexpectedDefault();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -59,172 +131,131 @@ internal class SaveDataIndexerManager : ISaveDataIndexerManager
|
|||
{
|
||||
UnsafeHelpers.SkipParamInit(out neededInit);
|
||||
|
||||
if (IsBisUserRedirectionEnabled && spaceId == SaveDataSpaceId.User)
|
||||
if (_isBisUserRedirectionEnabled && spaceId == SaveDataSpaceId.User)
|
||||
{
|
||||
spaceId = SaveDataSpaceId.ProperSystem;
|
||||
}
|
||||
|
||||
UniqueLock indexerLock = default;
|
||||
try
|
||||
{
|
||||
ISaveDataIndexer indexer;
|
||||
using var indexerLock = new UniqueLock<SdkMutex>();
|
||||
bool wasIndexerInitialized = false;
|
||||
|
||||
switch (spaceId)
|
||||
{
|
||||
case SaveDataSpaceId.System:
|
||||
case SaveDataSpaceId.User:
|
||||
indexerLock = new UniqueLock(_bisIndexer.Locker);
|
||||
|
||||
if (!_bisIndexer.IsInitialized)
|
||||
{
|
||||
_bisIndexer.Indexer = new SaveDataIndexer(FsClient, new U8Span(SystemIndexerMountName),
|
||||
SaveDataSpaceId.System, SaveDataId, MemoryResource);
|
||||
indexerLock.Reset(_bisIndexerMutex);
|
||||
|
||||
neededInit = true;
|
||||
if (!_bisIndexer.HasValue)
|
||||
{
|
||||
_bisIndexer.Set(new SaveDataIndexer(_fsClient, new U8Span(BisIndexerMountName),
|
||||
SaveDataSpaceId.System, _indexerSaveDataId, _memoryResource));
|
||||
wasIndexerInitialized = true;
|
||||
}
|
||||
|
||||
indexer = _bisIndexer.Indexer;
|
||||
indexer = _bisIndexer.Value;
|
||||
break;
|
||||
}
|
||||
case SaveDataSpaceId.Temporary:
|
||||
{
|
||||
indexerLock.Reset(_tempIndexerMutex);
|
||||
indexer = _tempIndexer;
|
||||
break;
|
||||
}
|
||||
case SaveDataSpaceId.SdSystem:
|
||||
case SaveDataSpaceId.SdUser:
|
||||
// ReSharper doesn't realize that UniqueLock locks the indexer's lock object
|
||||
// ReSharper disable InconsistentlySynchronizedField
|
||||
indexerLock = new UniqueLock(_sdCardIndexer.Locker);
|
||||
{
|
||||
if (_sdHandleManager is null)
|
||||
return ResultFs.InvalidArgument.Log();
|
||||
|
||||
indexerLock.Reset(_sdIndexerMutex);
|
||||
|
||||
// We need to reinitialize the indexer if the SD card has changed
|
||||
if (!_sdCardHandleManager.IsValid(in _sdCardHandle) && _sdCardIndexer.IsInitialized)
|
||||
if (!_sdHandleManager.IsValid(in _sdCardHandle) && _sdIndexer.HasValue)
|
||||
{
|
||||
_sdCardIndexer.Indexer.Dispose();
|
||||
_sdCardIndexer.Indexer = null;
|
||||
_sdIndexer.Value.Dispose();
|
||||
_sdIndexer.Clear();
|
||||
}
|
||||
|
||||
if (!_sdCardIndexer.IsInitialized)
|
||||
if (!_sdIndexer.HasValue)
|
||||
{
|
||||
_sdCardIndexer.Indexer = new SaveDataIndexer(FsClient, new U8Span(SdCardIndexerMountName),
|
||||
SaveDataSpaceId.SdSystem, SaveDataId, MemoryResource);
|
||||
_sdIndexer.Set(new SaveDataIndexer(_fsClient, new U8Span(SdCardIndexerMountName),
|
||||
SaveDataSpaceId.SdSystem, _indexerSaveDataId, _memoryResource));
|
||||
|
||||
_sdCardHandleManager.GetHandle(out _sdCardHandle).IgnoreResult();
|
||||
|
||||
neededInit = true;
|
||||
_sdHandleManager.GetHandle(out _sdCardHandle).IgnoreResult();
|
||||
wasIndexerInitialized = true;
|
||||
}
|
||||
|
||||
indexer = _sdCardIndexer.Indexer;
|
||||
// ReSharper restore InconsistentlySynchronizedField
|
||||
|
||||
break;
|
||||
case SaveDataSpaceId.Temporary:
|
||||
indexerLock = new UniqueLock(_tempIndexer.Locker);
|
||||
|
||||
indexer = _tempIndexer.Indexer;
|
||||
indexer = _sdIndexer.Value;
|
||||
break;
|
||||
}
|
||||
case SaveDataSpaceId.ProperSystem:
|
||||
indexerLock = new UniqueLock(_properSystemIndexer.Locker);
|
||||
|
||||
if (!_properSystemIndexer.IsInitialized)
|
||||
{
|
||||
_properSystemIndexer.Indexer = new SaveDataIndexer(FsClient,
|
||||
new U8Span(ProperSystemIndexerMountName),
|
||||
SaveDataSpaceId.ProperSystem, SaveDataId, MemoryResource);
|
||||
indexerLock.Reset(_properBisIndexerMutex);
|
||||
|
||||
neededInit = true;
|
||||
if (!_properBisIndexer.HasValue)
|
||||
{
|
||||
_properBisIndexer.Set(new SaveDataIndexer(_fsClient, new U8Span(ProperBisIndexerMountName),
|
||||
SaveDataSpaceId.ProperSystem, _indexerSaveDataId, _memoryResource));
|
||||
|
||||
wasIndexerInitialized = true;
|
||||
}
|
||||
|
||||
indexer = _properSystemIndexer.Indexer;
|
||||
indexer = _properBisIndexer.Value;
|
||||
break;
|
||||
}
|
||||
case SaveDataSpaceId.SafeMode:
|
||||
indexerLock = new UniqueLock(_safeIndexer.Locker);
|
||||
|
||||
if (!_safeIndexer.IsInitialized)
|
||||
{
|
||||
_safeIndexer.Indexer = new SaveDataIndexer(FsClient, new U8Span(SafeModeIndexerMountName),
|
||||
SaveDataSpaceId.SafeMode, SaveDataId, MemoryResource);
|
||||
indexerLock.Reset(_safeIndexerMutex);
|
||||
|
||||
neededInit = true;
|
||||
if (!_safeIndexer.HasValue)
|
||||
{
|
||||
_safeIndexer.Set(new SaveDataIndexer(_fsClient, new U8Span(SafeModeIndexerMountName),
|
||||
SaveDataSpaceId.SafeMode, _indexerSaveDataId, _memoryResource));
|
||||
|
||||
wasIndexerInitialized = true;
|
||||
}
|
||||
|
||||
indexer = _safeIndexer.Indexer;
|
||||
indexer = _safeIndexer.Value;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
outAccessor = default;
|
||||
return ResultFs.InvalidArgument.Log();
|
||||
}
|
||||
|
||||
|
||||
outAccessor.Reset(new SaveDataIndexerAccessor(indexer, ref indexerLock));
|
||||
outAccessor.Reset(new SaveDataIndexerAccessor(indexer, ref indexerLock.Ref()));
|
||||
neededInit = wasIndexerInitialized;
|
||||
return Result.Success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
indexerLock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetIndexer(SaveDataSpaceId spaceId)
|
||||
{
|
||||
if (spaceId != SaveDataSpaceId.Temporary)
|
||||
{
|
||||
Abort.UnexpectedDefault();
|
||||
}
|
||||
|
||||
// ReSharper disable once RedundantAssignment
|
||||
Result rc = _tempIndexer.Indexer.Reset();
|
||||
Assert.SdkAssert(rc.IsSuccess());
|
||||
}
|
||||
|
||||
public void InvalidateIndexer(SaveDataSpaceId spaceId)
|
||||
{
|
||||
// Note: Nintendo doesn't lock when doing this operation
|
||||
lock (_sdCardIndexer.Locker)
|
||||
{
|
||||
if (spaceId != SaveDataSpaceId.SdUser && spaceId != SaveDataSpaceId.SdSystem)
|
||||
{
|
||||
Abort.UnexpectedDefault();
|
||||
}
|
||||
|
||||
if (_sdCardIndexer.IsInitialized)
|
||||
{
|
||||
_sdCardIndexer.Indexer.Dispose();
|
||||
_sdCardIndexer.Indexer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct IndexerHolder
|
||||
{
|
||||
public object Locker { get; }
|
||||
public ISaveDataIndexer Indexer { get; set; }
|
||||
|
||||
public IndexerHolder(object locker)
|
||||
{
|
||||
Locker = locker;
|
||||
Indexer = null;
|
||||
}
|
||||
|
||||
public bool IsInitialized => Indexer != null;
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<byte> SystemIndexerMountName => // saveDataIxrDb
|
||||
/// <summary>"<c>saveDataIxrDb</c>"</summary>
|
||||
private static ReadOnlySpan<byte> BisIndexerMountName =>
|
||||
new[]
|
||||
{
|
||||
(byte) 's', (byte) 'a', (byte) 'v', (byte) 'e', (byte) 'D', (byte) 'a', (byte) 't', (byte) 'a',
|
||||
(byte) 'I', (byte) 'x', (byte) 'r', (byte) 'D', (byte) 'b'
|
||||
};
|
||||
|
||||
private static ReadOnlySpan<byte> SdCardIndexerMountName => // saveDataIxrDbSd
|
||||
/// <summary>"<c>saveDataIxrDbSd</c>"</summary>
|
||||
private static ReadOnlySpan<byte> SdCardIndexerMountName =>
|
||||
new[]
|
||||
{
|
||||
(byte) 's', (byte) 'a', (byte) 'v', (byte) 'e', (byte) 'D', (byte) 'a', (byte) 't', (byte) 'a',
|
||||
(byte) 'I', (byte) 'x', (byte) 'r', (byte) 'D', (byte) 'b', (byte) 'S', (byte) 'd'
|
||||
};
|
||||
|
||||
private static ReadOnlySpan<byte> ProperSystemIndexerMountName => // saveDataIxrDbPr
|
||||
/// <summary>"<c>saveDataIxrDbPr</c>"</summary>
|
||||
private static ReadOnlySpan<byte> ProperBisIndexerMountName =>
|
||||
new[]
|
||||
{
|
||||
(byte) 's', (byte) 'a', (byte) 'v', (byte) 'e', (byte) 'D', (byte) 'a', (byte) 't', (byte) 'a',
|
||||
(byte) 'I', (byte) 'x', (byte) 'r', (byte) 'D', (byte) 'b', (byte) 'P', (byte) 'r'
|
||||
};
|
||||
|
||||
private static ReadOnlySpan<byte> SafeModeIndexerMountName => // saveDataIxrDbSf
|
||||
/// <summary>"<c>saveDataIxrDbSf</c>"</summary>
|
||||
private static ReadOnlySpan<byte> SafeModeIndexerMountName =>
|
||||
new[]
|
||||
{
|
||||
(byte) 's', (byte) 'a', (byte) 'v', (byte) 'e', (byte) 'D', (byte) 'a', (byte) 't', (byte) 'a',
|
||||
|
@ -236,20 +267,25 @@ internal class SaveDataIndexerManager : ISaveDataIndexerManager
|
|||
/// Gives exclusive access to an <see cref="ISaveDataIndexer"/>.
|
||||
/// Releases the lock to the <see cref="ISaveDataIndexer"/> upon disposal.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 10.0.0 (nnSdk 10.4.0)</remarks>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
public class SaveDataIndexerAccessor : IDisposable
|
||||
{
|
||||
public ISaveDataIndexer Indexer { get; }
|
||||
private UniqueLock _locker;
|
||||
private readonly ISaveDataIndexer _indexer;
|
||||
private UniqueLock<SdkMutex> _lock;
|
||||
|
||||
public SaveDataIndexerAccessor(ISaveDataIndexer indexer, ref UniqueLock locker)
|
||||
public SaveDataIndexerAccessor(ISaveDataIndexer indexer, ref UniqueLock<SdkMutex> indexerLock)
|
||||
{
|
||||
Indexer = indexer;
|
||||
_locker = new UniqueLock(ref locker);
|
||||
_indexer = indexer;
|
||||
_lock = new UniqueLock<SdkMutex>(ref indexerLock);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_locker.Dispose();
|
||||
_lock.Dispose();
|
||||
}
|
||||
|
||||
public ISaveDataIndexer GetInterface()
|
||||
{
|
||||
return _indexer;
|
||||
}
|
||||
}
|
|
@ -156,6 +156,16 @@ public struct UniqueLock<TMutex> : IDisposable where TMutex : class, ILockable
|
|||
other = default;
|
||||
}
|
||||
|
||||
public void Reset(TMutex mutex)
|
||||
{
|
||||
if (_ownsLock)
|
||||
_mutex.Unlock();
|
||||
|
||||
_mutex = mutex;
|
||||
mutex.Lock();
|
||||
_ownsLock = true;
|
||||
}
|
||||
|
||||
public void Lock()
|
||||
{
|
||||
if (_mutex is null)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
|
@ -52,6 +52,11 @@ public struct Optional<T>
|
|||
public void Clear()
|
||||
{
|
||||
_hasValue = false;
|
||||
|
||||
// Clear types with references so the GC doesn't think we still need any contained objects
|
||||
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||||
{
|
||||
_value = default;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue