From 1cd4be1d0f837ea10741149bb2ea9c5e51ecb756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 2 Nov 2017 11:34:13 +0100 Subject: [PATCH 1/3] WiiUtils: Unify the check and repair functions Makes it clearer what actions will be taken for every issue that is found. --- Source/Core/Core/WiiUtils.cpp | 83 ++++++++++++++++------------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index bde5e04a10..034da32334 100644 --- a/Source/Core/Core/WiiUtils.cpp +++ b/Source/Core/Core/WiiUtils.cpp @@ -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; @@ -787,41 +800,23 @@ NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios) { 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; } } From 71d4c47eb5733e329474f934b54fd59eb23381fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 2 Nov 2017 11:37:51 +0100 Subject: [PATCH 2/3] UI: Tweak the NAND check popup message Inform the user that re-launching titles can also fix the issues. --- Source/Core/DolphinQt2/MenuBar.cpp | 24 +++++++++++++++--------- Source/Core/DolphinWX/FrameTools.cpp | 19 +++++++++++++------ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp index 401f7f4d7e..e0a6315551 100644 --- a/Source/Core/DolphinQt2/MenuBar.cpp +++ b/Source/Core/DolphinQt2/MenuBar.cpp @@ -4,6 +4,8 @@ #include "DolphinQt2/MenuBar.h" +#include + #include #include #include @@ -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) diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 752448ea95..48f9efe3b3 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -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) From f2eee368e07823277b42739e78aa36dec0d90ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 2 Nov 2017 17:59:53 +0100 Subject: [PATCH 3/3] WiiUtils: Ignore missing contents for DLC titles It is not possible to tell whether DLC contents are supposed to be present on the NAND or not, because they're treated as "optional". So this commit changes the NAND check to not consider missing contents for DLC titles as an issue. --- Source/Core/Core/WiiUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index 034da32334..c0c5cbc05a 100644 --- a/Source/Core/Core/WiiUtils.cpp +++ b/Source/Core/Core/WiiUtils.cpp @@ -796,7 +796,7 @@ static NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios, bool repair) [](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);