ctr_Repair/branches/2-1-1/sources/ConsoleBackup/SavedataChecker.cpp
N2614 fa59af905c 2ndNUP修正版2-1-1
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@548 385bec56-5757-e545-9c3a-d8741f4650f1
2011-12-21 08:21:20 +00:00

482 lines
16 KiB
C++

/*---------------------------------------------------------------------------*
Project: Horizon
File: NandSavedataChecker.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 <nn/fs/fs_ApiSysSaveData.h>
#include <nn/fs/fs_ApiSharedExtSaveData.h>
#include "SavedataChecker.h"
#include "CommonLogger.h"
#include "FileTransfer.h"
#include "FileName.h"
namespace ConsoleBackup
{
SavedataCheckerBase::SavedataCheckerBase(void* buf, size_t size) :
m_Buf(buf), m_Bufsize(size), m_CalculatedFileSize(0), m_TotalReadSize(0), m_CheckErrorOccured(false)
{
}
SavedataCheckerBase::~SavedataCheckerBase()
{
NN_LOG("m_TotalReadSize = %lld\n", m_TotalReadSize);
}
nn::Result SavedataCheckerBase::CleanUpFilesRecursively(bool* metaDataCrashed, bool* modified, std::string baseName,
std::wstring currentDirectory, bool erase)
{
nn::fs::Directory dir;
nn::fs::DirectoryEntry entry;
nn::Result result;
NN_LOG("%s\n", common::GetCharStr(currentDirectory.c_str()));
result = dir.TryInitialize(currentDirectory.c_str());
if (result.IsFailure())
{
COMMON_LOGGER_WARN(
"Error: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(currentDirectory).c_str()));
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
if (erase)
{
*metaDataCrashed = true;
}
return result;
}
for (;;)
{
s32 numRead;
result = dir.TryRead(&numRead, &entry, 1);
if (result.IsFailure())
{
dir.Finalize();
COMMON_LOGGER_WARN(
"Error: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(currentDirectory).c_str()));
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
if (erase)
{
*metaDataCrashed = true;
}
// ディレクトリの読み取りエラーなので再度読み取ってもエラーになる
return result;
}
if(numRead == 0)
{
break;
}
if (std::wcscmp(entry.entryName, L".") == 0 || std::wcscmp(entry.entryName, L"..") == 0)
{
continue;
}
// ディレクトリの場合
if (entry.attributes.isDirectory)
{
result = CleanUpFilesRecursively(metaDataCrashed, modified, baseName,
currentDirectory + std::wstring(entry.entryName) + std::wstring(L"/"), erase);
if(erase && result.IsFailure())
{
return result;
}
}
// ファイルの場合
else
{
nn::fs::FileInputStream file;
std::wstring filePath = (currentDirectory + std::wstring(entry.entryName)).c_str();
const wchar_t* path = filePath.c_str();
NN_LOG("%s\n", common::GetCharStr(path));
result = file.TryInitialize(path);
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED(result);
const bool silent = IsForceDeleteFile(common::GetCharStr(entry.entryName));
if(!silent)
{
COMMON_LOGGER_WARN("Error: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(filePath).c_str()));
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
}
if (erase || silent)
{
if(!silent)
{
COMMON_LOGGER_WARN("Deleting: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(filePath).c_str()));
}
result = nn::fs::TryDeleteFile(path);
*modified = true;
}
continue;
}
for (;;)
{
s32 readSize;
result = file.TryRead(&readSize, m_Buf, m_Bufsize);
if(result.IsFailure())
{
COMMON_LOGGER_RESULT_IF_FAILED(result);
const bool silent = IsForceDeleteFile(common::GetCharStr(entry.entryName));
if(!silent)
{
COMMON_LOGGER_WARN("Error: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(filePath).c_str()));
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
}
m_TotalReadSize += file.GetSize();
file.Finalize();
if (erase || silent)
{
if(!silent)
{
COMMON_LOGGER_WARN("Deleting: %s/%s\n", baseName.c_str(), common::GetCharStr(GetFilePathWithoutArchive(filePath).c_str()));
}
result = nn::fs::TryDeleteFile(path);
COMMON_LOGGER_RESULT_IF_FAILED(result);
*modified = true;
}
break;
}
else
{
m_TotalReadSize += readSize;
}
if(readSize == 0)
{
break;
}
}
}
}
return nn::ResultSuccess();
}
nn::Result SavedataCheckerBase::GetFileSize(std::wstring currentDirectory)
{
return common::CalculateFileSizeRecursively(currentDirectory, m_CalculatedFileSize);
}
s64 SavedataCheckerBase::GetCalculatedSize()
{
return m_CalculatedFileSize;
}
s64 SavedataCheckerBase::GetTotalReadSize()
{
return m_TotalReadSize;
}
bool SavedataCheckerBase::GetCheckErrorOccured()
{
return m_CheckErrorOccured;
}
std::wstring SavedataCheckerBase::GetFilePathWithoutArchive(std::wstring path)
{
std::wstring::size_type pos = path.find(L":/");
if(pos != std::wstring::npos)
{
return path.substr(pos + sizeof(L""));
}
else
{
return path;
}
}
bool SavedataCheckerBase::IsForceDeleteFile(const char* name)
{
return std::strcmp(common::BASHOTORYA_FILE_NAME, name) == 0;
}
NandSavedataChecker::NandSavedataChecker()
{
// TODO 自動生成されたコンストラクター・スタブ
}
NandSavedataChecker::NandSavedataChecker(void* buf, size_t size) : m_Buf(buf), m_Bufsize(size)
{
m_pSharedExtSaveChecker = new SharedExtSavedataChecker(buf, size);
m_pSysSaveChecker = new SystemSavedataChecker(buf, size);
}
NandSavedataChecker::~NandSavedataChecker()
{
delete m_pSharedExtSaveChecker;
delete m_pSysSaveChecker;
}
nn::Result NandSavedataChecker::CleanUp(bool erase)
{
nn::Result result;
m_pSharedExtSaveChecker->CalculateFileSize();
m_pSysSaveChecker->CalculateFileSize();
result = m_pSharedExtSaveChecker->CleanUp(erase);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = m_pSysSaveChecker->CleanUp(erase);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
return nn::ResultSuccess();
}
s64 NandSavedataChecker::GetProgress()
{
if (m_pSharedExtSaveChecker->GetCalculatedSize() == 0 || m_pSysSaveChecker->GetCalculatedSize() == 0)
{
return 0;
}
else
{
return (m_pSharedExtSaveChecker->GetTotalReadSize() + m_pSysSaveChecker->GetTotalReadSize()) * 100
/ (m_pSharedExtSaveChecker->GetCalculatedSize() + m_pSysSaveChecker->GetCalculatedSize());
}
}
bool NandSavedataChecker::GetCheckErrorOccured()
{
return m_pSharedExtSaveChecker->GetCheckErrorOccured() || m_pSysSaveChecker->GetCheckErrorOccured();
}
SystemSavedataChecker::SystemSavedataChecker()
{
}
SystemSavedataChecker::SystemSavedataChecker(void* buf, size_t size) : SavedataCheckerBase(buf, size)
{
}
SystemSavedataChecker::~SystemSavedataChecker()
{
}
nn::Result SystemSavedataChecker::CleanUp(bool erase)
{
nn::Result result;
std::wstring currentDirectory;
for (s32 i = 0; i < SYSTEM_SAVE_DATA_NUM; i++)
{
bool metaDataCrashed = false;
bool modified = false;
// SPIDERのスキップ
if(SYSTEM_SAVEDATA_COUPLE_LIST[i].id == 0x00020088 ||
SYSTEM_SAVEDATA_COUPLE_LIST[i].id == 0x0002009d ||
SYSTEM_SAVEDATA_COUPLE_LIST[i].id == 0x00020094)
{
NN_LOG("Skip SPIDER\n");
continue;
}
result = nn::fs::MountSystemSaveData(SYSTEM_SAVEDATA_ARCHIVE_NAME, SYSTEM_SAVEDATA_COUPLE_LIST[i].id );
if (result.IsFailure())
{
if(result <= nn::fs::ResultVerificationFailed())
{
NN_LOG("Mount Error: %s\n", SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str());
COMMON_LOGGER_WARN(
"Error: %s/\n", SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str());
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
if (erase)
{
COMMON_LOGGER_WARN(
"Deleting: %s/\n", SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str());
// 削除する
result = nn::fs::DeleteSystemSaveData(SYSTEM_SAVEDATA_COUPLE_LIST[i].id);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
}
else
{
NN_LOG("Mount %s\n", SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str());
// ファイルを個別にチェックする
result = CleanUpFilesRecursively(&metaDataCrashed, &modified, SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str(), L"ssave:/", erase);
// メタデータエラーの場合は一旦アンマウントしてからアーカイブごと削除
if (erase && metaDataCrashed)
{
// 削除する
COMMON_LOGGER_WARN( "Deleting: %s/\n", SYSTEM_SAVEDATA_COUPLE_LIST[i].name.c_str());
result = nn::fs::Unmount(SYSTEM_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::DeleteSystemSaveData(SYSTEM_SAVEDATA_COUPLE_LIST[i].id);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
continue;
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
if(modified)
{
result = nn::fs::CommitSystemSaveData(SYSTEM_SAVEDATA_ARCHIVE_NAME);
}
result = nn::fs::Unmount(SYSTEM_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
return nn::ResultSuccess();
}
nn::Result SystemSavedataChecker::CalculateFileSize()
{
nn::Result result;
for (s32 i = 0; i < SYSTEM_SAVE_DATA_NUM; i++)
{
result = nn::fs::MountSystemSaveData(SYSTEM_SAVEDATA_ARCHIVE_NAME, SYSTEM_SAVEDATA_COUPLE_LIST[i].id );
if (result.IsSuccess())
{
result = GetFileSize(L"ssave:/");
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::Unmount(SYSTEM_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
NN_LOG("CalculatedFileSize = %lld\n", m_CalculatedFileSize);
return result;
}
SharedExtSavedataChecker::SharedExtSavedataChecker()
{
}
SharedExtSavedataChecker::SharedExtSavedataChecker(void* buf, size_t size) : SavedataCheckerBase(buf, size)
{
}
SharedExtSavedataChecker::~SharedExtSavedataChecker()
{
}
nn::Result SharedExtSavedataChecker::CleanUp(bool erase)
{
nn::Result result;
const size_t ARRAY_SIZE = 256;
s32 numId;
bit32 IdArray[ARRAY_SIZE];
result = nn::fs::EnumerateSharedExtSaveData(&numId, IdArray, ARRAY_SIZE);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
NN_LOG_DEBUG("ExtData num = %d\n", numId);
for (s32 i = 0; i < numId; i++ )
{
bool metaDataCrashed = false;
bool modified = false;
char baseName[10];
nn::nstd::TSNPrintf(baseName, sizeof(baseName), "%X", IdArray[i]);
result = nn::fs::MountSharedExtSaveData(SHARED_EXT_SAVEDATA_ARCHIVE_NAME, IdArray[i]);
if (result.IsSuccess())
{
NN_LOG("Mount %x\n", IdArray[i]);
// アーカイブ内のファイル・ディレクトリをチェックする
result = CleanUpFilesRecursively(&metaDataCrashed, &modified, baseName, L"shext:/", erase);
// メタデータが壊れていた場合はアンマウントしてから削除する
if(erase && metaDataCrashed)
{
COMMON_LOGGER_WARN("Deleting %x/\n", IdArray[i]);
result = nn::fs::Unmount(SHARED_EXT_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::DeleteSharedExtSaveData(IdArray[i]);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
continue;
}
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::Unmount(SHARED_EXT_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
else
{
// アーカイブごと削除する
if(result <= nn::fs::ResultVerificationFailed())
{
NN_LOG("Mount Error: %x\n", IdArray[i]);
COMMON_LOGGER_WARN("Error: %x/\n", IdArray[i]);
m_CheckErrorOccured = true;
COMMON_LOGGER_RESULT_IF_FAILED(result);
if (erase)
{
COMMON_LOGGER_WARN("Deleting %x/\n", IdArray[i]);
result = nn::fs::DeleteSharedExtSaveData(IdArray[i]);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
}
}
return nn::ResultSuccess();
}
nn::Result SharedExtSavedataChecker::CalculateFileSize()
{
nn::Result result;
const size_t ARRAY_SIZE = 256;
s32 numId;
bit32 IdArray[ARRAY_SIZE];
result = nn::fs::EnumerateSharedExtSaveData(&numId, IdArray, ARRAY_SIZE);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
NN_LOG_DEBUG("ExtData num = %d\n", numId);
for (s32 i = 0; i < numId; i++ )
{
result = nn::fs::MountSharedExtSaveData(SHARED_EXT_SAVEDATA_ARCHIVE_NAME, IdArray[i]);
if (result.IsSuccess())
{
result = GetFileSize(L"shext:/");
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
result = nn::fs::Unmount(SHARED_EXT_SAVEDATA_ARCHIVE_NAME);
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result);
}
}
NN_LOG("CalculatedFileSize = %lld\n", m_CalculatedFileSize);
return nn::ResultSuccess();
}
} /* namespace ConsoleBackup */