mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 13:57:57 -07:00
WiiUtils: Attempt to fix the NAND more aggressively
Change the repair logic to fix issues more aggressively by deleting bad titles. This is necessary because of a bug in Dolphin's WAD boot code. The UI code was updated to inform the user about titles that will be deleted if they continue a repair, before deleting anything.
This commit is contained in:
parent
e1c0b8d011
commit
02e17594b0
@ -686,16 +686,16 @@ UpdateResult DoDiscUpdate(UpdateCallback update_callback, const std::string& ima
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckNAND(IOS::HLE::Kernel& ios)
|
NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios)
|
||||||
{
|
{
|
||||||
bool bad = false;
|
NANDCheckResult result;
|
||||||
const auto es = ios.GetES();
|
const auto es = ios.GetES();
|
||||||
|
|
||||||
// Check for NANDs that were used with old Dolphin versions.
|
// Check for NANDs that were used with old Dolphin versions.
|
||||||
if (File::Exists(Common::RootUserPath(Common::FROM_CONFIGURED_ROOT) + "/sys/replace"))
|
if (File::Exists(Common::RootUserPath(Common::FROM_CONFIGURED_ROOT) + "/sys/replace"))
|
||||||
{
|
{
|
||||||
ERROR_LOG(CORE, "CheckNAND: NAND was used with old versions, so it is likely to be damaged");
|
ERROR_LOG(CORE, "CheckNAND: NAND was used with old versions, so it is likely to be damaged");
|
||||||
bad = true;
|
result.bad = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const u64 title_id : es->GetInstalledTitles())
|
for (const u64 title_id : es->GetInstalledTitles())
|
||||||
@ -704,12 +704,12 @@ bool CheckNAND(IOS::HLE::Kernel& ios)
|
|||||||
if (!File::IsDirectory(Common::GetTitleContentPath(title_id, Common::FROM_CONFIGURED_ROOT)))
|
if (!File::IsDirectory(Common::GetTitleContentPath(title_id, Common::FROM_CONFIGURED_ROOT)))
|
||||||
{
|
{
|
||||||
ERROR_LOG(CORE, "CheckNAND: Missing content directory for title %016" PRIx64, title_id);
|
ERROR_LOG(CORE, "CheckNAND: Missing content directory for title %016" PRIx64, title_id);
|
||||||
bad = true;
|
result.bad = true;
|
||||||
}
|
}
|
||||||
if (!File::IsDirectory(Common::GetTitleDataPath(title_id, Common::FROM_CONFIGURED_ROOT)))
|
if (!File::IsDirectory(Common::GetTitleDataPath(title_id, Common::FROM_CONFIGURED_ROOT)))
|
||||||
{
|
{
|
||||||
ERROR_LOG(CORE, "CheckNAND: Missing data directory for title %016" PRIx64, title_id);
|
ERROR_LOG(CORE, "CheckNAND: Missing data directory for title %016" PRIx64, title_id);
|
||||||
bad = true;
|
result.bad = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for incomplete title installs (missing ticket, TMD or contents).
|
// Check for incomplete title installs (missing ticket, TMD or contents).
|
||||||
@ -717,13 +717,26 @@ bool CheckNAND(IOS::HLE::Kernel& ios)
|
|||||||
if (!IOS::ES::IsDiscTitle(title_id) && !ticket.IsValid())
|
if (!IOS::ES::IsDiscTitle(title_id) && !ticket.IsValid())
|
||||||
{
|
{
|
||||||
ERROR_LOG(CORE, "CheckNAND: Missing ticket for title %016" PRIx64, title_id);
|
ERROR_LOG(CORE, "CheckNAND: Missing ticket for title %016" PRIx64, title_id);
|
||||||
bad = true;
|
result.titles_to_remove.insert(title_id);
|
||||||
|
result.bad = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string content_dir =
|
||||||
|
Common::GetTitleContentPath(title_id, Common::FROM_CONFIGURED_ROOT);
|
||||||
|
|
||||||
const auto tmd = es->FindInstalledTMD(title_id);
|
const auto tmd = es->FindInstalledTMD(title_id);
|
||||||
if (!tmd.IsValid())
|
if (!tmd.IsValid())
|
||||||
{
|
{
|
||||||
WARN_LOG(CORE, "CheckNAND: Missing TMD for title %016" PRIx64, title_id);
|
if (File::ScanDirectoryTree(content_dir, false).children.empty())
|
||||||
|
{
|
||||||
|
WARN_LOG(CORE, "CheckNAND: Missing TMD for title %016" PRIx64, title_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR_LOG(CORE, "CheckNAND: Missing TMD for title %016" PRIx64, title_id);
|
||||||
|
result.titles_to_remove.insert(title_id);
|
||||||
|
result.bad = true;
|
||||||
|
}
|
||||||
// Further checks require the TMD to be valid.
|
// Further checks require the TMD to be valid.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -736,11 +749,12 @@ bool CheckNAND(IOS::HLE::Kernel& ios)
|
|||||||
(tmd.GetTitleFlags() & IOS::ES::TitleFlags::TITLE_TYPE_WFS_MAYBE) == 0)
|
(tmd.GetTitleFlags() & IOS::ES::TitleFlags::TITLE_TYPE_WFS_MAYBE) == 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG(CORE, "CheckNAND: Missing contents for title %016" PRIx64, title_id);
|
ERROR_LOG(CORE, "CheckNAND: Missing contents for title %016" PRIx64, title_id);
|
||||||
bad = true;
|
result.titles_to_remove.insert(title_id);
|
||||||
|
result.bad = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return !bad;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RepairNAND(IOS::HLE::Kernel& ios)
|
bool RepairNAND(IOS::HLE::Kernel& ios)
|
||||||
@ -759,15 +773,18 @@ bool RepairNAND(IOS::HLE::Kernel& ios)
|
|||||||
File::CreateDir(content_dir);
|
File::CreateDir(content_dir);
|
||||||
File::CreateDir(data_dir);
|
File::CreateDir(data_dir);
|
||||||
|
|
||||||
// If there's nothing in the content/data directories and no ticket,
|
// If there's nothing in the content directory and no ticket,
|
||||||
// this title shouldn't exist at all on the NAND.
|
// this title shouldn't exist at all on the NAND.
|
||||||
if (File::ScanDirectoryTree(content_dir, false).children.empty() &&
|
// WARNING: This will delete associated save data!
|
||||||
File::ScanDirectoryTree(data_dir, false).children.empty() &&
|
const auto content_files = File::ScanDirectoryTree(content_dir, false).children;
|
||||||
!DiscIO::FindSignedTicket(title_id).IsValid())
|
const bool has_no_tmd_but_contents =
|
||||||
|
!es->FindInstalledTMD(title_id).IsValid() && !content_files.empty();
|
||||||
|
if (has_no_tmd_but_contents || !DiscIO::FindSignedTicket(title_id).IsValid())
|
||||||
{
|
{
|
||||||
es->DeleteTitle(title_id);
|
const std::string title_dir = Common::GetTitlePath(title_id, Common::FROM_CONFIGURED_ROOT);
|
||||||
|
File::DeleteDirRecursively(title_dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return CheckNAND(ios);
|
return !CheckNAND(ios).bad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
@ -58,6 +59,11 @@ UpdateResult DoOnlineUpdate(UpdateCallback update_callback, const std::string& r
|
|||||||
UpdateResult DoDiscUpdate(UpdateCallback update_callback, const std::string& image_path);
|
UpdateResult DoDiscUpdate(UpdateCallback update_callback, const std::string& image_path);
|
||||||
|
|
||||||
// Check the emulated NAND for common issues.
|
// Check the emulated NAND for common issues.
|
||||||
bool CheckNAND(IOS::HLE::Kernel& ios);
|
struct NANDCheckResult
|
||||||
|
{
|
||||||
|
bool bad = false;
|
||||||
|
std::unordered_set<u64> titles_to_remove;
|
||||||
|
};
|
||||||
|
NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios);
|
||||||
bool RepairNAND(IOS::HLE::Kernel& ios);
|
bool RepairNAND(IOS::HLE::Kernel& ios);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "Core/IOS/IOS.h"
|
#include "Core/IOS/IOS.h"
|
||||||
#include "Core/Movie.h"
|
#include "Core/Movie.h"
|
||||||
#include "Core/State.h"
|
#include "Core/State.h"
|
||||||
|
#include "Core/TitleDatabase.h"
|
||||||
#include "Core/WiiUtils.h"
|
#include "Core/WiiUtils.h"
|
||||||
#include "DiscIO/NANDImporter.h"
|
#include "DiscIO/NANDImporter.h"
|
||||||
#include "DolphinQt2/AboutDialog.h"
|
#include "DolphinQt2/AboutDialog.h"
|
||||||
@ -537,21 +538,37 @@ void MenuBar::ExportWiiSaves()
|
|||||||
void MenuBar::CheckNAND()
|
void MenuBar::CheckNAND()
|
||||||
{
|
{
|
||||||
IOS::HLE::Kernel ios;
|
IOS::HLE::Kernel ios;
|
||||||
if (WiiUtils::CheckNAND(ios))
|
WiiUtils::NANDCheckResult result = WiiUtils::CheckNAND(ios);
|
||||||
|
if (!result.bad)
|
||||||
{
|
{
|
||||||
QMessageBox::information(this, tr("NAND Check"), tr("No issues have been detected."));
|
QMessageBox::information(this, tr("NAND Check"), tr("No issues have been detected."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (QMessageBox::question(
|
QString message = tr("The emulated NAND is damaged. System titles such as the Wii Menu and "
|
||||||
this, tr("NAND Check"),
|
"the Wii Shop Channel may not work correctly.\n\n"
|
||||||
tr("The emulated NAND is damaged. System titles such as the Wii Menu and "
|
"Do you want to try to repair the NAND?");
|
||||||
"the Wii Shop Channel may not work correctly.\n\n"
|
if (!result.titles_to_remove.empty())
|
||||||
"Do you want to try to repair the NAND?")) != QMessageBox::Yes)
|
|
||||||
{
|
{
|
||||||
return;
|
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");
|
||||||
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (QMessageBox::question(this, tr("NAND Check"), message) != QMessageBox::Yes)
|
||||||
|
return;
|
||||||
|
|
||||||
if (WiiUtils::RepairNAND(ios))
|
if (WiiUtils::RepairNAND(ios))
|
||||||
{
|
{
|
||||||
QMessageBox::information(this, tr("NAND Check"), tr("The NAND has been repaired."));
|
QMessageBox::information(this, tr("NAND Check"), tr("The NAND has been repaired."));
|
||||||
|
@ -1312,20 +1312,34 @@ void CFrame::OnImportBootMiiBackup(wxCommandEvent& WXUNUSED(event))
|
|||||||
void CFrame::OnCheckNAND(wxCommandEvent&)
|
void CFrame::OnCheckNAND(wxCommandEvent&)
|
||||||
{
|
{
|
||||||
IOS::HLE::Kernel ios;
|
IOS::HLE::Kernel ios;
|
||||||
if (WiiUtils::CheckNAND(ios))
|
WiiUtils::NANDCheckResult result = WiiUtils::CheckNAND(ios);
|
||||||
|
if (!result.bad)
|
||||||
{
|
{
|
||||||
wxMessageBox(_("No issues have been detected."), _("NAND Check"), wxOK | wxICON_INFORMATION);
|
wxMessageBox(_("No issues have been detected."), _("NAND Check"), wxOK | wxICON_INFORMATION);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxMessageBox("The emulated NAND is damaged. System titles such as the Wii Menu and "
|
wxString message = _("The emulated NAND is damaged. System titles such as the Wii Menu and "
|
||||||
"the Wii Shop Channel may not work correctly.\n\n"
|
"the Wii Shop Channel may not work correctly.\n\n"
|
||||||
"Do you want to try to repair the NAND?",
|
"Do you want to try to repair the NAND?");
|
||||||
_("NAND Check"), wxYES_NO) != wxYES)
|
if (!result.titles_to_remove.empty())
|
||||||
{
|
{
|
||||||
return;
|
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");
|
||||||
|
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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wxMessageBox(message, _("NAND Check"), wxYES_NO) != wxYES)
|
||||||
|
return;
|
||||||
|
|
||||||
if (WiiUtils::RepairNAND(ios))
|
if (WiiUtils::RepairNAND(ios))
|
||||||
{
|
{
|
||||||
wxMessageBox(_("The NAND has been repaired."), _("NAND Check"), wxOK | wxICON_INFORMATION);
|
wxMessageBox(_("The NAND has been repaired."), _("NAND Check"), wxOK | wxICON_INFORMATION);
|
||||||
|
Loading…
Reference in New Issue
Block a user