mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Implement SaveDataExtender
This commit is contained in:
parent
164382f998
commit
2501cd24d0
4 changed files with 123 additions and 56 deletions
|
@ -1,16 +1,25 @@
|
|||
// ReSharper disable UnusedMember.Local UnusedType.Local
|
||||
#pragma warning disable CS0169 // Field is never used
|
||||
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.FsSystem.Save;
|
||||
using LibHac.Util;
|
||||
|
||||
namespace LibHac.FsSrv.Impl;
|
||||
|
||||
/// <summary>
|
||||
/// Extends a save data image to a larger size. Keeps track of the extension progress by writing information about
|
||||
/// the extension to an "extension context" storage.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||
public class SaveDataExtender
|
||||
{
|
||||
private const uint MagicCode = 0x43545845; // EXTC
|
||||
private const uint Version1 = 0x10000;
|
||||
private const uint Version2 = 0x20000;
|
||||
|
||||
private enum State
|
||||
{
|
||||
Initial = 1,
|
||||
|
@ -18,6 +27,7 @@ public class SaveDataExtender
|
|||
Committed = 3
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct Context
|
||||
{
|
||||
public uint Magic;
|
||||
|
@ -36,62 +46,119 @@ public class SaveDataExtender
|
|||
|
||||
public SaveDataExtender()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
_contextStorage = null;
|
||||
}
|
||||
|
||||
public long GetLogSize() => JournalIntegritySaveDataFileSystemDriver.QueryExpandLogSize(_context.BlockSize,
|
||||
GetJournalBlockCount(), GetAvailableBlockCount());
|
||||
|
||||
public long GetAvailableSize() => _context.AvailableSize;
|
||||
public long GetJournalSize() => _context.JournalSize;
|
||||
public long GetExtendedSaveDataSize() => _context.ExtendedSaveDataSize;
|
||||
|
||||
private uint GetAvailableBlockCount() => (uint)BitUtil.DivideUp(_context.AvailableSize, _context.BlockSize);
|
||||
private uint GetJournalBlockCount() => (uint)BitUtil.DivideUp(_context.JournalSize, _context.BlockSize);
|
||||
|
||||
public Result InitializeContext(in JournalIntegritySaveDataParameters param, long sizeAvailable, long sizeReserved)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
_context.Magic = MagicCode;
|
||||
_context.Version = Version2;
|
||||
_context.State = State.Initial;
|
||||
_context.AvailableSize = sizeAvailable;
|
||||
_context.JournalSize = sizeReserved;
|
||||
_context.BlockSize = param.BlockSize;
|
||||
|
||||
Result res = JournalIntegritySaveDataFileSystemDriver.QueryTotalSize(out _context.ExtendedSaveDataSize,
|
||||
param.BlockSize, GetAvailableBlockCount(), GetJournalBlockCount(), param.CountExpandMax, param.Version);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result WriteContext(IStorage contextStorage)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Result res = contextStorage.Write(0, SpanHelpers.AsReadOnlyByteSpan(in _context));
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = contextStorage.Flush();
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result ReadContext(IStorage contextStorage)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Assert.SdkRequiresNull(_contextStorage);
|
||||
Assert.SdkRequiresNotNull(contextStorage);
|
||||
|
||||
Result res = contextStorage.Read(0, SpanHelpers.AsByteSpan(ref _context));
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (_context.Magic != MagicCode)
|
||||
return ResultFs.IncorrectSaveDataExtensionContextMagicCode.Log();
|
||||
|
||||
if (_context.Version == Version1)
|
||||
{
|
||||
UpdateContextV1ToV2(ref _context);
|
||||
}
|
||||
|
||||
public long GetLogSize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (_context.Version != Version2)
|
||||
return ResultFs.UnsupportedSaveDataVersion.Log();
|
||||
|
||||
public long GetAvailableSize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
State state = _context.State;
|
||||
if (state != State.Initial && state != State.Extended && state != State.Committed)
|
||||
return ResultFs.InvalidSaveDataExtensionContextState.Log();
|
||||
|
||||
public long GetJournalSize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (_context.BlockSize <= 0)
|
||||
return ResultFs.InvalidSaveDataExtensionContextParameter.Log();
|
||||
|
||||
public long GetExtendedSaveDataSize()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (_context.ExtendedSaveDataSize <= 0)
|
||||
return ResultFs.InvalidSaveDataExtensionContextParameter.Log();
|
||||
|
||||
private uint GetAvailableBlockCount()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private uint GetJournalBlockCount()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
_contextStorage = contextStorage;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Extend(in ValueSubStorage saveDataStorage, in ValueSubStorage logStorage, IBufferManager bufferManager,
|
||||
IMacGenerator macGenerator, IHash256GeneratorFactorySelector hashGeneratorFactorySelector, uint minimumVersion)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Assert.SdkRequiresNotNull(_contextStorage);
|
||||
|
||||
if (_context.State == State.Initial)
|
||||
{
|
||||
Result res = JournalIntegritySaveDataFileSystemDriver.OperateExpand(in saveDataStorage, in logStorage,
|
||||
_context.BlockSize, GetAvailableBlockCount(), GetJournalBlockCount(), bufferManager, macGenerator,
|
||||
hashGeneratorFactorySelector, minimumVersion);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
_context.State = State.Extended;
|
||||
res = WriteContext(_contextStorage);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
}
|
||||
|
||||
if (_context.State == State.Extended)
|
||||
{
|
||||
Result res = JournalIntegritySaveDataFileSystemDriver.CommitExpand(in saveDataStorage, in logStorage,
|
||||
_context.BlockSize, bufferManager);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
_context.State = State.Committed;
|
||||
res = WriteContext(_contextStorage);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
}
|
||||
|
||||
if (_context.State != State.Committed)
|
||||
return ResultFs.BadState.Log();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private void UpdateContextV1ToV2(ref Context context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Assert.SdkAssert(context.Version == Version1);
|
||||
|
||||
context.AvailableSize *= context.BlockSize;
|
||||
context.JournalSize *= context.BlockSize;
|
||||
context.Version = Version2;
|
||||
}
|
||||
}
|
|
@ -10,13 +10,13 @@ namespace LibHac.FsSrv.Impl;
|
|||
/// <summary>
|
||||
/// Holds the <see cref="ISaveDataExtraDataAccessor"/>s for opened save data file systems.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 14.3.0 (FS 14.1.0)</remarks>
|
||||
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||
public class SaveDataExtraDataAccessorCacheManager : ISaveDataExtraDataAccessorObserver
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds a single cached extra data accessor identified by its save data ID and save data space ID.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 14.3.0 (FS 14.1.0)</remarks>
|
||||
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||
[NonCopyable]
|
||||
private struct Cache : IDisposable
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace LibHac.FsSrv.Impl;
|
|||
/// Manages a list of cached save data file systems. Each file system is registered and retrieved
|
||||
/// based on its save data ID and save data space ID.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 14.3.0 (FS 14.1.0)</remarks>
|
||||
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||
public class SaveDataFileSystemCacheManager : IDisposable
|
||||
{
|
||||
[NonCopyable]
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace LibHac.FsSrv.Impl;
|
|||
/// Wraps an <see cref="ISaveDataFileSystem"/>.
|
||||
/// Upon disposal the base file system is returned to the provided <see cref="SaveDataFileSystemCacheManager"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 14.3.0 (FS 14.1.0)</remarks>
|
||||
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||
public class SaveDataFileSystemCacheRegister : IFileSystem
|
||||
{
|
||||
private SharedRef<ISaveDataFileSystem> _baseFileSystem;
|
||||
|
@ -36,87 +36,87 @@ public class SaveDataFileSystemCacheRegister : IFileSystem
|
|||
|
||||
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, ref readonly Path path, OpenMode mode)
|
||||
{
|
||||
return _baseFileSystem.Get.OpenFile(ref outFile, in path, mode);
|
||||
return _baseFileSystem.Get.OpenFile(ref outFile, in path, mode).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, ref readonly Path path,
|
||||
OpenDirectoryMode mode)
|
||||
{
|
||||
return _baseFileSystem.Get.OpenDirectory(ref outDirectory, in path, mode);
|
||||
return _baseFileSystem.Get.OpenDirectory(ref outDirectory, in path, mode).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, ref readonly Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.GetEntryType(out entryType, in path);
|
||||
return _baseFileSystem.Get.GetEntryType(out entryType, in path).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoCreateFile(ref readonly Path path, long size, CreateFileOptions option)
|
||||
{
|
||||
return _baseFileSystem.Get.CreateFile(in path, size, option);
|
||||
return _baseFileSystem.Get.CreateFile(in path, size, option).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoDeleteFile(ref readonly Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.DeleteFile(in path);
|
||||
return _baseFileSystem.Get.DeleteFile(in path).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoCreateDirectory(ref readonly Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.CreateDirectory(in path);
|
||||
return _baseFileSystem.Get.CreateDirectory(in path).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectory(ref readonly Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.DeleteDirectory(in path);
|
||||
return _baseFileSystem.Get.DeleteDirectory(in path).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectoryRecursively(ref readonly Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.DeleteDirectoryRecursively(in path);
|
||||
return _baseFileSystem.Get.DeleteDirectoryRecursively(in path).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoCleanDirectoryRecursively(ref readonly Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.CleanDirectoryRecursively(in path);
|
||||
return _baseFileSystem.Get.CleanDirectoryRecursively(in path).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoRenameFile(ref readonly Path currentPath, ref readonly Path newPath)
|
||||
{
|
||||
return _baseFileSystem.Get.RenameFile(in currentPath, in newPath);
|
||||
return _baseFileSystem.Get.RenameFile(in currentPath, in newPath).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoRenameDirectory(ref readonly Path currentPath, ref readonly Path newPath)
|
||||
{
|
||||
return _baseFileSystem.Get.RenameDirectory(in currentPath, in newPath);
|
||||
return _baseFileSystem.Get.RenameDirectory(in currentPath, in newPath).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoCommit()
|
||||
{
|
||||
return _baseFileSystem.Get.Commit();
|
||||
return _baseFileSystem.Get.Commit().Ret();
|
||||
}
|
||||
|
||||
protected override Result DoCommitProvisionally(long counter)
|
||||
{
|
||||
return _baseFileSystem.Get.CommitProvisionally(counter);
|
||||
return _baseFileSystem.Get.CommitProvisionally(counter).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoRollback()
|
||||
{
|
||||
return _baseFileSystem.Get.Rollback();
|
||||
return _baseFileSystem.Get.Rollback().Ret();
|
||||
}
|
||||
|
||||
protected override Result DoGetFreeSpaceSize(out long freeSpace, ref readonly Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.GetFreeSpaceSize(out freeSpace, in path);
|
||||
return _baseFileSystem.Get.GetFreeSpaceSize(out freeSpace, in path).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoGetTotalSpaceSize(out long totalSpace, ref readonly Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.GetTotalSpaceSize(out totalSpace, in path);
|
||||
return _baseFileSystem.Get.GetTotalSpaceSize(out totalSpace, in path).Ret();
|
||||
}
|
||||
|
||||
protected override Result DoGetFileSystemAttribute(out FileSystemAttribute outAttribute)
|
||||
{
|
||||
return _baseFileSystem.Get.GetFileSystemAttribute(out outAttribute);
|
||||
return _baseFileSystem.Get.GetFileSystemAttribute(out outAttribute).Ret();
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue