Combine common code in EnsureApplicationSaveData

This commit is contained in:
Alex Barney 2020-02-22 03:05:04 -07:00
parent cfb79f5780
commit 7bef4c6cd9

View File

@ -13,127 +13,55 @@ namespace LibHac.Fs
ref ApplicationControlProperty nacp, ref Uid uid)
{
requiredSize = default;
long requiredSizeSum = 0;
// If the application needs a user save
// Create local variable for use in closures
TitleId saveDataOwnerId = nacp.SaveDataOwnerId;
// Ensure the user account save exists
if (uid != Uid.Zero && nacp.UserAccountSaveDataSize > 0)
{
// More local variables for use in closures
Uid uidLocal = uid;
long accountSaveDataSize = nacp.UserAccountSaveDataSize;
long accountSaveJournalSize = nacp.UserAccountSaveDataJournalSize;
Result CreateAccountSaveFunc()
{
UserId userId = ConvertAccountUidToFsUserId(uidLocal);
return fs.CreateSaveData(applicationId, userId, saveDataOwnerId, accountSaveDataSize,
accountSaveJournalSize, SaveDataFlags.None);
}
var filter = new SaveDataFilter();
filter.SetProgramId(applicationId);
filter.SetSaveDataType(SaveDataType.Account);
filter.SetUserId(new UserId(uid.Id.High, uid.Id.Low));
Result rc = fs.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter);
// The 0x4c000 includes the save meta and other stuff
Result rc = EnsureAndExtendSaveData(fs, CreateAccountSaveFunc, ref requiredSizeSum, ref filter, 0x4c000,
accountSaveDataSize, accountSaveJournalSize);
// 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);
if (rc.IsFailure())
{
if (!ResultFs.InsufficientFreeSpace.Includes(rc))
{
return rc;
}
requiredSizeSum = requiredSizeUser;
}
}
else if (!ResultFs.TargetNotFound.Includes(rc))
{
return rc;
}
else
{
// The save doesn't exist, so try to create it
UserId userId = ConvertAccountUidToFsUserId(uid);
Result createRc = fs.CreateSaveData(applicationId, userId, nacp.SaveDataOwnerId,
nacp.UserAccountSaveDataSize, nacp.UserAccountSaveDataJournalSize, 0);
if (createRc.IsFailure())
{
// If there's insufficient free space, calculate the space required to create the save
if (ResultFs.InsufficientFreeSpace.Includes(createRc))
{
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 (ResultFs.PathAlreadyExists.Includes(createRc))
{
requiredSizeSum = 0;
}
else
{
return createRc;
}
}
}
if (rc.IsFailure()) return rc;
}
// Ensure the device save exists
if (nacp.DeviceSaveDataSize > 0)
{
long deviceSaveDataSize = nacp.DeviceSaveDataSize;
long deviceSaveJournalSize = nacp.DeviceSaveDataJournalSize;
Result CreateDeviceSaveFunc() => fs.CreateDeviceSaveData(applicationId, saveDataOwnerId,
deviceSaveDataSize, deviceSaveJournalSize, 0);
var filter = new SaveDataFilter();
filter.SetProgramId(applicationId);
filter.SetSaveDataType(SaveDataType.Device);
Result rc = fs.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter);
Result rc = EnsureAndExtendSaveData(fs, CreateDeviceSaveFunc, ref requiredSizeSum, ref filter, 0x4000,
deviceSaveDataSize, deviceSaveJournalSize);
if (rc.IsSuccess())
{
rc = ExtendSaveDataIfNeeded(fs, out long requiredSizeDevice, SaveDataSpaceId.User,
saveDataInfo.SaveDataId, nacp.DeviceSaveDataSize, nacp.DeviceSaveDataJournalSize);
if (rc.IsFailure())
{
if (!ResultFs.InsufficientFreeSpace.Includes(rc))
{
return rc;
}
requiredSizeSum += requiredSizeDevice;
}
}
else if (!ResultFs.TargetNotFound.Includes(rc))
{
return rc;
}
else
{
Result createRc = fs.CreateDeviceSaveData(applicationId, nacp.SaveDataOwnerId,
nacp.DeviceSaveDataSize, nacp.DeviceSaveDataJournalSize, 0);
if (createRc.IsFailure())
{
if (ResultFs.InsufficientFreeSpace.Includes(createRc))
{
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 (ResultFs.PathAlreadyExists.Includes(createRc))
{
requiredSizeSum += 0;
}
else
{
return createRc;
}
}
}
if (rc.IsFailure()) return rc;
}
Result bcatRc = EnsureApplicationBcatDeliveryCacheStorageImpl(fs,
@ -244,71 +172,63 @@ namespace LibHac.Fs
return Result.Success;
}
private static Result EnsureAndExtendSaveData(FileSystemClient fs, Func<Result> createFunc,
ref long requiredSize, ref SaveDataFilter filter, long baseSize, long dataSize, long journalSize)
{
Result rc = fs.FindSaveDataWithFilter(out SaveDataInfo info, SaveDataSpaceId.User, ref filter);
if (rc.IsFailure())
{
if (ResultFs.TargetNotFound.Includes(rc))
{
rc = CreateSaveData(fs, createFunc, ref requiredSize, baseSize, dataSize, journalSize);
}
return rc;
}
rc = ExtendSaveDataIfNeeded(fs, out long requiredSizeExtend, SaveDataSpaceId.User, info.SaveDataId,
dataSize, journalSize);
if (rc.IsFailure())
{
if (!ResultFs.InsufficientFreeSpace.Includes(rc))
return rc;
requiredSize += requiredSizeExtend;
}
return Result.Success;
}
private static Result EnsureApplicationBcatDeliveryCacheStorageImpl(FileSystemClient fs, out long requiredSize,
TitleId applicationId, ref ApplicationControlProperty nacp)
{
const long bcatDeliveryCacheJournalSize = 0x200000;
requiredSize = default;
if (nacp.BcatDeliveryCacheStorageSize <= 0)
long bcatStorageSize = nacp.BcatDeliveryCacheStorageSize;
if (bcatStorageSize <= 0)
{
requiredSize = 0;
return Result.Success;
}
requiredSize = default;
long requiredSizeBcat = 0;
var filter = new SaveDataFilter();
filter.SetProgramId(applicationId);
filter.SetSaveDataType(SaveDataType.Bcat);
Result rc = fs.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter);
Result CreateBcatStorageFunc() => fs.CreateBcatSaveData(applicationId, bcatStorageSize);
if (rc.IsSuccess())
{
rc = ExtendSaveDataIfNeeded(fs, out long requiredSizeBcat, SaveDataSpaceId.User,
saveDataInfo.SaveDataId, nacp.BcatDeliveryCacheStorageSize, bcatDeliveryCacheJournalSize);
Result rc = EnsureAndExtendSaveData(fs, CreateBcatStorageFunc,
ref requiredSizeBcat, ref filter, 0x4000, bcatStorageSize, bcatDeliveryCacheJournalSize);
if (rc.IsFailure())
{
if (!ResultFs.InsufficientFreeSpace.Includes(rc))
{
return rc;
}
if (rc.IsFailure()) return rc;
requiredSize = requiredSizeBcat;
}
}
else if (!ResultFs.TargetNotFound.Includes(rc))
{
return rc;
}
else
{
Result createRc = fs.CreateBcatSaveData(applicationId, nacp.BcatDeliveryCacheStorageSize);
if (createRc.IsFailure())
{
if (ResultFs.InsufficientFreeSpace.Includes(createRc))
{
Result queryRc = fs.QuerySaveDataTotalSize(out long saveTotalSize,
nacp.BcatDeliveryCacheStorageSize, bcatDeliveryCacheJournalSize);
if (queryRc.IsFailure()) return queryRc;
requiredSize = Util.AlignUp(saveTotalSize, 0x4000) + 0x4000;
}
else if (ResultFs.PathAlreadyExists.Includes(createRc))
{
requiredSize = 0;
}
else
{
return createRc;
}
}
}
return requiredSize > 0 ? ResultFs.InsufficientFreeSpace.Log() : Result.Success;
requiredSize = requiredSizeBcat;
return requiredSizeBcat > 0 ? ResultFs.InsufficientFreeSpace.Log() : Result.Success;
}
private static Result EnsureApplicationCacheStorageImpl(this FileSystemClient fs, out long requiredSize,
@ -407,6 +327,12 @@ namespace LibHac.Fs
nacp.SaveDataOwnerId, 0, nacp.CacheStorageSize, nacp.CacheStorageJournalSize, true);
}
public static Result EnsureApplicationBcatDeliveryCacheStorage(this FileSystemClient fs, out long requiredSize,
TitleId applicationId, ref ApplicationControlProperty nacp)
{
return EnsureApplicationBcatDeliveryCacheStorageImpl(fs, out requiredSize, applicationId, ref nacp);
}
public static Result TryCreateCacheStorage(this FileSystemClient fs, out long requiredSize,
SaveDataSpaceId spaceId, TitleId applicationId, TitleId saveDataOwnerId, short index, long dataSize,
long journalSize, bool allowExisting)
@ -464,44 +390,35 @@ namespace LibHac.Fs
private static Result GetCacheStorageTargetMediaImpl(this FileSystemClient fs, out CacheStorageTargetMedia target, TitleId applicationId)
{
target = default;
target = CacheStorageTargetMedia.None;
var filter = new SaveDataFilter();
filter.SetProgramId(applicationId);
filter.SetSaveDataType(SaveDataType.Cache);
if (fs.IsSdCardAccessible())
{
var filter = new SaveDataFilter();
filter.SetProgramId(applicationId);
filter.SetSaveDataType(SaveDataType.Cache);
Result rc = fs.FindSaveDataWithFilter(out _, SaveDataSpaceId.SdCache, ref filter);
if (rc.IsFailure() && !ResultFs.TargetNotFound.Includes(rc)) return rc;
if (rc.IsSuccess())
{
target = CacheStorageTargetMedia.SdCard;
return Result.Success;
}
if (!ResultFs.TargetNotFound.Includes(rc))
return rc;
}
// Not on the SD card. Check it it's in NAND
if (target == CacheStorageTargetMedia.None)
{
var filter = new SaveDataFilter();
filter.SetProgramId(applicationId);
filter.SetSaveDataType(SaveDataType.Cache);
Result rc = fs.FindSaveDataWithFilter(out _, SaveDataSpaceId.User, ref filter);
if (rc.IsFailure() && !ResultFs.TargetNotFound.Includes(rc)) return rc;
if (rc.IsSuccess())
{
target = CacheStorageTargetMedia.Nand;
return Result.Success;
}
if (!ResultFs.TargetNotFound.Includes(rc))
return rc;
}
target = CacheStorageTargetMedia.None;
return Result.Success;
}