summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2023-07-30 21:51:07 +0200
committerGitHub <noreply@github.com>2023-07-30 21:51:07 +0200
commita912a2c3f57f2e6a9f9e02da1ebd93fcf2bf5e75 (patch)
tree065062f8bb2ff11ff42618f2aeb4a0b4fe966312 /Source/Core
parent30c4ac34b0aebd4462eb3e8ab188a0de6209784e (diff)
parentcd5aebe5ac47ea305644ab62bebd057dbaa170d3 (diff)
Merge pull request #12047 from AdmiralCurtiss/nand-stats-user
Add file size stats to NAND Check.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/IOS/FS/FileSystem.h38
-rw-r--r--Source/Core/Core/IOS/FS/HostBackend/FS.cpp36
-rw-r--r--Source/Core/Core/IOS/FS/HostBackend/FS.h1
-rw-r--r--Source/Core/Core/WiiUtils.cpp28
-rw-r--r--Source/Core/Core/WiiUtils.h4
-rw-r--r--Source/Core/DolphinQt/MenuBar.cpp39
6 files changed, 125 insertions, 21 deletions
diff --git a/Source/Core/Core/IOS/FS/FileSystem.h b/Source/Core/Core/IOS/FS/FileSystem.h
index 581df6fbee..c0f59c2137 100644
--- a/Source/Core/Core/IOS/FS/FileSystem.h
+++ b/Source/Core/Core/IOS/FS/FileSystem.h
@@ -107,6 +107,33 @@ struct Metadata
u16 fst_index;
};
+// size of a single cluster in the NAND in bytes
+constexpr u16 CLUSTER_SIZE = 16384;
+
+// total number of clusters available in the NAND
+constexpr u16 TOTAL_CLUSTERS = 0x7ec0;
+
+// number of clusters reserved for bad blocks and similar, not accessible to normal writes
+constexpr u16 RESERVED_CLUSTERS = 0x0300;
+
+// number of clusters actually usable by the file system
+constexpr u16 USABLE_CLUSTERS = TOTAL_CLUSTERS - RESERVED_CLUSTERS;
+
+// size of a single 'block' as defined by the Wii System Menu in clusters
+constexpr u16 CLUSTERS_PER_BLOCK = 8;
+
+// total number of user-accessible blocks in the NAND
+constexpr u16 USER_BLOCKS = 2176;
+
+// total number of user-accessible clusters in the NAND
+constexpr u16 USER_CLUSTERS = USER_BLOCKS * CLUSTERS_PER_BLOCK;
+
+// the inverse of that, the amount of usable clusters reserved for system files
+constexpr u16 SYSTEM_CLUSTERS = USABLE_CLUSTERS - USER_CLUSTERS;
+
+// total number of inodes available in the NAND
+constexpr u16 TOTAL_INODES = 0x17ff;
+
struct NandStats
{
u32 cluster_size;
@@ -124,6 +151,14 @@ struct DirectoryStats
u32 used_inodes;
};
+// Not a real Wii data struct, but useful for calculating how full the user's NAND is even if it's
+// way larger than it should be.
+struct ExtendedDirectoryStats
+{
+ u64 used_clusters;
+ u64 used_inodes;
+};
+
struct FileStatus
{
u32 offset;
@@ -252,6 +287,9 @@ public:
/// Get usage information about a directory (used cluster and inode counts).
virtual Result<DirectoryStats> GetDirectoryStats(const std::string& path) = 0;
+ /// Like GetDirectoryStats() but not limited to the actual 512 MB NAND limit.
+ virtual Result<ExtendedDirectoryStats> GetExtendedDirectoryStats(const std::string& path) = 0;
+
virtual void SetNandRedirects(std::vector<NandRedirect> nand_redirects) = 0;
};
diff --git a/Source/Core/Core/IOS/FS/HostBackend/FS.cpp b/Source/Core/Core/IOS/FS/HostBackend/FS.cpp
index f09cadb7c8..a916ffba81 100644
--- a/Source/Core/Core/IOS/FS/HostBackend/FS.cpp
+++ b/Source/Core/Core/IOS/FS/HostBackend/FS.cpp
@@ -29,21 +29,6 @@ namespace IOS::HLE::FS
{
constexpr u32 BUFFER_CHUNK_SIZE = 65536;
-// size of a single cluster in the NAND
-constexpr u16 CLUSTER_SIZE = 16384;
-
-// total number of clusters available in the NAND
-constexpr u16 TOTAL_CLUSTERS = 0x7ec0;
-
-// number of clusters reserved for bad blocks and similar, not accessible to normal writes
-constexpr u16 RESERVED_CLUSTERS = 0x0300;
-
-// number of clusters actually usable by the file system
-constexpr u16 USABLE_CLUSTERS = TOTAL_CLUSTERS - RESERVED_CLUSTERS;
-
-// total number of inodes available in the NAND
-constexpr u16 TOTAL_INODES = 0x17ff;
-
HostFileSystem::HostFilename HostFileSystem::BuildFilename(const std::string& wii_path) const
{
for (const auto& redirect : m_nand_redirects)
@@ -819,10 +804,23 @@ Result<NandStats> HostFileSystem::GetNandStats()
Result<DirectoryStats> HostFileSystem::GetDirectoryStats(const std::string& wii_path)
{
+ const auto result = GetExtendedDirectoryStats(wii_path);
+ if (!result)
+ return result.Error();
+
+ DirectoryStats stats{};
+ stats.used_inodes = static_cast<u32>(std::min<u64>(result->used_inodes, TOTAL_INODES));
+ stats.used_clusters = static_cast<u32>(std::min<u64>(result->used_clusters, USABLE_CLUSTERS));
+ return stats;
+}
+
+Result<ExtendedDirectoryStats>
+HostFileSystem::GetExtendedDirectoryStats(const std::string& wii_path)
+{
if (!IsValidPath(wii_path))
return ResultCode::Invalid;
- DirectoryStats stats{};
+ ExtendedDirectoryStats stats{};
std::string path(BuildFilename(wii_path).host_path);
File::FileInfo info(path);
if (!info.Exists())
@@ -835,10 +833,8 @@ Result<DirectoryStats> HostFileSystem::GetDirectoryStats(const std::string& wii_
FixupDirectoryEntries(&parent_dir, wii_path == "/");
// add one for the folder itself
- stats.used_inodes = static_cast<u32>(std::min<u64>(1 + parent_dir.size, TOTAL_INODES));
-
- const u64 clusters = ComputeUsedClusters(parent_dir);
- stats.used_clusters = static_cast<u32>(std::min<u64>(clusters, USABLE_CLUSTERS));
+ stats.used_inodes = 1 + parent_dir.size;
+ stats.used_clusters = ComputeUsedClusters(parent_dir);
}
else
{
diff --git a/Source/Core/Core/IOS/FS/HostBackend/FS.h b/Source/Core/Core/IOS/FS/HostBackend/FS.h
index 1248c06736..3c68a59495 100644
--- a/Source/Core/Core/IOS/FS/HostBackend/FS.h
+++ b/Source/Core/Core/IOS/FS/HostBackend/FS.h
@@ -55,6 +55,7 @@ public:
Result<NandStats> GetNandStats() override;
Result<DirectoryStats> GetDirectoryStats(const std::string& path) override;
+ Result<ExtendedDirectoryStats> GetExtendedDirectoryStats(const std::string& path) override;
void SetNandRedirects(std::vector<NandRedirect> nand_redirects) override;
diff --git a/Source/Core/Core/WiiUtils.cpp b/Source/Core/Core/WiiUtils.cpp
index 30225febfb..92c2c19a0d 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 ae2d7c85e0..c8f86d7253 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<u64> 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 b0989fae66..37562a738c 100644
--- a/Source/Core/DolphinQt/MenuBar.cpp
+++ b/Source/Core/DolphinQt/MenuBar.cpp
@@ -15,6 +15,7 @@
#include <QMap>
#include <QUrl>
+#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("<b>%1</b><br/><br/>%2<br/><br/>%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("<b>%1</b><br/><br/>%2<br/><br/>%3")
+ .arg(tr("No issues have been detected."))
+ .arg(user_cluster_message)
+ .arg(system_cluster_message));
+ }
return;
}