TWLパーティションのセーブデータを吸い出すように

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@202 385bec56-5757-e545-9c3a-d8741f4650f1
This commit is contained in:
N2614 2011-04-15 05:30:09 +00:00
parent 09e9a36fca
commit 0a2855fa1b
7 changed files with 479 additions and 14 deletions

View File

@ -31,6 +31,7 @@ namespace
typedef enum BackupState
{
STARTUP, // 初期値
EXPORT_TWL_NAND, // TWLセーブデータ領域の吸出し中
EXPORT_TWL_SOUND, // TWLサウンド領域の吸出し中
EXPORT_TWL_PHOTO, // TWL写真領域の吸出し中
EXPORT_CTR_NAND, // 吸出し中
@ -145,6 +146,29 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep,
if (nextStep && !error)
{
COMMON_LOGGER("Start Export Data\n");
s_BackupState = EXPORT_TWL_NAND;
}
}
break;
// TWLセーブデータ領域の吸出し中
case EXPORT_TWL_NAND:
{
static bool init = true;
if(init)
{
// コンテキストを初期化する
InitializeFileListContext();
// データを書き込む
ExportTwlSaveData();
init = false;
}
// 処理が完了した
if (IsExportFinished())
{
FinalizeExportThread();
s_BackupState = EXPORT_TWL_SOUND;
}
}
@ -156,9 +180,6 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep,
static bool init = true;
if(init)
{
// コンテキストを初期化する
InitializeFileListContext();
// データを書き込む
ExportTwlSoundData();
init = false;

View File

@ -308,6 +308,138 @@ void CreateTwlDirectory(enum common::TWL_PATH_INDEX path)
std::wstring(common::SD_TWL_ROOTNAME_TABLE[path])).c_str());
}
void 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());
if(result.IsSuccess())
{
for(;;)
{
result = dir.TryRead(&numEntry, &entry, 1);
if(result.IsFailure())
{
dir.Finalize();
break;
}
if(numEntry == 0)
{
dir.Finalize();
}
else
{
common::SavePathInfo pathInfo;
pathInfo.name = currentDirectory + std::wstring(L"/") + std::wstring(entry.entryName);
pathInfo.isDirectory = false;
list->push_back(pathInfo);
}
}
}
}
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);
}
bool ListTwlSaveDataDirectory(std::wstring currentDirectory, u32 level, std::vector<common::SavePathInfo>* list)
{
// TODO: リードオンリーのファイルが消去できない
nn::fs::FileInputStream fis;
nn::fs::Directory dir;
nn::Result result;
std::vector<nn::fs::DirectoryEntry> entryList; //カレントディレクトリのエントリ一覧を格納
std::vector<nn::fs::DirectoryEntry>::iterator entryIndex;
const u8 TWL_SAVEDATA_DIRECTORY_LEVEL = 2; // data ディレクトリまでの階層
const wchar_t* const TWL_SAVEDATA_DIRECTORY_NAME = L"data";
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();
bool retValue = 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))
{
NN_LOG("%ls/%ls has data directory.\n", currentDirectory.c_str(), entryIndex->entryName);
retValue = true;
AddCurrentDirectory(list, currentDirectory, entryIndex->entryName);
}
}
}
// レベル2のディレクトリなら data かどうかチェック
else if(level == TWL_SAVEDATA_DIRECTORY_LEVEL && entryIndex->attributes.isDirectory)
{
if (std::wcscmp(entryIndex->entryName, TWL_SAVEDATA_DIRECTORY_NAME) == 0)
{
// ファイル一覧を取得する
retValue = true;
ListTwlSaveData(currentDirectory + std::wstring(L"/") + std::wstring(entryIndex->entryName), list);
AddCurrentDirectory(list, currentDirectory, entryIndex->entryName);
}
}
else
{
return false;
}
}
if(level != 0)
{
return retValue;
}
break;
}
else
{
// vectorに保存する
entryList.push_back(entry);
}
}
}
else
{
NN_LOG("failed initialize directory\n");
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
dir.Finalize();
}
return false;
}
void WriteTwlData(enum common::TWL_PATH_INDEX path)
{
NN_ASSERT(path < common::TWL_PATHNAME_MAX);
@ -348,7 +480,7 @@ void WriteTwlData(enum common::TWL_PATH_INDEX path)
result = list.TrySetPosition(fileSize);
if (result.IsSuccess())
{
wchar_t archiveName[256];
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);
@ -368,7 +500,123 @@ void WriteTwlData(enum common::TWL_PATH_INDEX path)
common::SdMountManager::Unmount();
nn::fs::Unmount(common::TWL_ARCHIVE_NAME_TABLE[path]);
}
void CalculateTwlSaveData(std::vector<common::SavePathInfo>* fileList, s64* fileSize)
{
NN_NULL_ASSERT(fileList);
NN_NULL_ASSERT(fileSize);
*fileSize = 0;
nn::Result result;
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;
}
}
}
}
}
void WriteTwlSaveData()
{
nn::Result result;
std::vector<common::SavePathInfo> fileList;
COMMON_LOGGER("Export Twl Save Data.\n");
// ディレクトリ作成
s_SdWriter.CreateDirectory((::std::wstring(common::SDMC_ROOT_DIRECTORY_PATH) +
std::wstring(common::SD_SAVEDATA_TWL_ROOT_NAME)).c_str());
// セーブデータを含むディレクトリ一覧を生成
result = nn::fs::MountSpecialArchive(common::NAND_TWL_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_TWL_NAND);
COMMON_LOGGER_RESULT_IF_FAILED(result);
ListTwlSaveDataDirectory(std::wstring(common::NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH), 0, &fileList);
NN_LOG("\n");
for (std::vector<common::SavePathInfo>::reverse_iterator it = fileList.rbegin(); it != fileList.rend(); it++)
{
NN_LOG("%ls\n", it->name.c_str());
}
// 合計サイズ取得
s64 fileSize;
CalculateTwlSaveData(&fileList, &fileSize);
common::InitializeTransferProgress(fileSize);
NN_LOG("\n");
// SDに書き出し
result = common::SdMountManager::Mount();
size_t bufSize = common::HeapManager::GetHeap()->GetAllocatableSize();
NN_LOG("AllocatableSize = %d\n", bufSize);
void* buf = common::HeapManager::GetHeap()->Allocate(bufSize, AES_BLOCK_SIZE);
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::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)
{
common::ExportTwlSaveDirectory(toPath.c_str(), &list, &s_FileListContext);
}
else
{
common::ExportTwlSaveFile(it->name.c_str(), toPath.c_str(), buf, bufSize, &list,
&s_FileListContext);
}
}
}
list.TryFlush();
list.Finalize();
}
}
common::HeapManager::GetHeap()->Free(buf);
}
common::SdMountManager::Unmount();
nn::fs::Unmount( common::NAND_TWL_ARCHIVE_NAME);
}
void WriteTwlPhotoData()
@ -391,6 +639,14 @@ void InitializeFileListContext()
s_FileListContext.Initialize();
}
void ExportTwlSaveData()
{
// 不要なデータを削除する
DeleteTrash(common::SDMC_ROOT_DIRECTORY_PATH);
s_ExportThread.Start(WriteTwlSaveData, s_ExportThreadStack);
}
void ExportTwlPhotoData()
{
s_ExportThread.Start(WriteTwlPhotoData, s_ExportThreadStack);
@ -398,9 +654,6 @@ void ExportTwlPhotoData()
void ExportTwlSoundData()
{
// 不要なデータを削除する
DeleteTrash(common::SDMC_ROOT_DIRECTORY_PATH);
s_ExportThread.Start(WriteTwlSoundData, s_ExportThreadStack);
}

View File

@ -22,6 +22,7 @@ namespace ConsoleBackup
{
void InitializeFileListContext();
void ExportTwlSaveData();
void ExportTwlPhotoData();
void ExportTwlSoundData();
void ExportData();

View File

@ -25,11 +25,13 @@ const char* const NAND_ARCHIVE_NAME = "nand:";
const char* const SDMC_ARCHIVE_NAME = "sdmc:";
const char* const NAND_TWL_PHOTO_ARCHIVE_NAME = "twlp:";
const char* const NAND_TWL_SOUND_ARCHIVE_NAME = "twls:";
const char* const NAND_TWL_ARCHIVE_NAME = "twln:";
const wchar_t* const LOG_ROOT_DIRECTORY_PATH = L"sdmc:/CTR_Console_Repair";
const wchar_t* const SD_SAVEDATA_ROOT_NAME = L"CTR_Console_Repair/CTRBackup/";
const wchar_t* const SD_SAVEDATA_TWL_PHOTO_ROOT_NAME = L"CTR_Console_Repair/TWLPhotoBackup/";
const wchar_t* const SD_SAVEDATA_TWL_SOUND_ROOT_NAME = L"CTR_Console_Repair/TWLSoundBackup/";
const wchar_t* const SD_SAVEDATA_TWL_ROOT_NAME = L"CTR_Console_Repair/TWLBackup/";
const wchar_t* const NIM_SAVEDATA_DIRECTORY_NAME = L"sysdata/0001002c";
const wchar_t* const LOG_PATHNAME = L"CTR_Console_Repair/Migration_Log.txt";
const wchar_t* const LOG_FILENAME = L"Migration_Log.txt";
@ -44,6 +46,7 @@ const wchar_t* const IVS_PATHNAME = L"sdmc:/CTR_Console_Repair/movable.sed";
const wchar_t* const NAND_DATA_ROOT_PATHNAME_WITH_SLASH = L"nand:/data/";
const wchar_t* const NAND_TWL_PHOTO_DATA_ROOT_PATHNAME_WITH_SLASH = L"twlp:/";
const wchar_t* const NAND_TWL_SOUND_DATA_ROOT_PATHNAME_WITH_SLASH = L"twls:/";
const wchar_t* const NAND_TWL_DATA_ROOT_PATHNAME_WITHOUT_SLASH = L"twln:/title";
const wchar_t* const SDMC_ROOT_DIRECTORY_PATH = L"sdmc:/";
const wchar_t* const WRITE_FINISHED_CHECK_PATHNAME = L"sdmc:/CTR_Console_Repair/WriteFinished";
const wchar_t* const UPDATE_CHECK_PATHNAME = L"sdmc:/CTR_Console_Repair/UpdateFinished";
@ -68,6 +71,7 @@ const char* const TWL_ARCHIVE_NAME_TABLE[TWL_PATHNAME_MAX] =
{
common::NAND_TWL_PHOTO_ARCHIVE_NAME,
common::NAND_TWL_SOUND_ARCHIVE_NAME
};
const wchar_t* const SD_TWL_ROOTNAME_TABLE[TWL_PATHNAME_MAX] =

View File

@ -134,6 +134,181 @@ bool ExistsInList(ImportDataList* fileList, const wchar_t* path, bool isDirector
return returnValue;
}
// 単一のディレクトリを作成する
// アーカイブはマウント済みにしておく
void ExportTwlSaveDirectory(const wchar_t* dirPath, nn::fs::FileOutputStream* list,
nn::crypto::Sha256Context* listContext)
{
NN_LOG("Create Directory %ls\n", dirPath);
nn::Result result = nn::fs::TryCreateDirectory(dirPath);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
AddPathNameAndUpdateContext(list, dirPath, -1, listContext);
}
// 単一のファイルをコピーする
// アーカイブはマウント済みにしておく
bool ExportTwlSaveFile(const wchar_t* from_path, const wchar_t* to_path, void* buf, const size_t bufSize,
nn::fs::FileOutputStream* list, nn::crypto::Sha256Context* listContext)
{
NN_LOG("from = %ls\n", from_path);
NN_LOG("to = %ls\n", to_path);
nn::Result result;
bool ret_value = false;
// ファイル作成
nn::fs::FileInputStream from_file;
nn::fs::FileStream to_file;
s64 filesize;
s32 readsize;
s32 writesize;
NN_LOG("Copy File %ls\n", from_path);
// 読み込み対象ファイル開く
result = from_file.TryInitialize(from_path);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
}
else
{
// 読み込み対象ファイルのサイズ取得
result = from_file.TryGetSize(&filesize);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
}
else
{
AddPathNameAndUpdateContext(list, to_path, filesize, listContext);
nn::crypto::SwAesCtrContext swAesCtrContext;
swAesCtrContext.Initialize(iv, common::key, sizeof(key));
size_t totalReadSize = 0;
nn::crypto::Sha256Context context;
context.Initialize();
// ファイルサイズをヘッダに書いておく
// 書き込み対象ファイル作成
result = nn::fs::TryCreateFile(to_path, filesize);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
result = to_file.TryInitialize(to_path,
nn::fs::OPEN_MODE_READ | nn::fs::OPEN_MODE_WRITE | nn::fs::OPEN_MODE_CREATE);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
}
// フルパスをハッシュに含める
context.Update(from_path, std::wcslen(from_path) * sizeof(wchar_t));
BackupDataHeader header;
BackupDataHeader enc;
std::memset(&header, 0, sizeof(header));
std::memset(&enc, 0, sizeof(enc));
header.size = filesize;
result = swAesCtrContext.Encrypt(&enc, &header, sizeof(header));
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
context.Update(&enc, sizeof(enc));
s32 writeSize;
result = to_file.TryWrite(&writeSize, &enc, sizeof(enc), false);
if (result.IsFailure())
{
ret_value = false;
return ret_value;
}
while (1)
{
// バッファの後半半分を暗号・復号用に使う
result = from_file.TryRead(&readsize, buf, bufSize / 2);
totalReadSize += readsize;
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
return ret_value;
}
else
{
if (readsize == 0)
{
NN_LOG("Add CMAC %ls\n", from_path);
// SHA256を計算してCMACを付加する
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);
result = to_file.TryWrite(&writesize, cmac, sizeof(cmac));
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
}
result = to_file.TryFlush();
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
}
break;
}
else
{
NN_LOG("EncryptSize = %d\n", readsize);
u8 paddingSize = 0;
AddPkcsPadding(&paddingSize, reinterpret_cast<bit8*> (buf), bufSize / 2, &readsize);
// 暗号化後SHA256を計算しつつ書き込み
result = swAesCtrContext.Encrypt(reinterpret_cast<bit8*> (buf) + bufSize / 2, buf, readsize);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
context.Update(reinterpret_cast<bit8*> (buf) + bufSize / 2, readsize);
result = to_file.TryWrite(&writesize, reinterpret_cast<bit8*> (buf) + bufSize / 2, readsize,
false);
// 事前計算したファイルサイズに一致させるためパディング分減算
readsize -= paddingSize;
s_FinishedFileSize += readsize;
s_Progress = s_FinishedFileSize * 100 / s_TotalFileSize;
NN_LOG("finish = %lld, total = %lld, progress = %lld\n", s_FinishedFileSize, s_TotalFileSize, s_Progress);
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
}
}
}
}
to_file.Finalize();
}
}
from_file.Finalize();
return ret_value;
}
// ディレクトリ間のコピー
// アーカイブ越しのコピーが可能
// アーカイブにマウントした状態で呼び出す必要あり
@ -195,12 +370,7 @@ bool CopyDirectory(ImportDataList* fileList, const wchar_t * from_path, const wc
// ディレクトリ作成
NN_LOG("Create Directory %ls\n", target_to.str().c_str());
result = nn::fs::TryCreateDirectory(target_to.str().c_str());
if (result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
}
else
if (result.IsSuccess() || result.IsFailure() && result <= nn::fs::ResultAlreadyExists())
{
target_from << L"/";
target_to << L"/";
@ -209,13 +379,17 @@ bool CopyDirectory(ImportDataList* fileList, const wchar_t * from_path, const wc
AddPathNameAndUpdateContext(list, target_to.str().c_str(), -1, listContext);
}
// 再帰処理
if (!CopyDirectory(fileList, target_from.str().c_str(), target_to.str().c_str(), buf, bufSize, encode, list, listContext))
{
ret_value = false;
}
}
else
{
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
ret_value = false;
}
}
// ファイルの場合
else

View File

@ -25,6 +25,10 @@ namespace common
{
nn::Result CalculateFileNum(std::wstring currentDirectory, u32& fileNum, s64& fileSize);
void ExportTwlSaveDirectory(const wchar_t* dirPath, nn::fs::FileOutputStream* list,
nn::crypto::Sha256Context* listContext);
bool ExportTwlSaveFile(const wchar_t* from_path, const wchar_t* to_path, void* buf, const size_t bufSize,
nn::fs::FileOutputStream* list, nn::crypto::Sha256Context* listContext);
bool CopyDirectory(ImportDataList* fileList, const wchar_t * from_path, const wchar_t * to_path, void* buf,
const size_t bufSize, bool encode, nn::fs::FileOutputStream* list, nn::crypto::Sha256Context* listContext);
u32 GetProgress();

View File

@ -99,6 +99,14 @@ struct ImportDataEntry
};
typedef std::vector<common::ImportDataEntry> ImportDataList;
struct SavePathInfo
{
std::wstring name;
NN_PADDING3;
bool isDirectory;
};
}
#endif /* COMMON_TYPES_H_ */