diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index bde5e04a1060..c0c5cbc05a14 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))) - { - 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). @@ -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; } -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; } } diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp index 401f7f4d7eb9..e0a6315551c0 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 752448ea9522..48f9efe3b3b2 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)