Esempio n. 1
0
        private static Result EnsureApplicationBcatDeliveryCacheStorageImpl(FileSystemClient fs, out long requiredSize,
                                                                            Ncm.ApplicationId applicationId, ref ApplicationControlProperty nacp)
        {
            const long bcatDeliveryCacheJournalSize = 0x200000;

            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 CreateBcatStorageFunc() => fs.CreateBcatSaveData(applicationId, bcatStorageSize);

            Result rc = EnsureAndExtendSaveData(fs, CreateBcatStorageFunc,
                                                ref requiredSizeBcat, ref filter, 0x4000, bcatStorageSize, bcatDeliveryCacheJournalSize);

            if (rc.IsFailure())
            {
                return(rc);
            }

            requiredSize = requiredSizeBcat;
            return(requiredSizeBcat > 0 ? ResultFs.InsufficientFreeSpace.Log() : Result.Success);
        }
Esempio n. 2
0
        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 (ResultFs.TargetNotFound.Includes(rc))
            {
                return(Result.Success);
            }

            return(rc);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        public static Result TryCreateCacheStorage(this FileSystemClient fs, out long requiredSize,
                                                   SaveDataSpaceId spaceId, Ncm.ApplicationId applicationId, ulong saveDataOwnerId, short index,
                                                   long dataSize, long journalSize, bool allowExisting)
        {
            requiredSize = default;
            long requiredSizeLocal = 0;

            var filter = new SaveDataFilter();

            filter.SetProgramId(applicationId);
            filter.SetIndex(index);
            filter.SetSaveDataType(SaveDataType.Cache);

            Result rc = fs.FindSaveDataWithFilter(out SaveDataInfo info, spaceId, ref filter);

            if (rc.IsFailure())
            {
                if (!ResultFs.TargetNotFound.Includes(rc))
                {
                    return(rc);
                }

                Result CreateCacheFunc() => fs.CreateCacheStorage(applicationId, spaceId, saveDataOwnerId, index,
                                                                  dataSize, journalSize, SaveDataFlags.None);

                rc = CreateSaveData(fs, CreateCacheFunc, ref requiredSizeLocal, 0x4000, dataSize, journalSize);
                if (rc.IsFailure())
                {
                    return(rc);
                }

                requiredSize = requiredSizeLocal;
                return(Result.Success);
            }

            if (!allowExisting)
            {
                return(ResultFs.SaveDataPathAlreadyExists.Log());
            }

            rc = ExtendSaveDataIfNeeded(fs, out requiredSizeLocal, spaceId, info.SaveDataId, dataSize, journalSize);

            if (rc.IsSuccess() || ResultFs.InsufficientFreeSpace.Includes(rc))
            {
                requiredSize = requiredSizeLocal;
                return(Result.Success);
            }

            if (ResultFs.SaveDataIsExtending.Includes(rc))
            {
                return(ResultFs.SaveDataCorrupted.LogConverted(rc));
            }

            return(rc);
        }
Esempio n. 5
0
        public static Result Make(out SaveDataFilter filter, Optional <ulong> programId, Optional <SaveDataType> saveType,
                                  Optional <UserId> userId, Optional <ulong> saveDataId, Optional <ushort> index, SaveDataRank rank)
        {
            UnsafeHelpers.SkipParamInit(out filter);

            SaveDataFilter tempFilter = Make(programId, saveType, userId, saveDataId, index, rank);

            if (!SaveDataTypesValidity.IsValid(in tempFilter))
            {
                return(ResultFs.InvalidArgument.Log());
            }

            filter = tempFilter;
            return(Result.Success);
        }
Esempio n. 6
0
        private static Result GetCacheStorageTargetMediaImpl(this FileSystemClient fs,
                                                             out CacheStorageTargetMedia target, Ncm.ApplicationId applicationId)
        {
            target = CacheStorageTargetMedia.None;

            var filter = new SaveDataFilter();

            filter.SetProgramId(applicationId);
            filter.SetSaveDataType(SaveDataType.Cache);

            if (fs.IsSdCardAccessible())
            {
                Result rc = fs.FindSaveDataWithFilter(out _, SaveDataSpaceId.SdCache, ref filter);
                if (rc.IsFailure() && !ResultFs.TargetNotFound.Includes(rc))
                {
                    return(rc);
                }

                if (rc.IsSuccess())
                {
                    target = CacheStorageTargetMedia.SdCard;
                }
            }

            // Not on the SD card. Check it it's in NAND
            if (target == CacheStorageTargetMedia.None)
            {
                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);
        }
Esempio n. 7
0
        public static SaveDataFilter Make(Optional <ulong> programId, Optional <SaveDataType> saveType,
                                          Optional <UserId> userId, Optional <ulong> saveDataId, Optional <ushort> index, SaveDataRank rank)
        {
            var filter = new SaveDataFilter();

            if (programId.HasValue)
            {
                filter.FilterByProgramId   = true;
                filter.Attribute.ProgramId = new ProgramId(programId.Value);
            }

            if (saveType.HasValue)
            {
                filter.FilterBySaveDataType = true;
                filter.Attribute.Type       = saveType.Value;
            }

            if (userId.HasValue)
            {
                filter.FilterByUserId   = true;
                filter.Attribute.UserId = userId.Value;
            }

            if (saveDataId.HasValue)
            {
                filter.FilterBySaveDataId         = true;
                filter.Attribute.StaticSaveDataId = saveDataId.Value;
            }

            if (index.HasValue)
            {
                filter.FilterByIndex   = true;
                filter.Attribute.Index = index.Value;
            }

            filter.Rank = rank;

            return(filter);
        }
Esempio n. 8
0
        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());
        }
        private static Result EnsureApplicationBcatDeliveryCacheStorageImpl(FileSystemClient fs, out long requiredSize,
                                                                            TitleId applicationId, ref ApplicationControlProperty nacp)
        {
            const long bcatDeliveryCacheJournalSize = 0x200000;

            requiredSize = default;

            if (nacp.BcatDeliveryCacheStorageSize <= 0)
            {
                requiredSize = 0;
                return(Result.Success);
            }

            var filter = new SaveDataFilter();

            filter.SetTitleId(applicationId);
            filter.SetSaveDataType(SaveDataType.BcatDeliveryCacheStorage);

            Result rc = fs.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter);

            if (rc.IsSuccess())
            {
                rc = ExtendSaveDataIfNeeded(fs, out long requiredSizeBcat, SaveDataSpaceId.User,
                                            saveDataInfo.SaveDataId, nacp.DeviceSaveDataSize, bcatDeliveryCacheJournalSize);

                if (rc.IsFailure())
                {
                    if (!ResultRangeFs.InsufficientFreeSpace.Contains(rc))
                    {
                        return(rc);
                    }

                    requiredSize = requiredSizeBcat;
                }
            }
            else if (rc != ResultFs.TargetNotFound)
            {
                return(rc);
            }
            else
            {
                Result createRc = fs.CreateBcatSaveData(applicationId, nacp.BcatDeliveryCacheStorageSize);

                if (createRc.IsFailure())
                {
                    if (ResultRangeFs.InsufficientFreeSpace.Contains(createRc))
                    {
                        // todo: Call QuerySaveDataTotalSize and assign the value to requiredSize
                        requiredSize = 0;
                    }
                    else if (createRc == ResultFs.PathAlreadyExists)
                    {
                        requiredSize = 0;
                    }
                    else
                    {
                        return(createRc);
                    }
                }
            }

            return(requiredSize > 0 ? ResultFs.InsufficientFreeSpace.Log() : Result.Success);
        }
        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());
        }
Esempio n. 11
0
 public static Result Make(out SaveDataFilter filter, Optional <ulong> programId, Optional <SaveDataType> saveType,
                           Optional <UserId> userId, Optional <ulong> saveDataId, Optional <ushort> index)
 {
     return(Make(out filter, programId, saveType, userId, saveDataId, index, SaveDataRank.Primary));
 }