mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add MultiCommitManager
- Recovering from an interrupted commit isn't implemented yet
This commit is contained in:
parent
d1110392b4
commit
ce54ae111c
8 changed files with 351 additions and 1 deletions
|
@ -127,6 +127,10 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary
|
||||||
2,4771,4779,SignedSystemPartitionDataCorrupted,
|
2,4771,4779,SignedSystemPartitionDataCorrupted,
|
||||||
2,4781,,GameCardLogoDataCorrupted,
|
2,4781,,GameCardLogoDataCorrupted,
|
||||||
|
|
||||||
|
2,4791,4799,MultiCommitContextCorrupted,
|
||||||
|
2,4791,,InvalidMultiCommitContextVersion,
|
||||||
|
2,4792,,InvalidMultiCommitContextState,
|
||||||
|
|
||||||
# The range name is a guess. 4812 is currently the only result in it
|
# The range name is a guess. 4812 is currently the only result in it
|
||||||
2,4811,4819,ZeroBitmapFileCorrupted,
|
2,4811,4819,ZeroBitmapFileCorrupted,
|
||||||
2,4812,,IncompleteBlockInZeroBitmapHashStorageFile,
|
2,4812,,IncompleteBlockInZeroBitmapHashStorageFile,
|
||||||
|
@ -197,14 +201,17 @@ Module,DescriptionStart,DescriptionEnd,Name,Summary
|
||||||
2,6454,,WriteStateUnflushed,
|
2,6454,,WriteStateUnflushed,
|
||||||
2,6457,,WriteModeFileNotClosed,
|
2,6457,,WriteModeFileNotClosed,
|
||||||
2,6461,,AllocatorAlignmentViolation,
|
2,6461,,AllocatorAlignmentViolation,
|
||||||
|
2,6463,,MultiCommitFileSystemAlreadyAdded,
|
||||||
2,6465,,UserNotExist,
|
2,6465,,UserNotExist,
|
||||||
|
|
||||||
2,6600,6699,EntryNotFound,
|
2,6600,6699,EntryNotFound,
|
||||||
2,6606,,TargetProgramIndexNotFound,Specified program index is not found
|
2,6606,,TargetProgramIndexNotFound,Specified program index is not found
|
||||||
|
|
||||||
2,6700,6799,OutOfResource,
|
2,6700,6799,OutOfResource,
|
||||||
2,6706,,MappingTableFull,
|
2,6706,,MappingTableFull,
|
||||||
2,6707,,AllocationTableInsufficientFreeBlocks,
|
2,6707,,AllocationTableInsufficientFreeBlocks,
|
||||||
2,6709,,OpenCountLimit,
|
2,6709,,OpenCountLimit,
|
||||||
|
2,6710,,MultiCommitFileSystemLimit,
|
||||||
|
|
||||||
2,6800,6899,MappingFailed,
|
2,6800,6899,MappingFailed,
|
||||||
2,6811,,RemapStorageMapFull,
|
2,6811,,RemapStorageMapFull,
|
||||||
|
|
|
|
@ -35,6 +35,21 @@ namespace LibHac.Fs
|
||||||
return ResultFs.NotImplemented.Log();
|
return ResultFs.NotImplemented.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual Result CommitProvisionallyImpl(long commitCount)
|
||||||
|
{
|
||||||
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Result RollbackImpl()
|
||||||
|
{
|
||||||
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Result FlushImpl()
|
||||||
|
{
|
||||||
|
return ResultFs.NotImplemented.Log();
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path)
|
protected virtual Result GetFileTimeStampRawImpl(out FileTimeStampRaw timeStamp, U8Span path)
|
||||||
{
|
{
|
||||||
timeStamp = default;
|
timeStamp = default;
|
||||||
|
@ -200,6 +215,27 @@ namespace LibHac.Fs
|
||||||
return CommitImpl();
|
return CommitImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Result CommitProvisionally(long commitCount)
|
||||||
|
{
|
||||||
|
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
|
||||||
|
|
||||||
|
return CommitProvisionallyImpl(commitCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Rollback()
|
||||||
|
{
|
||||||
|
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
|
||||||
|
|
||||||
|
return RollbackImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Flush()
|
||||||
|
{
|
||||||
|
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
|
||||||
|
|
||||||
|
return FlushImpl();
|
||||||
|
}
|
||||||
|
|
||||||
public Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, U8Span path)
|
public Result QueryEntry(Span<byte> outBuffer, ReadOnlySpan<byte> inBuffer, QueryId queryId, U8Span path)
|
||||||
{
|
{
|
||||||
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
|
if (IsDisposed) return ResultFs.PreconditionViolation.Log();
|
||||||
|
|
|
@ -183,6 +183,12 @@ namespace LibHac.Fs
|
||||||
/// <returns>The <see cref="Result"/> of the requested operation.</returns>
|
/// <returns>The <see cref="Result"/> of the requested operation.</returns>
|
||||||
Result Commit();
|
Result Commit();
|
||||||
|
|
||||||
|
Result CommitProvisionally(long commitCount);
|
||||||
|
|
||||||
|
Result Rollback();
|
||||||
|
|
||||||
|
Result Flush();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the creation, last accessed, and last modified timestamps of a file or directory.
|
/// Gets the creation, last accessed, and last modified timestamps of a file or directory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -256,6 +256,13 @@ namespace LibHac.Fs
|
||||||
/// <summary>Error code: 2002-4781; Inner value: 0x255a02</summary>
|
/// <summary>Error code: 2002-4781; Inner value: 0x255a02</summary>
|
||||||
public static Result.Base GameCardLogoDataCorrupted => new Result.Base(ModuleFs, 4781);
|
public static Result.Base GameCardLogoDataCorrupted => new Result.Base(ModuleFs, 4781);
|
||||||
|
|
||||||
|
/// <summary>Error code: 2002-4791; Range: 4791-4799; Inner value: 0x256e02</summary>
|
||||||
|
public static Result.Base MultiCommitContextCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4791, 4799); }
|
||||||
|
/// <summary>Error code: 2002-4791; Inner value: 0x256e02</summary>
|
||||||
|
public static Result.Base InvalidMultiCommitContextVersion => new Result.Base(ModuleFs, 4791);
|
||||||
|
/// <summary>Error code: 2002-4792; Inner value: 0x257002</summary>
|
||||||
|
public static Result.Base InvalidMultiCommitContextState => new Result.Base(ModuleFs, 4792);
|
||||||
|
|
||||||
/// <summary>Error code: 2002-4811; Range: 4811-4819; Inner value: 0x259602</summary>
|
/// <summary>Error code: 2002-4811; Range: 4811-4819; Inner value: 0x259602</summary>
|
||||||
public static Result.Base ZeroBitmapFileCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4811, 4819); }
|
public static Result.Base ZeroBitmapFileCorrupted { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 4811, 4819); }
|
||||||
/// <summary>Error code: 2002-4812; Inner value: 0x259802</summary>
|
/// <summary>Error code: 2002-4812; Inner value: 0x259802</summary>
|
||||||
|
@ -385,6 +392,8 @@ namespace LibHac.Fs
|
||||||
public static Result.Base WriteModeFileNotClosed => new Result.Base(ModuleFs, 6457);
|
public static Result.Base WriteModeFileNotClosed => new Result.Base(ModuleFs, 6457);
|
||||||
/// <summary>Error code: 2002-6461; Inner value: 0x327a02</summary>
|
/// <summary>Error code: 2002-6461; Inner value: 0x327a02</summary>
|
||||||
public static Result.Base AllocatorAlignmentViolation => new Result.Base(ModuleFs, 6461);
|
public static Result.Base AllocatorAlignmentViolation => new Result.Base(ModuleFs, 6461);
|
||||||
|
/// <summary>Error code: 2002-6463; Inner value: 0x327e02</summary>
|
||||||
|
public static Result.Base MultiCommitFileSystemAlreadyAdded => new Result.Base(ModuleFs, 6463);
|
||||||
/// <summary>Error code: 2002-6465; Inner value: 0x328202</summary>
|
/// <summary>Error code: 2002-6465; Inner value: 0x328202</summary>
|
||||||
public static Result.Base UserNotExist => new Result.Base(ModuleFs, 6465);
|
public static Result.Base UserNotExist => new Result.Base(ModuleFs, 6465);
|
||||||
|
|
||||||
|
@ -401,6 +410,8 @@ namespace LibHac.Fs
|
||||||
public static Result.Base AllocationTableInsufficientFreeBlocks => new Result.Base(ModuleFs, 6707);
|
public static Result.Base AllocationTableInsufficientFreeBlocks => new Result.Base(ModuleFs, 6707);
|
||||||
/// <summary>Error code: 2002-6709; Inner value: 0x346a02</summary>
|
/// <summary>Error code: 2002-6709; Inner value: 0x346a02</summary>
|
||||||
public static Result.Base OpenCountLimit => new Result.Base(ModuleFs, 6709);
|
public static Result.Base OpenCountLimit => new Result.Base(ModuleFs, 6709);
|
||||||
|
/// <summary>Error code: 2002-6710; Inner value: 0x346c02</summary>
|
||||||
|
public static Result.Base MultiCommitFileSystemLimit => new Result.Base(ModuleFs, 6710);
|
||||||
|
|
||||||
/// <summary>Error code: 2002-6800; Range: 6800-6899; Inner value: 0x352002</summary>
|
/// <summary>Error code: 2002-6800; Range: 6800-6899; Inner value: 0x352002</summary>
|
||||||
public static Result.Base MappingFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6800, 6899); }
|
public static Result.Base MappingFailed { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new Result.Base(ModuleFs, 6800, 6899); }
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace LibHac.Fs
|
||||||
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
|
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
|
||||||
public struct SaveDataAttribute : IEquatable<SaveDataAttribute>, IComparable<SaveDataAttribute>
|
public struct SaveDataAttribute : IEquatable<SaveDataAttribute>, IComparable<SaveDataAttribute>
|
||||||
{
|
{
|
||||||
|
// todo: rename to ProgramId
|
||||||
[FieldOffset(0x00)] public TitleId TitleId;
|
[FieldOffset(0x00)] public TitleId TitleId;
|
||||||
[FieldOffset(0x08)] public UserId UserId;
|
[FieldOffset(0x08)] public UserId UserId;
|
||||||
[FieldOffset(0x18)] public ulong SaveDataId;
|
[FieldOffset(0x18)] public ulong SaveDataId;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
|
using LibHac.FsService.Impl;
|
||||||
using LibHac.FsSystem;
|
using LibHac.FsSystem;
|
||||||
using LibHac.Kvdb;
|
using LibHac.Kvdb;
|
||||||
using LibHac.Ncm;
|
using LibHac.Ncm;
|
||||||
|
@ -12,7 +13,7 @@ namespace LibHac.FsService
|
||||||
public class FileSystemProxy : IFileSystemProxy
|
public class FileSystemProxy : IFileSystemProxy
|
||||||
{
|
{
|
||||||
private FileSystemProxyCore FsProxyCore { get; }
|
private FileSystemProxyCore FsProxyCore { get; }
|
||||||
private FileSystemServer FsServer { get; }
|
internal FileSystemServer FsServer { get; }
|
||||||
|
|
||||||
public long CurrentProcess { get; private set; }
|
public long CurrentProcess { get; private set; }
|
||||||
|
|
||||||
|
@ -1175,6 +1176,22 @@ namespace LibHac.FsService
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal Result OpenMultiCommitContextSaveData(out IFileSystem fileSystem)
|
||||||
|
{
|
||||||
|
fileSystem = default;
|
||||||
|
|
||||||
|
SaveDataAttribute attribute = default;
|
||||||
|
attribute.TitleId = new TitleId(MultiCommitManager.ProgramId);
|
||||||
|
attribute.SaveDataId = MultiCommitManager.SaveDataId;
|
||||||
|
|
||||||
|
Result rc = OpenSaveDataFileSystemImpl(out IFileSystem saveFs, out _, SaveDataSpaceId.System, ref attribute,
|
||||||
|
false, true);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
fileSystem = saveFs;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsSystemSaveDataId(ulong id)
|
private static bool IsSystemSaveDataId(ulong id)
|
||||||
{
|
{
|
||||||
return (long)id < 0;
|
return (long)id < 0;
|
||||||
|
|
10
src/LibHac/FsService/IMultiCommitManager.cs
Normal file
10
src/LibHac/FsService/IMultiCommitManager.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using LibHac.Fs;
|
||||||
|
|
||||||
|
namespace LibHac.FsService
|
||||||
|
{
|
||||||
|
public interface IMultiCommitManager
|
||||||
|
{
|
||||||
|
Result Add(IFileSystem fileSystem);
|
||||||
|
Result Commit();
|
||||||
|
}
|
||||||
|
}
|
262
src/LibHac/FsService/Impl/MultiCommitManager.cs
Normal file
262
src/LibHac/FsService/Impl/MultiCommitManager.cs
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.Fs.Shim;
|
||||||
|
|
||||||
|
namespace LibHac.FsService.Impl
|
||||||
|
{
|
||||||
|
internal class MultiCommitManager : IMultiCommitManager
|
||||||
|
{
|
||||||
|
private const int MaxFileSystemCount = 10;
|
||||||
|
private const int CurrentContextVersion = 0x10000;
|
||||||
|
|
||||||
|
public const ulong ProgramId = 0x100000000000000;
|
||||||
|
public const ulong SaveDataId = 0x8000000000000001;
|
||||||
|
private const long SaveDataSize = 0xC000;
|
||||||
|
private const long SaveJournalSize = 0xC000;
|
||||||
|
|
||||||
|
private const long ContextFileSize = 0x200;
|
||||||
|
|
||||||
|
// /commitinfo
|
||||||
|
private static U8Span ContextFileName =>
|
||||||
|
new U8Span(new[] { (byte)'/', (byte)'c', (byte)'o', (byte)'m', (byte)'m', (byte)'i', (byte)'t', (byte)'i', (byte)'n', (byte)'f', (byte)'o' });
|
||||||
|
|
||||||
|
private static readonly object Locker = new object();
|
||||||
|
|
||||||
|
private FileSystemProxy FsProxy { get; }
|
||||||
|
private List<IFileSystem> FileSystems { get; } = new List<IFileSystem>(MaxFileSystemCount);
|
||||||
|
private long CommitCount { get; set; }
|
||||||
|
|
||||||
|
public MultiCommitManager(FileSystemProxy fsProxy)
|
||||||
|
{
|
||||||
|
FsProxy = fsProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Add(IFileSystem fileSystem)
|
||||||
|
{
|
||||||
|
if (FileSystems.Count >= MaxFileSystemCount)
|
||||||
|
return ResultFs.MultiCommitFileSystemLimit.Log();
|
||||||
|
|
||||||
|
// Check that the file system hasn't already been added
|
||||||
|
for (int i = 0; i < FileSystems.Count; i++)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(FileSystems[i], fileSystem))
|
||||||
|
return ResultFs.MultiCommitFileSystemAlreadyAdded.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystems.Add(fileSystem);
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Commit()
|
||||||
|
{
|
||||||
|
lock (Locker)
|
||||||
|
{
|
||||||
|
Result rc = CreateSave();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = FsProxy.OpenMultiCommitContextSaveData(out IFileSystem contextFs);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
return CommitImpl(contextFs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result CommitImpl(IFileSystem contextFileSystem)
|
||||||
|
{
|
||||||
|
var context = new CommitContextManager(contextFileSystem);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CommitCount = 1;
|
||||||
|
|
||||||
|
Result rc = context.Initialize(CommitCount, FileSystems.Count);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = CommitProvisionally();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = context.SetCommittedProvisionally();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
foreach (IFileSystem fs in FileSystems)
|
||||||
|
{
|
||||||
|
rc = fs.Commit();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = context.Close();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
context.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result CreateSave()
|
||||||
|
{
|
||||||
|
Result rc = FsProxy.OpenMultiCommitContextSaveData(out IFileSystem contextFs);
|
||||||
|
|
||||||
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
if (!ResultFs.TargetNotFound.Includes(rc))
|
||||||
|
{
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = FsProxy.FsServer.FsClient.CreateSystemSaveData(SaveDataId, SaveDataSize, SaveJournalSize,
|
||||||
|
SaveDataFlags.None);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
contextFs?.Dispose();
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result CommitProvisionally()
|
||||||
|
{
|
||||||
|
Result rc = Result.Success;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < FileSystems.Count; i++)
|
||||||
|
{
|
||||||
|
rc = FileSystems[i].CommitProvisionally(CommitCount);
|
||||||
|
|
||||||
|
if (rc.IsFailure())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
// Rollback all provisional commits including the failed commit
|
||||||
|
for (int j = 0; j <= i; j++)
|
||||||
|
{
|
||||||
|
FileSystems[j].Rollback().IgnoreResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Size = 0x18)]
|
||||||
|
private struct CommitContext
|
||||||
|
{
|
||||||
|
public int Version;
|
||||||
|
public CommitState State;
|
||||||
|
public int FileSystemCount;
|
||||||
|
public long CommitCount; // I think?
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum CommitState
|
||||||
|
{
|
||||||
|
// ReSharper disable once UnusedMember.Local
|
||||||
|
None = 0,
|
||||||
|
NotCommitted = 1,
|
||||||
|
ProvisionallyCommitted = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct CommitContextManager
|
||||||
|
{
|
||||||
|
private IFileSystem _fileSystem;
|
||||||
|
private CommitContext _context;
|
||||||
|
|
||||||
|
public CommitContextManager(IFileSystem contextFileSystem)
|
||||||
|
{
|
||||||
|
_fileSystem = contextFileSystem;
|
||||||
|
_context = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Initialize(long commitCount, int fileSystemCount)
|
||||||
|
{
|
||||||
|
IFile contextFile = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Open context file and create if it doesn't exist
|
||||||
|
Result rc = _fileSystem.OpenFile(out contextFile, ContextFileName, OpenMode.Read);
|
||||||
|
|
||||||
|
if (rc.IsFailure())
|
||||||
|
{
|
||||||
|
if (!ResultFs.PathNotFound.Includes(rc))
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = _fileSystem.CreateFile(ContextFileName, ContextFileSize, CreateFileOptions.None);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = _fileSystem.OpenFile(out contextFile, ContextFileName, OpenMode.Read);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Version = CurrentContextVersion;
|
||||||
|
_context.State = CommitState.NotCommitted;
|
||||||
|
_context.FileSystemCount = fileSystemCount;
|
||||||
|
_context.CommitCount = commitCount;
|
||||||
|
|
||||||
|
// Write the initial context to the file
|
||||||
|
rc = contextFile.Write(0, SpanHelpers.AsByteSpan(ref _context), WriteOption.None);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = contextFile.Flush();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
contextFile?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _fileSystem.Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result SetCommittedProvisionally()
|
||||||
|
{
|
||||||
|
IFile contextFile = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Result rc = _fileSystem.OpenFile(out contextFile, ContextFileName, OpenMode.ReadWrite);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
_context.State = CommitState.ProvisionallyCommitted;
|
||||||
|
|
||||||
|
rc = contextFile.Write(0, SpanHelpers.AsByteSpan(ref _context), WriteOption.None);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = contextFile.Flush();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
contextFile?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _fileSystem.Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Close()
|
||||||
|
{
|
||||||
|
Result rc = _fileSystem.DeleteFile(ContextFileName);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = _fileSystem.Commit();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
_fileSystem = null;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_fileSystem is null) return;
|
||||||
|
|
||||||
|
_fileSystem.DeleteFile(ContextFileName).IgnoreResult();
|
||||||
|
_fileSystem.Commit().IgnoreResult();
|
||||||
|
|
||||||
|
_fileSystem = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue