Update SaveDataFileSystemService for 14.0.0

- Creating save data file systems now uses a new SaveDataCreationInfo2 struct.
- Ensure all implemented functions in the class are accurate to 14.0.0
This commit is contained in:
Alex Barney 2022-04-28 15:13:46 -07:00
parent 3725c21928
commit 7b44441ff2
14 changed files with 1256 additions and 589 deletions

View file

@ -43,4 +43,7 @@ public static class Log
diag.LogImpl(in metaData, message);
}
/// <summary>"<c>$</c>"</summary>
public static ReadOnlySpan<byte> EmptyModuleName => new[] { (byte)'$' }; // "$"
}

View file

@ -94,9 +94,17 @@ public ref struct Path
[DebuggerDisplay("{" + nameof(ToString) + "(),nq}")]
public struct Stored : IDisposable
{
private static readonly byte[] EmptyBuffer = { 0 };
private byte[] _buffer;
private int _length;
public Stored()
{
_buffer = EmptyBuffer;
_length = 0;
}
public void Dispose()
{
byte[] buffer = Shared.Move(ref _buffer);
@ -160,7 +168,8 @@ public ref struct Path
byte[] oldBuffer = _buffer;
_buffer = buffer;
if (oldBuffer is not null)
// Check if the buffer is longer than 1 so we don't try to return EmptyBuffer to the pool.
if (oldBuffer?.Length > 1)
ArrayPool<byte>.Shared.Return(oldBuffer);
return Result.Success;

View file

@ -16,8 +16,7 @@ public enum SaveDataSpaceId : byte
Temporary = 3,
SdUser = 4,
ProperSystem = 100,
SafeMode = 101,
BisAuto = 127
SafeMode = 101
}
public enum SaveDataType : byte
@ -99,6 +98,7 @@ public struct SaveDataExtraData
public ulong OwnerId;
public long TimeStamp;
public SaveDataFlags Flags;
public SaveDataFormatType FormatType;
public long DataSize;
public long JournalSize;
public long CommitId;
@ -371,7 +371,7 @@ internal static class SaveDataTypesValidity
{
public static bool IsValid(in SaveDataAttribute attribute)
{
return IsValid(in attribute.Type)&& IsValid(in attribute.Rank);
return IsValid(in attribute.Type) && IsValid(in attribute.Rank);
}
public static bool IsValid(in SaveDataCreationInfo creationInfo)

View file

@ -4,8 +4,9 @@ namespace LibHac.Fs.Impl;
internal readonly struct SaveDataMetaPolicy
{
internal const int ThumbnailFileSize = 0x40060;
private readonly SaveDataType _type;
private const int ThumbnailFileSize = 0x40060;
public SaveDataMetaPolicy(SaveDataType saveType)
{
@ -39,4 +40,4 @@ internal readonly struct SaveDataMetaPolicy
GenerateMetaInfo(out SaveDataMetaInfo metaInfo);
return metaInfo.Type;
}
}
}

View file

@ -352,6 +352,14 @@ public class FileSystemProxyImpl : IFileSystemProxy, IFileSystemProxyForLoader
return saveFsService.CreateSaveDataFileSystemBySystemSaveDataId(in attribute, in creationInfo);
}
public Result CreateSaveDataFileSystemWithCreationInfo2(in SaveDataCreationInfo2 creationInfo)
{
Result rc = GetSaveDataFileSystemService(out SaveDataFileSystemService saveFsService);
if (rc.IsFailure()) return rc;
return saveFsService.CreateSaveDataFileSystemWithCreationInfo2(in creationInfo);
}
public Result ExtendSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, long dataSize,
long journalSize)
{

View file

@ -136,7 +136,7 @@ public static class FileSystemServerInitializer
saveFsServiceConfig.BufferManager = bufferManager;
saveFsServiceConfig.GenerateRandomData = config.RandomGenerator;
saveFsServiceConfig.IsPseudoSaveData = () => true;
saveFsServiceConfig.MaxSaveFsCacheCount = 1;
saveFsServiceConfig.SaveDataFileSystemCacheCount = 1;
saveFsServiceConfig.SaveIndexerManager = saveDataIndexerManager;
saveFsServiceConfig.FsServer = server;

View file

@ -5,7 +5,7 @@ namespace LibHac.FsSrv;
public interface ISaveDataIndexerManager
{
Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor, out bool neededInit, SaveDataSpaceId spaceId);
Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor, out bool isInitialOpen, SaveDataSpaceId spaceId);
void ResetIndexer(SaveDataSpaceId spaceId);
void InvalidateIndexer(SaveDataSpaceId spaceId);
}

View file

@ -2,15 +2,15 @@
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.Os;
using LibHac.Util;
using IFileSf = LibHac.FsSrv.Sf.IFile;
namespace LibHac.FsSrv.Impl;
public interface ISaveDataTransferCoreInterface : IDisposable
{
Result GetFreeSpaceSizeForSaveData(out long freeSpaceSize, SaveDataSpaceId spaceId);
Result QuerySaveDataTotalSize(out long totalSize, long dataSize, long journalSize);
Result GetFreeSpaceSizeForSaveData(out long outFreeSpaceSize, SaveDataSpaceId spaceId);
Result QuerySaveDataTotalSize(out long outTotalSize, long dataSize, long journalSize);
Result CheckSaveDataFile(long saveDataId, SaveDataSpaceId spaceId);
Result CreateSaveDataFileSystemCore(in SaveDataAttribute attribute, in SaveDataCreationInfo creationInfo, in SaveDataMetaInfo metaInfo, in Optional<HashSalt> hashSalt, bool leaveUnfinalized);
Result GetSaveDataInfo(out SaveDataInfo saveInfo, SaveDataSpaceId spaceId, in SaveDataAttribute attribute);
@ -18,13 +18,15 @@ public interface ISaveDataTransferCoreInterface : IDisposable
Result WriteSaveDataFileSystemExtraDataCore(SaveDataSpaceId spaceId, ulong saveDataId, in SaveDataExtraData extraData, SaveDataType type, bool updateTimeStamp);
Result FinalizeSaveDataCreation(ulong saveDataId, SaveDataSpaceId spaceId);
Result CancelSaveDataCreation(ulong saveDataId, SaveDataSpaceId spaceId);
Result OpenSaveDataFile(ref SharedRef<IFileSf> file, SaveDataSpaceId spaceId, in SaveDataAttribute attribute, SaveDataMetaType metaType);
Result OpenSaveDataMetaFileRaw(ref SharedRef<IFile> file, SaveDataSpaceId spaceId, ulong saveDataId, SaveDataMetaType metaType, OpenMode mode);
Result OpenSaveDataFile(ref SharedRef<IFile> oufFile, SaveDataSpaceId spaceId, ulong saveDataId, OpenMode mode);
Result OpenSaveDataMetaFileRaw(ref SharedRef<IFile> outFile, SaveDataSpaceId spaceId, ulong saveDataId, SaveDataMetaType metaType, OpenMode mode);
Result OpenSaveDataInternalStorageFileSystemCore(ref SharedRef<IFileSystem> fileSystem, SaveDataSpaceId spaceId, ulong saveDataId, bool useSecondMacKey);
Result OpenSaveDataFileSystemCore(ref SharedRef<IFileSystem> outFileSystem, out ulong outSaveDataId, SaveDataSpaceId spaceId, in SaveDataAttribute attribute, bool openReadOnly, bool cacheExtraData);
Result ExtendSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, long dataSize, long journalSize);
Result DeleteSaveDataFileSystemBySaveDataSpaceId(SaveDataSpaceId spaceId, ulong saveDataId);
Result SwapSaveDataKeyAndState(SaveDataSpaceId spaceId, ulong saveDataId1, ulong saveDataId2);
Result SetSaveDataState(SaveDataSpaceId spaceId, ulong saveDataId, SaveDataState state);
Result SetSaveDataRank(SaveDataSpaceId spaceId, ulong saveDataId, SaveDataRank rank);
Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor, SaveDataSpaceId spaceId);
}
bool IsProhibited(ref UniqueLock<SdkMutex> outLock, ApplicationId applicationId);
}

View file

@ -46,7 +46,7 @@ internal class MultiCommitManager : IMultiCommitManager
{
private const int MaxFileSystemCount = 10;
public const ulong ProgramId = 0x0100000000000000;
public const ulong ProgramId = 0;
public const ulong SaveDataId = 0x8000000000000001;
private const long SaveDataSize = 0xC000;
private const long SaveJournalSize = 0xC000;

File diff suppressed because it is too large Load diff

View file

@ -15,13 +15,13 @@ using Utility = LibHac.FsSrv.Impl.Utility;
namespace LibHac.FsSrv;
public class SaveDataFileSystemServiceImpl
public class SaveDataFileSystemServiceImpl : IDisposable
{
private Configuration _config;
private EncryptionSeed _encryptionSeed;
private SaveDataFileSystemCacheManager _saveDataFsCacheManager;
private SaveDataExtraDataAccessorCacheManager _extraDataCacheManager;
private SaveDataFileSystemCacheManager _saveFileSystemCacheManager;
private SaveDataExtraDataAccessorCacheManager _saveExtraDataCacheManager;
// Save data porter manager
private bool _isSdCardAccessible;
private TimeStampGetter _timeStampGetter;
@ -40,22 +40,10 @@ public class SaveDataFileSystemServiceImpl
public Result Get(out long timeStamp)
{
return _saveService.GetSaveDataCommitTimeStamp(out timeStamp);
return _saveService.GetSaveDataCommitTimeStamp(out timeStamp).Ret();
}
}
public SaveDataFileSystemServiceImpl(in Configuration configuration)
{
_config = configuration;
_saveDataFsCacheManager = new SaveDataFileSystemCacheManager();
_extraDataCacheManager = new SaveDataExtraDataAccessorCacheManager();
_timeStampGetter = new TimeStampGetter(this);
Result rc = _saveDataFsCacheManager.Initialize(_config.MaxSaveFsCacheCount);
Abort.DoAbortUnless(rc.IsSuccess());
}
public struct Configuration
{
public BaseFileSystemServiceImpl BaseFsService;
@ -68,7 +56,7 @@ public class SaveDataFileSystemServiceImpl
public IBufferManager BufferManager;
public RandomDataGenerator GenerateRandomData;
public SaveDataTransferCryptoConfiguration SaveTransferCryptoConfig;
public int MaxSaveFsCacheCount;
public int SaveDataFileSystemCacheCount;
public Func<bool> IsPseudoSaveData;
public ISaveDataIndexerManager SaveIndexerManager;
@ -76,10 +64,36 @@ public class SaveDataFileSystemServiceImpl
public FileSystemServer FsServer;
}
internal Result GetProgramInfo(out ProgramInfo programInfo, ulong processId)
private static bool IsDeviceUniqueMac(SaveDataSpaceId spaceId)
{
var registry = new ProgramRegistryImpl(_config.FsServer);
return registry.GetProgramInfo(out programInfo, processId);
return spaceId == SaveDataSpaceId.System ||
spaceId == SaveDataSpaceId.User ||
spaceId == SaveDataSpaceId.Temporary ||
spaceId == SaveDataSpaceId.ProperSystem ||
spaceId == SaveDataSpaceId.SafeMode;
}
private static Result WipeData(IFileSystem fileSystem, in Path filePath, RandomDataGenerator random)
{
throw new NotImplementedException();
}
public SaveDataFileSystemServiceImpl(in Configuration configuration)
{
_config = configuration;
_saveFileSystemCacheManager = new SaveDataFileSystemCacheManager();
_saveExtraDataCacheManager = new SaveDataExtraDataAccessorCacheManager();
_timeStampGetter = new TimeStampGetter(this);
Result rc = _saveFileSystemCacheManager.Initialize(_config.SaveDataFileSystemCacheCount);
Abort.DoAbortUnless(rc.IsSuccess());
}
public void Dispose()
{
_saveFileSystemCacheManager.Dispose();
_saveExtraDataCacheManager.Dispose();
}
public Result DoesSaveDataEntityExist(out bool exists, SaveDataSpaceId spaceId, ulong saveDataId)
@ -116,7 +130,12 @@ public class SaveDataFileSystemServiceImpl
}
}
// 14.3.0
public Result OpenSaveDataFile(ref SharedRef<IFile> outFile, SaveDataSpaceId spaceId, ulong saveDataId,
OpenMode openMode)
{
throw new NotImplementedException();
}
public Result OpenSaveDataFileSystem(ref SharedRef<IFileSystem> outFileSystem, SaveDataSpaceId spaceId,
ulong saveDataId, in Path saveDataRootPath, bool openReadOnly, SaveDataType type, bool cacheExtraData)
{
@ -141,10 +160,10 @@ public class SaveDataFileSystemServiceImpl
using var saveDataFs = new SharedRef<ISaveDataFileSystem>();
using (_saveDataFsCacheManager.GetScopedLock())
using (_extraDataCacheManager.GetScopedLock())
using (_saveFileSystemCacheManager.GetScopedLock())
using (_saveExtraDataCacheManager.GetScopedLock())
{
if (isEmulatedOnHost || !_saveDataFsCacheManager.GetCache(ref saveDataFs.Ref(), spaceId, saveDataId))
if (isEmulatedOnHost || !_saveFileSystemCacheManager.GetCache(ref saveDataFs.Ref(), spaceId, saveDataId))
{
bool isDeviceUniqueMac = IsDeviceUniqueMac(spaceId);
bool isJournalingSupported = SaveDataProperties.IsJournalingSupported(type);
@ -163,13 +182,13 @@ public class SaveDataFileSystemServiceImpl
using SharedRef<ISaveDataExtraDataAccessor> extraDataAccessor =
SharedRef<ISaveDataExtraDataAccessor>.CreateCopy(in saveDataFs);
rc = _extraDataCacheManager.Register(in extraDataAccessor, spaceId, saveDataId);
rc = _saveExtraDataCacheManager.Register(in extraDataAccessor, spaceId, saveDataId);
if (rc.IsFailure()) return rc.Miss();
}
}
using var registerFs = new SharedRef<SaveDataFileSystemCacheRegister>(
new SaveDataFileSystemCacheRegister(ref saveDataFs.Ref(), _saveDataFsCacheManager, spaceId, saveDataId));
new SaveDataFileSystemCacheRegister(ref saveDataFs.Ref(), _saveFileSystemCacheManager, spaceId, saveDataId));
if (openReadOnly)
{
@ -203,11 +222,61 @@ public class SaveDataFileSystemServiceImpl
}
public Result OpenSaveDataInternalStorageFileSystem(ref SharedRef<IFileSystem> outFileSystem,
SaveDataSpaceId spaceId, ulong saveDataId, in Path saveDataRootPath, bool useSecondMacKey)
SaveDataSpaceId spaceId, ulong saveDataId, in Path saveDataRootPath, bool useSecondMacKey,
bool isReconstructible)
{
throw new NotImplementedException();
}
public Result ExtendSaveDataFileSystemCore(out long extendedTotalSize, ulong saveDataId, SaveDataSpaceId spaceId,
SaveDataType type, long dataSize, long journalSize, in Path saveDataRootPath, bool isExtensionStart)
{
throw new NotImplementedException();
}
private Result OpenSaveDataImageFile(ref UniqueRef<IFile> outFile, SaveDataSpaceId spaceId, ulong saveDataId,
in Path saveDataRootPath)
{
throw new NotImplementedException();
}
public Result StartExtendSaveDataFileSystem(out long extendedTotalSize, ulong saveDataId, SaveDataSpaceId spaceId,
SaveDataType type, long dataSize, long journalSize, in Path saveDataRootPath)
{
return ExtendSaveDataFileSystemCore(out extendedTotalSize, saveDataId, spaceId, type, dataSize, journalSize,
in saveDataRootPath, isExtensionStart: true);
}
public Result ResumeExtendSaveDataFileSystem(out long extendedTotalSize, ulong saveDataId, SaveDataSpaceId spaceId,
SaveDataType type, in Path saveDataRootPath)
{
return ExtendSaveDataFileSystemCore(out extendedTotalSize, saveDataId, spaceId, type, dataSize: 0,
journalSize: 0, in saveDataRootPath, isExtensionStart: false);
}
public Result FinishExtendSaveDataFileSystem(ulong saveDataId, SaveDataSpaceId spaceId)
{
Result rc = DeleteSaveDataMeta(saveDataId, spaceId, SaveDataMetaType.ExtensionContext);
if (rc.IsFailure() && !ResultFs.PathNotFound.Includes(rc))
return rc.Miss();
return Result.Success;
}
public void RevertExtendSaveDataFileSystem(ulong saveDataId, SaveDataSpaceId spaceId, long originalSize,
in Path saveDataRootPath)
{
using var saveDataFile = new UniqueRef<IFile>();
Result rc = OpenSaveDataImageFile(ref saveDataFile.Ref(), spaceId, saveDataId, in saveDataRootPath);
if (rc.IsSuccess())
{
saveDataFile.Get.SetSize(originalSize).IgnoreResult();
}
FinishExtendSaveDataFileSystem(saveDataId, spaceId).IgnoreResult();
}
public Result QuerySaveDataTotalSize(out long totalSize, int blockSize, long dataSize, long journalSize)
{
// Todo: Implement
@ -316,6 +385,82 @@ public class SaveDataFileSystemServiceImpl
return Result.Success;
}
public Result CreateSaveDataFileSystem(ulong saveDataId, in SaveDataCreationInfo2 creationInfo,
in Path saveDataRootPath, bool skipFormat)
{
Unsafe.SkipInit(out Array18<byte> saveImageNameBuffer);
long dataSize = creationInfo.Size;
long journalSize = creationInfo.JournalSize;
ulong ownerId = creationInfo.OwnerId;
SaveDataSpaceId spaceId = creationInfo.SpaceId;
SaveDataFlags flags = creationInfo.Flags;
using var fileSystem = new SharedRef<IFileSystem>();
Result rc = OpenSaveDataDirectoryFileSystem(ref fileSystem.Ref(), creationInfo.SpaceId, in saveDataRootPath,
allowEmulatedSave: false);
if (rc.IsFailure()) return rc.Miss();
using var saveImageName = new Path();
rc = PathFunctions.SetUpFixedPathSaveId(ref saveImageName.Ref(), saveImageNameBuffer.Items, saveDataId);
if (rc.IsFailure()) return rc.Miss();
bool isPseudoSaveFs = _config.IsPseudoSaveData();
bool isCreationSuccessful = false;
try
{
if (isPseudoSaveFs)
{
rc = FsSystem.Utility.EnsureDirectory(fileSystem.Get, in saveImageName);
if (rc.IsFailure()) return rc.Miss();
}
else
{
throw new NotImplementedException();
}
SaveDataExtraData extraData = default;
extraData.Attribute = creationInfo.Attribute;
extraData.OwnerId = ownerId;
rc = GetSaveDataCommitTimeStamp(out extraData.TimeStamp);
if (rc.IsFailure())
extraData.TimeStamp = 0;
extraData.CommitId = 0;
_config.GenerateRandomData(SpanHelpers.AsByteSpan(ref extraData.CommitId));
extraData.Flags = flags;
extraData.DataSize = dataSize;
extraData.JournalSize = journalSize;
extraData.FormatType = creationInfo.FormatType;
rc = WriteSaveDataFileSystemExtraData(spaceId, saveDataId, in extraData, in saveDataRootPath,
creationInfo.Attribute.Type, updateTimeStamp: true);
if (rc.IsFailure()) return rc.Miss();
isCreationSuccessful = true;
return Result.Success;
}
finally
{
// Delete any created save if something goes wrong.
if (!isCreationSuccessful)
{
if (isPseudoSaveFs)
{
fileSystem.Get.DeleteDirectoryRecursively(in saveImageName).IgnoreResult();
}
else
{
fileSystem.Get.DeleteFile(in saveImageName).IgnoreResult();
}
}
}
}
public Result CreateSaveDataFileSystem(ulong saveDataId, in SaveDataAttribute attribute,
in SaveDataCreationInfo creationInfo, in Path saveDataRootPath, in Optional<HashSalt> hashSalt,
bool skipFormat)
@ -379,11 +524,6 @@ public class SaveDataFileSystemServiceImpl
return Result.Success;
}
private Result WipeData(IFileSystem fileSystem, in Path filePath, RandomDataGenerator random)
{
throw new NotImplementedException();
}
public Result DeleteSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, bool wipeSaveFile,
in Path saveDataRootPath)
{
@ -391,7 +531,7 @@ public class SaveDataFileSystemServiceImpl
using var fileSystem = new SharedRef<IFileSystem>();
_saveDataFsCacheManager.Unregister(spaceId, saveDataId);
_saveFileSystemCacheManager.Unregister(spaceId, saveDataId);
// Open the directory containing the save data
Result rc = OpenSaveDataDirectoryFileSystem(ref fileSystem.Ref(), spaceId, in saveDataRootPath, false);
@ -433,13 +573,13 @@ public class SaveDataFileSystemServiceImpl
// Nintendo returns blank extra data for directory save data.
// We've extended directory save data to store extra data so we don't need to do that.
using UniqueLockRef<SdkRecursiveMutexType> scopedLockFsCache = _saveDataFsCacheManager.GetScopedLock();
using UniqueLockRef<SdkRecursiveMutexType> scopedLockExtraDataCache = _extraDataCacheManager.GetScopedLock();
using UniqueLockRef<SdkRecursiveMutexType> scopedLockFsCache = _saveFileSystemCacheManager.GetScopedLock();
using UniqueLockRef<SdkRecursiveMutexType> scopedLockExtraDataCache = _saveExtraDataCacheManager.GetScopedLock();
using var extraDataAccessor = new SharedRef<ISaveDataExtraDataAccessor>();
// Try to grab an extra data accessor for the requested save from the cache.
Result rc = _extraDataCacheManager.GetCache(ref extraDataAccessor.Ref(), spaceId, saveDataId);
Result rc = _saveExtraDataCacheManager.GetCache(ref extraDataAccessor.Ref(), spaceId, saveDataId);
if (rc.IsSuccess())
{
@ -456,7 +596,7 @@ public class SaveDataFileSystemServiceImpl
if (rc.IsFailure()) return rc.Miss();
// Try to grab an accessor from the cache again.
rc = _extraDataCacheManager.GetCache(ref extraDataAccessor.Ref(), spaceId, saveDataId);
rc = _saveExtraDataCacheManager.GetCache(ref extraDataAccessor.Ref(), spaceId, saveDataId);
if (rc.IsFailure())
{
@ -478,13 +618,13 @@ public class SaveDataFileSystemServiceImpl
// Nintendo does nothing when writing directory save data extra data.
// We've extended directory save data to store extra data so we don't return early.
using UniqueLockRef<SdkRecursiveMutexType> scopedLockFsCache = _saveDataFsCacheManager.GetScopedLock();
using UniqueLockRef<SdkRecursiveMutexType> scopedLockExtraDataCache = _extraDataCacheManager.GetScopedLock();
using UniqueLockRef<SdkRecursiveMutexType> scopedLockFsCache = _saveFileSystemCacheManager.GetScopedLock();
using UniqueLockRef<SdkRecursiveMutexType> scopedLockExtraDataCache = _saveExtraDataCacheManager.GetScopedLock();
using var extraDataAccessor = new SharedRef<ISaveDataExtraDataAccessor>();
// Try to grab an extra data accessor for the requested save from the cache.
Result rc = _extraDataCacheManager.GetCache(ref extraDataAccessor.Ref(), spaceId, saveDataId);
Result rc = _saveExtraDataCacheManager.GetCache(ref extraDataAccessor.Ref(), spaceId, saveDataId);
if (rc.IsFailure())
{
@ -498,7 +638,7 @@ public class SaveDataFileSystemServiceImpl
if (rc.IsFailure()) return rc.Miss();
// Try to grab an accessor from the cache again.
rc = _extraDataCacheManager.GetCache(ref extraDataAccessor.Ref(), spaceId, saveDataId);
rc = _saveExtraDataCacheManager.GetCache(ref extraDataAccessor.Ref(), spaceId, saveDataId);
if (rc.IsFailure())
{
@ -592,12 +732,6 @@ public class SaveDataFileSystemServiceImpl
return Result.Success;
}
public Result OpenSaveDataDirectoryFileSystemImpl(ref SharedRef<IFileSystem> outFileSystem,
SaveDataSpaceId spaceId, in Path basePath)
{
return OpenSaveDataDirectoryFileSystemImpl(ref outFileSystem, spaceId, in basePath, true);
}
public Result OpenSaveDataDirectoryFileSystemImpl(ref SharedRef<IFileSystem> outFileSystem,
SaveDataSpaceId spaceId, in Path basePath, bool createIfMissing)
{
@ -680,15 +814,10 @@ public class SaveDataFileSystemServiceImpl
}
}
public Result SetSdCardEncryptionSeed(in EncryptionSeed seed)
public Result OpenSaveDataDirectoryFileSystemImpl(ref SharedRef<IFileSystem> outFileSystem,
SaveDataSpaceId spaceId, in Path basePath)
{
_encryptionSeed = seed;
_config.SaveFsCreator.SetSdCardEncryptionSeed(seed.Value);
_config.SaveIndexerManager.InvalidateIndexer(SaveDataSpaceId.SdSystem);
_config.SaveIndexerManager.InvalidateIndexer(SaveDataSpaceId.SdUser);
return Result.Success;
return OpenSaveDataDirectoryFileSystemImpl(ref outFileSystem, spaceId, in basePath, true);
}
public Result IsProvisionallyCommittedSaveData(out bool isProvisionallyCommitted, in SaveDataInfo saveInfo)
@ -704,13 +833,15 @@ public class SaveDataFileSystemServiceImpl
return spaceId == SaveDataSpaceId.User && IsSaveEmulated(in saveDataRootPath);
}
public bool IsDeviceUniqueMac(SaveDataSpaceId spaceId)
public Result SetSdCardEncryptionSeed(in EncryptionSeed seed)
{
return spaceId == SaveDataSpaceId.System ||
spaceId == SaveDataSpaceId.User ||
spaceId == SaveDataSpaceId.Temporary ||
spaceId == SaveDataSpaceId.ProperSystem ||
spaceId == SaveDataSpaceId.SafeMode;
_encryptionSeed = seed;
_config.SaveFsCreator.SetSdCardEncryptionSeed(seed.Value);
_config.SaveIndexerManager.InvalidateIndexer(SaveDataSpaceId.SdSystem);
_config.SaveIndexerManager.InvalidateIndexer(SaveDataSpaceId.SdUser);
return Result.Success;
}
public void SetSdCardAccessibility(bool isAccessible)
@ -753,6 +884,11 @@ public class SaveDataFileSystemServiceImpl
return programId;
}
public SaveDataTransferCryptoConfiguration GetSaveDataTransferCryptoConfiguration()
{
throw new NotImplementedException();
}
public Result GetSaveDataIndexCount(out int count)
{
UnsafeHelpers.SkipParamInit(out count);
@ -766,10 +902,10 @@ public class SaveDataFileSystemServiceImpl
return Result.Success;
}
public Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor, out bool neededInit,
SaveDataSpaceId spaceId)
public Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor,
out bool isInitialOpen, SaveDataSpaceId spaceId)
{
return _config.SaveIndexerManager.OpenSaveDataIndexerAccessor(ref outAccessor, out neededInit, spaceId);
return _config.SaveIndexerManager.OpenSaveDataIndexerAccessor(ref outAccessor, out isInitialOpen, spaceId);
}
public void ResetTemporaryStorageIndexer()

View file

@ -122,14 +122,14 @@ internal class SaveDataIndexerManager : ISaveDataIndexerManager, IDisposable
/// The accessor must be disposed after use.
/// </remarks>
/// <param name="outAccessor">If the method returns successfully, contains the created accessor.</param>
/// <param name="neededInit">If the method returns successfully, contains <see langword="true"/>
/// if the indexer needed to be initialized.</param>
/// <param name="isInitialOpen">If the method returns successfully, contains <see langword="true"/>
/// if the indexer needed to be initialized because this was the first time it was opened.</param>
/// <param name="spaceId">The <see cref="SaveDataSpaceId"/> of the indexer to open.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
public Result OpenSaveDataIndexerAccessor(ref UniqueRef<SaveDataIndexerAccessor> outAccessor,
out bool neededInit, SaveDataSpaceId spaceId)
out bool isInitialOpen, SaveDataSpaceId spaceId)
{
UnsafeHelpers.SkipParamInit(out neededInit);
UnsafeHelpers.SkipParamInit(out isInitialOpen);
if (_isBisUserRedirectionEnabled && spaceId == SaveDataSpaceId.User)
{
@ -226,7 +226,7 @@ internal class SaveDataIndexerManager : ISaveDataIndexerManager, IDisposable
}
outAccessor.Reset(new SaveDataIndexerAccessor(indexer, ref indexerLock.Ref()));
neededInit = wasIndexerInitialized;
isInitialOpen = wasIndexerInitialized;
return Result.Success;
}

View file

@ -13,7 +13,7 @@ namespace LibHac.FsSrv.Sf;
/// <summary>
/// The interface most programs use to interact with the FS service.
/// </summary>
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
/// <remarks>Based on FS 14.1.0 (nnSdk 14.3.0)</remarks>
public interface IFileSystemProxy : IDisposable
{
Result SetCurrentProcess(ulong processId);
@ -42,6 +42,7 @@ public interface IFileSystemProxy : IDisposable
Result GetCacheStorageSize(out long dataSize, out long journalSize, ushort index);
Result CreateSaveDataFileSystemWithHashSalt(in SaveDataAttribute attribute, in SaveDataCreationInfo creationInfo, in SaveDataMetaInfo metaInfo, in HashSalt hashSalt);
Result OpenHostFileSystemWithOption(ref SharedRef<IFileSystemSf> outFileSystem, in FspPath path, MountHostOption option);
Result CreateSaveDataFileSystemWithCreationInfo2(in SaveDataCreationInfo2 creationInfo);
Result OpenSaveDataFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, SaveDataSpaceId spaceId, in SaveDataAttribute attribute);
Result OpenSaveDataFileSystemBySystemSaveDataId(ref SharedRef<IFileSystemSf> outFileSystem, SaveDataSpaceId spaceId, in SaveDataAttribute attribute);
Result OpenReadOnlySaveDataFileSystem(ref SharedRef<IFileSystemSf> outFileSystem, SaveDataSpaceId spaceId, in SaveDataAttribute attribute);

View file

@ -136,6 +136,7 @@ public class TypeLayoutTests
Assert.Equal(0x40, GetOffset(in s, in s.OwnerId));
Assert.Equal(0x48, GetOffset(in s, in s.TimeStamp));
Assert.Equal(0x50, GetOffset(in s, in s.Flags));
Assert.Equal(0x54, GetOffset(in s, in s.FormatType));
Assert.Equal(0x58, GetOffset(in s, in s.DataSize));
Assert.Equal(0x60, GetOffset(in s, in s.JournalSize));
Assert.Equal(0x68, GetOffset(in s, in s.CommitId));