mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add some save data transfer client classes
- Fs.ISaveDataChunkIterator - Fs.ISaveDataChunkExporter - Fs.ISaveDataChunkImporter - Fs.ISaveDataDivisionExporter - Fs.ISaveDataDivisionImporter - Fs.SaveDataTransferManagerVersion2 - Fs.SaveDataTransferProhibiterForCloudBackUp - Fs.Impl.SaveDataChunkIterator - Fs.Impl.SaveDataChunkExporter - Fs.Impl.SaveDataChunkImporter - Fs.Impl.SaveDataExporterVersion2 - Fs.Impl.SaveDataImporterVersion2 - Fs.Shim.SaveDataTransferVersion2Shim
This commit is contained in:
parent
ebc6e1b23d
commit
dea3b3a8b0
12 changed files with 1082 additions and 3 deletions
31
src/LibHac/Common/FixedArrays/Array16384.cs
Normal file
31
src/LibHac/Common/FixedArrays/Array16384.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma warning disable CS0169, CS0649, IDE0051 // Field is never used, Field is never assigned to, Remove unused private members
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Common.FixedArrays;
|
||||
|
||||
public struct Array16384<T>
|
||||
{
|
||||
public const int Length = 16384;
|
||||
|
||||
private Array8192<T> _0;
|
||||
private Array8192<T> _8192;
|
||||
|
||||
public ref T this[int i] => ref Items[i];
|
||||
|
||||
public Span<T> Items
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length);
|
||||
}
|
||||
|
||||
public readonly ReadOnlySpan<T> ItemsRo
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator ReadOnlySpan<T>(in Array16384<T> value) => value.ItemsRo;
|
||||
}
|
31
src/LibHac/Common/FixedArrays/Array4096.cs
Normal file
31
src/LibHac/Common/FixedArrays/Array4096.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma warning disable CS0169, CS0649, IDE0051 // Field is never used, Field is never assigned to, Remove unused private members
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Common.FixedArrays;
|
||||
|
||||
public struct Array4096<T>
|
||||
{
|
||||
public const int Length = 4096;
|
||||
|
||||
private Array2048<T> _0;
|
||||
private Array2048<T> _2048;
|
||||
|
||||
public ref T this[int i] => ref Items[i];
|
||||
|
||||
public Span<T> Items
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length);
|
||||
}
|
||||
|
||||
public readonly ReadOnlySpan<T> ItemsRo
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator ReadOnlySpan<T>(in Array4096<T> value) => value.ItemsRo;
|
||||
}
|
31
src/LibHac/Common/FixedArrays/Array8192.cs
Normal file
31
src/LibHac/Common/FixedArrays/Array8192.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma warning disable CS0169, CS0649, IDE0051 // Field is never used, Field is never assigned to, Remove unused private members
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Common.FixedArrays;
|
||||
|
||||
public struct Array8192<T>
|
||||
{
|
||||
public const int Length = 8192;
|
||||
|
||||
private Array4096<T> _0;
|
||||
private Array4096<T> _4096;
|
||||
|
||||
public ref T this[int i] => ref Items[i];
|
||||
|
||||
public Span<T> Items
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length);
|
||||
}
|
||||
|
||||
public readonly ReadOnlySpan<T> ItemsRo
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator ReadOnlySpan<T>(in Array8192<T> value) => value.ItemsRo;
|
||||
}
|
|
@ -17,6 +17,15 @@ public struct InitialDataMac
|
|||
public Array16<byte> Value;
|
||||
}
|
||||
|
||||
public struct ExportReportInfo
|
||||
{
|
||||
public byte DiffChunkCount;
|
||||
public byte DoubleDivisionDiffChunkCount;
|
||||
public byte HalfDivisionDiffChunkCount;
|
||||
public byte CompressionRate;
|
||||
public Array28<byte> Reserved;
|
||||
}
|
||||
|
||||
public struct ImportReportInfo
|
||||
{
|
||||
public byte DiffChunkCount;
|
||||
|
|
|
@ -8,5 +8,5 @@ public static class SaveData
|
|||
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;
|
||||
public static ulong InvalidSystemSaveDataId => 0;
|
||||
}
|
||||
|
|
|
@ -204,10 +204,16 @@ public struct SaveDataFilter
|
|||
return Result.Success;
|
||||
}
|
||||
|
||||
public static SaveDataFilter Make(Optional<ulong> programId, Optional<SaveDataType> saveType,
|
||||
Optional<UserId> userId, Optional<ulong> saveDataId, Optional<ushort> index)
|
||||
{
|
||||
return Make(programId, saveType, userId, saveDataId, index, SaveDataRank.Primary);
|
||||
}
|
||||
|
||||
public static SaveDataFilter Make(Optional<ulong> programId, Optional<SaveDataType> saveType,
|
||||
Optional<UserId> userId, Optional<ulong> saveDataId, Optional<ushort> index, SaveDataRank rank)
|
||||
{
|
||||
var filter = new SaveDataFilter();
|
||||
SaveDataFilter filter = default;
|
||||
|
||||
if (programId.HasValue)
|
||||
{
|
||||
|
|
69
src/LibHac/Fs/SaveDataTransferInterfaces.cs
Normal file
69
src/LibHac/Fs/SaveDataTransferInterfaces.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.FixedArrays;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.Time;
|
||||
|
||||
namespace LibHac.Fs;
|
||||
|
||||
public interface ISaveDataChunkIterator : IDisposable
|
||||
{
|
||||
ushort GetId();
|
||||
void Next();
|
||||
bool IsEnd();
|
||||
}
|
||||
|
||||
public interface ISaveDataChunkExporter : IDisposable
|
||||
{
|
||||
Result Pull(out ulong outPulledSize, Span<byte> destination);
|
||||
long GetRestRawDataSize();
|
||||
}
|
||||
|
||||
public interface ISaveDataChunkImporter : IDisposable
|
||||
{
|
||||
Result Push(ReadOnlySpan<byte> source);
|
||||
}
|
||||
|
||||
public interface ISaveDataDivisionExporter : IDisposable
|
||||
{
|
||||
Result SetDivisionCount(int divisionCount);
|
||||
Result OpenSaveDataDiffChunkIterator(ref UniqueRef<ISaveDataChunkIterator> outIterator);
|
||||
Result OpenSaveDataChunkExporter(ref UniqueRef<ISaveDataChunkExporter> outExporter, ushort chunkId);
|
||||
Result GetKeySeed(out KeySeed outKeySeed);
|
||||
Result GetInitialDataMac(out InitialDataMac outInitialDataMac);
|
||||
Result GetInitialDataMacKeyGeneration(out int outKeyGeneration);
|
||||
Result FinalizeExport();
|
||||
Result CancelExport();
|
||||
Result SuspendExport(out ExportContext outContext);
|
||||
Result GetImportInitialDataAad(out InitialDataAad outInitialDataAad);
|
||||
Result SetExportInitialDataAad(in InitialDataAad initialDataAad);
|
||||
Result GetSaveDataCommitId(out long outCommitId);
|
||||
Result GetSaveDataTimeStamp(out PosixTime outTimeStamp);
|
||||
Result GetReportInfo(out ExportReportInfo outReportInfo);
|
||||
|
||||
public struct ExportContext
|
||||
{
|
||||
public Array16384<byte> Value;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ISaveDataDivisionImporter : IDisposable
|
||||
{
|
||||
Result OpenSaveDataDiffChunkIterator(ref UniqueRef<ISaveDataChunkIterator> outIterator);
|
||||
Result InitializeImport(out long remaining, long sizeToProcess);
|
||||
Result FinalizeImport();
|
||||
Result FinalizeImportWithoutSwap();
|
||||
Result CancelImport();
|
||||
Result GetImportContext(out ImportContext outContext);
|
||||
Result SuspendImport();
|
||||
Result OpenSaveDataChunkImporter(ref UniqueRef<ISaveDataChunkImporter> outImporter, ushort chunkId);
|
||||
Result GetImportInitialDataAad(out InitialDataAad outInitialDataAad);
|
||||
Result GetSaveDataCommitId(out long outCommitId);
|
||||
Result GetSaveDataTimeStamp(out PosixTime outTimeStamp);
|
||||
Result GetReportInfo(out ImportReportInfo outReportInfo);
|
||||
|
||||
public struct ImportContext
|
||||
{
|
||||
public Array16384<byte> Value;
|
||||
}
|
||||
}
|
|
@ -10,4 +10,9 @@ public struct RsaEncryptedKey
|
|||
public struct AesKey
|
||||
{
|
||||
public Array16<byte> Value;
|
||||
}
|
||||
|
||||
public struct InitialDataVersion2
|
||||
{
|
||||
public Array8192<byte> Value;
|
||||
}
|
469
src/LibHac/Fs/Shim/SaveDataTransferAdapter.cs
Normal file
469
src/LibHac/Fs/Shim/SaveDataTransferAdapter.cs
Normal file
|
@ -0,0 +1,469 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Sf;
|
||||
using LibHac.Time;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace LibHac.Fs.Impl;
|
||||
|
||||
/// <summary>
|
||||
/// An adapter for interacting with an <see cref="FsSrv.Sf.ISaveDataChunkIterator"/>
|
||||
/// IPC service object via the non-IPC <see cref="ISaveDataChunkIterator"/> interface.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 13.4.0</remarks>
|
||||
public class SaveDataChunkIterator : ISaveDataChunkIterator
|
||||
{
|
||||
private SharedRef<FsSrv.Sf.ISaveDataChunkIterator> _baseInterface;
|
||||
|
||||
// LibHac addition
|
||||
private FileSystemClient _fsClient;
|
||||
|
||||
public SaveDataChunkIterator(FileSystemClient fs, ref SharedRef<FsSrv.Sf.ISaveDataChunkIterator> baseInterface)
|
||||
{
|
||||
_baseInterface = SharedRef<FsSrv.Sf.ISaveDataChunkIterator>.CreateMove(ref baseInterface);
|
||||
_fsClient = fs;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_baseInterface.Destroy();
|
||||
}
|
||||
|
||||
public ushort GetId()
|
||||
{
|
||||
Result rc = _baseInterface.Get.GetId(out uint id);
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
Abort.DoAbortUnless(rc.IsSuccess());
|
||||
|
||||
return (ushort)id;
|
||||
}
|
||||
|
||||
public void Next()
|
||||
{
|
||||
Result rc = _baseInterface.Get.Next();
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
Abort.DoAbortUnless(rc.IsSuccess());
|
||||
}
|
||||
|
||||
public bool IsEnd()
|
||||
{
|
||||
Result rc = _baseInterface.Get.IsEnd(out bool isEnd);
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
Abort.DoAbortUnless(rc.IsSuccess());
|
||||
|
||||
return isEnd;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An adapter for interacting with an <see cref="FsSrv.Sf.ISaveDataChunkExporter"/>
|
||||
/// IPC service object via the non-IPC <see cref="ISaveDataChunkExporter"/> interface.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 13.4.0</remarks>
|
||||
public class SaveDataChunkExporter : ISaveDataChunkExporter
|
||||
{
|
||||
private SharedRef<FsSrv.Sf.ISaveDataChunkExporter> _baseInterface;
|
||||
|
||||
// LibHac addition
|
||||
private FileSystemClient _fsClient;
|
||||
|
||||
public SaveDataChunkExporter(FileSystemClient fs, ref SharedRef<FsSrv.Sf.ISaveDataChunkExporter> baseInterface)
|
||||
{
|
||||
_baseInterface = SharedRef<FsSrv.Sf.ISaveDataChunkExporter>.CreateMove(ref baseInterface);
|
||||
_fsClient = fs;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_baseInterface.Destroy();
|
||||
}
|
||||
|
||||
public Result Pull(out ulong outPulledSize, Span<byte> destination)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outPulledSize);
|
||||
|
||||
Result rc = _baseInterface.Get.Pull(out ulong pulledSize, new OutBuffer(destination),
|
||||
(ulong)destination.Length);
|
||||
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outPulledSize = pulledSize;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public long GetRestRawDataSize()
|
||||
{
|
||||
Result rc = _baseInterface.Get.GetRestRawDataSize(out long restSize);
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
Abort.DoAbortUnless(rc.IsSuccess());
|
||||
|
||||
return restSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An adapter for interacting with an <see cref="FsSrv.Sf.ISaveDataChunkImporter"/>
|
||||
/// IPC service object via the non-IPC <see cref="ISaveDataChunkImporter"/> interface.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 13.4.0</remarks>
|
||||
public class SaveDataChunkImporter : ISaveDataChunkImporter
|
||||
{
|
||||
private SharedRef<FsSrv.Sf.ISaveDataChunkImporter> _baseInterface;
|
||||
|
||||
// LibHac addition
|
||||
private FileSystemClient _fsClient;
|
||||
|
||||
public SaveDataChunkImporter(FileSystemClient fs, ref SharedRef<FsSrv.Sf.ISaveDataChunkImporter> baseInterface)
|
||||
{
|
||||
_baseInterface = SharedRef<FsSrv.Sf.ISaveDataChunkImporter>.CreateMove(ref baseInterface);
|
||||
_fsClient = fs;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_baseInterface.Destroy();
|
||||
}
|
||||
|
||||
public Result Push(ReadOnlySpan<byte> source)
|
||||
{
|
||||
Result rc = _baseInterface.Get.Push(new InBuffer(source), (ulong)source.Length);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An adapter for interacting with an <see cref="FsSrv.Sf.ISaveDataDivisionExporter"/>
|
||||
/// IPC service object via the non-IPC <see cref="ISaveDataDivisionExporter"/> interface.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 13.4.0</remarks>
|
||||
public class SaveDataExporterVersion2 : ISaveDataDivisionExporter
|
||||
{
|
||||
private SharedRef<FsSrv.Sf.ISaveDataDivisionExporter> _baseInterface;
|
||||
|
||||
// LibHac addition
|
||||
private FileSystemClient _fsClient;
|
||||
|
||||
public SaveDataExporterVersion2(FileSystemClient fs,
|
||||
ref SharedRef<FsSrv.Sf.ISaveDataDivisionExporter> baseInterface)
|
||||
{
|
||||
_baseInterface = SharedRef<FsSrv.Sf.ISaveDataDivisionExporter>.CreateMove(ref baseInterface);
|
||||
_fsClient = fs;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_baseInterface.Destroy();
|
||||
}
|
||||
|
||||
public Result SetDivisionCount(int divisionCount)
|
||||
{
|
||||
Result rc = _baseInterface.Get.SetDivisionCount(divisionCount);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataDiffChunkIterator(ref UniqueRef<ISaveDataChunkIterator> outIterator)
|
||||
{
|
||||
using var iteratorObject = new SharedRef<FsSrv.Sf.ISaveDataChunkIterator>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataDiffChunkIterator(ref iteratorObject.Ref());
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outIterator.Reset(new SaveDataChunkIterator(_fsClient, ref iteratorObject.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataChunkExporter(ref UniqueRef<ISaveDataChunkExporter> outExporter, ushort chunkId)
|
||||
{
|
||||
using var exporterObject = new SharedRef<FsSrv.Sf.ISaveDataChunkExporter>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataChunkExporter(ref exporterObject.Ref(), chunkId);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outExporter.Reset(new SaveDataChunkExporter(_fsClient, ref exporterObject.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetKeySeed(out KeySeed outKeySeed)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outKeySeed);
|
||||
|
||||
Result rc = _baseInterface.Get.GetKeySeed(out KeySeed keySeed);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outKeySeed = keySeed;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetInitialDataMac(out InitialDataMac outInitialDataMac)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outInitialDataMac);
|
||||
|
||||
Result rc = _baseInterface.Get.GetInitialDataMac(out InitialDataMac initialDataMac);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outInitialDataMac = initialDataMac;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetInitialDataMacKeyGeneration(out int outKeyGeneration)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outKeyGeneration);
|
||||
|
||||
Result rc = _baseInterface.Get.GetInitialDataMacKeyGeneration(out int initialDataMacKeyGeneration);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outKeyGeneration = initialDataMacKeyGeneration;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result FinalizeExport()
|
||||
{
|
||||
Result rc = _baseInterface.Get.FinalizeExport();
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CancelExport()
|
||||
{
|
||||
Result rc = _baseInterface.Get.CancelExport();
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result SuspendExport(out ISaveDataDivisionExporter.ExportContext outContext)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outContext);
|
||||
|
||||
Result rc = _baseInterface.Get.SuspendExport(OutBuffer.FromStruct(ref outContext));
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetImportInitialDataAad(out InitialDataAad outInitialDataAad)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outInitialDataAad);
|
||||
|
||||
Result rc = _baseInterface.Get.GetImportInitialDataAad(out InitialDataAad initialDataAad);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outInitialDataAad = initialDataAad;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result SetExportInitialDataAad(in InitialDataAad initialDataAad)
|
||||
{
|
||||
Result rc = _baseInterface.Get.SetExportInitialDataAad(in initialDataAad);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetSaveDataCommitId(out long outCommitId)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outCommitId);
|
||||
Unsafe.SkipInit(out SaveDataExtraData extraData);
|
||||
|
||||
Result rc = _baseInterface.Get.ReadSaveDataExtraData(OutBuffer.FromStruct(ref extraData));
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outCommitId = extraData.CommitId;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetSaveDataTimeStamp(out PosixTime outTimeStamp)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outTimeStamp);
|
||||
Unsafe.SkipInit(out SaveDataExtraData extraData);
|
||||
|
||||
Result rc = _baseInterface.Get.ReadSaveDataExtraData(OutBuffer.FromStruct(ref extraData));
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outTimeStamp = new PosixTime(extraData.TimeStamp);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetReportInfo(out ExportReportInfo outReportInfo)
|
||||
{
|
||||
Result rc = _baseInterface.Get.GetReportInfo(out outReportInfo);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An adapter for interacting with an <see cref="FsSrv.Sf.ISaveDataDivisionImporter"/>
|
||||
/// IPC service object via the non-IPC <see cref="ISaveDataDivisionImporter"/> interface.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 13.4.0</remarks>
|
||||
public class SaveDataImporterVersion2 : ISaveDataDivisionImporter
|
||||
{
|
||||
private SharedRef<FsSrv.Sf.ISaveDataDivisionImporter> _baseInterface;
|
||||
|
||||
// LibHac addition
|
||||
private FileSystemClient _fsClient;
|
||||
|
||||
public SaveDataImporterVersion2(FileSystemClient fs,
|
||||
ref SharedRef<FsSrv.Sf.ISaveDataDivisionImporter> baseInterface)
|
||||
{
|
||||
_baseInterface = SharedRef<FsSrv.Sf.ISaveDataDivisionImporter>.CreateMove(ref baseInterface);
|
||||
_fsClient = fs;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_baseInterface.Destroy();
|
||||
}
|
||||
|
||||
public Result InitializeImport(out long remaining, long sizeToProcess)
|
||||
{
|
||||
Result rc = _baseInterface.Get.InitializeImport(out remaining, sizeToProcess);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result FinalizeImport()
|
||||
{
|
||||
Result rc = _baseInterface.Get.FinalizeImport();
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result FinalizeImportWithoutSwap()
|
||||
{
|
||||
Result rc = _baseInterface.Get.FinalizeImportWithoutSwap();
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CancelImport()
|
||||
{
|
||||
Result rc = _baseInterface.Get.CancelImport();
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetImportContext(out ISaveDataDivisionImporter.ImportContext outContext)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outContext);
|
||||
|
||||
Result rc = _baseInterface.Get.GetImportContext(OutBuffer.FromStruct(ref outContext));
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result SuspendImport()
|
||||
{
|
||||
Result rc = _baseInterface.Get.SuspendImport();
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataDiffChunkIterator(ref UniqueRef<ISaveDataChunkIterator> outIterator)
|
||||
{
|
||||
using var iteratorObject = new SharedRef<FsSrv.Sf.ISaveDataChunkIterator>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataDiffChunkIterator(ref iteratorObject.Ref());
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outIterator.Reset(new SaveDataChunkIterator(_fsClient, ref iteratorObject.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataChunkImporter(ref UniqueRef<ISaveDataChunkImporter> outImporter, ushort chunkId)
|
||||
{
|
||||
using var importerObject = new SharedRef<FsSrv.Sf.ISaveDataChunkImporter>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataChunkImporter(ref importerObject.Ref(), chunkId);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outImporter.Reset(new SaveDataChunkImporter(_fsClient, ref importerObject.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetImportInitialDataAad(out InitialDataAad outInitialDataAad)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outInitialDataAad);
|
||||
|
||||
Result rc = _baseInterface.Get.GetImportInitialDataAad(out InitialDataAad initialDataAad);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outInitialDataAad = initialDataAad;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetSaveDataCommitId(out long outCommitId)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outCommitId);
|
||||
Unsafe.SkipInit(out SaveDataExtraData extraData);
|
||||
|
||||
Result rc = _baseInterface.Get.ReadSaveDataExtraData(OutBuffer.FromStruct(ref extraData));
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outCommitId = extraData.CommitId;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetSaveDataTimeStamp(out PosixTime outTimeStamp)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outTimeStamp);
|
||||
Unsafe.SkipInit(out SaveDataExtraData extraData);
|
||||
|
||||
Result rc = _baseInterface.Get.ReadSaveDataExtraData(OutBuffer.FromStruct(ref extraData));
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outTimeStamp = new PosixTime(extraData.TimeStamp);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result GetReportInfo(out ImportReportInfo outReportInfo)
|
||||
{
|
||||
Result rc = _baseInterface.Get.GetReportInfo(out outReportInfo);
|
||||
_fsClient.Impl.AbortIfNeeded(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
374
src/LibHac/Fs/Shim/SaveDataTransferVersion2.cs
Normal file
374
src/LibHac/Fs/Shim/SaveDataTransferVersion2.cs
Normal file
|
@ -0,0 +1,374 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.FixedArrays;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs.Impl;
|
||||
using LibHac.Fs.Shim;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.Sf;
|
||||
using LibHac.Util;
|
||||
|
||||
using static LibHac.Fs.SaveData;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace LibHac.Fs
|
||||
{
|
||||
public class SaveDataTransferManagerVersion2 : IDisposable
|
||||
{
|
||||
private SharedRef<ISaveDataTransferManagerWithDivision> _baseInterface;
|
||||
|
||||
// LibHac addition
|
||||
private FileSystemClient _fsClient;
|
||||
|
||||
public struct Challenge
|
||||
{
|
||||
public Array16<byte> Value;
|
||||
}
|
||||
|
||||
public struct SaveDataTag
|
||||
{
|
||||
public Array64<byte> Value;
|
||||
}
|
||||
|
||||
public struct KeySeedPackage
|
||||
{
|
||||
public Array512<byte> Value;
|
||||
}
|
||||
|
||||
public SaveDataTransferManagerVersion2(FileSystemClient fs)
|
||||
{
|
||||
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
|
||||
|
||||
Result rc = fileSystemProxy.Get.OpenSaveDataTransferManagerVersion2(ref _baseInterface);
|
||||
fs.Impl.LogResultErrorMessage(rc);
|
||||
Abort.DoAbortUnless(rc.IsSuccess());
|
||||
|
||||
_fsClient = fs;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_baseInterface.Destroy();
|
||||
}
|
||||
|
||||
public Result GetChallenge(out Challenge outChallenge)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outChallenge);
|
||||
|
||||
Result rc = _baseInterface.Get.GetChallenge(OutBuffer.FromStruct(ref outChallenge));
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result SetKeySeedPackage(in KeySeedPackage keySeedPackage)
|
||||
{
|
||||
Result rc = _baseInterface.Get.SetKeySeedPackage(InBuffer.FromStruct(in keySeedPackage));
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataFullExporter(ref UniqueRef<ISaveDataDivisionExporter> outExporter,
|
||||
SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
using var exporterInterface = new SharedRef<FsSrv.Sf.ISaveDataDivisionExporter>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataExporter(ref exporterInterface.Ref(), spaceId, saveDataId);
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outExporter.Reset(new SaveDataExporterVersion2(_fsClient, ref exporterInterface.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataDiffExporter(ref UniqueRef<ISaveDataDivisionExporter> outExporter,
|
||||
in InitialDataVersion2 initialData, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
using var exporterInterface = new SharedRef<FsSrv.Sf.ISaveDataDivisionExporter>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataExporterForDiffExport(ref exporterInterface.Ref(),
|
||||
InBuffer.FromStruct(in initialData), spaceId, saveDataId);
|
||||
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outExporter.Reset(new SaveDataExporterVersion2(_fsClient, ref exporterInterface.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataExporterByContext(ref UniqueRef<ISaveDataDivisionExporter> outExporter,
|
||||
ISaveDataDivisionExporter.ExportContext exportContext)
|
||||
{
|
||||
using var exporterInterface = new SharedRef<FsSrv.Sf.ISaveDataDivisionExporter>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataExporterByContext(ref exporterInterface.Ref(),
|
||||
InBuffer.FromStruct(in exportContext));
|
||||
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outExporter.Reset(new SaveDataExporterVersion2(_fsClient, ref exporterInterface.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataFullImporter(ref UniqueRef<ISaveDataDivisionImporter> outImporter,
|
||||
in InitialDataVersion2 initialData, in UserId userId, SaveDataSpaceId spaceId)
|
||||
{
|
||||
using var importerInterface = new SharedRef<FsSrv.Sf.ISaveDataDivisionImporter>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataImporterDeprecated(ref importerInterface.Ref(),
|
||||
InBuffer.FromStruct(in initialData), in userId, spaceId);
|
||||
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outImporter.Reset(new SaveDataImporterVersion2(_fsClient, ref importerInterface.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataDiffImporter(ref UniqueRef<ISaveDataDivisionImporter> outImporter,
|
||||
in InitialDataVersion2 initialData, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
using var importerInterface = new SharedRef<FsSrv.Sf.ISaveDataDivisionImporter>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataImporterForDiffImport(ref importerInterface.Ref(),
|
||||
InBuffer.FromStruct(in initialData), spaceId, saveDataId);
|
||||
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outImporter.Reset(new SaveDataImporterVersion2(_fsClient, ref importerInterface.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataDuplicateDiffImporter(ref UniqueRef<ISaveDataDivisionImporter> outImporter,
|
||||
in InitialDataVersion2 initialData, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
using var importerInterface = new SharedRef<FsSrv.Sf.ISaveDataDivisionImporter>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataImporterForDuplicateDiffImport(ref importerInterface.Ref(),
|
||||
InBuffer.FromStruct(in initialData), spaceId, saveDataId);
|
||||
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outImporter.Reset(new SaveDataImporterVersion2(_fsClient, ref importerInterface.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataImporterImpl(ref UniqueRef<ISaveDataDivisionImporter> outImporter,
|
||||
in InitialDataVersion2 initialData, in UserId userId, SaveDataSpaceId spaceId, bool useSwap)
|
||||
{
|
||||
using var importerInterface = new SharedRef<FsSrv.Sf.ISaveDataDivisionImporter>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataImporter(ref importerInterface.Ref(),
|
||||
InBuffer.FromStruct(in initialData), in userId, spaceId, useSwap);
|
||||
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outImporter.Reset(new SaveDataImporterVersion2(_fsClient, ref importerInterface.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result OpenSaveDataImporter(ref UniqueRef<ISaveDataDivisionImporter> outImporter,
|
||||
in InitialDataVersion2 initialData, SaveDataSpaceId spaceId, bool useSwap)
|
||||
{
|
||||
return OpenSaveDataImporterImpl(ref outImporter, in initialData, UserId.InvalidId, spaceId, useSwap);
|
||||
}
|
||||
|
||||
public Result OpenSaveDataImporterByContext(ref UniqueRef<ISaveDataDivisionImporter> outImporter,
|
||||
in ISaveDataDivisionImporter.ImportContext importContext)
|
||||
{
|
||||
using var importerInterface = new SharedRef<FsSrv.Sf.ISaveDataDivisionImporter>();
|
||||
|
||||
Result rc = _baseInterface.Get.OpenSaveDataImporterByContext(ref importerInterface.Ref(),
|
||||
InBuffer.FromStruct(in importContext));
|
||||
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outImporter.Reset(new SaveDataImporterVersion2(_fsClient, ref importerInterface.Ref()));
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static SaveDataTag MakeUserAccountSaveDataTag(Ncm.ApplicationId applicationId, in UserId userId)
|
||||
{
|
||||
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, applicationId, SaveDataType.Account,
|
||||
userId, InvalidSystemSaveDataId, index: 0, SaveDataRank.Primary);
|
||||
Abort.DoAbortUnless(rc.IsSuccess());
|
||||
|
||||
return Unsafe.As<SaveDataAttribute, SaveDataTag>(ref attribute);
|
||||
}
|
||||
|
||||
public static SaveDataTag MakeDeviceSaveDataTag(Ncm.ApplicationId applicationId)
|
||||
{
|
||||
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, applicationId, SaveDataType.Device,
|
||||
InvalidUserId, InvalidSystemSaveDataId, index: 0, SaveDataRank.Primary);
|
||||
Abort.DoAbortUnless(rc.IsSuccess());
|
||||
|
||||
return Unsafe.As<SaveDataAttribute, SaveDataTag>(ref attribute);
|
||||
}
|
||||
|
||||
public Result CancelSuspendingImport(in SaveDataTag tag)
|
||||
{
|
||||
ref readonly SaveDataAttribute attribute =
|
||||
ref Unsafe.As<SaveDataTag, SaveDataAttribute>(ref Unsafe.AsRef(in tag));
|
||||
|
||||
Result rc = _baseInterface.Get.CancelSuspendingImportByAttribute(in attribute);
|
||||
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CancelSuspendingImport(Ncm.ApplicationId applicationId, in UserId userId)
|
||||
{
|
||||
Result rc = _baseInterface.Get.CancelSuspendingImport(applicationId, in userId);
|
||||
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result SwapSecondary(in SaveDataTag tag, Optional<long> primaryCommitId)
|
||||
{
|
||||
long commitId = primaryCommitId.HasValue ? primaryCommitId.Value : 0;
|
||||
bool doSwap = primaryCommitId.HasValue;
|
||||
ref readonly SaveDataAttribute attribute =
|
||||
ref Unsafe.As<SaveDataTag, SaveDataAttribute>(ref Unsafe.AsRef(in tag));
|
||||
|
||||
Result rc = _baseInterface.Get.SwapSecondary(in attribute, doSwap, commitId);
|
||||
|
||||
_fsClient.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public class SaveDataTransferProhibiterForCloudBackUp : IDisposable
|
||||
{
|
||||
private SharedRef<ISaveDataTransferProhibiter> _prohibiter;
|
||||
|
||||
public SaveDataTransferProhibiterForCloudBackUp(ref SharedRef<ISaveDataTransferProhibiter> prohibiter)
|
||||
{
|
||||
_prohibiter = SharedRef<ISaveDataTransferProhibiter>.CreateMove(ref prohibiter);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_prohibiter.Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace LibHac.Fs.Shim
|
||||
{
|
||||
public static class SaveDataTransferVersion2Shim
|
||||
{
|
||||
public static Result OpenSaveDataTransferProhibiterForCloudBackUp(this FileSystemClientImpl fs,
|
||||
ref UniqueRef<SaveDataTransferProhibiterForCloudBackUp> outProhibiter, Ncm.ApplicationId applicationId)
|
||||
{
|
||||
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
|
||||
using var prohibiter = new SharedRef<ISaveDataTransferProhibiter>();
|
||||
|
||||
// Todo: Uncomment once opening transfer prohibiters is implemented
|
||||
// Result rc = fileSystemProxy.Get.OpenSaveDataTransferProhibiter(ref prohibiter.Ref(), applicationId);
|
||||
// if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
outProhibiter.Reset(new SaveDataTransferProhibiterForCloudBackUp(ref prohibiter.Ref()));
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result OpenSaveDataTransferProhibiterForCloudBackUp(this FileSystemClient fs,
|
||||
ref UniqueRef<SaveDataTransferProhibiterForCloudBackUp> outProhibiter, Ncm.ApplicationId applicationId)
|
||||
{
|
||||
Result rc = fs.Impl.OpenSaveDataTransferProhibiterForCloudBackUp(ref outProhibiter, applicationId);
|
||||
fs.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result OpenSaveDataTransferProhibiterForCloudBackUp(this FileSystemClient fs,
|
||||
Span<UniqueRef<SaveDataTransferProhibiterForCloudBackUp>> outProhibiters,
|
||||
ReadOnlySpan<Ncm.ApplicationId> applicationIds)
|
||||
{
|
||||
for (int i = 0; i < applicationIds.Length; i++)
|
||||
{
|
||||
Result rc = fs.Impl.OpenSaveDataTransferProhibiterForCloudBackUp(ref outProhibiters[i],
|
||||
applicationIds[i]);
|
||||
|
||||
fs.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result GetCountOfApplicationAccessibleSaveDataOwnerId(this FileSystemClient fs, out int outCount,
|
||||
Ncm.ApplicationId applicationId, int programIndex)
|
||||
{
|
||||
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
|
||||
ulong tempAppId = 0;
|
||||
var programId = new Ncm.ProgramId(applicationId.Value + (uint)programIndex);
|
||||
|
||||
Result rc = fileSystemProxy.Get.ListAccessibleSaveDataOwnerId(out outCount,
|
||||
OutBuffer.FromStruct(ref tempAppId), programId, startIndex: 0, bufferIdCount: 0);
|
||||
|
||||
fs.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result GetOccupiedWorkSpaceSizeForCloudBackUp(this FileSystemClient fs, out long outSize)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outSize);
|
||||
|
||||
using var iterator = new UniqueRef<SaveDataIterator>();
|
||||
|
||||
// We want to iterate every save with a Secondary rank
|
||||
Result rc = SaveDataFilter.Make(out SaveDataFilter filter, programId: default, saveType: default,
|
||||
userId: default, saveDataId: default, index: default, SaveDataRank.Secondary);
|
||||
|
||||
fs.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
rc = fs.Impl.OpenSaveDataIterator(ref iterator.Ref(), SaveDataSpaceId.User, in filter);
|
||||
fs.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
long workSize = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
Unsafe.SkipInit(out SaveDataInfo info);
|
||||
|
||||
rc = fs.Impl.ReadSaveDataIteratorSaveDataInfo(out long count, SpanHelpers.AsSpan(ref info),
|
||||
iterator.Get);
|
||||
|
||||
fs.Impl.LogResultErrorMessage(rc);
|
||||
if (rc.IsFailure()) return rc.Miss();
|
||||
|
||||
// Break once we've iterated all saves
|
||||
if (count == 0)
|
||||
break;
|
||||
|
||||
if (info.Rank == SaveDataRank.Secondary)
|
||||
workSize += info.Size;
|
||||
}
|
||||
|
||||
outSize = workSize;
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,5 +19,5 @@ public interface ISaveDataDivisionExporter : IDisposable
|
|||
public Result GetInitialDataMacKeyGeneration(out int keyGeneration);
|
||||
public Result GetImportInitialDataAad(out InitialDataAad initialDataAad);
|
||||
public Result SetExportInitialDataAad(in InitialDataAad initialDataAad);
|
||||
public Result GetReportInfo(out ImportReportInfo reportInfo);
|
||||
public Result GetReportInfo(out ExportReportInfo reportInfo);
|
||||
}
|
||||
|
|
|
@ -341,6 +341,20 @@ public class TypeLayoutTests
|
|||
Assert.Equal(0x00, GetOffset(in s, in s.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void ExportReportInfo_Layout()
|
||||
{
|
||||
var s = new ExportReportInfo();
|
||||
|
||||
Assert.Equal(0x20, Unsafe.SizeOf<ExportReportInfo>());
|
||||
|
||||
Assert.Equal(0, GetOffset(in s, in s.DiffChunkCount));
|
||||
Assert.Equal(1, GetOffset(in s, in s.DoubleDivisionDiffChunkCount));
|
||||
Assert.Equal(2, GetOffset(in s, in s.HalfDivisionDiffChunkCount));
|
||||
Assert.Equal(3, GetOffset(in s, in s.CompressionRate));
|
||||
Assert.Equal(4, GetOffset(in s, in s.Reserved));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void ImportReportInfo_Layout()
|
||||
{
|
||||
|
@ -365,4 +379,44 @@ public class TypeLayoutTests
|
|||
Assert.Equal(0, GetOffset(in s, in s.Index));
|
||||
Assert.Equal(4, GetOffset(in s, in s.Reserved));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Challenge_Layout()
|
||||
{
|
||||
var s = new SaveDataTransferManagerVersion2.Challenge();
|
||||
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<SaveDataTransferManagerVersion2.Challenge>());
|
||||
|
||||
Assert.Equal(0, GetOffset(in s, in s.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void SaveDataTag_Layout()
|
||||
{
|
||||
var s = new SaveDataTransferManagerVersion2.SaveDataTag();
|
||||
|
||||
Assert.Equal(0x40, Unsafe.SizeOf<SaveDataTransferManagerVersion2.SaveDataTag>());
|
||||
|
||||
Assert.Equal(0, GetOffset(in s, in s.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void KeySeedPackage_Layout()
|
||||
{
|
||||
var s = new SaveDataTransferManagerVersion2.KeySeedPackage();
|
||||
|
||||
Assert.Equal(0x200, Unsafe.SizeOf<SaveDataTransferManagerVersion2.KeySeedPackage>());
|
||||
|
||||
Assert.Equal(0, GetOffset(in s, in s.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void InitialDataVersion2_Layout()
|
||||
{
|
||||
var s = new InitialDataVersion2();
|
||||
|
||||
Assert.Equal(0x2000, Unsafe.SizeOf<InitialDataVersion2>());
|
||||
|
||||
Assert.Equal(0, GetOffset(in s, in s.Value));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue