ダウンロード前にSDカードの容量チェックをしてからタイトルデータベースを作るように

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@604 385bec56-5757-e545-9c3a-d8741f4650f1
This commit is contained in:
N2614 2012-01-25 07:54:55 +00:00
parent 86a7f1526b
commit 4667e4e1c0
5 changed files with 262 additions and 50 deletions

View File

@ -86,6 +86,12 @@ bool s_ExecuteTwlTitleDownload = false;
// TWLタイトルのダウンロードを何回リトライしたか
u32 s_TwlTitleDownloadRetryCount = 0;
// プリインストールタイトルのダウンロード準備を開始したかどうか
bool s_ExecutePreparePreinstallTitleDownload = false;
// プリインストールタイトルのダウンロード準備を何回リトライしたか
u32 s_PreparePreinstallTitleDownloadRetryCount = 0;
// プリインストールタイトルのダウンロードを開始したかどうか
bool s_ExecutePreinstallTitleDownload = false;
// プリインストールタイトルのダウンロードを何回リトライしたか
@ -159,10 +165,12 @@ typedef enum RestoreState
// プリインストールダウンロードモード
PREINSTALL_WAIT_SYNC_TICKET, // 開始ボタン待ち
PREINSTALL_WAIT_USER_SD_INSERT, // ユーザSD挿入待ち
PREINSTALL_CHECK_USER_SD_INSERT, // ユーザSDの挿入チェック
PREINSTALL_CHECK_USER_SD, // ユーザSDのチェック
PREINSTALL_CHECK_SD_FAIL, // ユーザSDのチェック失敗
PREINSTALL_FAIL_CHECK_REPAIR_SD, // ユーザSDのチェック失敗後の修理用SDのチェック
PREINSTALL_DOWNLOAD_APP, // アプリダウンロード
PREINSTALL_DOWNLOAD_APP_NOT_ENOUGH_SPACE, // アプリダウンロード失敗、空き容量不足
PREINSTALL_WAIT_USER_SD_EJECT, // ユーザSD抜き出し待ち
PREINSTALL_CHECK_REPAIR_SD // 修理用SDのチェック
} RestoreState;
@ -1450,7 +1458,7 @@ void ControlState(common::HardwareStateManager& manager, ::std::vector<std::stri
if (s_TwlTitleDownloadRetryCount++ < RETRY_MAX)
{
// エラーのためやり直す
COMMON_LOGGER_RESULT_IF_FAILED(GetShopOperationSingleResult());
COMMON_LOGGER_RESULT_IF_FAILED(GetTitleDownloadResult());
COMMON_LOGGER("Download Twl Title Failed. Retrying... %d\n", s_TwlTitleDownloadRetryCount);
s_ExecuteTwlTitleDownload = false;
@ -1646,9 +1654,9 @@ void ControlState(common::HardwareStateManager& manager, ::std::vector<std::stri
}
break;
case PREINSTALL_CHECK_USER_SD:
case PREINSTALL_CHECK_USER_SD_INSERT:
{
RestoreState saved = PREINSTALL_CHECK_USER_SD;
RestoreState saved = PREINSTALL_CHECK_USER_SD_INSERT;
if (nn::fs::IsSdmcInserted())
{
NN_LOG("Check User's SD Card\n");
@ -1662,14 +1670,71 @@ void ControlState(common::HardwareStateManager& manager, ::std::vector<std::stri
{
// SD挿抜が起こったら抜ける
BREAK_IF_STATE_CHANGED(saved, s_RestoreState);
if (PreparePreinstallTitleDownload())
ChangeState(saved, s_RestoreState, PREINSTALL_CHECK_USER_SD);
}
}
}
break;
case PREINSTALL_CHECK_USER_SD:
{
if (!s_ExecutePreparePreinstallTitleDownload)
{
COMMON_LOGGER("Checking User's SD Card\n");
s_ExecutePreparePreinstallTitleDownload = true;
bit64 deviceId = manager.GetDeviceId() + 0x400000000;
u8 serial[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN];
manager.GetSerialNumberWithoutCD(serial);
StartPreparePreinstallTitleDownload(deviceId, serial);
}
// 動いていることを表示
{
PutAliveMessage(operationMessage, "Checking User's SD Card");
}
if (IsDownloadTitleFinished())
{
FinalizeTitleDownload();
if (DownloadTitleSucceeded())
{
s_RestoreState = PREINSTALL_DOWNLOAD_APP;
}
else
{
if (s_PreparePreinstallTitleDownloadRetryCount++ < RETRY_MAX)
{
ChangeState(saved, s_RestoreState, PREINSTALL_DOWNLOAD_APP);
COMMON_LOGGER_RESULT_IF_FAILED(GetTitleDownloadResult());
if(GetTitleDownloadResult() == nn::MakePermanentResult(nn::Result::SUMMARY_OUT_OF_RESOURCE,
nn::Result::MODULE_APPLICATION, nn::Result::DESCRIPTION_OUT_OF_MEMORY))
{
// SDカード容量不足
s_RestoreState = PREINSTALL_DOWNLOAD_APP_NOT_ENOUGH_SPACE;
}
else if(GetTitleDownloadResult() <= nn::fs::ResultNotEnoughSpace())
{
// SDカード容量不足
// 作成したデータを削除する
COMMON_LOGGER_RESULT_IF_FAILED(nn::fs::DeleteSdmcRoot());
s_RestoreState = PREINSTALL_DOWNLOAD_APP_NOT_ENOUGH_SPACE;
}
else if(GetTitleDownloadResult() == nn::MakePermanentResult(nn::Result::SUMMARY_INVALID_STATE,
nn::Result::MODULE_APPLICATION, nn::Result::DESCRIPTION_ALREADY_INITIALIZED))
{
// ユーザSDが初期化済み
s_RestoreState = PREINSTALL_CHECK_SD_FAIL;
}
else
{
// エラーのためやり直す
COMMON_LOGGER("Checking User's SD Card Failed. Retrying... %d\n", s_PreinstallTitleDownloadRetryCount);
s_ExecutePreparePreinstallTitleDownload = false;
}
}
else
{
COMMON_LOGGER("Error: Valid User Savedata Exists.\n");
ChangeState(saved, s_RestoreState, PREINSTALL_CHECK_SD_FAIL);
s_RestoreState = PREINSTALL_CHECK_SD_FAIL;
}
}
}
@ -1713,10 +1778,7 @@ void ControlState(common::HardwareStateManager& manager, ::std::vector<std::stri
{
COMMON_LOGGER("Download PreInstall Application\n");
s_ExecutePreinstallTitleDownload = true;
bit64 deviceId = manager.GetDeviceId() + 0x400000000;
u8 serial[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN];
manager.GetSerialNumberWithoutCD(serial);
StartPreinstallTitleDownload(deviceId, serial);
StartPreinstallTitleDownload();
}
// 動いていることを表示
@ -1737,10 +1799,20 @@ void ControlState(common::HardwareStateManager& manager, ::std::vector<std::stri
if (s_PreinstallTitleDownloadRetryCount++ < RETRY_MAX)
{
// エラーのためやり直す
COMMON_LOGGER_RESULT_IF_FAILED(GetShopOperationSingleResult());
COMMON_LOGGER("Download PreInstall Title Failed. Retrying... %d\n", s_PreinstallTitleDownloadRetryCount);
COMMON_LOGGER_RESULT_IF_FAILED(GetTitleDownloadResult());
if(GetTitleDownloadResult() <= nn::fs::ResultNotEnoughSpace())
{
// SDカード容量不足
// 作成したデータを削除する
COMMON_LOGGER_RESULT_IF_FAILED(nn::fs::DeleteSdmcRoot());
s_RestoreState = PREINSTALL_DOWNLOAD_APP_NOT_ENOUGH_SPACE;
}
else
{
COMMON_LOGGER("Download PreInstall Title Failed. Retrying... %d\n", s_PreinstallTitleDownloadRetryCount);
s_ExecutePreinstallTitleDownload = false;
s_ExecutePreinstallTitleDownload = false;
}
}
else
{
@ -1751,6 +1823,14 @@ void ControlState(common::HardwareStateManager& manager, ::std::vector<std::stri
}
break;
case PREINSTALL_DOWNLOAD_APP_NOT_ENOUGH_SPACE:
{
operationMessage.push_back(::std::string("Not enough space on User's SD Card"));
operationMessage.push_back(::std::string("Pull out User's SD Card"));
operationMessage.push_back(::std::string("and Insert Repairing SD Card"));
}
break;
case PREINSTALL_WAIT_USER_SD_EJECT:
{
operationMessage.push_back(::std::string("Pull out User's SD Card"));
@ -1826,12 +1906,13 @@ void OnSdEjected()
// IVSチェック時はユーザのSDカードを挿入してもらうため
// プリインストール時はユーザのSDカードを挿入してもらうため
else if (s_RestoreState != FAIL && s_RestoreState != CHECK_IVS && s_RestoreState != PREINSTALL_WAIT_USER_SD_INSERT
&& s_RestoreState != PREINSTALL_WAIT_USER_SD_EJECT && s_RestoreState != PREINSTALL_CHECK_SD_FAIL)
&& s_RestoreState != PREINSTALL_WAIT_USER_SD_EJECT && s_RestoreState != PREINSTALL_CHECK_SD_FAIL &&
s_RestoreState != PREINSTALL_DOWNLOAD_APP_NOT_ENOUGH_SPACE)
{
InitializeState();
ClearFileReadResult();
}
else if(s_RestoreState == PREINSTALL_CHECK_USER_SD)
else if(s_RestoreState == PREINSTALL_CHECK_USER_SD_INSERT)
{
s_RestoreState = PREINSTALL_WAIT_USER_SD_INSERT;
}
@ -1853,7 +1934,7 @@ void OnSdInserted()
{
// SDカードが変わるのでファイルチェックは初期化する
common::InitializeFileCheck();
s_RestoreState = PREINSTALL_CHECK_USER_SD;
s_RestoreState = PREINSTALL_CHECK_USER_SD_INSERT;
}
else if(s_RestoreState == PREINSTALL_WAIT_USER_SD_EJECT)
{
@ -1861,7 +1942,7 @@ void OnSdInserted()
common::InitializeFileCheck();
s_RestoreState = PREINSTALL_CHECK_REPAIR_SD;
}
else if(s_RestoreState == PREINSTALL_CHECK_SD_FAIL)
else if(s_RestoreState == PREINSTALL_CHECK_SD_FAIL || s_RestoreState == PREINSTALL_DOWNLOAD_APP_NOT_ENOUGH_SPACE)
{
// SDカードが変わるのでファイルチェックは初期化する
common::InitializeFileCheck();

View File

@ -19,6 +19,7 @@
#include <nn/CTR/CTR_ProgramId.h>
#include <nn/cfg/CTR/cfg_ApiSys.h>
#include "SdMountManager.h"
#include "common_Types.h"
#include "FileName.h"
#include "CommonLogger.h"
@ -34,6 +35,11 @@ namespace
bit8 s_buffer1[400 * 1024];
// ダウンロードするタイトルの個数
size_t s_ProgramIdNum = 0;
// ダウンロードするタイトルのProgramIdの配列
nn::ProgramId s_ProgramIdList[256];
const size_t TITLE_DOWNLOADER_STACK_SIZE = 0x2000;
nn::os::Thread s_TitleDownloaderThread;
nn::os::StackBuffer<TITLE_DOWNLOADER_STACK_SIZE> s_TitleDownloaderThreadStack;
@ -90,20 +96,22 @@ nn::Result GetEntry(ES_NAMESPACE::ESTitleId titleId, EC_NAMESPACE::ECTitleCatalo
return result;
}
nn::Result GetTitleConfig(const ES_NAMESPACE::ESTitleId titleId, nn::nim::TitleConfig *titleConfig)
nn::Result GetTitleConfig(const ES_NAMESPACE::ESTitleId titleId, nn::nim::TitleConfig *titleConfig, s64* requiredSize)
{
EC_NAMESPACE::ECTitleCatalogEntry *entry;
NN_UTIL_RETURN_IF_FAILED(GetEntry(titleId, &entry));
titleConfig->titleId=titleId;
titleConfig->titleId =titleId;
titleConfig->version=std::strtoull(GetAttribute(entry->attributes, entry->nAttributes, "Version"), NULL, 10);
titleConfig->ratingAge=0;
titleConfig->media=GetMediaType(titleId);
*requiredSize=std::strtoull(GetAttribute(entry->attributes, entry->nAttributes, "MaxUserFileSize"), NULL, 10);
COMMON_LOGGER_DETAIL("titleId : 0x%016llx\n", titleConfig->titleId);
COMMON_LOGGER_DETAIL("version : %lld\n" , titleConfig->version);
COMMON_LOGGER_DETAIL("ratingAge : %d\n" , titleConfig->ratingAge);
COMMON_LOGGER_DETAIL("media : %d\n" , titleConfig->media);
COMMON_LOGGER_DETAIL("size : %lld\n" , *requiredSize);
return nn::ResultSuccess();
@ -122,25 +130,18 @@ void TwlTitleDownloaderThreadFunc()
TitleDownloader TwlTitleDownloader;
s_Progress = 0;
size_t num = 0;
nn::ProgramId list[256];
TitleDownloader::m_Result = ListUpTwlTitles(list, &num);
TitleDownloader::m_Result = ListUpTwlTitles(s_ProgramIdList, &s_ProgramIdNum);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(TitleDownloader::m_Result);
TwlTitleDownloader.SetupTitleList(list, num);
TwlTitleDownloader.SetupTitleList(s_ProgramIdList, s_ProgramIdNum);
TwlTitleDownloader.Start();
}
void PreinstallTitleDownloaderThreadFunc(PreinstallListupParam param)
void PreinstallTitleDownloaderThreadFunc()
{
TitleDownloader PreinstallTitleDownloader;
PreinstallImporter importer;
s_Progress = 0;
size_t num = 0;
nn::ProgramId list[256];
TitleDownloader::m_Result = importer.ListTitles(list, &num, param.deviceId, param.serialNo);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(TitleDownloader::m_Result);
PreinstallTitleDownloader.SetupTitleList(list, num);
PreinstallTitleDownloader.Start();
}
@ -150,27 +151,60 @@ void StartTwlTitleDownload()
}
bool PreparePreinstallTitleDownload()
void PreparePreinstallTitleDownloadThreadFunc(PreinstallListupParam param)
{
PreinstallImporter importer;
bool isAlreadyAvailable = false;
TitleDownloader::m_Result = importer.SetupSd(&isAlreadyAvailable);
TitleDownloader preinstallTitleDownloader;
preinstallTitleDownloader.m_Result = importer.ListTitles(s_ProgramIdList, &s_ProgramIdNum, param.deviceId, param.serialNo);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(preinstallTitleDownloader.m_Result);
if(isAlreadyAvailable)
preinstallTitleDownloader.SetupTitleList(s_ProgramIdList, s_ProgramIdNum);
s64 requiredSize;
preinstallTitleDownloader.CalculateRequiredSize(&requiredSize);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(preinstallTitleDownloader.m_Result);
s64 total;
s64 free;
preinstallTitleDownloader.m_Result= common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_VOID_IF_FAILED(preinstallTitleDownloader.m_Result);
preinstallTitleDownloader.m_Result = nn::fs::GetSdmcSize(&total, &free);
NN_LOG("total = %lld, free = %lld\n", total, free);
COMMON_LOGGER_RETURN_VOID_IF_FAILED(preinstallTitleDownloader.m_Result);
preinstallTitleDownloader.m_Result= common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_VOID_IF_FAILED(preinstallTitleDownloader.m_Result);
NN_LOG("requiredSize = %lld\n", requiredSize + 8 * 1024 * 1024);
// TODO: SDデータベースの正確なサイズを反映する
if(free < requiredSize + 8 * 1024 * 1024)
{
return false;
preinstallTitleDownloader.m_Result = nn::MakePermanentResult(nn::Result::SUMMARY_OUT_OF_RESOURCE,
nn::Result::MODULE_APPLICATION, nn::Result::DESCRIPTION_OUT_OF_MEMORY);
return;
}
preinstallTitleDownloader.m_Result = importer.SetupSd(&isAlreadyAvailable);
if(isAlreadyAvailable)
{
preinstallTitleDownloader.m_Result = nn::MakePermanentResult(nn::Result::SUMMARY_INVALID_STATE,
nn::Result::MODULE_APPLICATION, nn::Result::DESCRIPTION_ALREADY_INITIALIZED);
return;
}
return TitleDownloader::m_Result.IsSuccess();
}
void StartPreinstallTitleDownload(bit64 deviceId, u8* serialNo)
void StartPreparePreinstallTitleDownload(bit64 deviceId, u8* serialNo)
{
PreinstallListupParam param;
param.deviceId = deviceId;
std::memcpy(param.serialNo, serialNo, nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN);
s_TitleDownloaderThread.Start(PreinstallTitleDownloaderThreadFunc, param, s_TitleDownloaderThreadStack);
s_TitleDownloaderThread.Start(PreparePreinstallTitleDownloadThreadFunc, param, s_TitleDownloaderThreadStack);
}
void StartPreinstallTitleDownload()
{
s_TitleDownloaderThread.Start(PreinstallTitleDownloaderThreadFunc, s_TitleDownloaderThreadStack);
}
bool IsDownloadTitleFinished()
@ -186,7 +220,12 @@ void FinalizeTitleDownload()
bool DownloadTitleSucceeded()
{
return TitleDownloader::m_Result.IsSuccess() && GetShopOperationSingleResult().IsSuccess();
return TitleDownloader::m_Result.IsSuccess();
}
nn::Result GetTitleDownloadResult()
{
return TitleDownloader::m_Result;
}
u32 GetTitleDownloadProgress()
@ -284,6 +323,19 @@ void WaitShopOperationAndFinalize()
FinalizeShopOperationSingle();
}
void StartShopOperationSingleRetry(ShopOperation op, u32 retryCount)
{
for(u32 i = 0; i < retryCount; i++)
{
StartShopOperationSingle(op);
WaitShopOperationAndFinalize();
if(GetShopOperationSingleResult().IsSuccess())
{
break;
}
}
}
void TitleDownloader::Start()
{
for(u8 i = 0; i < m_TiteNum; i++)
@ -291,15 +343,18 @@ void TitleDownloader::Start()
s_Progress = i * 100 / m_TiteNum;
StartShopOperationSingle(SHOP_OPERATION_CONNECT_WITHOUT_CLOSE);
WaitShopOperationAndFinalize();
m_Result = GetShopOperationSingleResult();
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
nn::nim::TitleConfig config;
m_Result = GetTitleConfig(m_ProgramIdList[i], &config);
s64 requiredSize;
m_Result = GetTitleConfig(m_ProgramIdList[i], &config, &requiredSize);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
if (m_Result.IsSuccess())
{
StartShopOperationSingle(SHOP_OPERATION_DOWNLOAD_TITLE, config);
WaitShopOperationAndFinalize();
}
StartShopOperationSingle(SHOP_OPERATION_DOWNLOAD_TITLE, config);
WaitShopOperationAndFinalize();
m_Result = GetShopOperationSingleResult();
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
}
}
@ -313,4 +368,30 @@ void TitleDownloader::SetupTitleList(nn::ProgramId* list, size_t num)
m_TiteNum = listNum;
}
void TitleDownloader::CalculateRequiredSize(s64* requiredSize)
{
*requiredSize = 0;
for(u8 i = 0; i < m_TiteNum; i++)
{
s_Progress = i * 100 / m_TiteNum;
StartShopOperationSingleRetry(SHOP_OPERATION_CONNECT_WITHOUT_CLOSE, 3);
m_Result = GetShopOperationSingleResult();
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
nn::nim::TitleConfig config;
s64 size;
for(u8 j = 0; j < 3; j++)
{
m_Result = GetTitleConfig(m_ProgramIdList[i], &config, &size);
if(m_Result.IsSuccess())
{
break;
}
}
COMMON_LOGGER_RETURN_VOID_IF_FAILED(m_Result);
*requiredSize += size;
}
}
}

View File

@ -24,15 +24,16 @@ namespace ConsoleRestore
// 新たにスレッドを立て、TWLタイトルのダウンロードを開始する
void StartTwlTitleDownload();
//! @brief SDカードをインポート可能状態にします
//! @brief プリインストールタイトルをSDカードにインポート可能かどうかサイズを確認し、<BR/>
//! 可能であればSDカードをインポート可能状態にします
//! @param[in] deviceId デバイスID
//! @param[in] serialNo シリアルナンバー
//! @return 正常に初期化できたかどうか
bool PreparePreinstallTitleDownload();
void StartPreparePreinstallTitleDownload(bit64 deviceId, u8* serialNo);
//! @brief 新たにスレッドを立て、プリインストールタイトルのダウンロードを開始します <BR/>
//! SDカードはインポート可能な状態にしておく必要があります。
//! @param[in] deviceId デバイスID
//! @param[in] serialNo シリアルナンバー
void StartPreinstallTitleDownload(bit64 deviceId, u8* serialNo);
void StartPreinstallTitleDownload();
// プリインストール情報取得に必要なパラメータをまとめた構造体
@ -51,6 +52,9 @@ bool IsDownloadTitleFinished();
// タイトルのダウンロードスレッドが成功したかどうか
bool DownloadTitleSucceeded();
// タイトルのダウンロード結果を取得する
nn::Result GetTitleDownloadResult();
// タイトルのダウンロードスレッドを終了する
void FinalizeTitleDownload();
@ -67,6 +71,9 @@ public:
//! @brief タイトルリストを設定する
void SetupTitleList(nn::ProgramId* list, size_t num);
//! @brief タイトルをダウンロードするのに必要なサイズを計算します
void CalculateRequiredSize(s64* requiredSize);
// タイトルのダウンロードを開始する
void Start();

View File

@ -145,6 +145,7 @@ void SdLogger::Print(const char* fmt, ::std::va_list arg)
NN_LOG("SD Write Not Permitted\n");
m_Buffer.push_back(std::string(str));
m_BufferSize += stringSize * sizeof(char);
SdMountManager::Unmount();
return;
}

View File

@ -41,10 +41,12 @@ public:
SUITE_NAME("TestUtil");
TEST_ADD(TitleDownloaderTest::ListUp);
TEST_ADD(TitleDownloaderTest::DownloadPreinstall);
TEST_ADD(TitleDownloaderTest::CalculateRequiredSize);
}
private:
void ListUp();
void DownloadPreinstall();
void CalculateRequiredSize();
};
namespace
@ -114,12 +116,52 @@ void TitleDownloaderTest::ListUp()
void TitleDownloaderTest::DownloadPreinstall()
{
ConsoleRestore::StartPreinstallTitleDownload(17179924184, reinterpret_cast<u8*>(const_cast<char*>("EJA20305940")));
ConsoleRestore::StartPreparePreinstallTitleDownload(17179924184, reinterpret_cast<u8*>(const_cast<char*>("EJA20305940")));
while(!ConsoleRestore::IsDownloadTitleFinished())
{
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(1));
}
ConsoleRestore::FinalizeTitleDownload();
ConsoleRestore::StartPreinstallTitleDownload();
while(!ConsoleRestore::IsDownloadTitleFinished())
{
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(1));
}
ConsoleRestore::FinalizeTitleDownload();
}
void TitleDownloaderTest::CalculateRequiredSize()
{
nn::ProgramId id[] =
{
0x000400000FEEB000,
0x0004000005430000,
0x000400000A006000,
0x0004000005421000,
0x000400000A006100,
0x0004000005421100,
0x0004000001A01B00,
0x0004000001A01100,
0x000400000E000100,
0x0004008C09A00100,
0x0004008C01000100,
0x0004008C0D000000
};
ConsoleRestore::TitleDownloader dl;
s64 requiredSize;
do
{
dl.SetupTitleList(id, sizeof(id) / sizeof(id[0]));
dl.CalculateRequiredSize(&requiredSize);
}while(dl.m_Result.IsFailure());
NN_LOG("size = %llu\n", requiredSize);
}
NN_TEST_DEFINE_MAIN(TitleDownloaderTest)