Merge pull request #6161 from leoetlino/nand-check-improvements

Improvements and important fix for NAND checks
This commit is contained in:
Anthony 2017-11-02 16:50:02 -07:00 committed by GitHub
commit 423cde2b9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 60 deletions

View File

@ -723,30 +723,40 @@ UpdateResult DoDiscUpdate(UpdateCallback update_callback, const std::string& ima
return updater.DoDiscUpdate();
}
NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios)
static NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios, bool repair)
{
NANDCheckResult result;
const auto es = ios.GetES();
// Check for NANDs that were used with old Dolphin versions.
if (File::Exists(Common::RootUserPath(Common::FROM_CONFIGURED_ROOT) + "/sys/replace"))
const std::string sys_replace_path =
Common::RootUserPath(Common::FROM_CONFIGURED_ROOT) + "/sys/replace";
if (File::Exists(sys_replace_path))
{
ERROR_LOG(CORE, "CheckNAND: NAND was used with old versions, so it is likely to be damaged");
result.bad = true;
if (repair)
File::Delete(sys_replace_path);
else
result.bad = true;
}
for (const u64 title_id : es->GetInstalledTitles())
{
const std::string title_dir = Common::GetTitlePath(title_id, Common::FROM_CONFIGURED_ROOT);
const std::string content_dir = title_dir + "/content";
const std::string data_dir = title_dir + "/data";
// Check for missing title sub directories.
if (!File::IsDirectory(Common::GetTitleContentPath(title_id, Common::FROM_CONFIGURED_ROOT)))
for (const std::string& dir : {content_dir, data_dir})
{
ERROR_LOG(CORE, "CheckNAND: Missing content directory for title %016" PRIx64, title_id);
result.bad = true;
}
if (!File::IsDirectory(Common::GetTitleDataPath(title_id, Common::FROM_CONFIGURED_ROOT)))
{
ERROR_LOG(CORE, "CheckNAND: Missing data directory for title %016" PRIx64, title_id);
result.bad = true;
if (File::IsDirectory(dir))
continue;
ERROR_LOG(CORE, "CheckNAND: Missing dir %s for title %016" PRIx64, dir.c_str(), title_id);
if (repair)
File::CreateDir(dir);
else
result.bad = true;
}
// Check for incomplete title installs (missing ticket, TMD or contents).
@ -755,12 +765,12 @@ NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios)
{
ERROR_LOG(CORE, "CheckNAND: Missing ticket for title %016" PRIx64, title_id);
result.titles_to_remove.insert(title_id);
result.bad = true;
if (repair)
File::DeleteDirRecursively(title_dir);
else
result.bad = true;
}
const std::string content_dir =
Common::GetTitleContentPath(title_id, Common::FROM_CONFIGURED_ROOT);
const auto tmd = es->FindInstalledTMD(title_id);
if (!tmd.IsValid())
{
@ -772,7 +782,10 @@ NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios)
{
ERROR_LOG(CORE, "CheckNAND: Missing TMD for title %016" PRIx64, title_id);
result.titles_to_remove.insert(title_id);
result.bad = true;
if (repair)
File::DeleteDirRecursively(title_dir);
else
result.bad = true;
}
// Further checks require the TMD to be valid.
continue;
@ -783,45 +796,27 @@ NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios)
[](const auto& content) { return !content.IsShared(); });
if (is_installed && installed_contents != tmd.GetContents() &&
(tmd.GetTitleFlags() & IOS::ES::TitleFlags::TITLE_TYPE_WFS_MAYBE) == 0)
(tmd.GetTitleFlags() & IOS::ES::TitleFlags::TITLE_TYPE_DATA) == 0)
{
ERROR_LOG(CORE, "CheckNAND: Missing contents for title %016" PRIx64, title_id);
result.titles_to_remove.insert(title_id);
result.bad = true;
if (repair)
File::DeleteDirRecursively(title_dir);
else
result.bad = true;
}
}
return result;
}
NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios)
{
return CheckNAND(ios, false);
}
bool RepairNAND(IOS::HLE::Kernel& ios)
{
const auto es = ios.GetES();
// Delete an old, unneeded file
File::Delete(Common::RootUserPath(Common::FROM_CONFIGURED_ROOT) + "/sys/replace");
for (const u64 title_id : es->GetInstalledTitles())
{
// Create missing title sub directories.
const std::string content_dir =
Common::GetTitleContentPath(title_id, Common::FROM_CONFIGURED_ROOT);
const std::string data_dir = Common::GetTitleDataPath(title_id, Common::FROM_CONFIGURED_ROOT);
File::CreateDir(content_dir);
File::CreateDir(data_dir);
// If there's nothing in the content directory and no ticket,
// this title shouldn't exist at all on the NAND.
// WARNING: This will delete associated save data!
const auto content_files = File::ScanDirectoryTree(content_dir, false).children;
const bool has_no_tmd_but_contents =
!es->FindInstalledTMD(title_id).IsValid() && !content_files.empty();
if (has_no_tmd_but_contents || !es->FindSignedTicket(title_id).IsValid())
{
const std::string title_dir = Common::GetTitlePath(title_id, Common::FROM_CONFIGURED_ROOT);
File::DeleteDirRecursively(title_dir);
}
}
return !CheckNAND(ios).bad;
return !CheckNAND(ios, true).bad;
}
}

View File

@ -4,6 +4,8 @@
#include "DolphinQt2/MenuBar.h"
#include <cinttypes>
#include <QAction>
#include <QDesktopServices>
#include <QFileDialog>
@ -13,6 +15,7 @@
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/StringUtil.h"
#include "Core/CommonTitles.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
@ -550,20 +553,23 @@ void MenuBar::CheckNAND()
"Do you want to try to repair the NAND?");
if (!result.titles_to_remove.empty())
{
message += tr("\n\nWARNING: Fixing this NAND requires the deletion of titles that have "
"incomplete data on the NAND, including all associated save data. "
"By continuing, the following title(s) will be removed:\n\n");
std::string title_listings;
Core::TitleDatabase title_db;
for (const u64 title_id : result.titles_to_remove)
{
const std::string name = title_db.GetTitleName(title_id);
message += !name.empty() ?
QStringLiteral("%1 (%2)")
.arg(QString::fromStdString(name))
.arg(title_id, 16, 16, QLatin1Char('0')) :
QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char('0'));
message += QStringLiteral("\n");
title_listings += !name.empty() ?
StringFromFormat("%s (%016" PRIx64 ")", name.c_str(), title_id) :
StringFromFormat("%016" PRIx64, title_id);
title_listings += "\n";
}
message += tr("\n\nWARNING: Fixing this NAND requires the deletion of titles that have "
"incomplete data on the NAND, including all associated save data. "
"By continuing, the following title(s) will be removed:\n\n"
"%1"
"\nLaunching these titles may also fix the issues.")
.arg(QString::fromStdString(title_listings));
}
if (QMessageBox::question(this, tr("NAND Check"), message) != QMessageBox::Yes)

View File

@ -1327,17 +1327,24 @@ void CFrame::OnCheckNAND(wxCommandEvent&)
"Do you want to try to repair the NAND?");
if (!result.titles_to_remove.empty())
{
message += _("\n\nWARNING: Fixing this NAND requires the deletion of titles that have "
"incomplete data on the NAND, including all associated save data. "
"By continuing, the following title(s) will be removed:\n\n");
std::string title_listings;
Core::TitleDatabase title_db;
for (const u64 title_id : result.titles_to_remove)
{
const std::string name = title_db.GetTitleName(title_id);
message += !name.empty() ? StringFromFormat("%s (%016" PRIx64 ")", name.c_str(), title_id) :
StringFromFormat("%016" PRIx64, title_id);
message += "\n";
title_listings += !name.empty() ?
StringFromFormat("%s (%016" PRIx64 ")", name.c_str(), title_id) :
StringFromFormat("%016" PRIx64, title_id);
title_listings += "\n";
}
message += wxString::Format(
_("\n\nWARNING: Fixing this NAND requires the deletion of titles that have "
"incomplete data on the NAND, including all associated save data. "
"By continuing, the following title(s) will be removed:\n\n"
"%s"
"\nLaunching these titles may also fix the issues."),
title_listings.c_str());
}
if (wxMessageBox(message, _("NAND Check"), wxYES_NO) != wxYES)