ctr_Repair/trunk/ConsoleDataMigration/ConsoleBackup/Exporter.cpp
N2614 5ed32bde66 本体データ移行ツールを追加
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@2 385bec56-5757-e545-9c3a-d8741f4650f1
2011-01-28 10:46:13 +00:00

415 lines
12 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/fs/CTR/fs_ArchiveTypesForSystem.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.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_SwAesCtrContext.h>
#include "Exporter.h"
#include "CommonLogger.h"
#include "SDMountManager.h"
#include "ConsoleBackup.h"
#include "HeapManager.h"
#include "SdReaderWriter.h"
#include "FileName.h"
#include "FileTransfer.h"
#include "common_Types.h"
#include "Aes_define.h"
namespace ConsoleBackup
{
namespace
{
common::SdReaderWriter s_SdWriter;
common::NtrNorData s_NtrNorData;
::std::string s_SysSaveRoot;
const size_t EXPORT_THREAD_STACK_SIZE = 0x4000;
nn::os::Thread s_ExportThread;
nn::os::StackBuffer<EXPORT_THREAD_STACK_SIZE> s_ExportThreadStack;
wchar_t s_RootName[256];
bool s_IsExportThreadFinished = false;
}
void DeleteTrash()
{
// TODO: リードオンリーのファイルが消去できない
COMMON_LOGGER("Delete Trash.\n");
std::wstring currentDirectory = common::SDMC_ROOT_DIRECTORY_PATH;
nn::fs::FileInputStream fis;
nn::fs::Directory dir;
nn::Result result;
std::vector<nn::fs::DirectoryEntry> entryList; //カレントディレクトリのエントリ一覧を格納
std::vector<nn::fs::DirectoryEntry>::iterator entryIndex;
common::SdMountManager::Mount();
result = dir.TryInitialize(currentDirectory.c_str());
if (result.IsSuccess())
{
nn::fs::DirectoryEntry entry;
s32 numEntry;
for (;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
if (result.IsFailure())
{
dir.Finalize();
}
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());
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_WITH_LINE(result , __LINE__);
}
}
// ファイルならログとAP設定以外は削除する
else
{
if (std::wcscmp(entryIndex->entryName, common::AP_SETTING_FILENAME) != 0 && std::wcscmp(
entryIndex->entryName, common::Logger::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());
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_WITH_LINE(result , __LINE__);
}
}
}
}
// 削除完了
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);
}
}
}
}
else
{
NN_LOG("failed initialize directory\n");
COMMON_LOGGER_RESULT_WITH_LINE(result , __LINE__);
dir.Finalize();
}
common::SdMountManager::Unmount();
}
void WriteNorData()
{
COMMON_LOGGER("Export NOR Data.\n");
nn::Result result;
nn::cfg::nor::CTR::Initialize();
NN_LOG("Get NTR User Setting\n");
// ユーザカラー
result = nn::cfg::nor::CTR::GetUserColor(&s_NtrNorData.userColor);
if (result.IsSuccess())
{
NN_LOG("NTR User Color = %d\n", s_NtrNorData.userColor);
}
else
{
COMMON_LOGGER_RESULT_WITH_LINE(result , __LINE__);
}
// コメント
result = nn::cfg::nor::CTR::GetComment(&s_NtrNorData.comment);
if (result.IsSuccess())
{
NN_LOG("NTR User Comment = %ls\n", s_NtrNorData.comment.buffer);
}
else
{
COMMON_LOGGER_RESULT_WITH_LINE(result , __LINE__);
}
// TWL WiFi設定
result = nn::cfg::nor::CTR::ReadTwlWifiSetting(0, s_NtrNorData.TwlWiFiSetting, common::TWL_WIFI_SETTING_SIZE);
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_WITH_LINE(result , __LINE__);
}
// NTR WiFi設定
result = nn::cfg::nor::CTR::ReadNtrWifiSetting(0, s_NtrNorData.NtrWiFiSetting, common::NTR_WIFI_SETTING_SIZE);
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_WITH_LINE(result , __LINE__);
}
s_SdWriter.WriteBuf(common::NOR_PATHNAME, &s_NtrNorData, sizeof(common::NtrNorData));
}
void WriteSerialNumber()
{
COMMON_LOGGER("Export Serial Number.\n");
u8* serial;
size_t size;
GetSerialNumber(&serial, &size);
s_SdWriter.WriteBuf(common::SERIAL_PATHNAME, serial, size);
}
void WriteIvs()
{
COMMON_LOGGER("Export IVS.\n");
bit8 iv[AES_BLOCK_SIZE] =
{
0xdf, 0x0f, 0xf9, 0x1b, 0x34, 0x47, 0x70, 0x7f,
0x7d, 0x06, 0x85, 0xe6, 0xe7, 0xb6, 0x4e, 0xe9
};
void* ivs;
size_t size;
GetIvs(&ivs, &size);
void* enc;
nn::Result result;
enc = common::HeapManager::GetHeap()->Allocate(size);
if(enc != NULL)
{
// AES暗号化する
nn::crypto::Initialize();
nn::crypto::SwAesCtrContext swAesCtrContest;
swAesCtrContest.Initialize(iv, common::key, sizeof(common::key));
swAesCtrContest.Encrypt(enc, ivs, size);
s_SdWriter.WriteBuf(common::IVS_PATHNAME, enc, size);
common::HeapManager::GetHeap()->Free(enc);
}
}
// IVSからセーブデータディレクトリ名を生成する
void GetSaveDataDirectoryRoot()
{
nn::Result result;
using namespace nn::dbg;
const size_t SEED_SIZE = 16;
bit8 hash[nn::crypto::Sha256Context::HASH_SIZE];
const size_t SYS_SAVE_ROOT_LENGTH = 16;
char rootHash[SYS_SAVE_ROOT_LENGTH];
char rootStr[SYS_SAVE_ROOT_LENGTH * 2 + 1];
void* addr;
size_t size;
GetIvs(&addr, &size);
// 最後の16バイトのハッシュを使う
nn::crypto::CalculateSha256(hash, &reinterpret_cast<bit8*> (addr)[size - SEED_SIZE], SEED_SIZE);
for (u8 i = 0; i < SEED_SIZE / 4; i++)
{
for (u8 j = 0; j < SEED_SIZE / 4; j++)
{
rootHash[i * 4 + j] = hash[i * 4 + 3 - j];
}
}
// 得られたハッシュから文字列を生成
for (s32 k = 0; k < SEED_SIZE; k++)
{
for (s32 i = 6; i < 8; ++i)
{
bit32 n = (rootHash[k] >> ((7 - i) * 4)) & 0xf;
NN_TASSERT_(0 <= n && n < 16);
rootStr[i - 6 + k * 2] = static_cast<char> (n < 10 ? '0' + n : 'a' + (n - 10));
}
}
rootStr[SYS_SAVE_ROOT_LENGTH * 2] = '\0';
// セーブデータディレクトリ名を保存する
s_SysSaveRoot = ::std::string(rootStr);
NN_LOG("%s\n", s_SysSaveRoot.c_str());
}
void ExportThreadFunc()
{
nn::Result result;
s_IsExportThreadFinished = false;
result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND);
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_WITH_LINE(result , __LINE__);
}
result = common::SdMountManager::Mount();
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize();
NN_LOG("AllocatableSize = %d\n", bufSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize);
if (buf != NULL)
{
common::CopyDirectory(
(::std::wstring(common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH) + ::std::wstring(s_RootName) + ::std::wstring(L"/")).c_str(),
(common::SDMC_ROOT_DIRECTORY_PATH + ::std::wstring(common::SD_SAVEDATA_ROOT_NAME) + ::std::wstring(s_RootName) + ::std::wstring(L"/")).c_str(),
buf, bufSize);
common::HeapManager::GetHeap()->Free(buf);
}
common::SdMountManager::Unmount();
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
NN_LOG("Export Thread Finalize\n");
s_IsExportThreadFinished = true;
}
nn::Result WriteSaveData()
{
// NANDからSDカードに書き出し
nn::Result result;
result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND);
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_WITH_LINE(result , __LINE__);
return result;
}
u32 fileNum = 0;
u32 fileSize = 0;
common::CalculateFileNum(::std::wstring(common::NAND_DATA_ROOT_PATHNAME_WITH_SLASH), fileNum, fileSize);
nn::fs::Unmount(common::NAND_ARCHIVE_NAME);
NN_LOG("File Number = %d\n", fileNum);
NN_LOG("File Size = %d\n", fileSize);
// 進捗表示用
common::SetTotalSize(fileSize);
::std::mbstowcs(s_RootName, s_SysSaveRoot.c_str(), s_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_LOGGER("Create Backup Directory.\n");
s_SdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(
common::SD_SAVEDATA_ROOT_NAME)).c_str());
s_SdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) + ::std::wstring(
common::SD_SAVEDATA_ROOT_NAME) + ::std::wstring(s_RootName) + ::std::wstring(L"/")).c_str());
COMMON_LOGGER("Export NAND Data Start...\n");
// SDにコピーするためのスレッドの作成
s_ExportThread.Start(ExportThreadFunc, s_ExportThreadStack);
return result;
}
void FinalizeExportThread()
{
s_ExportThread.Join();
}
void ExportData()
{
static bool init = true;
if (init)
{
// 不要なデータを削除する
DeleteTrash();
// NORデータをSDカードに書き込む
WriteNorData();
// シリアルナンバーをSDカードに書き込む
WriteSerialNumber();
// 完全性検証SEEDをSDカードに書き込む
WriteIvs();
// IVSからセーブデータディレクトリ名を計算
GetSaveDataDirectoryRoot();
// NANDのセーブデータをSDに書き出す
WriteSaveData();
init = false;
}
}
u32 GetProgress()
{
return common::GetProgress();
}
bool IsExportFinished()
{
return s_IsExportThreadFinished;
}
}