mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Update SaveDataFileSystemService for FS 17
This commit is contained in:
parent
e6d32b96d0
commit
037c5ace9e
7 changed files with 208 additions and 74 deletions
|
@ -11,21 +11,37 @@ namespace LibHac.Fs;
|
||||||
|
|
||||||
public struct PathFlags
|
public struct PathFlags
|
||||||
{
|
{
|
||||||
private uint _value;
|
private PathFormatFlags _formatFlags;
|
||||||
|
|
||||||
public void AllowWindowsPath() => _value |= 1 << 0;
|
[Flags]
|
||||||
public void AllowRelativePath() => _value |= 1 << 1;
|
public enum PathFormatFlags
|
||||||
public void AllowEmptyPath() => _value |= 1 << 2;
|
{
|
||||||
public void AllowMountName() => _value |= 1 << 3;
|
AllowWindowsPath = 1 << 0,
|
||||||
public void AllowBackslash() => _value |= 1 << 4;
|
AllowRelativePath = 1 << 1,
|
||||||
public void AllowAllCharacters() => _value |= 1 << 5;
|
AllowEmptyPath = 1 << 2,
|
||||||
|
AllowMountName = 1 << 3,
|
||||||
|
AllowBackslash = 1 << 4,
|
||||||
|
AllowInvalidCharacter = 1 << 5
|
||||||
|
}
|
||||||
|
|
||||||
public readonly bool IsWindowsPathAllowed() => (_value & (1 << 0)) != 0;
|
public PathFlags(PathFormatFlags formatFlags)
|
||||||
public readonly bool IsRelativePathAllowed() => (_value & (1 << 1)) != 0;
|
{
|
||||||
public readonly bool IsEmptyPathAllowed() => (_value & (1 << 2)) != 0;
|
_formatFlags = formatFlags;
|
||||||
public readonly bool IsMountNameAllowed() => (_value & (1 << 3)) != 0;
|
}
|
||||||
public readonly bool IsBackslashAllowed() => (_value & (1 << 4)) != 0;
|
|
||||||
public readonly bool AreAllCharactersAllowed() => (_value & (1 << 5)) != 0;
|
public void AllowWindowsPath() => _formatFlags |= PathFormatFlags.AllowWindowsPath;
|
||||||
|
public void AllowRelativePath() => _formatFlags |= PathFormatFlags.AllowRelativePath;
|
||||||
|
public void AllowEmptyPath() => _formatFlags |= PathFormatFlags.AllowEmptyPath;
|
||||||
|
public void AllowMountName() => _formatFlags |= PathFormatFlags.AllowMountName;
|
||||||
|
public void AllowBackslash() => _formatFlags |= PathFormatFlags.AllowBackslash;
|
||||||
|
public void AllowInvalidCharacter() => _formatFlags |= PathFormatFlags.AllowInvalidCharacter;
|
||||||
|
|
||||||
|
public readonly bool IsWindowsPathAllowed() => (_formatFlags & PathFormatFlags.AllowWindowsPath) != 0;
|
||||||
|
public readonly bool IsRelativePathAllowed() => (_formatFlags & PathFormatFlags.AllowRelativePath) != 0;
|
||||||
|
public readonly bool IsEmptyPathAllowed() => (_formatFlags & PathFormatFlags.AllowEmptyPath) != 0;
|
||||||
|
public readonly bool IsMountNameAllowed() => (_formatFlags & PathFormatFlags.AllowMountName) != 0;
|
||||||
|
public readonly bool IsBackslashAllowed() => (_formatFlags & PathFormatFlags.AllowBackslash) != 0;
|
||||||
|
public readonly bool IsInvalidCharacterAllowed() => (_formatFlags & PathFormatFlags.AllowInvalidCharacter) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -517,7 +517,7 @@ public static class PathFormatter
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = PathNormalizer.IsNormalized(out isNormalized, out int length, buffer, flags.AreAllCharactersAllowed());
|
res = PathNormalizer.IsNormalized(out isNormalized, out int length, buffer, flags.IsInvalidCharacterAllowed());
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
totalLength += length;
|
totalLength += length;
|
||||||
|
@ -639,7 +639,7 @@ public static class PathFormatter
|
||||||
}
|
}
|
||||||
|
|
||||||
res = PathNormalizer.Normalize(outputBuffer.Slice(currentPos), out _, src, isWindowsPath, isDriveRelative,
|
res = PathNormalizer.Normalize(outputBuffer.Slice(currentPos), out _, src, isWindowsPath, isDriveRelative,
|
||||||
flags.AreAllCharactersAllowed());
|
flags.IsInvalidCharacterAllowed());
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
|
|
@ -293,6 +293,8 @@ public class FileSystemInterfaceAdapter : IFileSystemSf
|
||||||
_selfReference.Destroy();
|
_selfReference.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PathFlags GetDefaultPathFlags() => new PathFlags();
|
||||||
|
|
||||||
private static ReadOnlySpan<byte> RootDir => "/"u8;
|
private static ReadOnlySpan<byte> RootDir => "/"u8;
|
||||||
|
|
||||||
private Result SetUpPath(ref Path fsPath, ref readonly PathSf sfPath)
|
private Result SetUpPath(ref Path fsPath, ref readonly PathSf sfPath)
|
||||||
|
|
|
@ -115,19 +115,57 @@ public static class SaveDataProperties
|
||||||
|
|
||||||
public static bool IsObsoleteSystemSaveData(in SaveDataInfo info)
|
public static bool IsObsoleteSystemSaveData(in SaveDataInfo info)
|
||||||
{
|
{
|
||||||
|
foreach (ulong id in ObsoleteSystemSaveDataIdList)
|
||||||
|
{
|
||||||
|
if (info.StaticSaveDataId == id)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsWipingNeededAtCleanUp(in SaveDataInfo info)
|
public static bool IsWipingNeededAtCleanUp(in SaveDataInfo info)
|
||||||
{
|
{
|
||||||
return false;
|
switch (info.Type)
|
||||||
throw new NotImplementedException();
|
{
|
||||||
|
case SaveDataType.System:
|
||||||
|
break;
|
||||||
|
case SaveDataType.Account:
|
||||||
|
case SaveDataType.Bcat:
|
||||||
|
case SaveDataType.Device:
|
||||||
|
case SaveDataType.Temporary:
|
||||||
|
case SaveDataType.Cache:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
Abort.UnexpectedDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ulong id in SystemSaveDataIdWipingExceptionList)
|
||||||
|
{
|
||||||
|
if (info.StaticSaveDataId == id)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsValidSpaceIdForSaveDataMover(SaveDataType type, SaveDataSpaceId spaceId)
|
public static bool IsValidSpaceIdForSaveDataMover(SaveDataType type, SaveDataSpaceId spaceId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
switch (type)
|
||||||
|
{
|
||||||
|
case SaveDataType.System:
|
||||||
|
case SaveDataType.Account:
|
||||||
|
case SaveDataType.Bcat:
|
||||||
|
case SaveDataType.Device:
|
||||||
|
case SaveDataType.Temporary:
|
||||||
|
return false;
|
||||||
|
case SaveDataType.Cache:
|
||||||
|
return spaceId == SaveDataSpaceId.User || spaceId == SaveDataSpaceId.SdUser;
|
||||||
|
default:
|
||||||
|
Abort.UnexpectedDefault();
|
||||||
|
return default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsReconstructible(SaveDataType type, SaveDataSpaceId spaceId)
|
public static bool IsReconstructible(SaveDataType type, SaveDataSpaceId spaceId)
|
||||||
|
@ -161,4 +199,16 @@ public static class SaveDataProperties
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ReadOnlySpan<ulong> ObsoleteSystemSaveDataIdList => [0x8000000000000060, 0x8000000000000075];
|
||||||
|
|
||||||
|
private static ReadOnlySpan<ulong> SystemSaveDataIdWipingExceptionList =>
|
||||||
|
[
|
||||||
|
0x8000000000000040, 0x8000000000000041, 0x8000000000000043, 0x8000000000000044, 0x8000000000000045,
|
||||||
|
0x8000000000000046, 0x8000000000000047, 0x8000000000000048, 0x8000000000000049, 0x800000000000004A,
|
||||||
|
0x8000000000000070, 0x8000000000000071, 0x8000000000000072, 0x8000000000000074, 0x8000000000000076,
|
||||||
|
0x8000000000000077, 0x8000000000000090, 0x8000000000000091, 0x8000000000000092, 0x80000000000000B0,
|
||||||
|
0x80000000000000C1, 0x80000000000000C2, 0x8000000000000120, 0x8000000000000121, 0x8000000000000180,
|
||||||
|
0x8000000000010003, 0x8000000000010004
|
||||||
|
];
|
||||||
}
|
}
|
|
@ -32,6 +32,12 @@ using Utility = LibHac.FsSystem.Utility;
|
||||||
|
|
||||||
namespace LibHac.FsSrv;
|
namespace LibHac.FsSrv;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates locks for incrementing and decrementing the save data open-count semaphore
|
||||||
|
/// from a <see cref="SaveDataFileSystemService"/> to keep track of how many save data files are currently open.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Used by objects such as <see cref="IFileSystem"/>s that open save data files.
|
||||||
|
/// <br/>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||||
file class SaveDataOpenCountAdapter : IEntryOpenCountSemaphoreManager
|
file class SaveDataOpenCountAdapter : IEntryOpenCountSemaphoreManager
|
||||||
{
|
{
|
||||||
private SharedRef<SaveDataFileSystemService> _saveService;
|
private SharedRef<SaveDataFileSystemService> _saveService;
|
||||||
|
@ -115,7 +121,7 @@ file static class Anonymous
|
||||||
: SaveDataFormatType.NoJournal;
|
: SaveDataFormatType.NoJournal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result CheckOpenSaveDataInfoReaderAccessControl(ProgramInfo programInfo, SaveDataSpaceId spaceId)
|
public static Result CheckOpenSaveDataInfoReaderAccessControl(ProgramInfo programInfo, ulong processId, SaveDataSpaceId spaceId)
|
||||||
{
|
{
|
||||||
Assert.SdkNotNull(programInfo);
|
Assert.SdkNotNull(programInfo);
|
||||||
|
|
||||||
|
@ -142,6 +148,10 @@ file static class Anonymous
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if a specified program has access to perform various functions on a specified save data.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||||
file static class SaveDataAccessibilityChecker
|
file static class SaveDataAccessibilityChecker
|
||||||
{
|
{
|
||||||
public delegate Result ExtraDataReader(out SaveDataExtraData extraData);
|
public delegate Result ExtraDataReader(out SaveDataExtraData extraData);
|
||||||
|
@ -565,7 +575,7 @@ file static class SaveDataAccessibilityChecker
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>FS will have one instance of this class for every connected process.
|
/// <remarks>FS will have one instance of this class for every connected process.
|
||||||
/// The FS permissions of the calling process are checked on every function call.
|
/// The FS permissions of the calling process are checked on every function call.
|
||||||
/// <br/>Based on nnSdk 14.3.0 (FS 14.1.0)</remarks>
|
/// <br/>Based on nnSdk 17.5.0 (FS 17.0.0)</remarks>
|
||||||
internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISaveDataMultiCommitCoreInterface
|
internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISaveDataMultiCommitCoreInterface
|
||||||
{
|
{
|
||||||
private const int OpenEntrySemaphoreCount = 256;
|
private const int OpenEntrySemaphoreCount = 256;
|
||||||
|
@ -761,8 +771,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
return DeleteSaveDataFileSystemCommon(spaceId, saveDataId).Ret();
|
return DeleteSaveDataFileSystemCommon(spaceId, saveDataId).Ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId,
|
public Result DeleteSaveDataFileSystemBySaveDataAttribute(SaveDataSpaceId spaceId, in SaveDataAttribute attribute)
|
||||||
in SaveDataAttribute attribute)
|
|
||||||
{
|
{
|
||||||
using var scopedContext = new ScopedStorageLayoutTypeSetter(StorageLayoutType.NonGameCard);
|
using var scopedContext = new ScopedStorageLayoutTypeSetter(StorageLayoutType.NonGameCard);
|
||||||
|
|
||||||
|
@ -1725,8 +1734,8 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
using var fileSystem = new SharedRef<IFileSystem>();
|
using var fileSystem = new SharedRef<IFileSystem>();
|
||||||
|
|
||||||
// Open the file system
|
// Open the file system
|
||||||
res = OpenSaveDataFileSystemCore(ref fileSystem.Ref, out ulong saveDataId, spaceId, in attribute,
|
res = OpenSaveDataFileSystemCore(ref fileSystem.Ref, out ulong saveDataId, spaceId, in attribute, openReadOnly,
|
||||||
openReadOnly, cacheExtraData: true);
|
cacheExtraData: true);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
// Can't use attribute in a closure, so copy the needed field
|
// Can't use attribute in a closure, so copy the needed field
|
||||||
|
@ -1764,9 +1773,9 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
using var openCountFileSystem = new SharedRef<IFileSystem>(new OpenCountFileSystem(ref asyncFileSystem.Ref,
|
using var openCountFileSystem = new SharedRef<IFileSystem>(new OpenCountFileSystem(ref asyncFileSystem.Ref,
|
||||||
ref openEntryCountAdapter.Ref, ref mountCountSemaphore.Ref));
|
ref openEntryCountAdapter.Ref, ref mountCountSemaphore.Ref));
|
||||||
|
|
||||||
var pathFlags = new PathFlags();
|
PathFlags pathFlags = FileSystemInterfaceAdapter.GetDefaultPathFlags();
|
||||||
pathFlags.AllowBackslash();
|
pathFlags.AllowBackslash();
|
||||||
pathFlags.AllowAllCharacters();
|
pathFlags.AllowInvalidCharacter();
|
||||||
|
|
||||||
using SharedRef<IFileSystemSf> fileSystemAdapter =
|
using SharedRef<IFileSystemSf> fileSystemAdapter =
|
||||||
FileSystemInterfaceAdapter.CreateShared(ref openCountFileSystem.Ref, pathFlags, false);
|
FileSystemInterfaceAdapter.CreateShared(ref openCountFileSystem.Ref, pathFlags, false);
|
||||||
|
@ -1862,7 +1871,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
Result ReadExtraData(out SaveDataExtraData data)
|
Result ReadExtraData(out SaveDataExtraData data)
|
||||||
{
|
{
|
||||||
using Path savePath = _saveDataRootPath.DangerousGetPath();
|
using Path savePath = _saveDataRootPath.DangerousGetPath();
|
||||||
return _serviceImpl.ReadSaveDataFileSystemExtraData(out data, spaceId, saveDataId, type, in savePath);
|
return _serviceImpl.ReadSaveDataFileSystemExtraData(out data, spaceId, saveDataId, type, in savePath).Ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have permissions to open this save data
|
// Check if we have permissions to open this save data
|
||||||
|
@ -1891,25 +1900,23 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
using var openCountFileSystem = new SharedRef<IFileSystem>(
|
using var openCountFileSystem = new SharedRef<IFileSystem>(
|
||||||
new OpenCountFileSystem(ref asyncFileSystem.Ref, ref openEntryCountAdapter.Ref));
|
new OpenCountFileSystem(ref asyncFileSystem.Ref, ref openEntryCountAdapter.Ref));
|
||||||
|
|
||||||
var pathFlags = new PathFlags();
|
PathFlags pathFlags = FileSystemInterfaceAdapter.GetDefaultPathFlags();
|
||||||
pathFlags.AllowBackslash();
|
pathFlags.AllowBackslash();
|
||||||
pathFlags.AllowAllCharacters();
|
pathFlags.AllowInvalidCharacter();
|
||||||
|
|
||||||
using SharedRef<IFileSystemSf> fileSystemAdapter =
|
using SharedRef<IFileSystemSf> fileSystemAdapter =
|
||||||
FileSystemInterfaceAdapter.CreateShared(ref openCountFileSystem.Ref, pathFlags,
|
FileSystemInterfaceAdapter.CreateShared(ref openCountFileSystem.Ref, pathFlags, allowAllOperations: false);
|
||||||
allowAllOperations: false);
|
|
||||||
|
|
||||||
outFileSystem.SetByMove(ref fileSystemAdapter.Ref);
|
outFileSystem.SetByMove(ref fileSystemAdapter.Ref);
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once UnusedParameter.Local
|
// ReSharper disable once UnusedParameter.Local
|
||||||
// Nintendo used isTemporarySaveData in older FS versions, but never removed the parameter.
|
// The unused parameter hasn't been removed because this method is part of an interface. It was used in older FS versions.
|
||||||
private Result ReadSaveDataFileSystemExtraDataCore(out SaveDataExtraData extraData, SaveDataSpaceId spaceId,
|
private Result ReadSaveDataFileSystemExtraDataCore(out SaveDataExtraData outExtraData, SaveDataSpaceId spaceId,
|
||||||
ulong saveDataId, bool isTemporarySaveData)
|
ulong saveDataId, bool isTemporarySaveData)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out extraData);
|
UnsafeHelpers.SkipParamInit(out outExtraData);
|
||||||
|
|
||||||
using var scopedContext = new ScopedStorageLayoutTypeSetter(StorageLayoutType.NonGameCard);
|
using var scopedContext = new ScopedStorageLayoutTypeSetter(StorageLayoutType.NonGameCard);
|
||||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||||
|
@ -1921,14 +1928,14 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||||
return _serviceImpl.ReadSaveDataFileSystemExtraData(out extraData, spaceId, saveDataId, key.Type,
|
return _serviceImpl.ReadSaveDataFileSystemExtraData(out outExtraData, spaceId, saveDataId, key.Type,
|
||||||
in saveDataRootPath).Ret();
|
in saveDataRootPath).Ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result ReadSaveDataFileSystemExtraDataCore(out SaveDataExtraData extraData,
|
private Result ReadSaveDataFileSystemExtraDataCore(out SaveDataExtraData outExtraData,
|
||||||
Optional<SaveDataSpaceId> spaceId, ulong saveDataId, in SaveDataExtraData extraDataMask)
|
Optional<SaveDataSpaceId> spaceId, ulong saveDataId, in SaveDataExtraData extraDataMask)
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out extraData);
|
UnsafeHelpers.SkipParamInit(out outExtraData);
|
||||||
|
|
||||||
using var scopedContext = new ScopedStorageLayoutTypeSetter(StorageLayoutType.NonGameCard);
|
using var scopedContext = new ScopedStorageLayoutTypeSetter(StorageLayoutType.NonGameCard);
|
||||||
|
|
||||||
|
@ -1971,7 +1978,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
res = accessor.Get.GetInterface().GetValue(out SaveDataIndexerValue _, saveDataId);
|
res = accessor.Get.GetInterface().GetValue(out SaveDataIndexerValue _, saveDataId);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
resolvedSpaceId = spaceId.ValueRo;
|
resolvedSpaceId = spaceId.Value;
|
||||||
|
|
||||||
res = accessor.Get.GetInterface().GetKey(out key, saveDataId);
|
res = accessor.Get.GetInterface().GetKey(out key, saveDataId);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
@ -1984,7 +1991,8 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
in savePath);
|
in savePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = SaveDataAccessibilityChecker.CheckReadExtraData(resolvedSpaceId, in key, in extraDataMask, programInfo, _processId, ReadExtraData);
|
res = SaveDataAccessibilityChecker.CheckReadExtraData(resolvedSpaceId, in key, in extraDataMask, programInfo,
|
||||||
|
_processId, ReadExtraData);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||||
|
@ -1993,7 +2001,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
MaskExtraData(ref tempExtraData, in extraDataMask);
|
MaskExtraData(ref tempExtraData, in extraDataMask);
|
||||||
extraData = tempExtraData;
|
outExtraData = tempExtraData;
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -2003,6 +2011,9 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (extraData.IsNull)
|
||||||
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
// Make a mask for reading the entire extra data
|
// Make a mask for reading the entire extra data
|
||||||
Unsafe.SkipInit(out SaveDataExtraData extraDataMask);
|
Unsafe.SkipInit(out SaveDataExtraData extraDataMask);
|
||||||
SpanHelpers.AsByteSpan(ref extraDataMask).Fill(0xFF);
|
SpanHelpers.AsByteSpan(ref extraDataMask).Fill(0xFF);
|
||||||
|
@ -2017,6 +2028,9 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (extraData.IsNull)
|
||||||
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
ref SaveDataExtraData extraDataRef = ref extraData.As<SaveDataExtraData>();
|
ref SaveDataExtraData extraDataRef = ref extraData.As<SaveDataExtraData>();
|
||||||
|
|
||||||
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
||||||
|
@ -2045,6 +2059,9 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (extraData.IsNull)
|
||||||
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
ref SaveDataExtraData extraDataRef = ref extraData.As<SaveDataExtraData>();
|
ref SaveDataExtraData extraDataRef = ref extraData.As<SaveDataExtraData>();
|
||||||
|
|
||||||
// Make a mask for reading the entire extra data
|
// Make a mask for reading the entire extra data
|
||||||
|
@ -2060,9 +2077,15 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (extraDataMask.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
if (extraDataMask.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (extraDataMask.IsNull)
|
||||||
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (extraData.IsNull)
|
||||||
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
ref readonly SaveDataExtraData maskRef = ref extraDataMask.As<SaveDataExtraData>();
|
ref readonly SaveDataExtraData maskRef = ref extraDataMask.As<SaveDataExtraData>();
|
||||||
ref SaveDataExtraData extraDataRef = ref extraData.As<SaveDataExtraData>();
|
ref SaveDataExtraData extraDataRef = ref extraData.As<SaveDataExtraData>();
|
||||||
|
|
||||||
|
@ -2101,13 +2124,14 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
using var accessor = new UniqueRef<SaveDataIndexerAccessor>();
|
||||||
|
|
||||||
res = OpenSaveDataIndexerAccessor(ref accessor.Ref, spaceId);
|
res = OpenSaveDataIndexerAccessor(ref accessor.Ref, spaceId);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
res = accessor.Get.GetInterface().GetKey(out SaveDataAttribute key, saveDataId);
|
res = accessor.Get.GetInterface().GetKey(out SaveDataAttribute key, saveDataId);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
SaveDataType saveDataType = key.Type;
|
||||||
|
|
||||||
Result ReadExtraData(out SaveDataExtraData data)
|
Result ReadExtraData(out SaveDataExtraData data)
|
||||||
{
|
{
|
||||||
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||||
|
@ -2120,13 +2144,13 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
|
|
||||||
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||||
res = _serviceImpl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraDataModify, spaceId, saveDataId,
|
res = _serviceImpl.ReadSaveDataFileSystemExtraData(out SaveDataExtraData extraDataModify, spaceId, saveDataId,
|
||||||
key.Type, in saveDataRootPath);
|
saveDataType, in saveDataRootPath);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
ModifySaveDataExtraData(ref extraDataModify, in extraData, in extraDataMask);
|
ModifySaveDataExtraData(ref extraDataModify, in extraData, in extraDataMask);
|
||||||
|
|
||||||
return _serviceImpl.WriteSaveDataFileSystemExtraData(spaceId, saveDataId, in extraDataModify,
|
return _serviceImpl.WriteSaveDataFileSystemExtraData(spaceId, saveDataId, in extraDataModify,
|
||||||
in saveDataRootPath, key.Type, updateTimeStamp: false).Ret();
|
in saveDataRootPath, saveDataType, updateTimeStamp: false).Ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result WriteSaveDataFileSystemExtraData(ulong saveDataId, SaveDataSpaceId spaceId, InBuffer extraData)
|
public Result WriteSaveDataFileSystemExtraData(ulong saveDataId, SaveDataSpaceId spaceId, InBuffer extraData)
|
||||||
|
@ -2134,6 +2158,9 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (extraData.IsNull)
|
||||||
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
ref readonly SaveDataExtraData extraDataRef = ref extraData.As<SaveDataExtraData>();
|
ref readonly SaveDataExtraData extraDataRef = ref extraData.As<SaveDataExtraData>();
|
||||||
|
|
||||||
SaveDataExtraData extraDataMask = default;
|
SaveDataExtraData extraDataMask = default;
|
||||||
|
@ -2167,9 +2194,15 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
if (extraData.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (extraData.IsNull)
|
||||||
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
if (extraDataMask.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
if (extraDataMask.Size != Unsafe.SizeOf<SaveDataExtraData>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (extraDataMask.IsNull)
|
||||||
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
ref readonly SaveDataExtraData extraDataRef = ref extraData.As<SaveDataExtraData>();
|
ref readonly SaveDataExtraData extraDataRef = ref extraData.As<SaveDataExtraData>();
|
||||||
ref readonly SaveDataExtraData maskRef = ref extraDataMask.As<SaveDataExtraData>();
|
ref readonly SaveDataExtraData maskRef = ref extraDataMask.As<SaveDataExtraData>();
|
||||||
|
|
||||||
|
@ -2213,7 +2246,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
res = CheckOpenSaveDataInfoReaderAccessControl(programInfo, spaceId);
|
res = CheckOpenSaveDataInfoReaderAccessControl(programInfo, _processId, spaceId);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
using var filterReader = new UniqueRef<SaveDataInfoFilterReader>();
|
using var filterReader = new UniqueRef<SaveDataInfoFilterReader>();
|
||||||
|
@ -2250,7 +2283,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (!programInfo.AccessControl.CanCall(OperationType.OpenSaveDataInfoReaderForInternal))
|
if (!programInfo.AccessControl.CanCall(OperationType.OpenSaveDataInfoReaderForInternal))
|
||||||
return ResultFs.PermissionDenied.Log();
|
return ResultFs.PermissionDenied.Log();
|
||||||
|
|
||||||
res = CheckOpenSaveDataInfoReaderAccessControl(programInfo, spaceId);
|
res = CheckOpenSaveDataInfoReaderAccessControl(programInfo, _processId, spaceId);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
using var filterReader = new UniqueRef<SaveDataInfoFilterReader>();
|
using var filterReader = new UniqueRef<SaveDataInfoFilterReader>();
|
||||||
|
@ -2303,17 +2336,20 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (saveDataInfoBuffer.Size != Unsafe.SizeOf<SaveDataInfo>())
|
if (saveDataInfoBuffer.Size != Unsafe.SizeOf<SaveDataInfo>())
|
||||||
return ResultFs.InvalidArgument.Log();
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
|
||||||
|
if (saveDataInfoBuffer.IsNull)
|
||||||
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
using var scopedContext = new ScopedStorageLayoutTypeSetter(StorageLayoutType.NonGameCard);
|
using var scopedContext = new ScopedStorageLayoutTypeSetter(StorageLayoutType.NonGameCard);
|
||||||
|
|
||||||
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
res = CheckOpenSaveDataInfoReaderAccessControl(programInfo, spaceId);
|
res = CheckOpenSaveDataInfoReaderAccessControl(programInfo, _processId, spaceId);
|
||||||
|
|
||||||
if (res.IsFailure())
|
if (res.IsFailure())
|
||||||
{
|
{
|
||||||
if (!ResultFs.PermissionDenied.Includes(res))
|
if (!ResultFs.PermissionDenied.Includes(res))
|
||||||
return res;
|
return res.Miss();
|
||||||
|
|
||||||
// Don't have full info reader permissions. Check if we have find permissions.
|
// Don't have full info reader permissions. Check if we have find permissions.
|
||||||
res = SaveDataAccessibilityChecker.CheckFind(spaceId, in filter, programInfo, _processId);
|
res = SaveDataAccessibilityChecker.CheckFind(spaceId, in filter, programInfo, _processId);
|
||||||
|
@ -2328,7 +2364,11 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
|
|
||||||
var infoFilter = new SaveDataInfoFilter(ConvertToRealSpaceId(spaceId), in tempFilter);
|
var infoFilter = new SaveDataInfoFilter(ConvertToRealSpaceId(spaceId), in tempFilter);
|
||||||
|
|
||||||
return FindSaveDataWithFilterImpl(out count, out saveDataInfoBuffer.As<SaveDataInfo>(), spaceId, in infoFilter).Ret();
|
res = FindSaveDataWithFilterImpl(out var outCount, out saveDataInfoBuffer.As<SaveDataInfo>(), spaceId, in infoFilter);
|
||||||
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
|
count = outCount;
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result CreateEmptyThumbnailFile(SaveDataSpaceId spaceId, ulong saveDataId)
|
private Result CreateEmptyThumbnailFile(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||||
|
@ -2519,10 +2559,14 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
|
|
||||||
if (res.IsFailure())
|
if (res.IsFailure())
|
||||||
{
|
{
|
||||||
spaceId = SaveDataSpaceId.User;
|
if (ResultFs.TargetNotFound.Includes(res))
|
||||||
|
{
|
||||||
if (!ResultFs.TargetNotFound.Includes(res))
|
spaceId = SaveDataSpaceId.User;
|
||||||
return res;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return res.Miss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return OpenSaveDataInfoReaderOnlyCacheStorage(ref outInfoReader, spaceId).Ret();
|
return OpenSaveDataInfoReaderOnlyCacheStorage(ref outInfoReader, spaceId).Ret();
|
||||||
|
@ -2536,7 +2580,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
Result res = GetProgramInfo(out ProgramInfo programInfo);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
if (spaceId != SaveDataSpaceId.SdUser && spaceId != SaveDataSpaceId.User)
|
if (spaceId != SaveDataSpaceId.User && spaceId != SaveDataSpaceId.SdUser)
|
||||||
return ResultFs.InvalidSaveDataSpaceId.Log();
|
return ResultFs.InvalidSaveDataSpaceId.Log();
|
||||||
|
|
||||||
using var filterReader = new UniqueRef<SaveDataInfoFilterReader>();
|
using var filterReader = new UniqueRef<SaveDataInfoFilterReader>();
|
||||||
|
@ -2686,7 +2730,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
ulong resolvedProgramId = ResolveDefaultSaveDataReferenceProgramId(programInfo.ProgramId).Value;
|
ulong resolvedProgramId = ResolveDefaultSaveDataReferenceProgramId(programInfo.ProgramId).Value;
|
||||||
return GetCacheStorageSpaceId(out spaceId, resolvedProgramId);
|
return GetCacheStorageSpaceId(out spaceId, resolvedProgramId).Ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result GetCacheStorageSpaceId(out SaveDataSpaceId spaceId, ulong programId)
|
private Result GetCacheStorageSpaceId(out SaveDataSpaceId spaceId, ulong programId)
|
||||||
|
@ -2694,7 +2738,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
UnsafeHelpers.SkipParamInit(out spaceId);
|
UnsafeHelpers.SkipParamInit(out spaceId);
|
||||||
Result res;
|
Result res;
|
||||||
|
|
||||||
// Cache storage on the SD card will always take priority over case storage in NAND
|
// Cache storage on the SD card will always take priority over cache storage in NAND
|
||||||
if (_serviceImpl.IsSdCardAccessible())
|
if (_serviceImpl.IsSdCardAccessible())
|
||||||
{
|
{
|
||||||
res = DoesCacheStorageExist(out bool existsOnSdCard, SaveDataSpaceId.SdUser);
|
res = DoesCacheStorageExist(out bool existsOnSdCard, SaveDataSpaceId.SdUser);
|
||||||
|
@ -2722,8 +2766,8 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
{
|
{
|
||||||
UnsafeHelpers.SkipParamInit(out exists);
|
UnsafeHelpers.SkipParamInit(out exists);
|
||||||
|
|
||||||
var filter = new SaveDataInfoFilter(saveSpaceId, new ProgramId(programId), SaveDataType.Cache,
|
var filter = new SaveDataInfoFilter(ConvertToRealSpaceId(saveSpaceId), new ProgramId(programId),
|
||||||
userId: default, saveDataId: default, index: default, (int)SaveDataRank.Primary);
|
SaveDataType.Cache, userId: default, saveDataId: default, index: default, (int)SaveDataRank.Primary);
|
||||||
|
|
||||||
Result result = FindSaveDataWithFilterImpl(out long count, out _, saveSpaceId, in filter);
|
Result result = FindSaveDataWithFilterImpl(out long count, out _, saveSpaceId, in filter);
|
||||||
if (result.IsFailure()) return result;
|
if (result.IsFailure()) return result;
|
||||||
|
@ -2954,6 +2998,9 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
|
|
||||||
if (bufferIdCount > 0)
|
if (bufferIdCount > 0)
|
||||||
{
|
{
|
||||||
|
if (idBuffer.IsNull)
|
||||||
|
return ResultFs.NullptrArgument.Log();
|
||||||
|
|
||||||
ids = idBuffer.AsSpan<Ncm.ApplicationId>();
|
ids = idBuffer.AsSpan<Ncm.ApplicationId>();
|
||||||
|
|
||||||
if (ids.Length < bufferIdCount)
|
if (ids.Length < bufferIdCount)
|
||||||
|
@ -3015,8 +3062,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
|
|
||||||
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
using Path saveDataRootPath = _saveDataRootPath.DangerousGetPath();
|
||||||
res = _serviceImpl.OpenSaveDataFileSystem(ref fileSystem.Ref, value.SpaceId, saveDataId,
|
res = _serviceImpl.OpenSaveDataFileSystem(ref fileSystem.Ref, value.SpaceId, saveDataId,
|
||||||
in saveDataRootPath,
|
in saveDataRootPath, openReadOnly: false, saveDataType, cacheExtraData: true);
|
||||||
openReadOnly: false, saveDataType, cacheExtraData: true);
|
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
// Verify the file system.
|
// Verify the file system.
|
||||||
|
@ -3027,7 +3073,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// Make sure we don't leak any invalid data.
|
// Make sure we don't leak any data.
|
||||||
workBuffer.Buffer.Clear();
|
workBuffer.Buffer.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3305,8 +3351,12 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
|
|
||||||
public Result RecoverProvisionallyCommittedSaveData(in SaveDataInfo saveInfo, bool doRollback)
|
public Result RecoverProvisionallyCommittedSaveData(in SaveDataInfo saveInfo, bool doRollback)
|
||||||
{
|
{
|
||||||
|
ulong saveDataId = IsStaticSaveDataIdValueRange(saveInfo.SaveDataId)
|
||||||
|
? saveInfo.SaveDataId
|
||||||
|
: InvalidSystemSaveDataId;
|
||||||
|
|
||||||
Result res = SaveDataAttribute.Make(out SaveDataAttribute attribute, saveInfo.ProgramId, saveInfo.Type,
|
Result res = SaveDataAttribute.Make(out SaveDataAttribute attribute, saveInfo.ProgramId, saveInfo.Type,
|
||||||
saveInfo.UserId, saveInfo.SaveDataId, saveInfo.Index);
|
saveInfo.UserId, saveDataId, saveInfo.Index);
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
using var fileSystem = new SharedRef<IFileSystem>();
|
using var fileSystem = new SharedRef<IFileSystem>();
|
||||||
|
@ -3333,8 +3383,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
{
|
{
|
||||||
using SharedRef<SaveDataFileSystemService> saveService = GetSharedFromThis();
|
using SharedRef<SaveDataFileSystemService> saveService = GetSharedFromThis();
|
||||||
|
|
||||||
Result res = Utility.MakeUniqueLockWithPin(ref outSemaphoreLock, _openEntryCountSemaphore,
|
Result res = Utility.MakeUniqueLockWithPin(ref outSemaphoreLock, _openEntryCountSemaphore, ref saveService.Ref);
|
||||||
ref saveService.Ref);
|
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@ -3344,8 +3393,7 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
{
|
{
|
||||||
using SharedRef<SaveDataFileSystemService> saveService = GetSharedFromThis();
|
using SharedRef<SaveDataFileSystemService> saveService = GetSharedFromThis();
|
||||||
|
|
||||||
Result res = Utility.MakeUniqueLockWithPin(ref outSemaphoreLock, _saveDataMountCountSemaphore,
|
Result res = Utility.MakeUniqueLockWithPin(ref outSemaphoreLock, _saveDataMountCountSemaphore, ref saveService.Ref);
|
||||||
ref saveService.Ref);
|
|
||||||
if (res.IsFailure()) return res.Miss();
|
if (res.IsFailure()) return res.Miss();
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@ -3407,8 +3455,23 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
|
|
||||||
if (isInitialOpen)
|
if (isInitialOpen)
|
||||||
{
|
{
|
||||||
CleanUpSaveData(accessor.Get).IgnoreResult();
|
Unsafe.SkipInit(out Array80<byte> stringBuffer);
|
||||||
CompleteSaveDataExtension(accessor.Get).IgnoreResult();
|
|
||||||
|
Result result = CleanUpSaveData(accessor.Get);
|
||||||
|
if (result.IsFailure())
|
||||||
|
{
|
||||||
|
var sb = new U8StringBuilder(stringBuffer, true);
|
||||||
|
sb.Append("[fs] Failed to clean up save data ("u8).AppendFormat(result.Value, 'x').Append(")\n"u8);
|
||||||
|
Hos.Diag.Impl.LogImpl(Log.EmptyModuleName, LogSeverity.Info, sb.Buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = CompleteSaveDataExtension(accessor.Get);
|
||||||
|
if (result.IsFailure())
|
||||||
|
{
|
||||||
|
var sb = new U8StringBuilder(stringBuffer, true);
|
||||||
|
sb.Append("[fs] Failed to complete save data extension ("u8).AppendFormat(result.Value, 'x').Append(")\n"u8);
|
||||||
|
Hos.Diag.Impl.LogImpl(Log.EmptyModuleName, LogSeverity.Info, sb.Buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outAccessor.Set(ref accessor.Ref);
|
outAccessor.Set(ref accessor.Ref);
|
||||||
|
@ -3419,14 +3482,13 @@ internal class SaveDataFileSystemService : ISaveDataTransferCoreInterface, ISave
|
||||||
in SaveDataCreationInfo creationInfo, in SaveDataMetaInfo metaInfo, in Optional<HashSalt> hashSalt,
|
in SaveDataCreationInfo creationInfo, in SaveDataMetaInfo metaInfo, in Optional<HashSalt> hashSalt,
|
||||||
bool leaveUnfinalized)
|
bool leaveUnfinalized)
|
||||||
{
|
{
|
||||||
return CreateSaveDataFileSystemCore(in attribute, in creationInfo, in metaInfo, in hashSalt,
|
return CreateSaveDataFileSystemCore(in attribute, in creationInfo, in metaInfo, in hashSalt, leaveUnfinalized);
|
||||||
leaveUnfinalized);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ISaveDataTransferCoreInterface.ReadSaveDataFileSystemExtraDataCore(out SaveDataExtraData extraData,
|
Result ISaveDataTransferCoreInterface.ReadSaveDataFileSystemExtraDataCore(out SaveDataExtraData outExtraData,
|
||||||
SaveDataSpaceId spaceId, ulong saveDataId, bool isTemporarySaveData)
|
SaveDataSpaceId spaceId, ulong saveDataId, bool isTemporarySaveData)
|
||||||
{
|
{
|
||||||
return ReadSaveDataFileSystemExtraDataCore(out extraData, spaceId, saveDataId, isTemporarySaveData);
|
return ReadSaveDataFileSystemExtraDataCore(out outExtraData, spaceId, saveDataId, isTemporarySaveData);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ISaveDataTransferCoreInterface.WriteSaveDataFileSystemExtraDataCore(SaveDataSpaceId spaceId,
|
Result ISaveDataTransferCoreInterface.WriteSaveDataFileSystemExtraDataCore(SaveDataSpaceId spaceId,
|
||||||
|
|
|
@ -11,6 +11,7 @@ public readonly ref struct InBuffer
|
||||||
|
|
||||||
public int Size => _buffer.Length;
|
public int Size => _buffer.Length;
|
||||||
public ReadOnlySpan<byte> Buffer => _buffer;
|
public ReadOnlySpan<byte> Buffer => _buffer;
|
||||||
|
public bool IsNull => Unsafe.IsNullRef(ref MemoryMarshal.GetReference(_buffer));
|
||||||
|
|
||||||
public InBuffer(ReadOnlySpan<byte> buffer)
|
public InBuffer(ReadOnlySpan<byte> buffer)
|
||||||
{
|
{
|
||||||
|
@ -46,6 +47,7 @@ public readonly ref struct OutBuffer
|
||||||
|
|
||||||
public int Size => _buffer.Length;
|
public int Size => _buffer.Length;
|
||||||
public Span<byte> Buffer => _buffer;
|
public Span<byte> Buffer => _buffer;
|
||||||
|
public bool IsNull => Unsafe.IsNullRef(ref MemoryMarshal.GetReference(_buffer));
|
||||||
|
|
||||||
public OutBuffer(Span<byte> buffer)
|
public OutBuffer(Span<byte> buffer)
|
||||||
{
|
{
|
||||||
|
@ -81,6 +83,7 @@ public readonly ref struct InArray<T> where T : unmanaged
|
||||||
|
|
||||||
public int Size => _array.Length;
|
public int Size => _array.Length;
|
||||||
public ReadOnlySpan<T> Array => _array;
|
public ReadOnlySpan<T> Array => _array;
|
||||||
|
public bool IsNull => Unsafe.IsNullRef(ref MemoryMarshal.GetReference(_array));
|
||||||
|
|
||||||
public InArray(ReadOnlySpan<T> array)
|
public InArray(ReadOnlySpan<T> array)
|
||||||
{
|
{
|
||||||
|
@ -96,6 +99,7 @@ public readonly ref struct OutArray<T> where T : unmanaged
|
||||||
|
|
||||||
public int Size => _array.Length;
|
public int Size => _array.Length;
|
||||||
public Span<T> Array => _array;
|
public Span<T> Array => _array;
|
||||||
|
public bool IsNull => Unsafe.IsNullRef(ref MemoryMarshal.GetReference(_array));
|
||||||
|
|
||||||
public OutArray(Span<T> array)
|
public OutArray(Span<T> array)
|
||||||
{
|
{
|
||||||
|
|
|
@ -455,7 +455,7 @@ public class PathFormatterTests
|
||||||
flags.AllowWindowsPath();
|
flags.AllowWindowsPath();
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
flags.AllowAllCharacters();
|
flags.AllowInvalidCharacter();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
|
|
Loading…
Reference in a new issue