public static Result EnsureApplicationSaveData(FileSystemClient fs, out long requiredSize, Ncm.ApplicationId applicationId, ref ApplicationControlProperty nacp, ref Uid uid) { requiredSize = default; long requiredSizeSum = 0; // Create local variable for use in closures ProgramId 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.Value, 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.Value, 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 += Utilities.AlignUp(tempSaveTotalSize, 0x4000) + 0x4000; } } else { Result createRc = fs.CreateTemporaryStorage(applicationId, nacp.SaveDataOwnerId.Value, 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 += Utilities.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()); }
public static Result EnsureApplicationSaveData(FileSystemClient fs, out long requiredSize, TitleId applicationId, ref ApplicationControlProperty nacp, ref Uid uid) { requiredSize = default; long requiredSizeSum = 0; if (uid != Uid.Zero && nacp.UserAccountSaveDataSize > 0) { var filter = new SaveDataFilter(); filter.SetTitleId(applicationId); filter.SetSaveDataType(SaveDataType.SaveData); filter.SetUserId(new UserId(uid.Id.High, uid.Id.Low)); Result rc = fs.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter); if (rc.IsSuccess()) { rc = ExtendSaveDataIfNeeded(fs, out long requiredSizeUser, SaveDataSpaceId.User, saveDataInfo.SaveDataId, nacp.UserAccountSaveDataSize, nacp.UserAccountSaveDataJournalSize); if (rc.IsFailure()) { if (!ResultRangeFs.InsufficientFreeSpace.Contains(rc)) { return(rc); } requiredSizeSum = requiredSizeUser; } } else if (rc != ResultFs.TargetNotFound) { return(rc); } else { UserId userId = ConvertAccountUidToFsUserId(uid); Result createRc = fs.CreateSaveData(applicationId, userId, nacp.SaveDataOwnerId, nacp.UserAccountSaveDataSize, nacp.UserAccountSaveDataJournalSize, 0); if (createRc.IsFailure()) { if (ResultRangeFs.InsufficientFreeSpace.Contains(createRc)) { // todo: Call QuerySaveDataTotalSize and assign the value to requiredSizeSum requiredSizeSum = 0; } else if (createRc == ResultFs.PathAlreadyExists) { requiredSizeSum = 0; } else { return(createRc); } } } } if (nacp.DeviceSaveDataSize > 0) { var filter = new SaveDataFilter(); filter.SetTitleId(applicationId); filter.SetSaveDataType(SaveDataType.DeviceSaveData); Result rc = fs.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter); if (rc.IsSuccess()) { rc = ExtendSaveDataIfNeeded(fs, out long requiredSizeDevice, SaveDataSpaceId.User, saveDataInfo.SaveDataId, nacp.DeviceSaveDataSize, nacp.DeviceSaveDataJournalSize); if (rc.IsFailure()) { if (!ResultRangeFs.InsufficientFreeSpace.Contains(rc)) { return(rc); } requiredSizeSum += requiredSizeDevice; } } else if (rc != ResultFs.TargetNotFound) { return(rc); } else { Result createRc = fs.CreateDeviceSaveData(applicationId, nacp.SaveDataOwnerId, nacp.DeviceSaveDataSize, nacp.DeviceSaveDataJournalSize, 0); if (createRc.IsFailure()) { if (ResultRangeFs.InsufficientFreeSpace.Contains(createRc)) { // todo: Call QuerySaveDataTotalSize and add the value to requiredSizeSum requiredSizeSum += 0; } else if (createRc == ResultFs.PathAlreadyExists) { requiredSizeSum += 0; } else { return(createRc); } } } } Result bcatRc = EnsureApplicationBcatDeliveryCacheStorageImpl(fs, out long requiredSizeBcat, applicationId, ref nacp); if (bcatRc.IsFailure()) { if (!ResultRangeFs.InsufficientFreeSpace.Contains(bcatRc)) { return(bcatRc); } requiredSizeSum += requiredSizeBcat; } // Don't actually do this yet because the temp save indexer hasn't been implemented // todo: Flip the operator when it is if (nacp.TemporaryStorageSize < 0) { if (requiredSizeSum > 0) { var filter = new SaveDataFilter(); filter.SetTitleId(applicationId); filter.SetSaveDataType(SaveDataType.TemporaryStorage); Result rc = fs.FindSaveDataWithFilter(out _, SaveDataSpaceId.User, ref filter); if (rc.IsFailure()) { if (rc != ResultFs.TargetNotFound) { return(rc); } // todo: Call QuerySaveDataTotalSize and add the value to requiredSizeSum requiredSizeSum += 0; } } else { Result createRc = fs.CreateTemporaryStorage(applicationId, nacp.SaveDataOwnerId, nacp.TemporaryStorageSize, 0); if (createRc.IsFailure()) { if (ResultRangeFs.InsufficientFreeSpace.Contains(createRc)) { // todo: Call QuerySaveDataTotalSize and assign the value to requiredSizeSum requiredSizeSum += 0; } else if (createRc == ResultFs.PathAlreadyExists) { requiredSizeSum += 0; } else { return(createRc); } } } } requiredSize = requiredSizeSum; return(requiredSize == 0 ? Result.Success : ResultFs.InsufficientFreeSpace.Log()); }