Add or update some save data FS shim classes for 14.0.0

- SaveData
- SaveDataForDebug
- SaveDataManagement
This commit is contained in:
Alex Barney 2022-04-30 01:13:10 -07:00
parent 0875f5950c
commit 366aa51912
4 changed files with 345 additions and 24 deletions

View file

@ -241,6 +241,16 @@ namespace LibHac.Fs.Impl
} }
} }
public ReadOnlySpan<byte> ToString(SaveDataFormatType value)
{
switch (value)
{
case SaveDataFormatType.Normal: return new[] { (byte)'N', (byte)'o', (byte)'r', (byte)'m', (byte)'a', (byte)'l' };
case SaveDataFormatType.NoJournal: return new[] { (byte)'N', (byte)'o', (byte)'J', (byte)'o', (byte)'u', (byte)'r', (byte)'n', (byte)'a', (byte)'l' };
default: return ToValueString((int)value);
}
}
public ReadOnlySpan<byte> ToString(ContentType value) public ReadOnlySpan<byte> ToString(ContentType value)
{ {
switch (value) switch (value)
@ -1083,6 +1093,16 @@ namespace LibHac.Fs.Impl
(byte)'d', (byte)':', (byte)' ' (byte)'d', (byte)':', (byte)' '
}; };
/// <summary>"<c>, save_data_format_type: </c>"</summary>
public static ReadOnlySpan<byte> LogSaveDataFormatType => // ", save_data_format_type: "
new[]
{
(byte)',', (byte)' ', (byte)'s', (byte)'a', (byte)'v', (byte)'e', (byte)'_', (byte)'d',
(byte)'a', (byte)'t', (byte)'a', (byte)'_', (byte)'f', (byte)'o', (byte)'r', (byte)'m',
(byte)'a', (byte)'t', (byte)'_', (byte)'t', (byte)'y', (byte)'p', (byte)'e', (byte)':',
(byte)' '
};
/// <summary>"<c>, save_data_time_stamp: </c>"</summary> /// <summary>"<c>, save_data_time_stamp: </c>"</summary>
public static ReadOnlySpan<byte> LogSaveDataTimeStamp => // ", save_data_time_stamp: " public static ReadOnlySpan<byte> LogSaveDataTimeStamp => // ", save_data_time_stamp: "
new[] new[]

View file

@ -6,7 +6,7 @@ using LibHac.Fs.Impl;
using LibHac.FsSrv.Sf; using LibHac.FsSrv.Sf;
using LibHac.Ncm; using LibHac.Ncm;
using LibHac.Os; using LibHac.Os;
using LibHac.Util;
using static LibHac.Fs.Impl.AccessLogStrings; using static LibHac.Fs.Impl.AccessLogStrings;
using static LibHac.Fs.SaveData; using static LibHac.Fs.SaveData;
using IFileSystem = LibHac.Fs.Fsa.IFileSystem; using IFileSystem = LibHac.Fs.Fsa.IFileSystem;
@ -17,12 +17,12 @@ namespace LibHac.Fs.Shim;
/// <summary> /// <summary>
/// Contains functions for mounting save data and checking if save data already exists or not. /// Contains functions for mounting save data and checking if save data already exists or not.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 13.4.0</remarks> /// <remarks>Based on nnSdk 14.3.0</remarks>
[SkipLocalsInit] [SkipLocalsInit]
public static class SaveData public static class SaveData
{ {
private const long SaveDataSizeForDebug = 0x2000000; private const long SaveDataTotalSizeMax = 0xFA000000;
private const long SaveDataJournalSizeForDebug = 0x2000000; private const int SaveDataBlockSize = 0x4000;
private static Result OpenSaveDataInternalStorageFileSystemImpl(FileSystemClient fs, private static Result OpenSaveDataInternalStorageFileSystemImpl(FileSystemClient fs,
ref UniqueRef<IFileSystem> outFileSystem, SaveDataSpaceId spaceId, ulong saveDataId) ref UniqueRef<IFileSystem> outFileSystem, SaveDataSpaceId spaceId, ulong saveDataId)
@ -42,6 +42,39 @@ public static class SaveData
return Result.Success; return Result.Success;
} }
private static Result ExtendSaveDataIfNeeded(FileSystemClient fs, UserId userId, long saveDataSize,
long saveDataJournalSize)
{
// Find the save data for the current program.
Result rc = SaveDataFilter.Make(out SaveDataFilter filter, InvalidProgramId.Value, SaveDataType.Account, userId,
InvalidSystemSaveDataId, index: 0, SaveDataRank.Primary);
if (rc.IsFailure()) return rc.Miss();
rc = fs.Impl.FindSaveDataWithFilter(out SaveDataInfo info, SaveDataSpaceId.User, in filter);
if (rc.IsFailure()) return rc.Miss();
SaveDataSpaceId spaceId = info.SpaceId;
ulong saveDataId = info.SaveDataId;
// Get the current save data's sizes.
rc = fs.Impl.GetSaveDataAvailableSize(out long availableSize, spaceId, saveDataId);
if (rc.IsFailure()) return rc.Miss();
rc = fs.Impl.GetSaveDataJournalSize(out long journalSize, spaceId, saveDataId);
if (rc.IsFailure()) return rc.Miss();
// Extend the save data if it's not large enough.
if (availableSize < saveDataSize || journalSize < saveDataJournalSize)
{
long newSaveDataSize = Math.Max(saveDataSize, availableSize);
long newJournalSize = Math.Max(saveDataJournalSize, journalSize);
rc = fs.Impl.ExtendSaveData(spaceId, saveDataId, newSaveDataSize, newJournalSize);
if (rc.IsFailure()) return rc.Miss();
}
return Result.Success;
}
private static Result MountSaveDataImpl(this FileSystemClientImpl fs, U8Span mountName, SaveDataSpaceId spaceId, private static Result MountSaveDataImpl(this FileSystemClientImpl fs, U8Span mountName, SaveDataSpaceId spaceId,
ProgramId programId, UserId userId, SaveDataType type, bool openReadOnly, ushort index) ProgramId programId, UserId userId, SaveDataType type, bool openReadOnly, ushort index)
{ {
@ -84,16 +117,26 @@ public static class SaveData
return Result.Success; return Result.Success;
} }
public static Result EnsureSaveDataForDebug(this FileSystemClientImpl fs, UserId userId) public static Result EnsureSaveDataImpl(this FileSystemClientImpl fs, UserId userId, long saveDataSize,
long saveDataJournalSize, bool extendIfNeeded)
{ {
if (!Alignment.IsAlignedPow2(saveDataSize, SaveDataBlockSize))
return ResultFs.InvalidSize.Log();
if (!Alignment.IsAlignedPow2(saveDataJournalSize, SaveDataBlockSize))
return ResultFs.InvalidSize.Log();
if (saveDataSize + saveDataJournalSize > SaveDataTotalSizeMax)
return ResultFs.InvalidSize.Log();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject(); using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, ProgramId.InvalidId, SaveDataType.Account, Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, InvalidProgramId, SaveDataType.Account,
InvalidUserId, InvalidSystemSaveDataId); userId, InvalidSystemSaveDataId);
if (rc.IsFailure()) return rc; if (rc.IsFailure()) return rc;
rc = SaveDataCreationInfo.Make(out SaveDataCreationInfo creationInfo, SaveDataSizeForDebug, rc = SaveDataCreationInfo.Make(out SaveDataCreationInfo creationInfo, saveDataSize, saveDataJournalSize,
SaveDataJournalSizeForDebug, default, SaveDataFlags.None, SaveDataSpaceId.User); ownerId: 0, SaveDataFlags.None, SaveDataSpaceId.User);
if (rc.IsFailure()) return rc.Miss(); if (rc.IsFailure()) return rc.Miss();
var metaInfo = new SaveDataMetaInfo var metaInfo = new SaveDataMetaInfo
@ -106,17 +149,25 @@ public static class SaveData
if (rc.IsFailure()) if (rc.IsFailure())
{ {
// Return successfully if the save data already exists // Ensure the save is large enough if it already exists
if (ResultFs.PathAlreadyExists.Includes(rc)) if (ResultFs.PathAlreadyExists.Includes(rc))
rc.Catch(); {
if (extendIfNeeded)
{
rc = ExtendSaveDataIfNeeded(fs.Fs, userId, saveDataSize, saveDataJournalSize);
if (rc.IsFailure()) return rc.Miss();
}
}
else else
{
return rc.Miss(); return rc.Miss();
}
} }
return Result.Success; return Result.Success;
} }
public static Result MountSaveData(this FileSystemClientImpl fs, U8Span mountName, UserId userId) public static Result MountSaveDataImpl(this FileSystemClientImpl fs, U8Span mountName, UserId userId)
{ {
return MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, ProgramId.InvalidId, userId, return MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, ProgramId.InvalidId, userId,
SaveDataType.Account, openReadOnly: false, index: 0); SaveDataType.Account, openReadOnly: false, index: 0);
@ -130,7 +181,7 @@ public static class SaveData
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application)) if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{ {
Tick start = fs.Hos.Os.GetSystemTick(); Tick start = fs.Hos.Os.GetSystemTick();
rc = MountSaveData(fs.Impl, mountName, InvalidUserId); rc = MountSaveDataImpl(fs.Impl, mountName, InvalidUserId);
Tick end = fs.Hos.Os.GetSystemTick(); Tick end = fs.Hos.Os.GetSystemTick();
var sb = new U8StringBuilder(logBuffer, true); var sb = new U8StringBuilder(logBuffer, true);
@ -141,7 +192,7 @@ public static class SaveData
} }
else else
{ {
rc = MountSaveData(fs.Impl, mountName, InvalidUserId); rc = MountSaveDataImpl(fs.Impl, mountName, InvalidUserId);
} }
fs.Impl.AbortIfNeeded(rc); fs.Impl.AbortIfNeeded(rc);
@ -150,7 +201,7 @@ public static class SaveData
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application)) if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName); fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return rc; return Result.Success;
} }
public static Result MountSaveData(this FileSystemClient fs, U8Span mountName, Ncm.ApplicationId applicationId, public static Result MountSaveData(this FileSystemClient fs, U8Span mountName, Ncm.ApplicationId applicationId,
@ -185,7 +236,7 @@ public static class SaveData
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application)) if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName); fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return rc; return Result.Success;
} }
public static Result MountSaveDataReadOnly(this FileSystemClient fs, U8Span mountName, public static Result MountSaveDataReadOnly(this FileSystemClient fs, U8Span mountName,
@ -220,7 +271,7 @@ public static class SaveData
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application)) if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName); fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return rc; return Result.Success;
} }
public static Result IsSaveDataExisting(this FileSystemClientImpl fs, out bool exists, UserId userId) public static Result IsSaveDataExisting(this FileSystemClientImpl fs, out bool exists, UserId userId)
@ -292,7 +343,7 @@ public static class SaveData
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application)) if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName); fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return rc; return Result.Success;
} }
public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName) public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName)
@ -324,7 +375,7 @@ public static class SaveData
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application)) if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName); fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return rc; return Result.Success;
} }
public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName, int index) public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName, int index)
@ -358,7 +409,7 @@ public static class SaveData
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application)) if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName); fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return rc; return Result.Success;
} }
public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName, Ncm.ApplicationId applicationId) public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName, Ncm.ApplicationId applicationId)
@ -391,7 +442,7 @@ public static class SaveData
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System)) if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName); fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return rc; return Result.Success;
} }
public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName, Ncm.ApplicationId applicationId, public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName, Ncm.ApplicationId applicationId,
@ -426,7 +477,7 @@ public static class SaveData
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System)) if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName); fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return rc; return Result.Success;
} }
public static Result OpenSaveDataInternalStorageFileSystem(this FileSystemClient fs, public static Result OpenSaveDataInternalStorageFileSystem(this FileSystemClient fs,

View file

@ -0,0 +1,189 @@
using System;
using System.Runtime.CompilerServices;
using LibHac.Common;
using LibHac.Diag;
using LibHac.Fs.Impl;
using LibHac.FsSrv.Sf;
using LibHac.Os;
using static LibHac.Fs.Impl.AccessLogStrings;
using static LibHac.Fs.SaveData;
namespace LibHac.Fs.Shim;
/// <summary>
/// Contains save data functions used for debugging during development.
/// </summary>
/// <remarks>Based on nnSdk 14.3.0</remarks>
[SkipLocalsInit]
public static class SaveDataForDebug
{
private const long SaveDataSizeForDebug = 0x2000000;
private const long SaveDataJournalSizeForDebug = 0x2000000;
public static void SetSaveDataRootPath(this FileSystemClient fs, U8Span path)
{
Result rc;
Span<byte> logBuffer = stackalloc byte[0x300];
if (fs.Impl.IsEnabledAccessLog() && fs.Impl.IsEnabledHandleAccessLog(null))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = SetRootPath(fs, path);
Tick end = fs.Hos.Os.GetSystemTick();
var sb = new U8StringBuilder(logBuffer, true);
sb.Append(LogPath).Append(path).Append(LogQuote);
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
}
else
{
rc = SetRootPath(fs, path);
}
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnlessSuccess(rc);
static Result SetRootPath(FileSystemClient fs, U8Span path)
{
Result rc = PathUtility.ConvertToFspPath(out FspPath sfPath, path);
if (rc.IsFailure()) return rc.Miss();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
rc = fileSystemProxy.Get.SetSaveDataRootPath(in sfPath);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
public static void UnsetSaveDataRootPath(this FileSystemClient fs)
{
Result rc;
if (fs.Impl.IsEnabledAccessLog() && fs.Impl.IsEnabledHandleAccessLog(null))
{
Tick start = fs.Hos.Os.GetSystemTick();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
rc = fileSystemProxy.Get.UnsetSaveDataRootPath();
Tick end = fs.Hos.Os.GetSystemTick();
fs.Impl.OutputAccessLog(rc, start, end, null, U8Span.Empty);
}
else
{
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.Impl.GetFileSystemProxyServiceObject();
rc = fileSystemProxy.Get.UnsetSaveDataRootPath();
}
fs.Impl.LogResultErrorMessage(rc);
Abort.DoAbortUnlessSuccess(rc);
}
/// <summary>
/// Ensures the current application's debug save data is at least as large as the specified values.
/// </summary>
/// <remarks>Each application can have a single debug save. This save data is not associated with any
/// user account and is intended for debug use when developing an application.</remarks>
/// <param name="fs">The <see cref="FileSystemClient"/> to use.</param>
/// <param name="saveDataSize">The size of the usable space in the save data.</param>
/// <param name="saveDataJournalSize">The size of the save data's journal.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.TargetNotFound"/>: The save data was not found.<br/>
/// <see cref="ResultFs.TargetLocked"/>: The save data is currently open or otherwise in use.<br/>
/// <see cref="ResultFs.UsableSpaceNotEnough"/>: Insufficient free space to create or extend the save data.<br/>
/// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.</returns>
public static Result EnsureSaveDataForDebug(this FileSystemClient fs, long saveDataSize, long saveDataJournalSize)
{
Result rc;
Span<byte> logBuffer = stackalloc byte[0x60];
if (fs.Impl.IsEnabledAccessLog() && fs.Impl.IsEnabledHandleAccessLog(null))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = Ensure(fs, saveDataSize, saveDataJournalSize);
Tick end = fs.Hos.Os.GetSystemTick();
var sb = new U8StringBuilder(logBuffer, true);
sb.Append(LogSaveDataSize).AppendFormat(saveDataSize, 'd')
.Append(LogSaveDataJournalSize).AppendFormat(saveDataJournalSize, 'd');
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
}
else
{
rc = Ensure(fs, saveDataSize, saveDataJournalSize);
}
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
static Result Ensure(FileSystemClient fs, long saveDataSize, long saveDataJournalSize)
{
UserId userIdForDebug = InvalidUserId;
Result rc = fs.Impl.EnsureSaveDataImpl(userIdForDebug, saveDataSize, saveDataJournalSize,
extendIfNeeded: true);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
/// <summary>
/// Mounts the debug save data for the current application. Each application can have its own debug save
/// that is not associated with any user account.
/// </summary>
/// <remarks>Each application can have a single debug save. This save data is not associated with any
/// user account and is intended for debug use when developing an application.</remarks>
/// <param name="fs">The <see cref="FileSystemClient"/> to use.</param>
/// <param name="mountName">The mount name at which the file system will be mounted.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.<br/>
/// <see cref="ResultFs.TargetNotFound"/>: The save data was not found.<br/>
/// <see cref="ResultFs.TargetLocked"/>: The save data is currently open or otherwise in use.<br/>
/// <see cref="ResultFs.PermissionDenied"/>: Insufficient permissions.</returns>
public static Result MountSaveDataForDebug(this FileSystemClient fs, U8Span mountName)
{
Result rc;
Span<byte> logBuffer = stackalloc byte[0x30];
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = Mount(fs, mountName);
Tick end = fs.Hos.Os.GetSystemTick();
var sb = new U8StringBuilder(logBuffer, true);
sb.Append(LogName).Append(mountName).Append(LogQuote);
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
}
else
{
rc = Mount(fs, mountName);
}
if (rc.IsFailure()) return rc.Miss();
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.Application))
fs.Impl.EnableFileSystemAccessorAccessLog(mountName);
return Result.Success;
static Result Mount(FileSystemClient fs, U8Span mountName)
{
UserId userIdForDebug = InvalidUserId;
Result rc = fs.Impl.EnsureSaveDataImpl(userIdForDebug, SaveDataSizeForDebug, SaveDataJournalSizeForDebug,
extendIfNeeded: false);
if (rc.IsFailure()) return rc.Miss();
rc = fs.Impl.MountSaveDataImpl(mountName, userIdForDebug);
if (rc.IsFailure()) return rc.Miss();
return Result.Success;
}
}
}

View file

@ -21,7 +21,7 @@ namespace LibHac.Fs
/// <summary> /// <summary>
/// Allows iterating through the <see cref="SaveDataInfo"/> of a list of save data. /// Allows iterating through the <see cref="SaveDataInfo"/> of a list of save data.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 13.4.0</remarks> /// <remarks>Based on nnSdk 14.3.0</remarks>
public class SaveDataIterator : IDisposable public class SaveDataIterator : IDisposable
{ {
private readonly FileSystemClient _fsClient; private readonly FileSystemClient _fsClient;
@ -81,10 +81,12 @@ namespace LibHac.Fs.Shim
/// <summary> /// <summary>
/// Contains functions for creating, deleting, and otherwise managing save data. /// Contains functions for creating, deleting, and otherwise managing save data.
/// </summary> /// </summary>
/// <remarks>Based on nnSdk 13.4.0</remarks> /// <remarks>Based on nnSdk 14.3.0</remarks>
[SkipLocalsInit] [SkipLocalsInit]
public static class SaveDataManagement public static class SaveDataManagement
{ {
private const int SaveDataBlockSize = 0x4000;
private class CacheStorageListCache : IDisposable private class CacheStorageListCache : IDisposable
{ {
public readonly struct CacheEntry public readonly struct CacheEntry
@ -990,6 +992,65 @@ namespace LibHac.Fs.Shim
return CreateSystemSaveData(fs, spaceId, saveDataId, InvalidUserId, ownerId, size, journalSize, flags); return CreateSystemSaveData(fs, spaceId, saveDataId, InvalidUserId, ownerId, size, journalSize, flags);
} }
public static Result CreateSystemSaveData(this FileSystemClientImpl fs, SaveDataSpaceId spaceId,
ulong saveDataId, UserId userId, ulong ownerId, long size, long journalSize, SaveDataFlags flags,
SaveDataFormatType formatType)
{
if (formatType == SaveDataFormatType.NoJournal && journalSize != 0)
return ResultFs.InvalidArgument.Log();
using SharedRef<IFileSystemProxy> fileSystemProxy = fs.GetFileSystemProxyServiceObject();
Result rc = SaveDataAttribute.Make(out SaveDataAttribute attribute, InvalidProgramId, SaveDataType.System,
userId, saveDataId);
if (rc.IsFailure()) return rc.Miss();
rc = SaveDataCreationInfo2.Make(out SaveDataCreationInfo2 creationInfo, in attribute, size, journalSize,
SaveDataBlockSize, ownerId, flags, spaceId, formatType);
if (rc.IsFailure()) return rc.Miss();
creationInfo.MetaType = SaveDataMetaType.None;
creationInfo.MetaSize = 0;
return fileSystemProxy.Get.CreateSaveDataFileSystemWithCreationInfo2(in creationInfo).Ret();
}
public static Result CreateSystemSaveData(this FileSystemClient fs, SaveDataSpaceId spaceId, ulong saveDataId,
ulong ownerId, long size, long journalSize, SaveDataFlags flags, SaveDataFormatType formatType)
{
Result rc;
Span<byte> logBuffer = stackalloc byte[0x180];
if (fs.Impl.IsEnabledAccessLog(AccessLogTarget.System) && fs.Impl.IsEnabledHandleAccessLog(null))
{
Tick start = fs.Hos.Os.GetSystemTick();
rc = CreateSystemSaveData(fs.Impl, spaceId, saveDataId, InvalidUserId, ownerId, size, journalSize,
flags, formatType);
Tick end = fs.Hos.Os.GetSystemTick();
var idString = new IdString();
var sb = new U8StringBuilder(logBuffer, true);
sb.Append(LogSaveDataSpaceId).Append(idString.ToString(spaceId))
.Append(LogSaveDataId).AppendFormat(saveDataId, 'X')
.Append(LogUserId).AppendFormat(InvalidUserId.Id.High, 'X', 16).AppendFormat(InvalidUserId.Id.Low, 'X', 16)
.Append(LogSaveDataOwnerId).AppendFormat(ownerId, 'X')
.Append(LogSaveDataSize).AppendFormat(size, 'd')
.Append(LogSaveDataJournalSize).AppendFormat(journalSize, 'd')
.Append(LogSaveDataFlags).AppendFormat((int)flags, 'X', 8)
.Append(LogSaveDataFormatType).Append(idString.ToString(formatType));
fs.Impl.OutputAccessLog(rc, start, end, null, new U8Span(sb.Buffer));
}
else
{
rc = CreateSystemSaveData(fs.Impl, spaceId, saveDataId, InvalidUserId, ownerId, size, journalSize,
flags, formatType);
}
fs.Impl.AbortIfNeeded(rc);
return rc;
}
public static Result ExtendSaveData(this FileSystemClientImpl fs, SaveDataSpaceId spaceId, ulong saveDataId, public static Result ExtendSaveData(this FileSystemClientImpl fs, SaveDataSpaceId spaceId, ulong saveDataId,
long saveDataSize, long journalSize) long saveDataSize, long journalSize)
{ {