mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Implement SaveDataMover
This commit is contained in:
parent
c3981d0e16
commit
a3a226599b
4 changed files with 387 additions and 20 deletions
|
@ -40,4 +40,24 @@ internal readonly struct SaveDataMetaPolicy
|
||||||
GenerateMetaInfo(out SaveDataMetaInfo metaInfo);
|
GenerateMetaInfo(out SaveDataMetaInfo metaInfo);
|
||||||
return metaInfo.Type;
|
return metaInfo.Type;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal readonly struct SaveDataMetaPolicyForSaveDataTransfer
|
||||||
|
{
|
||||||
|
private readonly SaveDataMetaPolicy _base;
|
||||||
|
|
||||||
|
public SaveDataMetaPolicyForSaveDataTransfer(SaveDataType saveType) => _base = new SaveDataMetaPolicy(saveType);
|
||||||
|
public void GenerateMetaInfo(out SaveDataMetaInfo metaInfo) => _base.GenerateMetaInfo(out metaInfo);
|
||||||
|
public long GetSaveDataMetaSize() => _base.GetSaveDataMetaSize();
|
||||||
|
public SaveDataMetaType GetSaveDataMetaType() => _base.GetSaveDataMetaType();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal readonly struct SaveDataMetaPolicyForSaveDataTransferVersion2
|
||||||
|
{
|
||||||
|
private readonly SaveDataMetaPolicy _base;
|
||||||
|
|
||||||
|
public SaveDataMetaPolicyForSaveDataTransferVersion2(SaveDataType saveType) => _base = new SaveDataMetaPolicy(saveType);
|
||||||
|
public void GenerateMetaInfo(out SaveDataMetaInfo metaInfo) => _base.GenerateMetaInfo(out metaInfo);
|
||||||
|
public long GetSaveDataMetaSize() => _base.GetSaveDataMetaSize();
|
||||||
|
public SaveDataMetaType GetSaveDataMetaType() => _base.GetSaveDataMetaType();
|
||||||
}
|
}
|
|
@ -1,16 +1,25 @@
|
||||||
// ReSharper disable UnusedMember.Local UnusedType.Local
|
using System;
|
||||||
#pragma warning disable CS0169 // Field is never used
|
using System.Runtime.CompilerServices;
|
||||||
using System;
|
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Common.FixedArrays;
|
using LibHac.Common.FixedArrays;
|
||||||
|
using LibHac.Diag;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
|
using LibHac.Fs.Impl;
|
||||||
using LibHac.FsSrv.Sf;
|
using LibHac.FsSrv.Sf;
|
||||||
using LibHac.Os;
|
using LibHac.Os;
|
||||||
using LibHac.Sf;
|
using LibHac.Sf;
|
||||||
using LibHac.Util;
|
using LibHac.Util;
|
||||||
|
using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
|
||||||
|
using IStorage = LibHac.Fs.IStorage;
|
||||||
|
|
||||||
namespace LibHac.FsSrv.Impl;
|
namespace LibHac.FsSrv.Impl;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bulk moves save data from one save data space to another.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks><para>To use this class, call <see cref="Register"/> for each save data to be moved. After all save data
|
||||||
|
/// have been registered, repeatedly call <see cref="Process"/> until it returns 0 for the remaining size.</para>
|
||||||
|
/// <para>Based on nnSdk 18.3.0 (FS 18.0.0)</para></remarks>
|
||||||
public class SaveDataMover : ISaveDataMover
|
public class SaveDataMover : ISaveDataMover
|
||||||
{
|
{
|
||||||
private enum State
|
private enum State
|
||||||
|
@ -25,13 +34,13 @@ public class SaveDataMover : ISaveDataMover
|
||||||
|
|
||||||
private SharedRef<ISaveDataTransferCoreInterface> _transferInterface;
|
private SharedRef<ISaveDataTransferCoreInterface> _transferInterface;
|
||||||
private Optional<StorageDuplicator> _duplicator;
|
private Optional<StorageDuplicator> _duplicator;
|
||||||
private SaveDataSpaceId _sourceSpaceId;
|
private SaveDataSpaceId _srcSpaceId;
|
||||||
private Array128<ulong> _sourceSaveIds;
|
private Array128<ulong> _srcSaveIds;
|
||||||
private SaveDataSpaceId _destinationSpaceId;
|
private SaveDataSpaceId _dstSpaceId;
|
||||||
private Array128<ulong> _destinationSaveIds;
|
private Array128<ulong> _dstSaveIds;
|
||||||
// private TransferMemory _transferMemory;
|
// private TransferMemory _transferMemory;
|
||||||
private Memory<byte> _workBuffer;
|
private Memory<byte> _workBuffer;
|
||||||
// private ulong _transferMemorySize;
|
private ulong _transferMemorySize;
|
||||||
private int _saveCount;
|
private int _saveCount;
|
||||||
private int _currentSaveIndex;
|
private int _currentSaveIndex;
|
||||||
private long _remainingSize;
|
private long _remainingSize;
|
||||||
|
@ -42,46 +51,377 @@ public class SaveDataMover : ISaveDataMover
|
||||||
SaveDataSpaceId sourceSpaceId, SaveDataSpaceId destinationSpaceId, NativeHandle transferMemoryHandle,
|
SaveDataSpaceId sourceSpaceId, SaveDataSpaceId destinationSpaceId, NativeHandle transferMemoryHandle,
|
||||||
ulong transferMemorySize)
|
ulong transferMemorySize)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_transferInterface = SharedRef<ISaveDataTransferCoreInterface>.CreateCopy(in transferInterface);
|
||||||
|
_duplicator = new Optional<StorageDuplicator>();
|
||||||
|
|
||||||
|
_srcSpaceId = sourceSpaceId;
|
||||||
|
_srcSaveIds = default;
|
||||||
|
_dstSpaceId = destinationSpaceId;
|
||||||
|
_dstSaveIds = default;
|
||||||
|
|
||||||
|
// Missing: Attach transfer memory
|
||||||
|
|
||||||
|
_workBuffer = default;
|
||||||
|
_transferMemorySize = transferMemorySize;
|
||||||
|
_saveCount = 0;
|
||||||
|
_currentSaveIndex = 0;
|
||||||
|
_remainingSize = 0;
|
||||||
|
_state = State.Initial;
|
||||||
|
_mutex = new SdkMutex();
|
||||||
|
transferMemoryHandle.Detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
// Missing: Destroy transfer memory
|
||||||
|
|
||||||
|
if (_duplicator.HasValue)
|
||||||
|
{
|
||||||
|
_duplicator.Value.Dispose();
|
||||||
|
_duplicator.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
_transferInterface.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result OpenDuplicator()
|
private Result OpenDuplicator()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
Result res;
|
||||||
|
|
||||||
|
using var srcFileStorage = new SharedRef<IStorage>();
|
||||||
|
using (var srcInternalStorageAccessor = new SharedRef<SaveDataInternalStorageAccessor>())
|
||||||
|
{
|
||||||
|
res = SaveDataTransferUtilityGlobalMethods.OpenSaveDataInternalStorageAccessor(null,
|
||||||
|
ref srcInternalStorageAccessor.Ref, _srcSpaceId, _srcSaveIds[_currentSaveIndex]);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = srcInternalStorageAccessor.Get.Initialize(coreInterface: _transferInterface.Get,
|
||||||
|
isTemporaryTransferSave: false, hashSalt: default);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = srcInternalStorageAccessor.Get.OpenConcatenationStorage(ref srcFileStorage.Ref);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var dstFileStorage = new SharedRef<IStorage>();
|
||||||
|
using var dstFs = new SharedRef<IFileSystem>();
|
||||||
|
using (var dstInternalStorageAccessor = new SharedRef<SaveDataInternalStorageAccessor>())
|
||||||
|
{
|
||||||
|
res = SaveDataTransferUtilityGlobalMethods.OpenSaveDataInternalStorageAccessor(null,
|
||||||
|
ref dstInternalStorageAccessor.Ref, _dstSpaceId, _dstSaveIds[_currentSaveIndex]);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = dstInternalStorageAccessor.Get.Initialize(coreInterface: _transferInterface.Get,
|
||||||
|
isTemporaryTransferSave: false, hashSalt: default);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = dstInternalStorageAccessor.Get.OpenConcatenationStorage(ref dstFileStorage.Ref);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
using SharedRef<IFileSystem> fs = dstInternalStorageAccessor.Get.GetSaveDataInternalFileSystem();
|
||||||
|
dstFs.SetByMove(ref fs.Ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
_duplicator.Set(new StorageDuplicator(in srcFileStorage, in dstFileStorage, in dstFs));
|
||||||
|
res = _duplicator.Value.Initialize();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result Initialize()
|
private Result Initialize()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
// Missing: Map transfer memory
|
||||||
|
|
||||||
|
_remainingSize = 0;
|
||||||
|
for (int i = 0; i < _saveCount; i++)
|
||||||
|
{
|
||||||
|
Result res = _transferInterface.Get.ReadSaveDataFileSystemExtraDataCore(out SaveDataExtraData srcExtraData,
|
||||||
|
_srcSpaceId, _srcSaveIds[i], isTemporarySaveData: false);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
if (!SaveDataProperties.IsValidSpaceIdForSaveDataMover(srcExtraData.Attribute.Type, _dstSpaceId))
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (_srcSpaceId == _dstSpaceId)
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
Unsafe.SkipInit(out IntegrityParam integrityParam);
|
||||||
|
|
||||||
|
using (var srcInternalStorageAccessor = new SharedRef<SaveDataInternalStorageAccessor>())
|
||||||
|
{
|
||||||
|
res = SaveDataTransferUtilityGlobalMethods.OpenSaveDataInternalStorageAccessor(null,
|
||||||
|
ref srcInternalStorageAccessor.Ref, _srcSpaceId, _srcSaveIds[_currentSaveIndex]);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = srcInternalStorageAccessor.Get.Initialize(coreInterface: _transferInterface.Get,
|
||||||
|
isTemporaryTransferSave: false, hashSalt: default);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = srcInternalStorageAccessor.Get.GetIntegrityParam(ref integrityParam);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
using var srcFileStorage = new SharedRef<IStorage>();
|
||||||
|
res = srcInternalStorageAccessor.Get.OpenConcatenationStorage(ref srcFileStorage.Ref);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = srcFileStorage.Get.GetSize(out long size);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
_remainingSize += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveDataAttribute attribute = srcExtraData.Attribute;
|
||||||
|
res = SaveDataCreationInfo.Make(out SaveDataCreationInfo creationInfo, srcExtraData.DataSize,
|
||||||
|
srcExtraData.JournalSize, srcExtraData.OwnerId, srcExtraData.Flags, _dstSpaceId);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
new SaveDataMetaPolicyForSaveDataTransferVersion2(srcExtraData.Attribute.Type).GenerateMetaInfo(out SaveDataMetaInfo metaInfo);
|
||||||
|
|
||||||
|
res = _transferInterface.Get.CreateSaveDataFileSystemCore(in attribute, in creationInfo, in metaInfo,
|
||||||
|
new Optional<HashSalt>(in integrityParam.IntegritySeed), leaveUnfinalized: true);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = _transferInterface.Get.GetSaveDataInfo(out SaveDataInfo info, _dstSpaceId, attribute);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
_dstSaveIds[i] = info.SaveDataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OpenDuplicator().Ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result Register(ulong saveDataId)
|
public Result Register(ulong saveDataId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
bool isSuccess = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var scopedLock = new ScopedLock<SdkMutex>(ref _mutex);
|
||||||
|
|
||||||
|
if (_saveCount >= _srcSaveIds.Length)
|
||||||
|
return ResultFs.PreconditionViolation.Log();
|
||||||
|
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case State.Initial:
|
||||||
|
case State.Registered:
|
||||||
|
_srcSaveIds[_saveCount] = saveDataId;
|
||||||
|
_saveCount++;
|
||||||
|
_state = State.Registered;
|
||||||
|
|
||||||
|
isSuccess = true;
|
||||||
|
return Result.Success;
|
||||||
|
case State.Copying:
|
||||||
|
case State.Finished:
|
||||||
|
case State.Fatal:
|
||||||
|
case State.Canceled:
|
||||||
|
return ResultFs.PreconditionViolation.Log();
|
||||||
|
default:
|
||||||
|
Abort.UnexpectedDefault();
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!isSuccess)
|
||||||
|
ChangeStateToFatal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result Process(out long remainingSize, long sizeToProcess)
|
public Result Process(out long outRemainingSize, long sizeToProcess)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
UnsafeHelpers.SkipParamInit(out outRemainingSize);
|
||||||
|
bool isSuccess = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var scopedLock = new ScopedLock<SdkMutex>(ref _mutex);
|
||||||
|
|
||||||
|
if ((long)_transferMemorySize < sizeToProcess)
|
||||||
|
return ResultFs.InvalidSize.Log();
|
||||||
|
|
||||||
|
Result res;
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case State.Initial:
|
||||||
|
return ResultFs.PreconditionViolation.Log();
|
||||||
|
case State.Registered:
|
||||||
|
res = Initialize();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
_state = State.Copying;
|
||||||
|
goto case State.Copying;
|
||||||
|
case State.Copying:
|
||||||
|
Assert.SdkAssert(!_workBuffer.IsEmpty);
|
||||||
|
Span<byte> workBuffer = _workBuffer.Span.Slice(0, (int)_transferMemorySize);
|
||||||
|
|
||||||
|
// Call the current duplicator with a size of zero to get the remaining size for this save before processing
|
||||||
|
res = _duplicator.Value.ProcessDuplication(out long remainingSizeBefore, workBuffer, 0);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = _duplicator.Value.ProcessDuplication(out long remainingSize, workBuffer, sizeToProcess);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
// Update the total remaining size with how much data was processed in this iteration
|
||||||
|
_remainingSize -= remainingSizeBefore - remainingSize;
|
||||||
|
|
||||||
|
if (remainingSize == 0)
|
||||||
|
{
|
||||||
|
// When finished copying this save, finalize and close the duplicator
|
||||||
|
res = _duplicator.Value.FinalizeObject();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
_duplicator.Value.Dispose();
|
||||||
|
_duplicator.Clear();
|
||||||
|
|
||||||
|
// Copy the extra data from the old save to the new save
|
||||||
|
res = _transferInterface.Get.ReadSaveDataFileSystemExtraDataCore(out SaveDataExtraData extraData,
|
||||||
|
_srcSpaceId, _srcSaveIds[_currentSaveIndex], isTemporarySaveData: false);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = _transferInterface.Get.WriteSaveDataFileSystemExtraDataCore(_dstSpaceId,
|
||||||
|
_dstSaveIds[_currentSaveIndex], in extraData, extraData.Attribute.Type,
|
||||||
|
updateTimeStamp: false);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
if (_currentSaveIndex == _saveCount - 1)
|
||||||
|
{
|
||||||
|
// If this was the last save to copy, finalize the entire move operation
|
||||||
|
FinalizeObject().IgnoreResult();
|
||||||
|
_state = State.Finished;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If there are still saves to copy, open the duplicator for the next one
|
||||||
|
_currentSaveIndex++;
|
||||||
|
|
||||||
|
res = OpenDuplicator();
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outRemainingSize = _remainingSize;
|
||||||
|
isSuccess = true;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
case State.Finished:
|
||||||
|
outRemainingSize = 0;
|
||||||
|
isSuccess = true;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
case State.Fatal:
|
||||||
|
return ResultFs.PreconditionViolation.Log();
|
||||||
|
case State.Canceled:
|
||||||
|
return ResultFs.PreconditionViolation.Log();
|
||||||
|
default:
|
||||||
|
Abort.UnexpectedDefault();
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!isSuccess)
|
||||||
|
ChangeStateToFatal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result FinalizeObject()
|
private Result FinalizeObject()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
Assert.SdkAssert(_mutex.IsLockedByCurrentThread());
|
||||||
|
|
||||||
|
Result res = SetStates(_dstSpaceId, _dstSaveIds, SaveDataState.Normal);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
res = SetStates(_srcSpaceId, _srcSaveIds, SaveDataState.Processing);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
for (int i = 0; i < _saveCount; i++)
|
||||||
|
{
|
||||||
|
res = _transferInterface.Get.DeleteSaveDataFileSystemBySaveDataSpaceId(_srcSpaceId, _srcSaveIds[i]);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
}
|
||||||
|
|
||||||
|
_state = State.Finished;
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
Result SetStates(SaveDataSpaceId spaceId, ReadOnlySpan<ulong> saveDataIds, SaveDataState state)
|
||||||
|
{
|
||||||
|
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||||
|
Result r = _transferInterface.Get.OpenSaveDataIndexerAccessor(ref accessor.Ref, spaceId);
|
||||||
|
if (r.IsFailure()) return r.Miss();
|
||||||
|
|
||||||
|
ReadOnlySpan<ulong> ids = saveDataIds.Slice(0, _saveCount);
|
||||||
|
for (int i = 0; i < ids.Length; i++)
|
||||||
|
{
|
||||||
|
r = accessor.Get.GetInterface().SetState(ids[i], state);
|
||||||
|
if (r.IsFailure()) return r.Miss();
|
||||||
|
}
|
||||||
|
|
||||||
|
r = accessor.Get.GetInterface().Commit();
|
||||||
|
if (r.IsFailure()) return r.Miss();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result Cancel()
|
public Result Cancel()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
Result DoCancel()
|
||||||
|
{
|
||||||
|
_duplicator.Value.Dispose();
|
||||||
|
_duplicator.Clear();
|
||||||
|
|
||||||
|
Result result = Result.Success;
|
||||||
|
|
||||||
|
for (int i = 0; i < _saveCount; i++)
|
||||||
|
{
|
||||||
|
Result res = _transferInterface.Get.DeleteSaveDataFileSystemBySaveDataSpaceId(_dstSpaceId, _dstSaveIds[_saveCount]);
|
||||||
|
if (!res.IsSuccess() && !ResultFs.TargetNotFound.Includes(res))
|
||||||
|
{
|
||||||
|
if (result.IsSuccess())
|
||||||
|
result = res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_state = State.Canceled;
|
||||||
|
return result.Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var scopedLock = new ScopedLock<SdkMutex>(ref _mutex);
|
||||||
|
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case State.Initial:
|
||||||
|
case State.Registered:
|
||||||
|
case State.Copying:
|
||||||
|
case State.Fatal:
|
||||||
|
return DoCancel().Ret();
|
||||||
|
case State.Finished:
|
||||||
|
case State.Canceled:
|
||||||
|
return ResultFs.PreconditionViolation.Log();
|
||||||
|
default:
|
||||||
|
Abort.UnexpectedDefault();
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChangeStateToFatal()
|
private void ChangeStateToFatal()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
switch (_state)
|
||||||
|
{
|
||||||
|
case State.Initial:
|
||||||
|
case State.Registered:
|
||||||
|
case State.Copying:
|
||||||
|
_state = State.Fatal;
|
||||||
|
break;
|
||||||
|
case State.Finished:
|
||||||
|
case State.Fatal:
|
||||||
|
case State.Canceled:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Abort.UnexpectedDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -329,7 +329,8 @@ public static partial class SaveDataTransferUtilityGlobalMethods
|
||||||
public static Result OpenSaveDataInternalStorageAccessor(this FileSystemServer fsSrv,
|
public static Result OpenSaveDataInternalStorageAccessor(this FileSystemServer fsSrv,
|
||||||
ref SharedRef<SaveDataInternalStorageAccessor> outAccessor, SaveDataSpaceId spaceId, ulong saveDataId)
|
ref SharedRef<SaveDataInternalStorageAccessor> outAccessor, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
outAccessor.Reset(new SaveDataInternalStorageAccessor(spaceId, saveDataId));
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result CommitConcatenatedSaveDataStorage(this FileSystemServer fsSrv, IFileSystem fileSystem,
|
public static Result CommitConcatenatedSaveDataStorage(this FileSystemServer fsSrv, IFileSystem fileSystem,
|
||||||
|
|
|
@ -2,9 +2,15 @@
|
||||||
|
|
||||||
namespace LibHac.FsSrv.Sf;
|
namespace LibHac.FsSrv.Sf;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bulk moves save data from one save data space to another.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks><para>To use this class, call <see cref="Register"/> for each save data to be moved. After all save data
|
||||||
|
/// have been registered, repeatedly call <see cref="Process"/> until it returns 0 for the remaining size.</para>
|
||||||
|
/// <para>Based on nnSdk 18.3.0 (FS 18.0.0)</para></remarks>
|
||||||
public interface ISaveDataMover : IDisposable
|
public interface ISaveDataMover : IDisposable
|
||||||
{
|
{
|
||||||
Result Register(ulong saveDataId);
|
Result Register(ulong saveDataId);
|
||||||
Result Process(out long remainingSize, long sizeToProcess);
|
Result Process(out long outRemainingSize, long sizeToProcess);
|
||||||
Result Cancel();
|
Result Cancel();
|
||||||
}
|
}
|
Loading…
Reference in a new issue