Implement the rest of SaveDataInternalStorageFileSystem

This commit is contained in:
Alex Barney 2024-03-09 15:23:26 -07:00
parent 2501cd24d0
commit 2b2b7471ea
12 changed files with 528 additions and 51 deletions

View file

@ -0,0 +1,6 @@
namespace LibHac.Common;
public interface IConstant<T> where T : struct
{
static abstract T Value { get; }
}

View file

@ -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.PathNotFound"/>: The specified path does not exist or is a directory.<br/>
/// <see cref="ResultFs.TargetLocked"/>: When opening as <see cref="OpenMode.Write"/>, /// <see cref="ResultFs.TargetLocked"/>: When opening as <see cref="OpenMode.Write"/>,
/// the file is already opened as <see cref="OpenMode.Write"/>.</returns> /// 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>(); using var baseFile = new UniqueRef<IFile>();
@ -187,7 +187,7 @@ public class FileStorageBasedFileSystem : FileStorage
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
SetFile(baseFile.Get); SetFile(baseFile.Get);
_baseFileSystem.SetByMove(ref baseFileSystem); _baseFileSystem.SetByCopy(in baseFileSystem);
_baseFile.Set(ref baseFile.Ref); _baseFile.Set(ref baseFile.Ref);
return Result.Success; return Result.Success;

View file

@ -37,7 +37,7 @@ public class DefaultFsServerObjects
creators.StorageOnNcaCreator = new StorageOnNcaCreator(keySet); creators.StorageOnNcaCreator = new StorageOnNcaCreator(keySet);
creators.TargetManagerFileSystemCreator = new TargetManagerFileSystemCreator(); creators.TargetManagerFileSystemCreator = new TargetManagerFileSystemCreator();
creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator(); creators.SubDirectoryFileSystemCreator = new SubDirectoryFileSystemCreator();
creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(fsServer, keySet, null, randomGenerator); creators.SaveDataFileSystemCreator = new SaveDataFileSystemCreator(fsServer, null, randomGenerator);
creators.GameCardStorageCreator = gcStorageCreator; creators.GameCardStorageCreator = gcStorageCreator;
creators.GameCardFileSystemCreator = new GameCardFileSystemCreator(new ArrayPoolMemoryResource(), gcStorageCreator, fsServer); creators.GameCardFileSystemCreator = new GameCardFileSystemCreator(new ArrayPoolMemoryResource(), gcStorageCreator, fsServer);
creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keySet); creators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator(keySet);

View file

@ -1,8 +1,12 @@
using System; using System;
using LibHac.Common; using LibHac.Common;
using LibHac.FsSrv.FsCreator;
namespace LibHac.FsSrv; 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, public delegate Result SaveTransferAesKeyGenerator(Span<byte> outKeyBuffer,
SaveDataTransferCryptoConfiguration.KeyIndex index, ReadOnlySpan<byte> keySource, int keyGeneration); SaveDataTransferCryptoConfiguration.KeyIndex index, ReadOnlySpan<byte> keySource, int keyGeneration);

View file

@ -8,7 +8,7 @@ using LibHac.FsSystem.Save;
namespace LibHac.FsSrv.FsCreator; 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); Result CreateRaw(ref SharedRef<IFile> outFile, in SharedRef<IFileSystem> fileSystem, ulong saveDataId, OpenMode openMode);

View file

@ -2,74 +2,314 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using LibHac.Common; using LibHac.Common;
using LibHac.Common.FixedArrays; using LibHac.Common.FixedArrays;
using LibHac.Common.Keys; using LibHac.Crypto;
using LibHac.Diag;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.Fs.Shim;
using LibHac.FsSrv.Impl; using LibHac.FsSrv.Impl;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.FsSystem.Save; using LibHac.FsSystem.Save;
using LibHac.Util; using LibHac.Util;
using OpenType = LibHac.FsSrv.SaveDataOpenTypeSetFileStorage.OpenType; using OpenType = LibHac.FsSrv.SaveDataOpenTypeSetFileStorage.OpenType;
using ValueSubStorage = LibHac.Fs.ValueSubStorage;
namespace LibHac.FsSrv.FsCreator; 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 public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator
{ {
// Option to disable some restrictions enforced in actual FS. // Option to disable some restrictions enforced in actual FS.
private static readonly bool EnforceSaveTypeRestrictions = false; 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 // ReSharper disable once NotAccessedField.Local
private IBufferManager _bufferManager; 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 // LibHac Additions
// ReSharper disable once NotAccessedField.Local
private KeySet _keySet;
private FileSystemServer _fsServer; private FileSystemServer _fsServer;
public SaveDataFileSystemCreator(FileSystemServer fsServer, KeySet keySet, IBufferManager bufferManager, public SaveDataFileSystemCreator(FileSystemServer fsServer, IBufferManager bufferManager,
RandomDataGenerator randomGenerator) 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; _bufferManager = bufferManager;
_randomGenerator = randomGenerator; _randomDataGenerator = randomDataGenerator;
_fsServer = fsServer; _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, public Result Format(in ValueSubStorage saveImageStorage, long blockSize, int countExpandMax, uint blockCount,
uint journalBlockCount, IBufferManager bufferManager, bool isDeviceUniqueMac, in HashSalt hashSalt, uint journalBlockCount, IBufferManager bufferManager, bool isDeviceUniqueMac, in HashSalt hashSalt,
RandomDataGenerator encryptionKeyGenerator, bool isReconstructible, uint version) 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, public Result FormatAsIntegritySaveData(in ValueSubStorage saveImageStorage, long blockSize, uint blockCount,
IBufferManager bufferManager, bool isDeviceUniqueMac, RandomDataGenerator encryptionKeyGenerator, IBufferManager bufferManager, bool isDeviceUniqueMac, RandomDataGenerator encryptionKeyGenerator,
bool isReconstructible, uint version) 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, public Result ExtractSaveDataParameters(out JournalIntegritySaveDataParameters outParams, IStorage saveFileStorage,
bool isDeviceUniqueMac, bool isReconstructible) 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, public Result ExtendSaveData(SaveDataExtender extender, in ValueSubStorage baseStorage,
in ValueSubStorage logStorage, bool isDeviceUniqueMac, bool isReconstructible) 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) 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) 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, public Result Create(ref SharedRef<ISaveDataFileSystem> outFileSystem, ref SharedRef<IFileSystem> baseFileSystem,
@ -87,7 +327,10 @@ public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator
if (res.IsFailure()) 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>(); using var saveDataFs = new SharedRef<ISaveDataFileSystem>();
@ -118,7 +361,7 @@ public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator
return ResultFs.AllocationMemoryFailedInSaveDataFileSystemCreatorB.Log(); return ResultFs.AllocationMemoryFailedInSaveDataFileSystemCreatorB.Log();
res = saveDirFs.Get.Initialize(isJournalingSupported, isMultiCommitSupported, !openReadOnly, res = saveDirFs.Get.Initialize(isJournalingSupported, isMultiCommitSupported, !openReadOnly,
timeStampGetter, _randomGenerator); timeStampGetter, _randomDataGenerator);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
saveDataFs.SetByMove(ref saveDirFs.Ref); saveDataFs.SetByMove(ref saveDirFs.Ref);
@ -134,7 +377,37 @@ public class SaveDataFileSystemCreator : ISaveDataFileSystemCreator
OpenMode.ReadWrite, openType); OpenMode.ReadWrite, openType);
if (res.IsFailure()) return res.Miss(); 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 // 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)); new SaveDataResultConvertFileSystem(ref saveDataFs.Ref, isReconstructible));
outFileSystem.SetByMove(ref resultConvertFs.Ref); outFileSystem.SetByMove(ref resultConvertFs.Ref);
return Result.Success; return Result.Success;
} }
public Result CreateExtraDataAccessor(ref SharedRef<ISaveDataExtraDataAccessor> outExtraDataAccessor, public Result CreateExtraDataAccessor(ref SharedRef<ISaveDataExtraDataAccessor> outExtraDataAccessor,
in SharedRef<IStorage> baseStorage, bool isDeviceUniqueMac, bool isIntegritySaveData, bool isReconstructible) 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, public Result CreateInternalStorage(ref SharedRef<IFileSystem> outFileSystem,
in SharedRef<IFileSystem> baseFileSystem, SaveDataSpaceId spaceId, ulong saveDataId, bool isDeviceUniqueMac, in SharedRef<IFileSystem> baseFileSystem, SaveDataSpaceId spaceId, ulong saveDataId, bool isDeviceUniqueMac,
bool useUniqueKey1, ISaveDataCommitTimeStampGetter timeStampGetter, bool isReconstructible) 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, public Result RecoverMasterHeader(in SharedRef<IFileSystem> baseFileSystem, ulong saveDataId,
IBufferManager bufferManager, bool isDeviceUniqueMac, bool isReconstructible) 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, public Result UpdateMac(in SharedRef<IFileSystem> baseFileSystem, ulong saveDataId, bool isDeviceUniqueMac,
bool isReconstructible) 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, public Result IsProvisionallyCommittedSaveData(out bool outIsProvisionallyCommitted,
in SharedRef<IFileSystem> baseFileSystem, in SaveDataInfo info, bool isDeviceUniqueMac, in SharedRef<IFileSystem> baseFileSystem, in SaveDataInfo info, bool isDeviceUniqueMac,
ISaveDataCommitTimeStampGetter timeStampGetter, bool isReconstructible) 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) public IMacGenerator GetMacGenerator(bool isDeviceUniqueMac, bool isTemporaryTransferSave)
{ {
throw new NotImplementedException(); DeviceUniqueMacType macType = isTemporaryTransferSave ? DeviceUniqueMacType.Temporary : DeviceUniqueMacType.Normal;
return GetMacGenerator(isDeviceUniqueMac, macType);
} }
} }

View file

@ -18,12 +18,12 @@ namespace LibHac.FsSrv;
public static class SaveDataSharedFileStorageGlobalMethods public static class SaveDataSharedFileStorageGlobalMethods
{ {
public static Result OpenSaveDataStorage(this FileSystemServer fsSrv, 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, SaveDataSpaceId spaceId, ulong saveDataId, OpenMode mode,
Optional<SaveDataOpenTypeSetFileStorage.OpenType> type) Optional<SaveDataOpenTypeSetFileStorage.OpenType> type)
{ {
return fsSrv.Globals.SaveDataSharedFileStorage.SaveDataFileStorageHolder.OpenSaveDataStorage( 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(); _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(); if (res.IsFailure()) return res.Miss();
return SetOpenType(type); return SetOpenType(type);
@ -331,7 +331,7 @@ public class SaveDataFileStorageHolder
} }
public Result OpenSaveDataStorage(ref SharedRef<IStorage> outSaveDataStorage, 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) Optional<SaveDataOpenTypeSetFileStorage.OpenType> type)
{ {
Unsafe.SkipInit(out Array18<byte> saveImageNameBuffer); Unsafe.SkipInit(out Array18<byte> saveImageNameBuffer);
@ -344,7 +344,7 @@ public class SaveDataFileStorageHolder
if (!type.HasValue) if (!type.HasValue)
{ {
using var fileStorage = new SharedRef<FileStorageBasedFileSystem>(new FileStorageBasedFileSystem()); 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(); if (res.IsFailure()) return res.Miss();
outSaveDataStorage.SetByMove(ref fileStorage.Ref); outSaveDataStorage.SetByMove(ref fileStorage.Ref);
@ -363,7 +363,7 @@ public class SaveDataFileStorageHolder
else else
{ {
baseFileStorage.Reset(new SaveDataOpenTypeSetFileStorage(_fsServer, spaceId, saveDataId)); 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(); if (res.IsFailure()) return res.Miss();
using SharedRef<SaveDataOpenTypeSetFileStorage> baseFileStorageCopy = using SharedRef<SaveDataOpenTypeSetFileStorage> baseFileStorageCopy =

View file

@ -54,7 +54,7 @@ file class ApplicationTemporaryFile : IFile
} }
} }
public class ApplicationTemporaryFileSystem : IFileSystem, ICacheableSaveDataFileSystem, ISaveDataExtraDataAccessor public class ApplicationTemporaryFileSystem : ISaveDataFileSystem, ISaveDataExtraDataAccessor
{ {
private SharedRef<IStorage> _baseStorage; private SharedRef<IStorage> _baseStorage;
private IntegritySaveDataFileSystemDriver _saveFsDriver; private IntegritySaveDataFileSystemDriver _saveFsDriver;
@ -166,12 +166,12 @@ public class ApplicationTemporaryFileSystem : IFileSystem, ICacheableSaveDataFil
throw new NotImplementedException(); throw new NotImplementedException();
} }
public bool IsSaveDataFileSystemCacheEnabled() public override bool IsSaveDataFileSystemCacheEnabled()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Result RollbackOnlyModified() public override Result RollbackOnlyModified()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -181,22 +181,22 @@ public class ApplicationTemporaryFileSystem : IFileSystem, ICacheableSaveDataFil
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Result WriteExtraData(in SaveDataExtraData extraData) public override Result WriteExtraData(in SaveDataExtraData extraData)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Result CommitExtraData(bool updateTimeStamp) public override Result CommitExtraData(bool updateTimeStamp)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public Result ReadExtraData(out SaveDataExtraData extraData) public override Result ReadExtraData(out SaveDataExtraData extraData)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public void RegisterExtraDataAccessorObserver(ISaveDataExtraDataAccessorObserver observer, SaveDataSpaceId spaceId, public override void RegisterExtraDataAccessorObserver(ISaveDataExtraDataAccessorObserver observer, SaveDataSpaceId spaceId,
ulong saveDataId) ulong saveDataId)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

View file

@ -322,7 +322,7 @@ public class JournalIntegritySaveDataFileSystem : IFileSystem
throw new NotImplementedException(); throw new NotImplementedException();
} }
public static void SetGenerateRandomFunction(RandomDataGenerator func) public static void SetGenerateRandomFunction(FileSystemServer fsServer, RandomDataGenerator func)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -479,7 +479,7 @@ public class JournalIntegritySaveDataFileSystem : IFileSystem
throw new NotImplementedException(); 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) FileSystemBufferManagerSet integrityCacheBufferSet, IBufferManager bufferManager, SdkRecursiveMutex mutex)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
@ -497,7 +497,7 @@ public class JournalIntegritySaveDataFileSystem : IFileSystem
} }
public Result Initialize( public Result Initialize(
in SubStorage saveImageStorage, in ValueSubStorage saveImageStorage,
FileSystemBufferManagerSet integrityCacheBufferSet, FileSystemBufferManagerSet integrityCacheBufferSet,
IBufferManager duplicateCacheBuffer, IBufferManager duplicateCacheBuffer,
SdkRecursiveMutex mutex, SdkRecursiveMutex mutex,
@ -518,13 +518,13 @@ public class JournalIntegritySaveDataFileSystem : IFileSystem
throw new NotImplementedException(); 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) IHash256GeneratorFactorySelector hashGeneratorFactorySelector, uint minimumVersion)
{ {
throw new NotImplementedException(); 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) IMacGenerator macGenerator, IHash256GeneratorFactorySelector hashGeneratorFactorySelector, uint minimumVersion)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

View file

@ -177,6 +177,11 @@ public class SaveDataFileSystem : ISaveDataFileSystem, InternalStorageFileSystem
throw new NotImplementedException(); throw new NotImplementedException();
} }
public long GetCounterForBundledCommit()
{
throw new NotImplementedException();
}
protected override Result DoCommitProvisionally(long counter) protected override Result DoCommitProvisionally(long counter)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

View file

@ -1,10 +1,9 @@
using LibHac.Common; using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Fsa; using LibHac.Fs.Fsa;
using LibHac.FsSystem; using static LibHac.FsSystem.SaveDataResultConverter;
using static LibHac.FsSrv.FsCreator.SaveDataResultConverter;
namespace LibHac.FsSrv.FsCreator; namespace LibHac.FsSystem;
/// <summary> /// <summary>
/// Wraps an <see cref="IFile"/>, converting its returned <see cref="Result"/>s /// Wraps an <see cref="IFile"/>, converting its returned <see cref="Result"/>s

View file

@ -1,7 +1,7 @@
using LibHac.Diag; using LibHac.Diag;
using LibHac.Fs; using LibHac.Fs;
namespace LibHac.FsSrv.FsCreator; namespace LibHac.FsSystem;
/// <summary> /// <summary>
/// Contains functions for converting internal save data <see cref="Result"/>s to external <see cref="Result"/>s. /// Contains functions for converting internal save data <see cref="Result"/>s to external <see cref="Result"/>s.