diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp index 30225febfbc3..92c2c19a0d98 100644 --- a/Source/Core/Core/WiiUtils.cpp +++ b/Source/Core/Core/WiiUtils.cpp @@ -961,6 +961,34 @@ static NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios, bool repair) } } + // Get some storage stats. + const auto fs = ios.GetFS(); + const auto root_stats = fs->GetExtendedDirectoryStats("/"); + + // The Wii System Menu's save/channel management only considers a specific subset of the Wii NAND + // user-accessible and will only use those folders when calculating the amount of free blocks it + // displays. This can have weird side-effects where the other parts of the NAND contain more data + // than reserved and it will display free blocks even though there isn't any space left. To avoid + // confusion, report the 'user' and 'system' data separately to the user. + u64 used_clusters_user = 0; + u64 used_inodes_user = 0; + for (std::string user_path : {"/meta", "/ticket", "/title/00010000", "/title/00010001", + "/title/00010003", "/title/00010004", "/title/00010005", + "/title/00010006", "/title/00010007", "/shared2/title"}) + { + const auto dir_stats = fs->GetExtendedDirectoryStats(user_path); + if (dir_stats) + { + used_clusters_user += dir_stats->used_clusters; + used_inodes_user += dir_stats->used_inodes; + } + } + + result.used_clusters_user = used_clusters_user; + result.used_clusters_system = root_stats ? (root_stats->used_clusters - used_clusters_user) : 0; + result.used_inodes_user = used_inodes_user; + result.used_inodes_system = root_stats ? (root_stats->used_inodes - used_inodes_user) : 0; + return result; } diff --git a/Source/Core/Core/WiiUtils.h b/Source/Core/Core/WiiUtils.h index ae2d7c85e080..c8f86d7253c0 100644 --- a/Source/Core/Core/WiiUtils.h +++ b/Source/Core/Core/WiiUtils.h @@ -101,6 +101,10 @@ struct NANDCheckResult { bool bad = false; std::unordered_set titles_to_remove; + u64 used_clusters_user = 0; + u64 used_clusters_system = 0; + u64 used_inodes_user = 0; + u64 used_inodes_system = 0; }; NANDCheckResult CheckNAND(IOS::HLE::Kernel& ios); bool RepairNAND(IOS::HLE::Kernel& ios); diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index b0989fae66af..f1c6ea2993f9 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -15,6 +15,7 @@ #include #include +#include "Common/Align.h" #include "Common/CommonPaths.h" #include "Common/FileUtil.h" #include "Common/StringUtil.h" @@ -32,6 +33,7 @@ #include "Core/HW/WiiSave.h" #include "Core/HW/Wiimote.h" #include "Core/IOS/ES/ES.h" +#include "Core/IOS/FS/FileSystem.h" #include "Core/IOS/IOS.h" #include "Core/IOS/USB/Bluetooth/BTEmu.h" #include "Core/Movie.h" @@ -1137,7 +1139,42 @@ void MenuBar::CheckNAND() WiiUtils::NANDCheckResult result = WiiUtils::CheckNAND(ios); if (!result.bad) { - ModalMessageBox::information(this, tr("NAND Check"), tr("No issues have been detected.")); + const bool overfull = result.used_clusters_user > IOS::HLE::FS::USER_CLUSTERS || + result.used_clusters_system > IOS::HLE::FS::SYSTEM_CLUSTERS; + const QString user_cluster_message = + tr("The user-accessible part of your NAND contains %1 blocks (%2 KiB) " + "of data, out of an allowed maximum of %3 blocks (%4 KiB).") + .arg(Common::AlignUp(result.used_clusters_user, IOS::HLE::FS::CLUSTERS_PER_BLOCK) / + IOS::HLE::FS::CLUSTERS_PER_BLOCK) + .arg((result.used_clusters_user * IOS::HLE::FS::CLUSTER_SIZE) / 1024) + .arg(IOS::HLE::FS::USER_CLUSTERS / IOS::HLE::FS::CLUSTERS_PER_BLOCK) + .arg((IOS::HLE::FS::USER_CLUSTERS * IOS::HLE::FS::CLUSTER_SIZE) / 1024); + const QString system_cluster_message = + tr("The system-reserved part of your NAND contains %1 blocks (%2 KiB) " + "of data, out of an allowed maximum of %3 blocks (%4 KiB).") + .arg(Common::AlignUp(result.used_clusters_system, IOS::HLE::FS::CLUSTERS_PER_BLOCK) / + IOS::HLE::FS::CLUSTERS_PER_BLOCK) + .arg((result.used_clusters_system * IOS::HLE::FS::CLUSTER_SIZE) / 1024) + .arg(IOS::HLE::FS::SYSTEM_CLUSTERS / IOS::HLE::FS::CLUSTERS_PER_BLOCK) + .arg((IOS::HLE::FS::SYSTEM_CLUSTERS * IOS::HLE::FS::CLUSTER_SIZE) / 1024); + + if (overfull) + { + ModalMessageBox::warning(this, tr("NAND Check"), + QStringLiteral("%1\n\n%2\n\n%3") + .arg(tr("Your NAND contains more data than allowed. Wii " + "software may behave incorrectly or not allow saving.")) + .arg(user_cluster_message) + .arg(system_cluster_message)); + } + else + { + ModalMessageBox::information(this, tr("NAND Check"), + QStringLiteral("%1\n\n%2\n\n%3") + .arg(tr("No issues have been detected.")) + .arg(user_cluster_message) + .arg(system_cluster_message)); + } return; }