public static Result EnsureApplicationSaveData(FileSystemClient fs, out long requiredSize, TitleId applicationId, ref ApplicationControlProperty nacp, ref Uid uid) { requiredSize = default; long requiredSizeSum = 0; // 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)); // The 0x4c000 includes the save meta and other stuff Result rc = EnsureAndExtendSaveData(fs, CreateAccountSaveFunc, ref requiredSizeSum, ref filter, 0x4c000, accountSaveDataSize, accountSaveJournalSize); 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 = EnsureAndExtendSaveData(fs, CreateDeviceSaveFunc, ref requiredSizeSum, ref filter, 0x4000, deviceSaveDataSize, deviceSaveJournalSize); if (rc.IsFailure()) { return(rc); } } Result bcatRc = EnsureApplicationBcatDeliveryCacheStorageImpl(fs, out long requiredSizeBcat, applicationId, ref nacp); if (bcatRc.IsFailure()) { if (!ResultFs.InsufficientFreeSpace.Includes(bcatRc)) { return(bcatRc); } requiredSizeSum += requiredSizeBcat; } if (nacp.TemporaryStorageSize > 0) { 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.SetProgramId(applicationId); filter.SetSaveDataType(SaveDataType.Temporary); Result rc = fs.FindSaveDataWithFilter(out _, SaveDataSpaceId.Temporary, ref filter); if (rc.IsFailure()) { if (!ResultFs.TargetNotFound.Includes(rc)) { return(rc); } Result queryRc = fs.QuerySaveDataTotalSize(out long tempSaveTotalSize, nacp.TemporaryStorageSize, 0); if (queryRc.IsFailure()) { return(queryRc); } requiredSizeSum += Util.AlignUp(tempSaveTotalSize, 0x4000) + 0x4000; } } else { Result createRc = fs.CreateTemporaryStorage(applicationId, nacp.SaveDataOwnerId, nacp.TemporaryStorageSize, 0); if (createRc.IsFailure()) { if (ResultFs.InsufficientFreeSpace.Includes(createRc)) { Result queryRc = fs.QuerySaveDataTotalSize(out long tempSaveTotalSize, nacp.TemporaryStorageSize, 0); if (queryRc.IsFailure()) { return(queryRc); } requiredSizeSum += Util.AlignUp(tempSaveTotalSize, 0x4000) + 0x4000; } else if (ResultFs.PathAlreadyExists.Includes(createRc)) { requiredSizeSum += 0; } else { return(createRc); } } } } requiredSize = requiredSizeSum; return(requiredSize == 0 ? Result.Success : ResultFs.InsufficientFreeSpace.Log()); }