Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements and important fix for NAND checks #6161

Merged
merged 3 commits into from Nov 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 40 additions & 45 deletions Source/Core/Core/WiiUtils.cpp
Expand Up @@ -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)))
{
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)))
for (const std::string& dir : {content_dir, data_dir})
{
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).
Expand All @@ -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())
{
Expand All @@ -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;
Expand All @@ -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;
}

bool RepairNAND(IOS::HLE::Kernel& ios)
NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios)
{
const auto es = ios.GetES();

// Delete an old, unneeded file
File::Delete(Common::RootUserPath(Common::FROM_CONFIGURED_ROOT) + "/sys/replace");
return CheckNAND(ios, false);
}

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;
bool RepairNAND(IOS::HLE::Kernel& ios)
{
return !CheckNAND(ios, true).bad;
}
}
24 changes: 15 additions & 9 deletions Source/Core/DolphinQt2/MenuBar.cpp
Expand Up @@ -4,6 +4,8 @@

#include "DolphinQt2/MenuBar.h"

#include <cinttypes>

#include <QAction>
#include <QDesktopServices>
#include <QFileDialog>
Expand All @@ -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"
Expand Down Expand Up @@ -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)
Expand Down
19 changes: 13 additions & 6 deletions Source/Core/DolphinWX/FrameTools.cpp
Expand Up @@ -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)
Expand Down