From 5373fcc1e7351b80b64072b7edf625f5bae00c44 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Fri, 31 Mar 2023 20:50:56 +0200 Subject: [PATCH] IOS/FS: Filter files exposed to the emulated system in ReadDirectory() and GetDirectoryStats(). --- Source/Core/Core/IOS/FS/FileSystem.h | 3 ++ Source/Core/Core/IOS/FS/FileSystemCommon.cpp | 8 ++++ Source/Core/Core/IOS/FS/HostBackend/FS.cpp | 47 +++++++++++++++++--- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/IOS/FS/FileSystem.h b/Source/Core/Core/IOS/FS/FileSystem.h index 6b1d7ddf78..581df6fbee 100644 --- a/Source/Core/Core/IOS/FS/FileSystem.h +++ b/Source/Core/Core/IOS/FS/FileSystem.h @@ -134,10 +134,13 @@ struct FileStatus constexpr size_t MaxPathDepth = 8; /// The maximum number of characters a path can have. constexpr size_t MaxPathLength = 64; +/// The maximum number of characters a filename can have. +constexpr size_t MaxFilenameLength = 12; /// Returns whether a Wii path is valid. bool IsValidPath(std::string_view path); bool IsValidNonRootPath(std::string_view path); +bool IsValidFilename(std::string_view filename); struct SplitPathResult { diff --git a/Source/Core/Core/IOS/FS/FileSystemCommon.cpp b/Source/Core/Core/IOS/FS/FileSystemCommon.cpp index 8d246157bb..1ec5dbe068 100644 --- a/Source/Core/Core/IOS/FS/FileSystemCommon.cpp +++ b/Source/Core/Core/IOS/FS/FileSystemCommon.cpp @@ -3,6 +3,8 @@ #include "Core/IOS/FS/FileSystem.h" +#include + #include "Common/Assert.h" #include "Common/FileUtil.h" #include "Core/IOS/Device.h" @@ -21,6 +23,12 @@ bool IsValidNonRootPath(std::string_view path) path.back() != '/'; } +bool IsValidFilename(std::string_view filename) +{ + return filename.length() <= MaxFilenameLength && + !std::any_of(filename.begin(), filename.end(), [](char c) { return c == '/'; }); +} + SplitPathResult SplitPathAndBasename(std::string_view path) { const auto last_separator = path.rfind('/'); diff --git a/Source/Core/Core/IOS/FS/HostBackend/FS.cpp b/Source/Core/Core/IOS/FS/HostBackend/FS.cpp index 7a2d2135c2..991f1353d2 100644 --- a/Source/Core/Core/IOS/FS/HostBackend/FS.cpp +++ b/Source/Core/Core/IOS/FS/HostBackend/FS.cpp @@ -104,6 +104,45 @@ auto GetNamePredicate(const std::string& name) { return [&name](const auto& entry) { return entry.name == name; }; } + +// Convert the host directory entries into ones that can be exposed to the emulated system. +static u64 FixupDirectoryEntries(File::FSTEntry* dir, bool is_root) +{ + u64 removed_entries = 0; + for (auto it = dir->children.begin(); it != dir->children.end();) + { + // Drop files in the root of the Wii NAND folder, since we store extra files there that the + // emulated system shouldn't know about. + if (is_root && !it->isDirectory) + { + ++removed_entries; + it = dir->children.erase(it); + continue; + } + + // Decode escaped invalid file system characters so that games (such as Harry Potter and the + // Half-Blood Prince) can find what they expect. + if (it->virtualName.find("__") != std::string::npos) + it->virtualName = Common::UnescapeFileName(it->virtualName); + + // Drop files that have too long filenames. + if (!IsValidFilename(it->virtualName)) + { + if (it->isDirectory) + removed_entries += it->size; + ++removed_entries; + it = dir->children.erase(it); + continue; + } + + if (dir->isDirectory) + removed_entries += FixupDirectoryEntries(&*it, false); + + ++it; + } + dir->size -= removed_entries; + return removed_entries; +} } // namespace bool HostFileSystem::FstEntry::CheckPermission(Uid caller_uid, Gid caller_gid, @@ -647,12 +686,7 @@ Result> HostFileSystem::ReadDirectory(Uid uid, Gid gid, const std::string host_path = BuildFilename(path).host_path; File::FSTEntry host_entry = File::ScanDirectoryTree(host_path, false); - for (File::FSTEntry& child : host_entry.children) - { - // Decode escaped invalid file system characters so that games (such as - // Harry Potter and the Half-Blood Prince) can find what they expect. - child.virtualName = Common::UnescapeFileName(child.virtualName); - } + FixupDirectoryEntries(&host_entry, path == "/"); // Sort files according to their order in the FST tree (issue 10234). // The result should look like this: @@ -795,6 +829,7 @@ Result HostFileSystem::GetDirectoryStats(const std::string& wii_ if (info.IsDirectory()) { File::FSTEntry parent_dir = File::ScanDirectoryTree(path, true); + FixupDirectoryEntries(&parent_dir, wii_path == "/"); // add one for the folder itself stats.used_inodes = static_cast(std::min(1 + parent_dir.size, TOTAL_INODES));