Add more savedata shim functions

This commit is contained in:
Alex Barney 2020-01-05 17:11:42 -07:00
parent b868c8f51a
commit 6abe565de1
4 changed files with 274 additions and 26 deletions

View file

@ -15,6 +15,7 @@ namespace LibHac.Fs
long requiredSizeSum = 0;
// If the application needs a user save
if (uid != Uid.Zero && nacp.UserAccountSaveDataSize > 0)
{
var filter = new SaveDataFilter();
@ -24,8 +25,10 @@ namespace LibHac.Fs
Result rc = fs.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter);
// If the save already exists
if (rc.IsSuccess())
{
// Make sure the save is large enough
rc = ExtendSaveDataIfNeeded(fs, out long requiredSizeUser, SaveDataSpaceId.User,
saveDataInfo.SaveDataId, nacp.UserAccountSaveDataSize, nacp.UserAccountSaveDataJournalSize);
@ -45,6 +48,7 @@ namespace LibHac.Fs
}
else
{
// The save doesn't exist, so try to create it
UserId userId = ConvertAccountUidToFsUserId(uid);
Result createRc = fs.CreateSaveData(applicationId, userId, nacp.SaveDataOwnerId,
@ -52,10 +56,16 @@ namespace LibHac.Fs
if (createRc.IsFailure())
{
// If there's insufficient free space, calculate the space required to create the save
if (ResultRangeFs.InsufficientFreeSpace.Contains(createRc))
{
// todo: Call QuerySaveDataTotalSize and assign the value to requiredSizeSum
requiredSizeSum = 0;
Result queryRc = fs.QuerySaveDataTotalSize(out long userAccountTotalSize,
nacp.UserAccountSaveDataSize, nacp.UserAccountSaveDataJournalSize);
if (queryRc.IsFailure()) return queryRc;
// The 0x4c000 includes the save meta and other stuff
requiredSizeSum = Util.AlignUp(userAccountTotalSize, 0x4000) + 0x4c000;
}
else if (createRc == ResultFs.PathAlreadyExists)
{
@ -105,8 +115,13 @@ namespace LibHac.Fs
{
if (ResultRangeFs.InsufficientFreeSpace.Contains(createRc))
{
// todo: Call QuerySaveDataTotalSize and add the value to requiredSizeSum
requiredSizeSum += 0;
Result queryRc = fs.QuerySaveDataTotalSize(out long deviceSaveTotalSize,
nacp.DeviceSaveDataSize, nacp.DeviceSaveDataJournalSize);
if (queryRc.IsFailure()) return queryRc;
// Not sure what the additional 0x4000 is
requiredSizeSum += Util.AlignUp(deviceSaveTotalSize, 0x4000) + 0x4000;
}
else if (createRc == ResultFs.PathAlreadyExists)
{
@ -139,11 +154,13 @@ namespace LibHac.Fs
{
if (requiredSizeSum > 0)
{
// If there was already insufficient space to create the previous saves, check if the temp
// save already exists instead of trying to create a new one.
var filter = new SaveDataFilter();
filter.SetTitleId(applicationId);
filter.SetSaveDataType(SaveDataType.Temporary);
Result rc = fs.FindSaveDataWithFilter(out _, SaveDataSpaceId.User, ref filter);
Result rc = fs.FindSaveDataWithFilter(out _, SaveDataSpaceId.Temporary, ref filter);
if (rc.IsFailure())
{
@ -152,8 +169,12 @@ namespace LibHac.Fs
return rc;
}
// todo: Call QuerySaveDataTotalSize and add the value to requiredSizeSum
requiredSizeSum += 0;
Result queryRc = fs.QuerySaveDataTotalSize(out long tempSaveTotalSize,
nacp.TemporaryStorageSize, 0);
if (queryRc.IsFailure()) return queryRc;
requiredSizeSum += Util.AlignUp(tempSaveTotalSize, 0x4000) + 0x4000;
}
}
else
@ -165,8 +186,12 @@ namespace LibHac.Fs
{
if (ResultRangeFs.InsufficientFreeSpace.Contains(createRc))
{
// todo: Call QuerySaveDataTotalSize and assign the value to requiredSizeSum
requiredSizeSum += 0;
Result queryRc = fs.QuerySaveDataTotalSize(out long tempSaveTotalSize,
nacp.TemporaryStorageSize, 0);
if (queryRc.IsFailure()) return queryRc;
requiredSizeSum += Util.AlignUp(tempSaveTotalSize, 0x4000) + 0x4000;
}
else if (createRc == ResultFs.PathAlreadyExists)
{
@ -219,7 +244,7 @@ namespace LibHac.Fs
if (rc.IsSuccess())
{
rc = ExtendSaveDataIfNeeded(fs, out long requiredSizeBcat, SaveDataSpaceId.User,
saveDataInfo.SaveDataId, nacp.DeviceSaveDataSize, bcatDeliveryCacheJournalSize);
saveDataInfo.SaveDataId, nacp.BcatDeliveryCacheStorageSize, bcatDeliveryCacheJournalSize);
if (rc.IsFailure())
{
@ -243,8 +268,12 @@ namespace LibHac.Fs
{
if (ResultRangeFs.InsufficientFreeSpace.Contains(createRc))
{
// todo: Call QuerySaveDataTotalSize and assign the value to requiredSize
requiredSize = 0;
Result queryRc = fs.QuerySaveDataTotalSize(out long saveTotalSize,
nacp.BcatDeliveryCacheStorageSize, bcatDeliveryCacheJournalSize);
if (queryRc.IsFailure()) return queryRc;
requiredSize = Util.AlignUp(saveTotalSize, 0x4000) + 0x4000;
}
else if (createRc == ResultFs.PathAlreadyExists)
{
@ -260,6 +289,29 @@ namespace LibHac.Fs
return requiredSize > 0 ? ResultFs.InsufficientFreeSpace.Log() : Result.Success;
}
public static Result CleanUpTemporaryStorage(FileSystemClient fs)
{
var filter = new SaveDataFilter();
filter.SetSaveDataType(SaveDataType.Temporary);
Result rc;
while (true)
{
rc = fs.FindSaveDataWithFilter(out SaveDataInfo saveInfo, SaveDataSpaceId.Temporary, ref filter);
if (rc.IsFailure()) break;
rc = fs.DeleteSaveData(SaveDataSpaceId.Temporary, saveInfo.SaveDataId);
if (rc.IsFailure()) return rc;
}
if (rc == ResultFs.TargetNotFound)
return Result.Success;
return rc;
}
public static UserId ConvertAccountUidToFsUserId(Uid uid)
{
return new UserId(uid.Id.High, uid.Id.Low);

View file

@ -7,21 +7,21 @@ namespace LibHac.Fs.Shim
{
public static class SaveData
{
public static Result MountSaveData(this FileSystemClient fs, U8Span mountName, TitleId titleId, UserId userId)
public static Result MountSaveData(this FileSystemClient fs, U8Span mountName, TitleId applicationId, UserId userId)
{
Result rc;
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
{
TimeSpan startTime = fs.Time.GetCurrent();
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, titleId, userId, SaveDataType.Account, false, 0);
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, userId, SaveDataType.Account, false, 0);
TimeSpan endTime = fs.Time.GetCurrent();
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", applicationid: 0x{titleId}, userid: 0x{userId}");
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", applicationid: 0x{applicationId}, userid: 0x{userId}");
}
else
{
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, titleId, userId, SaveDataType.Account, false, 0);
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, userId, SaveDataType.Account, false, 0);
}
if (rc.IsSuccess() && fs.IsEnabledAccessLog(AccessLogTarget.Application))
@ -32,21 +32,21 @@ namespace LibHac.Fs.Shim
return rc;
}
public static Result MountSaveDataReadOnly(this FileSystemClient fs, U8Span mountName, TitleId titleId, UserId userId)
public static Result MountSaveDataReadOnly(this FileSystemClient fs, U8Span mountName, TitleId applicationId, UserId userId)
{
Result rc;
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
{
TimeSpan startTime = fs.Time.GetCurrent();
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, titleId, userId, SaveDataType.Account, true, 0);
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, userId, SaveDataType.Account, true, 0);
TimeSpan endTime = fs.Time.GetCurrent();
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", applicationid: 0x{titleId}, userid: 0x{userId}");
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", applicationid: 0x{applicationId}, userid: 0x{userId}");
}
else
{
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, titleId, userId, SaveDataType.Account, false, 0);
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, userId, SaveDataType.Account, false, 0);
}
if (rc.IsSuccess() && fs.IsEnabledAccessLog(AccessLogTarget.Application))
@ -57,6 +57,131 @@ namespace LibHac.Fs.Shim
return rc;
}
public static Result MountTemporaryStorage(this FileSystemClient fs, U8Span mountName)
{
Result rc;
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
{
TimeSpan startTime = fs.Time.GetCurrent();
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.Temporary, default, default, SaveDataType.Temporary, false, 0);
TimeSpan endTime = fs.Time.GetCurrent();
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\"");
}
else
{
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.Temporary, default, default, SaveDataType.Temporary, false, 0);
}
if (rc.IsSuccess() && fs.IsEnabledAccessLog(AccessLogTarget.Application))
{
fs.EnableFileSystemAccessorAccessLog(mountName);
}
return rc;
}
public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName)
{
Result rc;
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
{
TimeSpan startTime = fs.Time.GetCurrent();
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, default, default, SaveDataType.Cache, false, 0);
TimeSpan endTime = fs.Time.GetCurrent();
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\"");
}
else
{
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, default, default, SaveDataType.Cache, false, 0);
}
if (rc.IsSuccess() && fs.IsEnabledAccessLog(AccessLogTarget.Application))
{
fs.EnableFileSystemAccessorAccessLog(mountName);
}
return rc;
}
public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName, int index)
{
Result rc;
if (fs.IsEnabledAccessLog(AccessLogTarget.Application))
{
TimeSpan startTime = fs.Time.GetCurrent();
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, default, default, SaveDataType.Cache, false, (short)index);
TimeSpan endTime = fs.Time.GetCurrent();
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", index: {index}");
}
else
{
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, default, default, SaveDataType.Cache, false, (short)index);
}
if (rc.IsSuccess() && fs.IsEnabledAccessLog(AccessLogTarget.Application))
{
fs.EnableFileSystemAccessorAccessLog(mountName);
}
return rc;
}
public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName, TitleId applicationId)
{
Result rc;
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
{
TimeSpan startTime = fs.Time.GetCurrent();
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, default, SaveDataType.Cache, false, 0);
TimeSpan endTime = fs.Time.GetCurrent();
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", applicationid: 0x{applicationId}");
}
else
{
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, default, SaveDataType.Cache, false, 0);
}
if (rc.IsSuccess() && fs.IsEnabledAccessLog(AccessLogTarget.System))
{
fs.EnableFileSystemAccessorAccessLog(mountName);
}
return rc;
}
public static Result MountCacheStorage(this FileSystemClient fs, U8Span mountName, TitleId applicationId, int index)
{
Result rc;
if (fs.IsEnabledAccessLog(AccessLogTarget.System))
{
TimeSpan startTime = fs.Time.GetCurrent();
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, default, SaveDataType.Cache, false, (short)index);
TimeSpan endTime = fs.Time.GetCurrent();
fs.OutputAccessLog(rc, startTime, endTime, $", name: \"{mountName.ToString()}\", applicationid: 0x{applicationId}, index: {index}");
}
else
{
rc = MountSaveDataImpl(fs, mountName, SaveDataSpaceId.User, applicationId, default, SaveDataType.Cache, false, (short)index);
}
if (rc.IsSuccess() && fs.IsEnabledAccessLog(AccessLogTarget.System))
{
fs.EnableFileSystemAccessorAccessLog(mountName);
}
return rc;
}
private static Result MountSaveDataImpl(this FileSystemClient fs, U8Span mountName, SaveDataSpaceId spaceId,
TitleId titleId, UserId userId, SaveDataType type, bool openReadOnly, short index)
{

View file

@ -41,7 +41,7 @@ namespace LibHac.Fs.Shim
return fsProxy.CreateSaveDataFileSystem(ref attribute, ref createInfo, ref metaInfo);
},
() => $", applicationid: 0x{applicationId.Value:X}, userid: 0x{userId}, save_data_owner_id: 0x{ownerId.Value:X}, save_data_size: {size}, save_data_journal_size: {journalSize}, save_data_flags: 0x{(int)flags:x8}");
() => $", applicationid: 0x{applicationId.Value:X}, userid: 0x{userId}, save_data_owner_id: 0x{ownerId.Value:X}, save_data_size: {size}, save_data_journal_size: {journalSize}, save_data_flags: 0x{(int)flags:X8}");
}
public static Result CreateSaveData(this FileSystemClient fs, TitleId applicationId, UserId userId, TitleId ownerId,
@ -77,7 +77,7 @@ namespace LibHac.Fs.Shim
return fsProxy.CreateSaveDataFileSystemWithHashSalt(ref attribute, ref createInfo, ref metaInfo, ref hashSalt);
},
() => $", applicationid: 0x{applicationId.Value:X}, userid: 0x{userId}, save_data_owner_id: 0x{ownerId.Value:X}, save_data_size: {size}, save_data_journal_size: {journalSize}, save_data_flags: 0x{(int)flags:x8}");
() => $", applicationid: 0x{applicationId.Value:X}, userid: 0x{userId}, save_data_owner_id: 0x{ownerId.Value:X}, save_data_size: {size}, save_data_journal_size: {journalSize}, save_data_flags: 0x{(int)flags:X8}");
}
public static Result CreateBcatSaveData(this FileSystemClient fs, TitleId applicationId, long size)
@ -138,7 +138,7 @@ namespace LibHac.Fs.Shim
return fsProxy.CreateSaveDataFileSystem(ref attribute, ref createInfo, ref metaInfo);
},
() => $", applicationid: 0x{applicationId.Value:X}, save_data_owner_id: 0x{ownerId.Value:X}, save_data_size: {size}, save_data_journal_size: {journalSize}, save_data_flags: 0x{(int)flags:x8}");
() => $", applicationid: 0x{applicationId.Value:X}, save_data_owner_id: 0x{ownerId.Value:X}, save_data_size: {size}, save_data_journal_size: {journalSize}, save_data_flags: 0x{(int)flags:X8}");
}
public static Result CreateTemporaryStorage(this FileSystemClient fs, TitleId applicationId, TitleId ownerId, long size, SaveDataFlags flags)
@ -167,7 +167,51 @@ namespace LibHac.Fs.Shim
return fsProxy.CreateSaveDataFileSystem(ref attribute, ref createInfo, ref metaInfo);
},
() => $", applicationid: 0x{applicationId.Value:X}, save_data_owner_id: 0x{ownerId.Value:X}, save_data_size: {size}, save_data_flags: 0x{(int)flags:x8}");
() => $", applicationid: 0x{applicationId.Value:X}, save_data_owner_id: 0x{ownerId.Value:X}, save_data_size: {size}, save_data_flags: 0x{(int)flags:X8}");
}
public static Result CreateCacheStorage(this FileSystemClient fs, TitleId applicationId,
SaveDataSpaceId spaceId, TitleId ownerId, short index, long size, long journalSize, SaveDataFlags flags)
{
return fs.RunOperationWithAccessLog(AccessLogTarget.System,
() =>
{
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
var attribute = new SaveDataAttribute
{
TitleId = applicationId,
Type = SaveDataType.Cache,
Index = index
};
var creationInfo = new SaveDataCreationInfo
{
Size = size,
JournalSize = journalSize,
BlockSize = 0x4000,
OwnerId = ownerId,
Flags = flags,
SpaceId = spaceId
};
var metaInfo = new SaveMetaCreateInfo();
return fsProxy.CreateSaveDataFileSystem(ref attribute, ref creationInfo, ref metaInfo);
},
() => $", applicationid: 0x{applicationId.Value:X}, savedataspaceid: {spaceId}, save_data_owner_id: 0x{ownerId.Value:X}, save_data_size: {size}, save_data_journal_size: {journalSize}, save_data_flags: 0x{(int)flags:X8}");
}
public static Result CreateCacheStorage(this FileSystemClient fs, TitleId applicationId,
SaveDataSpaceId spaceId, TitleId ownerId, long size, long journalSize, SaveDataFlags flags)
{
return CreateCacheStorage(fs, applicationId, spaceId, ownerId, 0, size, journalSize, flags);
}
public static Result CreateCacheStorage(this FileSystemClient fs, TitleId applicationId, TitleId ownerId,
long size, long journalSize, SaveDataFlags flags)
{
return CreateCacheStorage(fs, applicationId, SaveDataSpaceId.User, ownerId, 0, size, journalSize, flags);
}
public static Result CreateSystemSaveData(this FileSystemClient fs, SaveDataSpaceId spaceId,
@ -285,6 +329,29 @@ namespace LibHac.Fs.Shim
return result;
}
public static Result QuerySaveDataTotalSize(this FileSystemClient fs, out long totalSize, long size, long journalSize)
{
totalSize = default;
long totalSizeTemp = 0;
Result result = fs.RunOperationWithAccessLog(AccessLogTarget.System,
() =>
{
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
return fsProxy.QuerySaveDataTotalSize(out totalSizeTemp, size, journalSize);
},
() => $", save_data_size: {size}, save_data_journal_size: {journalSize}");
if (result.IsSuccess())
{
totalSize = totalSizeTemp;
}
return result;
}
public static Result OpenSaveDataIterator(this FileSystemClient fs, out SaveDataIterator iterator, SaveDataSpaceId spaceId)
{
var tempIterator = new SaveDataIterator();

View file

@ -929,7 +929,11 @@ namespace LibHac.FsService
public Result QuerySaveDataTotalSize(out long totalSize, long dataSize, long journalSize)
{
throw new NotImplementedException();
// todo: Implement properly
totalSize = 0;
return Result.Success;
}
public Result SetCurrentPosixTimeWithTimeDifference(long time, int difference)