ctr_Repair/branches/work/VerificationFailed/sources/ConsoleBackup/Exporter.cpp
N2614 7a747bf781 マージされたリビジョン517を branches/work/VerificationFailed から取り消す:
32バイトアラインのヒープを渡す
........
すでに32バイトアラインになっていた

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@518 385bec56-5757-e545-9c3a-d8741f4650f1
2011-11-16 23:54:37 +00:00

1005 lines
34 KiB
C++

/*---------------------------------------------------------------------------*
Project: Horizon
File: Exporter.cpp
Copyright 2009 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Rev$
*---------------------------------------------------------------------------*/
#include <vector>
#include <cstdlib>
#include <cwchar>
#include <string>
#include <cstdlib>
#include <nn/nstd.h>
#include <nn/fs/CTR/fs_ArchiveTypesForSystem.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include <nn/cfg/CTR/cfg_Api.h>
#include <nn/cfg/CTR/cfg_ApiNor.h> // cfg:norの初期化に必要
#include <nn/cfg/CTR/cfg_NtrSettings.h>
#include <nn/ps/CTR/ps_API.h>
#include <nn/drivers/aes/CTR/ARM946ES/driverAes_Types.h>
#include <nn/crypto/crypto_AesCmac.h>
#include <nn/crypto/crypto_SwAesCtrContext.h>
#include <nn/crypto/crypto_Sha256.h>
#include <nn/crypto/crypto_SwAesCmac.h>
#include <nn/mcu.h>
#include <nn/am.h>
#include <nn/pl/CTR/pl_PlayHistoryApi.h>
#include <nn/pl/CTR/pl_PlayHistoryApiSysmenu.h>
#include "Exporter.h"
#include "CommonLogger.h"
#include "SDMountManager.h"
#include "HeapManager.h"
#include "SdReaderWriter.h"
#include "FileName.h"
#include "FileTransfer.h"
#include "common_Types.h"
#include "Aes_define.h"
#include "VersionDetect.h"
#include "Util.h"
namespace ConsoleBackup
{
namespace
{
common::NtrNorData s_NtrNorData;
common::CfgCountryLanguage s_CountryLanguage;
const size_t EXPORT_THREAD_STACK_SIZE = 0x4000;
nn::os::Thread s_ExportThread;
nn::os::StackBuffer<EXPORT_THREAD_STACK_SIZE> s_ExportThreadStack;
bool s_IsExportSucceeded;
wchar_t s_RootName[256];
nn::crypto::Sha256Context s_FileListContext;
}
void AddCmac(nn::fs::FileOutputStream* file, nn::crypto::Sha256Context* context);
nn::Result DeleteTrash(std::wstring currentDirectory)
{
// TODO: リードオンリーのファイルが消去できない
COMMON_LOGGER("Delete Trash.\n");
nn::fs::FileInputStream fis;
nn::fs::Directory dir;
nn::Result result;
std::vector<nn::fs::DirectoryEntry> entryList; //カレントディレクトリのエントリ一覧を格納
std::vector<nn::fs::DirectoryEntry>::iterator entryIndex;
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = dir.TryInitialize(currentDirectory.c_str());
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
if (numEntry == 0)
{
// ルートディレクトリを閉じる
dir.Finalize();
// ルートディレクトリの子を開く
for (entryIndex = entryList.begin(); entryIndex != entryList.end(); entryIndex++)
{
// ディレクトリなら削除する
if (entryIndex->attributes.isDirectory)
{
NN_LOG("Try Delete %ls%ls/\n", currentDirectory.c_str(), entryIndex->entryName);
result = nn::fs::TryDeleteDirectoryRecursively(
(currentDirectory + ::std::wstring(entryIndex->entryName)).c_str());
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
// ファイルならログとAP設定以外は削除する
else
{
if (std::wcscmp(entryIndex->entryName, common::AP_SETTING_FILENAME) != 0
&& std::wcscmp(entryIndex->entryName, common::LOG_FILENAME) != 0)
{
NN_LOG("Try Delete %ls%ls\n", currentDirectory.c_str(), entryIndex->entryName);
result = nn::fs::TryDeleteFile(
(currentDirectory + ::std::wstring(entryIndex->entryName)).c_str());
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
}
// 削除完了
break;
}
else
{
// vectorに保存する
entryList.push_back(entry);
if (entry.attributes.isDirectory)
{
NN_LOG("%ls%ls/\n", currentDirectory.c_str(), entry.entryName);
}
else
{
NN_LOG("%ls%ls\n", currentDirectory.c_str(), entry.entryName);
}
}
}
result = common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
return nn::ResultSuccess();
}
nn::Result WriteTwlTitleList(std::vector<std::wstring>& programIdList)
{
nn::Result result;
COMMON_LOGGER("Export TwlTitle List.\n");
size_t heapSize = common::GetAllocatableSize();
if(heapSize > common::FILE_COPY_HEAP_SIZE)
{
heapSize = common::FILE_COPY_HEAP_SIZE;
}
common::HeapManager manager(heapSize);
char* titleListBuf = reinterpret_cast<char*> (manager.GetAddr());
size_t writeSize = 0;
if (titleListBuf != NULL)
{
for (std::vector<std::wstring>::iterator it = programIdList.begin(); it != programIdList.end(); it++)
{
nn::nstd::TSNPrintf(titleListBuf + writeSize, heapSize - writeSize, "%s\n", common::GetCharStr(it->c_str()));
NN_LOG("%ls\n", it->c_str());
writeSize += it->size() + sizeof('\n');
}
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::TWL_TITLELIST_PATHNAME, titleListBuf, writeSize);
}
else
{
return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
}
nn::Result WriteRegionData()
{
COMMON_LOGGER("Export Region Data.\n");
nn::cfg::CTR::CfgRegionCode region;
region = nn::cfg::CTR::GetRegion();
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::REGION_DATA_PATHNAME, &region, sizeof(nn::cfg::CTR::CfgRegionCode));
}
nn::Result WriteCountryLanguageData()
{
COMMON_LOGGER("Export Country and Language Data.\n");
nn::Result result;
nn::cfg::nor::CTR::Initialize();
// 国設定
s_CountryLanguage.country = nn::cfg::CTR::GetCountry();
if (s_CountryLanguage.country != nn::cfg::CTR::CFG_COUNTRY_UNKNOWN)
{
// 言語設定
s_CountryLanguage.language = nn::cfg::CTR::GetLanguage();
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::COUNTRY_SETTING_PATHNAME, &s_CountryLanguage, sizeof(s_CountryLanguage));
}
return nn::ResultSuccess();
}
nn::Result WriteNorData()
{
COMMON_LOGGER("Export NOR Data.\n");
nn::Result result;
nn::cfg::nor::CTR::Initialize();
NN_LOG("Get NTR User Setting\n");
// NTR設定
result = nn::cfg::nor::CTR::GetNtrSetting(&s_NtrNorData.ntrConfig.ncd, &s_NtrNorData.ntrConfig.ncd_ex);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// TWL WiFi設定
result = nn::cfg::nor::CTR::ReadTwlWifiSetting(0, s_NtrNorData.TwlWiFiSetting, common::TWL_WIFI_SETTING_SIZE);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
// NTR WiFi設定
result = nn::cfg::nor::CTR::ReadNtrWifiSetting(0, s_NtrNorData.NtrWiFiSetting, common::NTR_WIFI_SETTING_SIZE);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::NOR_PATHNAME, &s_NtrNorData, sizeof(common::NtrNorData));
}
nn::Result WriteSerialNumber(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Export Serial Number.\n");
u8* serial;
size_t size;
manager.GetSerialNumber(&serial, &size);
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::SERIAL_PATHNAME, serial, size);
}
nn::Result WriteDeviceId(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Export Device ID.\n");
bit32 deviceId = manager.GetDeviceId();
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::DEVICE_ID_PATHNAME, &deviceId, sizeof(deviceId));
}
nn::Result WriteIvs(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Export SDCI.\n");
void* ivs;
size_t size;
manager.GetIvs(&ivs, &size);
void* enc;
nn::Result result;
common::HeapManager ivsHeap(size);
enc = ivsHeap.GetAddr();
if(enc != NULL)
{
// AES暗号化する
nn::crypto::Initialize();
nn::crypto::SwAesCtrContext swAesCtrContest;
swAesCtrContest.Initialize(common::iv, common::key, sizeof(common::key));
swAesCtrContest.Encrypt(enc, ivs, size);
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::IVS_PATHNAME, enc, size);
}
else
{
return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
}
void CreateTwlDirectory(enum common::TWL_PATH_INDEX path)
{
NN_ASSERT(path < common::TWL_PATHNAME_MAX);
common::SdReaderWriter sdWriter;
sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) +
std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str());
}
bool ListTwlSaveData(std::wstring currentDirectory, std::vector<common::SavePathInfo>* list)
{
nn::fs::Directory dir;
nn::fs::DirectoryEntry entry;
s32 numEntry;
nn::Result result = dir.TryInitialize(currentDirectory.c_str());
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (numEntry == 0)
{
break;
}
else
{
common::SavePathInfo pathInfo;
pathInfo.name = currentDirectory + std::wstring(L"/") + std::wstring(entry.entryName);
pathInfo.isDirectory = false;
list->push_back(pathInfo);
}
}
return true;
}
void AddCurrentProgramIdPath(std::vector<std::wstring>* programIdList, std::wstring currentDir)
{
std::wstring currentPath(currentDir);
std::wstring token(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH);
std::wstring::size_type pos;
pos = currentPath.find(token);
if(pos != std::wstring::npos)
{
std::wstring subStr = currentPath.substr(token.size());
std::wstring slash(L"/");
pos = subStr.find(slash);
while(pos != std::wstring::npos)
{
subStr.erase(pos, slash.size());
pos = subStr.find(slash);
}
std::wstring ctrProgramIdHi(L"00048");
subStr.replace(0, ctrProgramIdHi.size(), ctrProgramIdHi);
programIdList->push_back(subStr);
}
else
{
NN_LOG("Can't find %ls\n", common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH);
}
}
void AddCurrentDirectory(std::vector<common::SavePathInfo>* list, std::wstring currentDir, wchar_t* currentEntry)
{
common::SavePathInfo pathInfo;
pathInfo.name = currentDir + std::wstring(L"/") + std::wstring(currentEntry) + std::wstring(L"/");
pathInfo.isDirectory = true;
list->push_back(pathInfo);
}
// TWLセーブデータが存在するディレクトリの一覧をlistに追加する
// return: dataディレクトリが存在するかどうか
bool ListTwlSaveDataDirectory(std::wstring currentDirectory, u32 level, std::vector<common::SavePathInfo>* list,
std::vector<std::wstring>* programIdList)
{
nn::fs::FileInputStream fis;
nn::fs::Directory dir;
nn::Result result;
std::vector<nn::fs::DirectoryEntry> entryList; //カレントディレクトリのエントリ一覧を格納
std::vector<nn::fs::DirectoryEntry>::iterator entryIndex;
// level 0 1 2
// twln:/title/00030005/484e4441/data/
const u8 TWL_SAVEDATA_DIRECTORY_LEVEL = 2; // data ディレクトリまでの階層
const wchar_t* const TWL_SAVEDATA_DIRECTORY_NAME = L"data";
result = dir.TryInitialize(currentDirectory.c_str());
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
if (numEntry == 0)
{
dir.Finalize();
bool hasDataDirectory = false;
for (entryIndex = entryList.begin(); entryIndex != entryList.end(); entryIndex++)
{
// レベル2未満のディレクトリなら再帰的に開く
if (level < TWL_SAVEDATA_DIRECTORY_LEVEL)
{
if (entryIndex->attributes.isDirectory)
{
if (!ListTwlSaveDataDirectory(
currentDirectory + std::wstring(L"/") + std::wstring(entryIndex->entryName), level + 1,
list, programIdList))
{
hasDataDirectory |= false;
}
else
{
NN_LOG("%ls/%ls has data directory.\n", currentDirectory.c_str(), entryIndex->entryName);
AddCurrentDirectory(list, currentDirectory, entryIndex->entryName);
hasDataDirectory |= true;
}
}
}
// レベル2のディレクトリなら data かどうかチェック
else if (level == TWL_SAVEDATA_DIRECTORY_LEVEL && entryIndex->attributes.isDirectory)
{
if (std::wcscmp(entryIndex->entryName, TWL_SAVEDATA_DIRECTORY_NAME) == 0)
{
// ファイル一覧を取得する
if (!ListTwlSaveData(
currentDirectory + std::wstring(L"/") + std::wstring(entryIndex->entryName), list))
{
hasDataDirectory |= false;
}
NN_LOG("%ls/%ls has data directory.\n", currentDirectory.c_str(), entryIndex->entryName);
AddCurrentDirectory(list, currentDirectory, entryIndex->entryName);
AddCurrentProgramIdPath(programIdList, currentDirectory);
hasDataDirectory |= true;
}
}
else
{
return false;
}
}
return hasDataDirectory;
}
else
{
// vectorに保存する
entryList.push_back(entry);
}
}
}
void WriteTwlData(enum common::TWL_PATH_INDEX path)
{
NN_ASSERT(path < common::TWL_PATHNAME_MAX);
nn::Result result;
s_IsExportSucceeded = true;
result = nn::fs::MountSpecialArchive(common::TWL_ARCHIVE_NAME_TABLE[path], common::TWL_FS_ARCHIVE_KIND[path]);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
u32 fileNum = 0;
s64 fileSize = 0;
result = common::CalculateFileNum(::std::wstring(common::NAND_TWL_ROOT_PATHNAME_WITH_SLASH_TABLE[path]), fileNum, fileSize);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
NN_LOG("File Number = %d\n", fileNum);
NN_LOG("File Size = %d\n", fileSize);
// 進捗表示用
common::InitializeTransferProgress(fileSize);
size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2);
NN_LOG("AllocatableSize = %d\n", bufSize);
if(bufSize > common::FILE_COPY_HEAP_SIZE)
{
bufSize = common::FILE_COPY_HEAP_SIZE;
}
common::HeapManager writeHeap(bufSize, AES_BLOCK_SIZE * 2);
void* buf = writeHeap.GetAddr();
if (buf != NULL)
{
nn::fs::FileOutputStream list;
result = list.TryInitialize(common::FILE_LIST_PATHNAME, true);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsSuccess())
{
result = list.TryGetSize(&fileSize);
if (result.IsSuccess())
{
// 末尾に移動
result = list.TrySetPosition(fileSize);
if (result.IsSuccess())
{
wchar_t archiveName[nn::fs::MAX_FILE_PATH_LENGTH];
::std::mbstowcs(archiveName, common::TWL_ARCHIVE_NAME_TABLE[path],
std::strlen(common::TWL_ARCHIVE_NAME_TABLE[path]) + 1);
std::wstring archiveString(archiveName);
if(!common::CopyDirectory(
NULL,
(archiveString + ::std::wstring(L"/")).c_str(),
(common::SDMC_ROOT_DIRECTORY_PATH + ::std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str(),
buf, bufSize, true, &list, &s_FileListContext))
{
s_IsExportSucceeded = false;
return;
}
}
list.TryFlush();
list.Finalize();
}
}
else
{
s_IsExportSucceeded = false;
}
}
common::SdMountManager::Unmount();
nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[path]);
}
nn::Result CalculateTwlSaveData(std::vector<common::SavePathInfo>* fileList, s64* fileSize)
{
NN_NULL_ASSERT(fileList);
NN_NULL_ASSERT(fileSize);
*fileSize = 0;
nn::Result result = nn::ResultSuccess();
for (std::vector<common::SavePathInfo>::iterator it = fileList->begin(); it != fileList->end(); it++)
{
if(!it->isDirectory)
{
nn::fs::FileInputStream file;
result = file.TryInitialize(it->name.c_str());
if(result.IsSuccess())
{
s64 size;
result = file.TryGetSize(&size);
if(result.IsSuccess())
{
*fileSize += size;
}
}
}
}
return result;
}
void WriteTwlSaveData()
{
nn::Result result;
s_IsExportSucceeded = true;
std::vector<common::SavePathInfo> fileList;
std::vector<std::wstring> programIdList;
COMMON_LOGGER("Export Twl Save Data.\n");
// ディレクトリ作成
common::SdReaderWriter sdWriter;
result = sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) +
std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str());
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
// セーブデータを含むディレクトリ一覧を生成
result = nn::fs::MountSpecialArchive(common::NAND_TWL_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_TWL_NAND);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
if(!ListTwlSaveDataDirectory(std::wstring(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH), 0, &fileList, & programIdList))
{
NN_LOG("No Twl Savedata\n");
s_IsExportSucceeded = true;
return;
}
NN_LOG("listup Twl Savedata Directory\n");
for (std::vector<common::SavePathInfo>::reverse_iterator it = fileList.rbegin(); it != fileList.rend(); it++)
{
NN_LOG("%ls\n", it->name.c_str());
}
result = WriteTwlTitleList(programIdList);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
// 合計サイズ取得
s64 fileSize;
result = CalculateTwlSaveData(&fileList, &fileSize);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
common::InitializeTransferProgress(fileSize);
NN_LOG("\n");
// SDに書き出し
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2);
NN_LOG("AllocatableSize = %d\n", bufSize);
if(bufSize > common::FILE_COPY_HEAP_SIZE)
{
bufSize = common::FILE_COPY_HEAP_SIZE;
}
common::HeapManager writeHeap(bufSize, AES_BLOCK_SIZE * 2);
void* buf = writeHeap.GetAddr();
if (buf != NULL)
{
nn::fs::FileOutputStream list;
result = list.TryInitialize(common::FILE_LIST_PATHNAME, true);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
result = list.TryGetSize(&fileSize);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
// 末尾に移動
result = list.TrySetPosition(fileSize);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
wchar_t archiveName[nn::fs::MAX_FILE_PATH_LENGTH];
::std::mbstowcs(archiveName, common::NAND_TWL_ARCHIVE_NAME, std::strlen(common::NAND_TWL_ARCHIVE_NAME) + 1);
std::wstring archiveString(archiveName);
for (std::vector<common::SavePathInfo>::reverse_iterator it = fileList.rbegin(); it != fileList.rend(); it++)
{
// twln:/title/をsdmc:/CTR_Console_Repair/TWLBackup/に置換
std::wstring toPath(it->name.c_str());
toPath.replace(0, std::wcslen(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH) + 1,
std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME));
if (it->isDirectory)
{
if(!common::ExportTwlSaveDirectory(toPath.c_str(), &list, &s_FileListContext))
{
s_IsExportSucceeded = false;
return;
}
}
else
{
if(!common::ExportTwlSaveFile(it->name.c_str(), toPath.c_str(), buf, bufSize, &list, &s_FileListContext))
{
s_IsExportSucceeded = false;
return;
}
}
}
result = list.TryFlush();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
list.Finalize();
}
result = common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
result = nn::fs::Unmount(common::NAND_TWL_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_VOID_SET_BOOL_IF_FAILED(result, s_IsExportSucceeded);
}
void WriteTwlPhotoData()
{
COMMON_LOGGER("Export Twl Photo Data.\n");
CreateTwlDirectory(common::TWL_PHOTO);
WriteTwlData(common::TWL_PHOTO);
}
void WriteTwlSoundData()
{
COMMON_LOGGER("Export Twl Sound Data.\n");
CreateTwlDirectory(common::TWL_SOUND);
WriteTwlData(common::TWL_SOUND);
}
void InitializeFileListContext()
{
nn::crypto::Initialize();
s_FileListContext.Initialize();
}
nn::Result ExportTwlSaveData()
{
// 不要なデータを削除する
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
DeleteTrash((std::wstring(common::LOG_ROOT_DIRECTORY_PATH) + std::wstring(L"/")).c_str()));
s_ExportThread.Start(WriteTwlSaveData, s_ExportThreadStack);
return nn::ResultSuccess();
}
void ExportTwlPhotoData()
{
s_ExportThread.Start(WriteTwlPhotoData, s_ExportThreadStack);
}
void ExportTwlSoundData()
{
s_ExportThread.Start(WriteTwlSoundData, s_ExportThreadStack);
}
nn::Result WriteMcuRtcData(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Export RTC Data.\n");
nn::Result result;
nn::Handle handle = manager.GetMcuHandle();
if(handle.IsValid())
{
nn::mcu::CTR::HwCheck mcu(handle);
nn::mcu::CTR::RtcData rtc;
const u8 RETRY = 10;
for (u8 i = 0; i < RETRY; i++)
{
result = mcu.GetRtcAll(&rtc);
if (result.IsSuccess())
{
NN_LOG("RTC = 20%02d/%02d/%02d %02d:%02d:%02d\n", rtc.m_Year, rtc.m_Month, rtc.m_Day, rtc.m_Hour, rtc.m_Minute, rtc.m_Second);
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::MCU_RTC_PATHNAME, &rtc, sizeof(rtc));
}
nn::os::Thread::Sleep(
nn::fnd::TimeSpan::FromMilliSeconds(
nn::os::Tick::GetSystemCurrent().ToTimeSpan().GetMilliSeconds() % 100));
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
else
{
NN_LOG("invalid handle\n");
return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_INVALID_STATE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_INVALID_HANDLE);
}
return nn::ResultSuccess();
}
void ExportThreadFunc()
{
nn::Result result;
s_IsExportSucceeded = true;
result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = common::SdMountManager::Mount();
size_t bufSize = common::GetAllocatableSize(AES_BLOCK_SIZE * 2);
NN_LOG("AllocatableSize = %d\n", bufSize);
if(bufSize > common::FILE_COPY_HEAP_SIZE)
{
bufSize = common::FILE_COPY_HEAP_SIZE;
}
common::HeapManager writeHeap(bufSize, AES_BLOCK_SIZE * 2);
void* buf = writeHeap.GetAddr();
if (buf != NULL)
{
nn::fs::FileOutputStream list;
result = list.TryInitialize(common::FILE_LIST_PATHNAME, true);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsSuccess())
{
s64 fileSize;
result = list.TryGetSize(&fileSize);
if (result.IsSuccess())
{
// 末尾に移動
result = list.TrySetPosition(fileSize);
if (result.IsSuccess())
{
if(!common::CopyDirectory(
NULL,
::std::wstring(common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH).c_str(),
(std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(
common::SD_SAVEDATA_ROOT_NAME)).c_str(), buf, bufSize, true, &list,
&s_FileListContext))
{
s_IsExportSucceeded = false;
return;
}
AddCmac(&list, &s_FileListContext);
list.TryFlush();
list.Finalize();
}
}
}
}
common::SdMountManager::Unmount();
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
NN_LOG("Export Thread Finalize\n");
}
nn::Result WriteSaveData(::std::string& sysSaveRoot)
{
// NANDからSDカードに書き出し
nn::Result result;
result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
u32 fileNum = 0;
s64 fileSize = 0;
result = common::CalculateFileNum(::std::wstring(common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH), fileNum, fileSize);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
NN_LOG("File Number = %d\n", fileNum);
NN_LOG("File Size = %d\n", fileSize);
// 進捗表示用
common::InitializeTransferProgress(fileSize);
::std::mbstowcs(s_RootName, sysSaveRoot.c_str(), sysSaveRoot.size() + 1);
NN_LOG("%ls\n", (::std::wstring(common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH) + ::std::wstring(s_RootName) + ::std::wstring(L"/")).c_str());
// セーブデータディレクトリ以下のデータをSDカードにコピー
// コピー用ディレクトリ作成
common::SdReaderWriter sdWriter;
result = sdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(
common::SD_SAVEDATA_ROOT_NAME)).c_str());
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
COMMON_LOGGER("Export NAND Data Start...\n");
// SDにコピーするためのスレッドの作成
s_ExportThread.Start(ExportThreadFunc, s_ExportThreadStack);
return result;
}
void FinalizeExportThread()
{
s_ExportThread.Join();
s_ExportThread.Finalize();
}
nn::Result WriteVersionData(common::HardwareStateManager& manager)
{
COMMON_LOGGER("Export Version Data.\n");
common::VerDef versionData;
manager.GetVersionData(&versionData);
common::SdReaderWriter sdWriter;
return sdWriter.WriteBufWithCmac(common::VERSION_DATA_PATHNAME, &versionData, sizeof(common::VerDef));
}
bool DeleteNimSaveData()
{
nn::Result result;
::std::wstring nimSaveDataPath =
::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) +
::std::wstring(common::SD_SAVEDATA_ROOT_NAME) +
::std::wstring(s_RootName) +
::std::wstring(L"/") +
std::wstring(common::NIM_SAVEDATA_DIRECTORY_NAME);
result = common::SdMountManager::Mount();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
NN_LOG("%ls\n", nimSaveDataPath.c_str());
result = nn::fs::TryDeleteDirectoryRecursively(nimSaveDataPath.c_str());
if (result.IsFailure() && !nn::fs::ResultNotFound::Includes(result))
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
return false;
}
result = common::SdMountManager::Unmount();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
return true;
}
void AddShutDownPtmEvent()
{
nn::pl::CTR::NotifyPlayEvent(nn::pl::CTR::EVENTTYPE_TERMINATE, nn::CTR::INVALID_PROGRAM_ID,
nn::fnd::DateTime::GetNow());
}
bool ExportData(common::HardwareStateManager& manager)
{
static bool init = true;
if (init)
{
nn::Result result;
// 電源断の履歴をptmに追加する
AddShutDownPtmEvent();
// リージョンデータをSDに書き込む
result = WriteRegionData();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 国データと言語データをSDに書き込む
result = WriteCountryLanguageData();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// NORデータをSDカードに書き込む
result = WriteNorData();
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// シリアルナンバーをSDカードに書き込む
result = WriteSerialNumber(manager);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// デバイスIDをSDカードに書き込む
result = WriteDeviceId(manager);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// 完全性検証SEEDをSDカードに書き込む
result = WriteIvs(manager);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// RTCをSDに書き出す
result = WriteMcuRtcData(manager);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
// バージョン情報をSDに書き出す
result = WriteVersionData(manager);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
::std::string systemSaveRoot;
void* ivs;
size_t size;
manager.GetIvs(&ivs, &size);
// IVSからセーブデータディレクトリ名を計算
common::Util::GetSaveDataDirectoryRoot(systemSaveRoot, ivs, size);
// NANDのセーブデータをSDに書き出す
result = WriteSaveData(systemSaveRoot);
COMMON_LOGGER_RETURN_FALSE_IF_FAILED(result);
init = false;
}
return true;
}
u32 GetExportProgress()
{
return common::GetProgress();
}
bool IsExportThreadFinished()
{
return s_ExportThread.IsValid() && !s_ExportThread.IsAlive();
}
bool IsExportSucceeded()
{
return s_IsExportSucceeded;
}
//!@ brief ファイルにSHA256から計算したAES-CMACを付加します
//!@ param[in] file CMACを付加したいInitialize済みのファイル
//!@ param[in] context CMAC計算元のSHA256コンテキスト
void AddCmac(nn::fs::FileOutputStream* file, nn::crypto::Sha256Context* context)
{
nn::Result result;
bit8 sha256Hash[nn::crypto::Sha256Context::HASH_SIZE];
context->GetHash(sha256Hash);
bit8 cmac[nn::crypto::AES_CMAC_MAC_SIZE];
result = nn::crypto::CalculateAesCmacSw(cmac, sha256Hash, nn::crypto::Sha256Context::HASH_SIZE, common::cmacKey);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
s32 writeSize;
result = file->TryWrite(&writeSize, cmac, sizeof(cmac), false);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
}
}