mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Merge pull request #12047 from AdmiralCurtiss/nand-stats-user
Add file size stats to NAND Check.
This commit is contained in:
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
@ -818,11 +803,24 @@ 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
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user