Add save data extra data functions to SaveDataFileSystemServiceImpl

Adds ReadSaveDataFileSystemExtraData and WriteSaveDataFileSystemExtraData
Auto-format SaveDataFileSystemServiceImpl
Use SdkRecursiveMutexType instead of SdkRecursiveMutex in SaveDataExtraDataAccessorCacheManager
This commit is contained in:
Alex Barney 2021-05-09 21:45:54 -07:00
parent 7aae39c358
commit f67d51cb37
3 changed files with 134 additions and 25 deletions

View file

@ -37,12 +37,12 @@ namespace LibHac.FsSrv.Impl
} }
private readonly LinkedList<Cache> _accessorList; private readonly LinkedList<Cache> _accessorList;
private SdkRecursiveMutex _mutex; private SdkRecursiveMutexType _mutex;
public SaveDataExtraDataAccessorCacheManager() public SaveDataExtraDataAccessorCacheManager()
{ {
_accessorList = new LinkedList<Cache>(); _accessorList = new LinkedList<Cache>();
_mutex = new SdkRecursiveMutex(); _mutex.Initialize();
} }
public void Dispose() public void Dispose()
@ -55,7 +55,7 @@ namespace LibHac.FsSrv.Impl
{ {
var cache = new Cache(accessor, spaceId, saveDataId); var cache = new Cache(accessor, spaceId, saveDataId);
using ScopedLock<SdkRecursiveMutex> scopedLock = ScopedLock.Lock(ref _mutex); using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
_accessorList.AddLast(cache); _accessorList.AddLast(cache);
return Result.Success; return Result.Success;
@ -63,7 +63,7 @@ namespace LibHac.FsSrv.Impl
public void Unregister(SaveDataSpaceId spaceId, ulong saveDataId) public void Unregister(SaveDataSpaceId spaceId, ulong saveDataId)
{ {
using ScopedLock<SdkRecursiveMutex> scopedLock = ScopedLock.Lock(ref _mutex); using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
UnregisterImpl(spaceId, saveDataId); UnregisterImpl(spaceId, saveDataId);
} }
@ -89,7 +89,7 @@ namespace LibHac.FsSrv.Impl
{ {
UnsafeHelpers.SkipParamInit(out accessor); UnsafeHelpers.SkipParamInit(out accessor);
using ScopedLock<SdkRecursiveMutex> scopedLock = ScopedLock.Lock(ref _mutex); using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
LinkedListNode<Cache> currentNode = _accessorList.First; LinkedListNode<Cache> currentNode = _accessorList.First;
@ -126,9 +126,9 @@ namespace LibHac.FsSrv.Impl
} }
} }
public ScopedLock<SdkRecursiveMutex> GetScopedLock() public ScopedLock<SdkRecursiveMutexType> GetScopedLock()
{ {
return new ScopedLock<SdkRecursiveMutex>(ref _mutex); return new ScopedLock<SdkRecursiveMutexType>(ref _mutex);
} }
} }
} }

View file

@ -165,7 +165,7 @@ namespace LibHac.FsSrv
ReferenceCountedDisposable<ISaveDataExtraDataAccessor> extraDataAccessor = null; ReferenceCountedDisposable<ISaveDataExtraDataAccessor> extraDataAccessor = null;
try try
{ {
using ScopedLock<SdkRecursiveMutex> scopedLock = _extraDataCacheManager.GetScopedLock(); using ScopedLock<SdkRecursiveMutexType> scopedLock = _extraDataCacheManager.GetScopedLock();
// Todo: Update ISaveDataFileSystemCreator // Todo: Update ISaveDataFileSystemCreator
bool useDeviceUniqueMac = IsDeviceUniqueMac(spaceId); bool useDeviceUniqueMac = IsDeviceUniqueMac(spaceId);
@ -427,15 +427,115 @@ namespace LibHac.FsSrv
public Result ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, SaveDataSpaceId spaceId, public Result ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraData, SaveDataSpaceId spaceId,
ulong saveDataId, SaveDataType type, U8Span saveDataRootPath) ulong saveDataId, SaveDataType type, U8Span saveDataRootPath)
{ {
// Todo: Find a way to store extra data for directory save data UnsafeHelpers.SkipParamInit(out extraData);
// 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 ScopedLock<SdkRecursiveMutexType> scopedLockFsCache = _saveDataFsCacheManager.GetScopedLock();
using ScopedLock<SdkRecursiveMutexType> scopedLockExtraDataCache = _extraDataCacheManager.GetScopedLock();
ReferenceCountedDisposable<ISaveDataExtraDataAccessor> extraDataAccessor = null;
try
{
// Try to grab an extra data accessor for the requested save from the cache.
Result rc = _extraDataCacheManager.GetCache(out extraDataAccessor, spaceId, saveDataId);
if (rc.IsSuccess())
{
// An extra data accessor was found in the cache. Read the extra data from it.
return extraDataAccessor.Target.ReadExtraData(out extraData);
}
ReferenceCountedDisposable<IFileSystem> unusedSaveDataFs = null;
try
{
// We won't actually use the returned save data FS.
// Opening the FS should cache an extra data accessor for it.
rc = OpenSaveDataFileSystem(out unusedSaveDataFs, spaceId, saveDataId, saveDataRootPath,
openReadOnly: true, type, cacheExtraData: true);
if (rc.IsFailure()) return rc;
// Try to grab an accessor from the cache again.
rc = _extraDataCacheManager.GetCache(out extraDataAccessor, spaceId, saveDataId);
if (rc.IsFailure())
{
// No extra data accessor was registered for the requested save data.
// Return a blank extra data struct.
extraData = new SaveDataExtraData(); extraData = new SaveDataExtraData();
return Result.Success; return rc;
}
return extraDataAccessor.Target.ReadExtraData(out extraData);
}
finally
{
unusedSaveDataFs?.Dispose();
}
}
finally
{
extraDataAccessor?.Dispose();
}
} }
public Result WriteSaveDataFileSystemExtraData(SaveDataSpaceId spaceId, ulong saveDataId, public Result WriteSaveDataFileSystemExtraData(SaveDataSpaceId spaceId, ulong saveDataId,
in SaveDataExtraData extraData, U8Span saveDataRootPath, SaveDataType type, bool updateTimeStamp) in SaveDataExtraData extraData, U8Span saveDataRootPath, SaveDataType type, bool updateTimeStamp)
{ {
throw new NotImplementedException(); // 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 ScopedLock<SdkRecursiveMutexType> scopedLockFsCache = _saveDataFsCacheManager.GetScopedLock();
using ScopedLock<SdkRecursiveMutexType> scopedLockExtraDataCache = _extraDataCacheManager.GetScopedLock();
ReferenceCountedDisposable<ISaveDataExtraDataAccessor> extraDataAccessor = null;
try
{
// Try to grab an extra data accessor for the requested save from the cache.
Result rc = _extraDataCacheManager.GetCache(out extraDataAccessor, spaceId, saveDataId);
if (rc.IsFailure())
{
// No accessor was found in the cache. Try to open one.
ReferenceCountedDisposable<IFileSystem> unusedSaveDataFs = null;
try
{
// We won't actually use the returned save data FS.
// Opening the FS should cache an extra data accessor for it.
rc = OpenSaveDataFileSystem(out unusedSaveDataFs, spaceId, saveDataId, saveDataRootPath,
openReadOnly: false, type, cacheExtraData: true);
if (rc.IsFailure()) return rc;
// Try to grab an accessor from the cache again.
rc = _extraDataCacheManager.GetCache(out extraDataAccessor, spaceId, saveDataId);
if (rc.IsFailure())
{
// No extra data accessor was registered for the requested save data, so don't do anything.
return rc;
}
}
finally
{
unusedSaveDataFs?.Dispose();
}
}
// We should have a valid accessor if we've reached this point.
// Write and commit the extra data.
rc = extraDataAccessor.Target.WriteExtraData(in extraData);
if (rc.IsFailure()) return rc;
rc = extraDataAccessor.Target.CommitExtraData(updateTimeStamp);
if (rc.IsFailure()) return rc;
return Result.Success;
}
finally
{
extraDataAccessor?.Dispose();
}
} }
public Result CorruptSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, long offset, public Result CorruptSaveDataFileSystem(SaveDataSpaceId spaceId, ulong saveDataId, long offset,
@ -527,14 +627,16 @@ namespace LibHac.FsSrv
switch (spaceId) switch (spaceId)
{ {
case SaveDataSpaceId.System: case SaveDataSpaceId.System:
rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.System, true); rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.System,
true);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing); return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing);
case SaveDataSpaceId.User: case SaveDataSpaceId.User:
case SaveDataSpaceId.Temporary: case SaveDataSpaceId.Temporary:
rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.User, true); rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.User,
true);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing); return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing);
@ -558,13 +660,15 @@ namespace LibHac.FsSrv
in _encryptionSeed); in _encryptionSeed);
case SaveDataSpaceId.ProperSystem: case SaveDataSpaceId.ProperSystem:
rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.SystemProperPartition, true); rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty,
BisPartitionId.SystemProperPartition, true);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing); return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing);
case SaveDataSpaceId.SafeMode: case SaveDataSpaceId.SafeMode:
rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.SafeMode, true); rc = _config.BaseFsService.OpenBisFileSystem(out tempFs, U8Span.Empty, BisPartitionId.SafeMode,
true);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing); return Utility.WrapSubDirectory(out fileSystem, ref tempFs, basePath, createIfMissing);

View file

@ -155,5 +155,10 @@ namespace LibHac.FsSystem
} }
} }
} }
public ScopedLock<SdkRecursiveMutexType> GetScopedLock()
{
return new ScopedLock<SdkRecursiveMutexType>(ref _mutex);
}
} }
} }