mirror of
https://github.com/rvtr/ctr_Repair.git
synced 2025-10-31 13:51:08 -04:00
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@692 385bec56-5757-e545-9c3a-d8741f4650f1
491 lines
16 KiB
C++
491 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 <nn/fs/fs_ResultPrivate.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)
|
|
{
|
|
if((std::strcmp(common::BASHOTORYA_FILE_NAME, name) == 0) ||
|
|
(std::strcmp(common::BASHOTORYA2_FILE_NAME, name) == 0))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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() || result <= nn::fs::ResultDbmFileNotFound())
|
|
{
|
|
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 */
|