mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Implement the rest of SaveDataInternalStorageFileSystem
This commit is contained in:
parent
2501cd24d0
commit
2b2b7471ea
12 changed files with 528 additions and 51 deletions
6
src/LibHac/Common/ConstGenerics.cs
Normal file
6
src/LibHac/Common/ConstGenerics.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
namespace LibHac.Common;
|
||||
|
||||
public interface IConstant<T> where T : struct
|
||||
{
|
||||
static abstract T Value { get; }
|
||||
}
|
|
@ -179,7 +179,7 @@ public class FileStorageBasedFileSystem : FileStorage
|
|||
/// <see cref="ResultFs.PathNotFound"/>: The specified path does not exist or is a directory.<br/>
|
||||
/// <see cref="ResultFs.TargetLocked"/>: When opening as <see cref="OpenMode.Write"/>,
|
||||
/// the file is already opened as <see cref="OpenMode.Write"/>.</returns>
|
||||
public Result Initialize(ref SharedRef<IFileSystem> baseFileSystem, ref readonly Path path, OpenMode mode)
|
||||
public Result Initialize(ref readonly SharedRef<IFileSystem> baseFileSystem, ref readonly Path path, OpenMode mode)
|
||||
{
|
||||
using var baseFile = new UniqueRef<IFile>();
|
||||
|
||||
|
@ -187,7 +187,7 @@ public class FileStorageBasedFileSystem : FileStorage
|
|||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
SetFile(baseFile.Get);
|
||||
_baseFileSystem.SetByMove(ref baseFileSystem);
|
||||
_baseFileSystem.SetByCopy(in baseFileSystem);
|
||||
_baseFile.Set(ref baseFile.Ref);
|
||||
|
||||
return Result.Success;
|
||||
|
|
|
@ -37,7 +37,7 @@ public class DefaultFsServerObjects
|
|||
creators.StorageOnNcaCreator = new StorageOnNcaCreator(keySet);
|
||||
creators.TargetManagerFileSystemCreator = new TargetManagerFileSystemCreator();
|
||||
creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator();
|
||||
creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(fsServer, keySet, null, randomGenerator);
|
||||
creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(fsServer, null, randomGenerator);
|
||||
creators.GameCardStorageCreator = gcStorageCreator;
|
||||
creators.GameCardFileSystemCreator = new GameCardFileSystemCreator(new ArrayPoolMemoryResource(), gcStorageCreator, fsServer);
|
||||
creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keySet);
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.FsSrv.FsCreator;
|
||||
|
||||
namespace LibHac.FsSrv;
|
||||
|
||||
public delegate Result GenerateSeedUniqueMac(Span<byte> outMacBuffer, ReadOnlySpan<byte> data, ReadOnlySpan<byte> seed);
|
||||
public delegate Result GenerateDeviceUniqueMac(Span<byte> outMacBuffer, ReadOnlySpan<byte> data, DeviceUniqueMacType macType);
|
||||
|
||||
public delegate Result SaveTransferAesKeyGenerator(Span<byte> outKeyBuffer,
|
||||
SaveDataTransferCryptoConfiguration.KeyIndex index, ReadOnlySpan<byte> keySource, int keyGeneration);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ using LibHac.FsSystem.Save;
|
|||
|
||||
namespace LibHac.FsSrv.FsCreator;
|
||||
|
||||
public interface ISaveDataFileSystemCreator
|
||||
public interface ISaveDataFileSystemCreator : IDisposable
|
||||
{
|
||||
Result CreateRaw(ref SharedRef<IFile> outFile, in SharedRef<IFileSystem> fileSystem, ulong saveDataId, OpenMode openMode);
|
||||
|
||||
|
|
|
@ -2,74 +2,314 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.FixedArrays;
|
||||
using LibHac.Common.Keys;
|
||||
using LibHac.Crypto;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Shim;
|
||||
using LibHac.FsSrv.Impl;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.FsSystem.Save;
|
||||
using LibHac.Util;
|
||||
using OpenType = LibHac.FsSrv.SaveDataOpenTypeSetFileStorage.OpenType;
|
||||
using ValueSubStorage = LibHac.Fs.ValueSubStorage;
|
||||
|
||||
namespace LibHac.FsSrv.FsCreator;
|
||||
|
||||
public enum DeviceUniqueMacType
|
||||
{
|
||||
Normal,
|
||||
Temporary
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extends <see cref="LibHac.FsSystem.Save.SaveDataInternalStorageFileSystem"/> to allow initializing it with a
|
||||
/// <see cref="SaveDataFileSystem"/> instead of directly using an <see cref="IInternalStorageFileSystem"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||
file class SaveDataInternalStorageFileSystem : LibHac.FsSystem.Save.SaveDataInternalStorageFileSystem
|
||||
{
|
||||
private SharedRef<SaveDataFileSystem> _saveDataFileSystem;
|
||||
|
||||
public SaveDataInternalStorageFileSystem()
|
||||
{
|
||||
_saveDataFileSystem = new SharedRef<SaveDataFileSystem>();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_saveDataFileSystem.Destroy();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
public Result Initialize(ref readonly SharedRef<SaveDataFileSystem> saveDataFileSystem,
|
||||
IMacGenerator normalMacGenerator, IMacGenerator temporaryMacGenerator,
|
||||
IHash256GeneratorFactorySelector hashGeneratorFactorySelector)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(in saveDataFileSystem);
|
||||
Assert.SdkRequiresNotNull(normalMacGenerator);
|
||||
Assert.SdkRequiresNotNull(temporaryMacGenerator);
|
||||
Assert.SdkRequiresNotNull(hashGeneratorFactorySelector);
|
||||
|
||||
_saveDataFileSystem.SetByCopy(in saveDataFileSystem);
|
||||
|
||||
Result res = Initialize(_saveDataFileSystem.Get.GetInternalStorageFileSystem(), normalMacGenerator,
|
||||
temporaryMacGenerator, hashGeneratorFactorySelector);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
file static class Anonymous
|
||||
{
|
||||
public static Result GetSaveDataFormatType(out SaveDataFormatType outFormatType, IStorage saveImageStorage,
|
||||
IBufferManager bufferManager, IMacGenerator macGenerator,
|
||||
IHash256GeneratorFactorySelector hashGeneratorFactorySelector, uint minimumVersion)
|
||||
{
|
||||
UnsafeHelpers.SkipParamInit(out outFormatType);
|
||||
|
||||
Result res = saveImageStorage.GetSize(out long storageSize);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var saveSubStorage = new ValueSubStorage(saveImageStorage, 0, storageSize);
|
||||
|
||||
Result resultJournalIntegrity = JournalIntegritySaveDataFileSystem.VerifyMasterHeader(in saveSubStorage,
|
||||
bufferManager, macGenerator, hashGeneratorFactorySelector, minimumVersion);
|
||||
if (resultJournalIntegrity.IsSuccess())
|
||||
{
|
||||
outFormatType = SaveDataFormatType.Normal;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
Result resultIntegrity = IntegritySaveDataFileSystem.VerifyMasterHeader(in saveSubStorage, bufferManager,
|
||||
macGenerator, hashGeneratorFactorySelector);
|
||||
if (resultIntegrity.IsSuccess())
|
||||
{
|
||||
outFormatType = SaveDataFormatType.NoJournal;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
return resultJournalIntegrity.Miss();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by <see cref="SaveDataFileSystemServiceImpl"/> for opening, formatting, and working with save data.
|
||||
/// This class directly operates on save data <see cref="IStorage"/>s and the directories containing the save data,
|
||||
/// whereas <see cref="SaveDataFileSystemServiceImpl"/> handles higher level tasks such as opening or creating
|
||||
/// the save data images on the file system, managing caches, etc.
|
||||
/// </summary>
|
||||
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||
public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator
|
||||
{
|
||||
// Option to disable some restrictions enforced in actual FS.
|
||||
private static readonly bool EnforceSaveTypeRestrictions = false;
|
||||
|
||||
private class MacGenerationSeed
|
||||
{
|
||||
public const uint Size = Aes.KeySize128;
|
||||
|
||||
public Array16<byte> Value;
|
||||
}
|
||||
|
||||
private struct DeviceUniqueMacTypeNormal : IConstant<DeviceUniqueMacType>
|
||||
{
|
||||
public static DeviceUniqueMacType Value => DeviceUniqueMacType.Normal;
|
||||
}
|
||||
|
||||
private struct DeviceUniqueMacTypeTemporary : IConstant<DeviceUniqueMacType>
|
||||
{
|
||||
public static DeviceUniqueMacType Value => DeviceUniqueMacType.Temporary;
|
||||
}
|
||||
|
||||
private class DeviceUniqueMacGenerator<TMacType> : IMacGenerator where TMacType : IConstant<DeviceUniqueMacType>
|
||||
{
|
||||
private GenerateDeviceUniqueMac _generatorFunction;
|
||||
|
||||
public DeviceUniqueMacGenerator(GenerateDeviceUniqueMac generatorFunction)
|
||||
{
|
||||
_generatorFunction = generatorFunction;
|
||||
}
|
||||
|
||||
public Result Generate(Span<byte> macDestBuffer, ReadOnlySpan<byte> data)
|
||||
{
|
||||
return _generatorFunction(macDestBuffer, data, TMacType.Value).Ret();
|
||||
}
|
||||
}
|
||||
|
||||
private class SeedUniqueMacGenerator : IMacGenerator
|
||||
{
|
||||
private GenerateSeedUniqueMac _generatorFunction;
|
||||
private MacGenerationSeed _seed;
|
||||
|
||||
public SeedUniqueMacGenerator(GenerateSeedUniqueMac generatorFunction, MacGenerationSeed seed)
|
||||
{
|
||||
_generatorFunction = generatorFunction;
|
||||
_seed = seed;
|
||||
}
|
||||
|
||||
public Result Generate(Span<byte> macDestBuffer, ReadOnlySpan<byte> data)
|
||||
{
|
||||
return _generatorFunction(macDestBuffer, data, _seed.Value).Ret();
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once NotAccessedField.Local
|
||||
private IBufferManager _bufferManager;
|
||||
private RandomDataGenerator _randomGenerator;
|
||||
private DeviceUniqueMacGenerator<DeviceUniqueMacTypeNormal> _deviceUniqueMacGeneratorNormal;
|
||||
private DeviceUniqueMacGenerator<DeviceUniqueMacTypeTemporary> _deviceUniqueMacGeneratorTemporary;
|
||||
private SeedUniqueMacGenerator _seedUniqueMacGenerator;
|
||||
private MacGenerationSeed _macGenerationSeed;
|
||||
private IHash256GeneratorFactorySelector _hashGeneratorFactorySelector;
|
||||
private uint _saveDataMinimumVersion;
|
||||
private RandomDataGenerator _randomDataGenerator;
|
||||
private Func<DebugOptionKey, long, long> _debugValueGetter;
|
||||
|
||||
// LibHac Additions
|
||||
// ReSharper disable once NotAccessedField.Local
|
||||
private KeySet _keySet;
|
||||
private FileSystemServer _fsServer;
|
||||
|
||||
public SaveDataFileSystemCreator(FileSystemServer fsServer, KeySet keySet, IBufferManager bufferManager,
|
||||
RandomDataGenerator randomGenerator)
|
||||
public SaveDataFileSystemCreator(FileSystemServer fsServer, IBufferManager bufferManager,
|
||||
GenerateDeviceUniqueMac deviceUniqueMacGenerator, GenerateSeedUniqueMac seedUniqueMacGenerator,
|
||||
RandomDataGenerator randomDataGenerator, IHash256GeneratorFactorySelector hashGeneratorFactorySelector,
|
||||
uint minimumVersion, Func<DebugOptionKey, long, long> debugValueGetter)
|
||||
{
|
||||
_fsServer = fsServer;
|
||||
_macGenerationSeed = new MacGenerationSeed();
|
||||
|
||||
_bufferManager = bufferManager;
|
||||
_deviceUniqueMacGeneratorNormal = new DeviceUniqueMacGenerator<DeviceUniqueMacTypeNormal>(deviceUniqueMacGenerator);
|
||||
_deviceUniqueMacGeneratorTemporary = new DeviceUniqueMacGenerator<DeviceUniqueMacTypeTemporary>(deviceUniqueMacGenerator);
|
||||
_seedUniqueMacGenerator = new SeedUniqueMacGenerator(seedUniqueMacGenerator, _macGenerationSeed);
|
||||
_hashGeneratorFactorySelector = hashGeneratorFactorySelector;
|
||||
_saveDataMinimumVersion = minimumVersion;
|
||||
_randomDataGenerator = randomDataGenerator;
|
||||
_debugValueGetter = debugValueGetter;
|
||||
|
||||
JournalIntegritySaveDataFileSystem.SetGenerateRandomFunction(fsServer, randomDataGenerator);
|
||||
}
|
||||
|
||||
public SaveDataFileSystemCreator(FileSystemServer fsServer, IBufferManager bufferManager,
|
||||
RandomDataGenerator randomDataGenerator)
|
||||
{
|
||||
_bufferManager = bufferManager;
|
||||
_randomGenerator = randomGenerator;
|
||||
_randomDataGenerator = randomDataGenerator;
|
||||
_fsServer = fsServer;
|
||||
_keySet = keySet;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
private IMacGenerator GetDeviceUniqueMacGenerator(DeviceUniqueMacType macType)
|
||||
{
|
||||
switch (macType)
|
||||
{
|
||||
case DeviceUniqueMacType.Normal:
|
||||
return _deviceUniqueMacGeneratorNormal;
|
||||
case DeviceUniqueMacType.Temporary:
|
||||
return _deviceUniqueMacGeneratorTemporary;
|
||||
default:
|
||||
Abort.UnexpectedDefault();
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
private IMacGenerator GetMacGenerator(bool isDeviceUnique, DeviceUniqueMacType macType)
|
||||
{
|
||||
return isDeviceUnique ? GetDeviceUniqueMacGenerator(macType) : _seedUniqueMacGenerator;
|
||||
}
|
||||
|
||||
public Result Format(in ValueSubStorage saveImageStorage, long blockSize, int countExpandMax, uint blockCount,
|
||||
uint journalBlockCount, IBufferManager bufferManager, bool isDeviceUniqueMac, in HashSalt hashSalt,
|
||||
RandomDataGenerator encryptionKeyGenerator, bool isReconstructible, uint version)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Result res = JournalIntegritySaveDataFileSystemDriver.Format(in saveImageStorage, blockSize, blockCount,
|
||||
journalBlockCount, countExpandMax, bufferManager,
|
||||
GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal), _hashGeneratorFactorySelector, hashSalt,
|
||||
encryptionKeyGenerator, version);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result FormatAsIntegritySaveData(in ValueSubStorage saveImageStorage, long blockSize, uint blockCount,
|
||||
IBufferManager bufferManager, bool isDeviceUniqueMac, RandomDataGenerator encryptionKeyGenerator,
|
||||
bool isReconstructible, uint version)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Result res = IntegritySaveDataFileSystemDriver.Format(in saveImageStorage, blockSize, blockCount, bufferManager,
|
||||
GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal), _hashGeneratorFactorySelector,
|
||||
encryptionKeyGenerator, version);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result ExtractSaveDataParameters(out JournalIntegritySaveDataParameters outParams, IStorage saveFileStorage,
|
||||
bool isDeviceUniqueMac, bool isReconstructible)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Result res = SaveDataFileSystem.ExtractParameters(out outParams, saveFileStorage, _bufferManager,
|
||||
GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal), _hashGeneratorFactorySelector,
|
||||
_saveDataMinimumVersion);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result ExtendSaveData(SaveDataExtender extender, in ValueSubStorage baseStorage,
|
||||
in ValueSubStorage logStorage, bool isDeviceUniqueMac, bool isReconstructible)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Assert.SdkRequiresNotNull(extender);
|
||||
|
||||
Result res = extender.Extend(in baseStorage, in logStorage, _bufferManager,
|
||||
GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal), _hashGeneratorFactorySelector,
|
||||
_saveDataMinimumVersion);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public void SetMacGenerationSeed(ReadOnlySpan<byte> seed)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Assert.SdkRequires(seed.Length == MacGenerationSeed.Size);
|
||||
seed.CopyTo(_macGenerationSeed.Value);
|
||||
}
|
||||
|
||||
public Result CreateRaw(ref SharedRef<IFile> outFile, in SharedRef<IFileSystem> fileSystem, ulong saveDataId, OpenMode openMode)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Unsafe.SkipInit(out Array18<byte> saveImageNameBuffer);
|
||||
|
||||
using scoped var saveImageName = new Path();
|
||||
Result res = PathFunctions.SetUpFixedPathSaveId(ref saveImageName.Ref(), saveImageNameBuffer, saveDataId);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = fileSystem.Get.GetEntryType(out DirectoryEntryType type, in saveImageName);
|
||||
|
||||
if (res.IsFailure())
|
||||
{
|
||||
if (ResultFs.PathNotFound.Includes(res))
|
||||
return ResultFs.TargetNotFound.LogConverted(res);
|
||||
|
||||
return res.Miss();
|
||||
}
|
||||
|
||||
if (type == DirectoryEntryType.Directory)
|
||||
{
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
}
|
||||
|
||||
using var file = new UniqueRef<IFile>();
|
||||
res = fileSystem.Get.OpenFile(ref file.Ref, in saveImageName, openMode);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
outFile.Set(ref file.Ref);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result Create(ref SharedRef<ISaveDataFileSystem> outFileSystem, ref SharedRef<IFileSystem> baseFileSystem,
|
||||
|
@ -87,7 +327,10 @@ public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator
|
|||
|
||||
if (res.IsFailure())
|
||||
{
|
||||
return ResultFs.PathNotFound.Includes(res) ? ResultFs.TargetNotFound.LogConverted(res) : res.Miss();
|
||||
if (ResultFs.PathNotFound.Includes(res))
|
||||
return ResultFs.TargetNotFound.LogConverted(res);
|
||||
|
||||
return res.Miss();
|
||||
}
|
||||
|
||||
using var saveDataFs = new SharedRef<ISaveDataFileSystem>();
|
||||
|
@ -118,7 +361,7 @@ public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator
|
|||
return ResultFs.AllocationMemoryFailedInSaveDataFileSystemCreatorB.Log();
|
||||
|
||||
res = saveDirFs.Get.Initialize(isJournalingSupported, isMultiCommitSupported, !openReadOnly,
|
||||
timeStampGetter, _randomGenerator);
|
||||
timeStampGetter, _randomDataGenerator);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
saveDataFs.SetByMove(ref saveDirFs.Ref);
|
||||
|
@ -134,7 +377,37 @@ public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator
|
|||
OpenMode.ReadWrite, openType);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
throw new NotImplementedException();
|
||||
res = Anonymous.GetSaveDataFormatType(out SaveDataFormatType formatType, fileStorage.Get, _bufferManager,
|
||||
GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal), _hashGeneratorFactorySelector,
|
||||
_saveDataMinimumVersion);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
if (!SaveDataProperties.IsJournalingSupported(formatType))
|
||||
{
|
||||
using var fs = new SharedRef<ApplicationTemporaryFileSystem>(new ApplicationTemporaryFileSystem());
|
||||
res = fs.Get.Initialize(in fileStorage, _bufferManager,
|
||||
GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal), _hashGeneratorFactorySelector);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
saveDataFs.SetByMove(ref fs.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
using var fs = new SharedRef<SaveDataFileSystem>(new SaveDataFileSystem());
|
||||
if (!fs.HasValue)
|
||||
return ResultFs.AllocationMemoryFailedInSaveDataFileSystemCreatorD.Log();
|
||||
|
||||
res = fs.Get.Initialize(in fileStorage, _bufferManager,
|
||||
GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal), _hashGeneratorFactorySelector,
|
||||
timeStampGetter, _randomDataGenerator, _saveDataMinimumVersion, isMultiCommitSupported);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
saveDataFs.SetByMove(ref fs.Ref);
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap the save FS in a result convert FS and set it as the output FS
|
||||
|
@ -142,44 +415,234 @@ public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator
|
|||
new SaveDataResultConvertFileSystem(ref saveDataFs.Ref, isReconstructible));
|
||||
|
||||
outFileSystem.SetByMove(ref resultConvertFs.Ref);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CreateExtraDataAccessor(ref SharedRef<ISaveDataExtraDataAccessor> outExtraDataAccessor,
|
||||
in SharedRef<IStorage> baseStorage, bool isDeviceUniqueMac, bool isIntegritySaveData, bool isReconstructible)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
using var saveDataFs = new SharedRef<ISaveDataFileSystem>();
|
||||
|
||||
if (!isIntegritySaveData)
|
||||
{
|
||||
using var fs = new SharedRef<ApplicationTemporaryFileSystem>(new ApplicationTemporaryFileSystem());
|
||||
Result res = fs.Get.Initialize(in baseStorage, _bufferManager,
|
||||
GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal), _hashGeneratorFactorySelector);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
saveDataFs.SetByMove(ref fs.Ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
using var fs = new SharedRef<SaveDataFileSystem>(new SaveDataFileSystem());
|
||||
Result res = fs.Get.Initialize(in baseStorage, _bufferManager,
|
||||
GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal), _hashGeneratorFactorySelector,
|
||||
_saveDataMinimumVersion, canCommitProvisionally: false);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
saveDataFs.SetByMove(ref fs.Ref);
|
||||
}
|
||||
|
||||
using var resultConvertFs = new SharedRef<SaveDataResultConvertFileSystem>(
|
||||
new SaveDataResultConvertFileSystem(ref saveDataFs.Ref, isReconstructible));
|
||||
|
||||
outExtraDataAccessor.SetByMove(ref resultConvertFs.Ref);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result CreateInternalStorage(ref SharedRef<IFileSystem> outFileSystem,
|
||||
in SharedRef<IFileSystem> baseFileSystem, SaveDataSpaceId spaceId, ulong saveDataId, bool isDeviceUniqueMac,
|
||||
bool useUniqueKey1, ISaveDataCommitTimeStampGetter timeStampGetter, bool isReconstructible)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Result res;
|
||||
Unsafe.SkipInit(out Array18<byte> saveImageNameBuffer);
|
||||
|
||||
using (scoped var saveImageName = new Path())
|
||||
{
|
||||
res = PathFunctions.SetUpFixedPathSaveId(ref saveImageName.Ref(), saveImageNameBuffer, saveDataId);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = baseFileSystem.Get.GetEntryType(out DirectoryEntryType entryType, in saveImageName);
|
||||
|
||||
if (res.IsFailure())
|
||||
{
|
||||
if (ResultFs.PathNotFound.Includes(res))
|
||||
return ResultFs.TargetNotFound.LogConverted(res);
|
||||
|
||||
return res.Miss();
|
||||
}
|
||||
|
||||
if (entryType == DirectoryEntryType.Directory)
|
||||
return ResultFs.InvalidSaveDataEntryType.Log();
|
||||
}
|
||||
|
||||
IMacGenerator normalMacGenerator = GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal);
|
||||
IMacGenerator temporaryMacGenerator = GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Temporary);
|
||||
IMacGenerator macGenerator = useUniqueKey1 ? temporaryMacGenerator : normalMacGenerator;
|
||||
|
||||
using var fileStorage = new SharedRef<IStorage>();
|
||||
res = _fsServer.OpenSaveDataStorage(ref fileStorage.Ref, in baseFileSystem, spaceId, saveDataId,
|
||||
OpenMode.ReadWrite, OpenType.Internal);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var saveFs = new SharedRef<SaveDataFileSystem>(new SaveDataFileSystem());
|
||||
res = saveFs.Get.Initialize(in fileStorage, _bufferManager, macGenerator, _hashGeneratorFactorySelector,
|
||||
timeStampGetter, _randomDataGenerator, _saveDataMinimumVersion, canCommitProvisionally: false);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var internalStorage = new SharedRef<SaveDataInternalStorageFileSystem>(new SaveDataInternalStorageFileSystem());
|
||||
res = internalStorage.Get.Initialize(in saveFs, normalMacGenerator, temporaryMacGenerator, _hashGeneratorFactorySelector);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using SharedRef<ISaveDataFileSystem> tempSaveFs = SharedRef<ISaveDataFileSystem>.CreateMove(ref saveFs.Ref);
|
||||
using var resultConvertFs = new SharedRef<SaveDataResultConvertFileSystem>(
|
||||
new SaveDataResultConvertFileSystem(ref tempSaveFs.Ref, isReconstructible));
|
||||
|
||||
outFileSystem.SetByMove(ref resultConvertFs.Ref);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result RecoverMasterHeader(in SharedRef<IFileSystem> baseFileSystem, ulong saveDataId,
|
||||
IBufferManager bufferManager, bool isDeviceUniqueMac, bool isReconstructible)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Unsafe.SkipInit(out Array18<byte> saveImageNameBuffer);
|
||||
|
||||
using scoped var saveImageName = new Path();
|
||||
Result res = PathFunctions.SetUpFixedPathSaveId(ref saveImageName.Ref(), saveImageNameBuffer, saveDataId);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = baseFileSystem.Get.GetEntryType(out DirectoryEntryType entryType, in saveImageName);
|
||||
|
||||
if (res.IsFailure())
|
||||
{
|
||||
if (ResultFs.PathNotFound.Includes(res))
|
||||
return ResultFs.TargetNotFound.LogConverted(res);
|
||||
|
||||
return res.Miss();
|
||||
}
|
||||
|
||||
if (entryType == DirectoryEntryType.Directory)
|
||||
{
|
||||
// Directory save data doesn't have a master header
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
using var fileStorage = new SharedRef<FileStorageBasedFileSystem>();
|
||||
res = fileStorage.Get.Initialize(in baseFileSystem, in saveImageName, OpenMode.ReadWrite);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = fileStorage.Get.GetSize(out long size);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var fileSubStorage = new ValueSubStorage(fileStorage.Get, 0, size);
|
||||
IMacGenerator macGenerator = GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal);
|
||||
|
||||
res = JournalIntegritySaveDataFileSystem.RecoverMasterHeader(in fileSubStorage, bufferManager, macGenerator,
|
||||
_hashGeneratorFactorySelector, _saveDataMinimumVersion);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result UpdateMac(in SharedRef<IFileSystem> baseFileSystem, ulong saveDataId, bool isDeviceUniqueMac,
|
||||
bool isReconstructible)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Unsafe.SkipInit(out Array18<byte> saveImageNameBuffer);
|
||||
|
||||
using scoped var saveImageName = new Path();
|
||||
Result res = PathFunctions.SetUpFixedPathSaveId(ref saveImageName.Ref(), saveImageNameBuffer, saveDataId);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = baseFileSystem.Get.GetEntryType(out DirectoryEntryType entryType, in saveImageName);
|
||||
|
||||
if (res.IsFailure())
|
||||
{
|
||||
if (ResultFs.PathNotFound.Includes(res))
|
||||
return ResultFs.TargetNotFound.LogConverted(res);
|
||||
|
||||
return res.Miss();
|
||||
}
|
||||
|
||||
if (entryType == DirectoryEntryType.Directory)
|
||||
{
|
||||
// Directory save data doesn't contain a MAC
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
using var fileStorage = new SharedRef<FileStorageBasedFileSystem>();
|
||||
res = fileStorage.Get.Initialize(in baseFileSystem, in saveImageName, OpenMode.ReadWrite);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = fileStorage.Get.GetSize(out long size);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var fileSubStorage = new ValueSubStorage(fileStorage.Get, 0, size);
|
||||
IMacGenerator macGenerator = GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal);
|
||||
|
||||
res = JournalIntegritySaveDataFileSystem.UpdateMac(in fileSubStorage, macGenerator,
|
||||
_hashGeneratorFactorySelector, _saveDataMinimumVersion);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public Result IsProvisionallyCommittedSaveData(out bool outIsProvisionallyCommitted,
|
||||
in SharedRef<IFileSystem> baseFileSystem, in SaveDataInfo info, bool isDeviceUniqueMac,
|
||||
ISaveDataCommitTimeStampGetter timeStampGetter, bool isReconstructible)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
UnsafeHelpers.SkipParamInit(out outIsProvisionallyCommitted);
|
||||
Unsafe.SkipInit(out Array18<byte> saveImageNameBuffer);
|
||||
|
||||
using scoped var saveImageName = new Path();
|
||||
Result res = PathFunctions.SetUpFixedPathSaveId(ref saveImageName.Ref(), saveImageNameBuffer, info.SaveDataId);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
res = baseFileSystem.Get.GetEntryType(out DirectoryEntryType entryType, in saveImageName);
|
||||
|
||||
if (res.IsFailure())
|
||||
{
|
||||
if (ResultFs.PathNotFound.Includes(res))
|
||||
return ResultFs.TargetNotFound.LogConverted(res);
|
||||
|
||||
return res.Miss();
|
||||
}
|
||||
|
||||
if (entryType == DirectoryEntryType.Directory)
|
||||
return ResultFs.InvalidSaveDataEntryType.Log();
|
||||
|
||||
using var fileStorage = new SharedRef<IStorage>();
|
||||
res = _fsServer.OpenSaveDataStorage(ref fileStorage.Ref, in baseFileSystem, info.SpaceId, info.SaveDataId,
|
||||
OpenMode.ReadWrite, OpenType.Internal);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using var saveFs = new SharedRef<SaveDataFileSystem>(new SaveDataFileSystem());
|
||||
|
||||
res = saveFs.Get.Initialize(in fileStorage, _bufferManager,
|
||||
GetMacGenerator(isDeviceUniqueMac, DeviceUniqueMacType.Normal), _hashGeneratorFactorySelector,
|
||||
timeStampGetter, _randomDataGenerator, _saveDataMinimumVersion, canCommitProvisionally: false);
|
||||
|
||||
res = SaveDataResultConverter.ConvertSaveDataFsResult(res, isReconstructible);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
outIsProvisionallyCommitted = saveFs.Get.GetCounterForBundledCommit() != 0;
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public IMacGenerator GetMacGenerator(bool isDeviceUniqueMac, bool isTemporaryTransferSave)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
DeviceUniqueMacType macType = isTemporaryTransferSave ? DeviceUniqueMacType.Temporary : DeviceUniqueMacType.Normal;
|
||||
return GetMacGenerator(isDeviceUniqueMac, macType);
|
||||
}
|
||||
}
|
|
@ -18,12 +18,12 @@ namespace LibHac.FsSrv;
|
|||
public static class SaveDataSharedFileStorageGlobalMethods
|
||||
{
|
||||
public static Result OpenSaveDataStorage(this FileSystemServer fsSrv,
|
||||
ref SharedRef<IStorage> outSaveDataStorage, ref SharedRef<IFileSystem> baseFileSystem,
|
||||
ref SharedRef<IStorage> outSaveDataStorage, ref readonly SharedRef<IFileSystem> baseFileSystem,
|
||||
SaveDataSpaceId spaceId, ulong saveDataId, OpenMode mode,
|
||||
Optional<SaveDataOpenTypeSetFileStorage.OpenType> type)
|
||||
{
|
||||
return fsSrv.Globals.SaveDataSharedFileStorage.SaveDataFileStorageHolder.OpenSaveDataStorage(
|
||||
ref outSaveDataStorage, ref baseFileSystem, spaceId, saveDataId, mode, type);
|
||||
ref outSaveDataStorage, in baseFileSystem, spaceId, saveDataId, mode, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,9 +74,9 @@ public class SaveDataOpenTypeSetFileStorage : FileStorageBasedFileSystem
|
|||
_mutex = new SdkMutexType();
|
||||
}
|
||||
|
||||
public Result Initialize(ref SharedRef<IFileSystem> baseFileSystem, ref readonly Path path, OpenMode mode, OpenType type)
|
||||
public Result Initialize(ref readonly SharedRef<IFileSystem> baseFileSystem, ref readonly Path path, OpenMode mode, OpenType type)
|
||||
{
|
||||
Result res = Initialize(ref baseFileSystem, in path, mode);
|
||||
Result res = Initialize(in baseFileSystem, in path, mode);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
return SetOpenType(type);
|
||||
|
@ -331,7 +331,7 @@ public class SaveDataFileStorageHolder
|
|||
}
|
||||
|
||||
public Result OpenSaveDataStorage(ref SharedRef<IStorage> outSaveDataStorage,
|
||||
ref SharedRef<IFileSystem> baseFileSystem, SaveDataSpaceId spaceId, ulong saveDataId, OpenMode mode,
|
||||
ref readonly SharedRef<IFileSystem> baseFileSystem, SaveDataSpaceId spaceId, ulong saveDataId, OpenMode mode,
|
||||
Optional<SaveDataOpenTypeSetFileStorage.OpenType> type)
|
||||
{
|
||||
Unsafe.SkipInit(out Array18<byte> saveImageNameBuffer);
|
||||
|
@ -344,7 +344,7 @@ public class SaveDataFileStorageHolder
|
|||
if (!type.HasValue)
|
||||
{
|
||||
using var fileStorage = new SharedRef<FileStorageBasedFileSystem>(new FileStorageBasedFileSystem());
|
||||
res = fileStorage.Get.Initialize(ref baseFileSystem, in saveImageName, mode);
|
||||
res = fileStorage.Get.Initialize(in baseFileSystem, in saveImageName, mode);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
outSaveDataStorage.SetByMove(ref fileStorage.Ref);
|
||||
|
@ -363,7 +363,7 @@ public class SaveDataFileStorageHolder
|
|||
else
|
||||
{
|
||||
baseFileStorage.Reset(new SaveDataOpenTypeSetFileStorage(_fsServer, spaceId, saveDataId));
|
||||
res = baseFileStorage.Get.Initialize(ref baseFileSystem, in saveImageName, mode, type.ValueRo);
|
||||
res = baseFileStorage.Get.Initialize(in baseFileSystem, in saveImageName, mode, type.ValueRo);
|
||||
if (res.IsFailure()) return res.Miss();
|
||||
|
||||
using SharedRef<SaveDataOpenTypeSetFileStorage> baseFileStorageCopy =
|
||||
|
|
|
@ -54,7 +54,7 @@ file class ApplicationTemporaryFile : IFile
|
|||
}
|
||||
}
|
||||
|
||||
public class ApplicationTemporaryFileSystem : IFileSystem, ICacheableSaveDataFileSystem, ISaveDataExtraDataAccessor
|
||||
public class ApplicationTemporaryFileSystem : ISaveDataFileSystem, ISaveDataExtraDataAccessor
|
||||
{
|
||||
private SharedRef<IStorage> _baseStorage;
|
||||
private IntegritySaveDataFileSystemDriver _saveFsDriver;
|
||||
|
@ -166,12 +166,12 @@ public class ApplicationTemporaryFileSystem : IFileSystem, ICacheableSaveDataFil
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsSaveDataFileSystemCacheEnabled()
|
||||
public override bool IsSaveDataFileSystemCacheEnabled()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result RollbackOnlyModified()
|
||||
public override Result RollbackOnlyModified()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -181,22 +181,22 @@ public class ApplicationTemporaryFileSystem : IFileSystem, ICacheableSaveDataFil
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result WriteExtraData(in SaveDataExtraData extraData)
|
||||
public override Result WriteExtraData(in SaveDataExtraData extraData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result CommitExtraData(bool updateTimeStamp)
|
||||
public override Result CommitExtraData(bool updateTimeStamp)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result ReadExtraData(out SaveDataExtraData extraData)
|
||||
public override Result ReadExtraData(out SaveDataExtraData extraData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RegisterExtraDataAccessorObserver(ISaveDataExtraDataAccessorObserver observer, SaveDataSpaceId spaceId,
|
||||
public override void RegisterExtraDataAccessorObserver(ISaveDataExtraDataAccessorObserver observer, SaveDataSpaceId spaceId,
|
||||
ulong saveDataId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
|
|
@ -322,7 +322,7 @@ public class JournalIntegritySaveDataFileSystem : IFileSystem
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static void SetGenerateRandomFunction(RandomDataGenerator func)
|
||||
public static void SetGenerateRandomFunction(FileSystemServer fsServer, RandomDataGenerator func)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
@ -479,7 +479,7 @@ public class JournalIntegritySaveDataFileSystem : IFileSystem
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Result MountSaveData(in FileSystemLayoutHeader layoutHeader, in SubStorage saveImageStorage, long blockSize,
|
||||
private Result MountSaveData(in FileSystemLayoutHeader layoutHeader, in ValueSubStorage saveImageStorage, long blockSize,
|
||||
FileSystemBufferManagerSet integrityCacheBufferSet, IBufferManager bufferManager, SdkRecursiveMutex mutex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
@ -497,7 +497,7 @@ public class JournalIntegritySaveDataFileSystem : IFileSystem
|
|||
}
|
||||
|
||||
public Result Initialize(
|
||||
in SubStorage saveImageStorage,
|
||||
in ValueSubStorage saveImageStorage,
|
||||
FileSystemBufferManagerSet integrityCacheBufferSet,
|
||||
IBufferManager duplicateCacheBuffer,
|
||||
SdkRecursiveMutex mutex,
|
||||
|
@ -518,13 +518,13 @@ public class JournalIntegritySaveDataFileSystem : IFileSystem
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static Result UpdateMac(in SubStorage saveImageStorage, IMacGenerator macGenerator,
|
||||
public static Result UpdateMac(in ValueSubStorage saveImageStorage, IMacGenerator macGenerator,
|
||||
IHash256GeneratorFactorySelector hashGeneratorFactorySelector, uint minimumVersion)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static Result RecoverMasterHeader(in SubStorage saveImageStorage, IBufferManager bufferManager,
|
||||
public static Result RecoverMasterHeader(in ValueSubStorage saveImageStorage, IBufferManager bufferManager,
|
||||
IMacGenerator macGenerator, IHash256GeneratorFactorySelector hashGeneratorFactorySelector, uint minimumVersion)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
|
|
@ -177,6 +177,11 @@ public class SaveDataFileSystem : ISaveDataFileSystem, InternalStorageFileSystem
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public long GetCounterForBundledCommit()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Result DoCommitProvisionally(long counter)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
using static LibHac.FsSrv.FsCreator.SaveDataResultConverter;
|
||||
using static LibHac.FsSystem.SaveDataResultConverter;
|
||||
|
||||
namespace LibHac.FsSrv.FsCreator;
|
||||
namespace LibHac.FsSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps an <see cref="IFile"/>, converting its returned <see cref="Result"/>s
|
|
@ -1,7 +1,7 @@
|
|||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSrv.FsCreator;
|
||||
namespace LibHac.FsSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Contains functions for converting internal save data <see cref="Result"/>s to external <see cref="Result"/>s.
|
Loading…
Reference in a new issue