From 427ffae2684190b95fbd908eca9ab75ff4eabd2f Mon Sep 17 00:00:00 2001 From: rainmakerv2 <30595646+rainmakerv3@users.noreply.github.com> Date: Sun, 5 Apr 2026 05:00:29 +0800 Subject: [PATCH] get mod folder entries in MntPoints::IterateDirectory --- src/core/file_sys/fs.cpp | 59 +++++++++++++++++++++++++++++----------- src/core/file_sys/fs.h | 10 ++++++- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/core/file_sys/fs.cpp b/src/core/file_sys/fs.cpp index a60ef8e9b..8327b51de 100644 --- a/src/core/file_sys/fs.cpp +++ b/src/core/file_sys/fs.cpp @@ -42,7 +42,7 @@ void MntPoints::UnmountAll() { } std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_read_only, - bool force_base_path) { + HostPathType path_type) { // Evil games like Turok2 pass double slashes e.g /app0//game.kpf std::string corrected_path(path); size_t pos = corrected_path.find("//"); @@ -84,13 +84,20 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea mods_path += "-mods"; mods_path /= rel_path; + if (path_type == HostPathType::Mod) { + return mods_path; + } else if (path_type == HostPathType::Patch) { + return patch_path; + } + if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) && - std::filesystem::exists(mods_path)) { + path_type != HostPathType::Base && std::filesystem::exists(mods_path)) { return mods_path; } if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) && - !force_base_path && !ignore_game_patches && std::filesystem::exists(patch_path)) { + path_type != HostPathType::Base && !ignore_game_patches && + std::filesystem::exists(patch_path)) { return patch_path; } @@ -152,7 +159,7 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea return std::optional(current_path); }; - if (!force_base_path && !ignore_game_patches) { + if (path_type != HostPathType::Base && !ignore_game_patches) { if (const auto path = search(patch_path)) { return *path; } @@ -169,34 +176,54 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea // TODO: Does not handle mount points inside mount points. void MntPoints::IterateDirectory(std::string_view guest_directory, const IterateDirectoryCallback& callback) { - const auto base_path = GetHostPath(guest_directory, nullptr, true); - const auto patch_path = GetHostPath(guest_directory, nullptr, false); - // Only need to consider patch path if it exists and does not resolve to the same as base. - const auto apply_patch = base_path != patch_path && std::filesystem::exists(patch_path); + const auto base_path = GetHostPath(guest_directory, nullptr, HostPathType::Base); + + // Forces path types so as not to resolve to base path + const auto patch_path = GetHostPath(guest_directory, nullptr, HostPathType::Patch); + const auto mod_path = GetHostPath(guest_directory, nullptr, HostPathType::Mod); // Prepend entries for . and .., as both are treated as files on PS4. callback(base_path / ".", false); callback(base_path / "..", false); - // Pass 1: Any files that existed in the base directory, using patch directory if needed. + // Pass 1: Any files that existed in the base directory, using mod/patch directory if needed. if (std::filesystem::exists(base_path)) { for (const auto& entry : std::filesystem::directory_iterator(base_path)) { - if (apply_patch) { - const auto patch_entry_path = patch_path / entry.path().filename(); - if (std::filesystem::exists(patch_entry_path)) { - callback(patch_entry_path, !std::filesystem::is_directory(patch_entry_path)); - continue; - } + const auto mod_entry_path = mod_path / entry.path().filename(); + const auto patch_entry_path = patch_path / entry.path().filename(); + if (std::filesystem::exists(mod_entry_path)) { + callback(mod_entry_path, !std::filesystem::is_directory(mod_entry_path)); + continue; + } else if (std::filesystem::exists(patch_entry_path)) { + callback(patch_entry_path, !std::filesystem::is_directory(patch_entry_path)); + continue; } callback(entry.path(), !entry.is_directory()); } } // Pass 2: Any files that exist only in the patch directory. - if (apply_patch) { + if (std::filesystem::exists(patch_path)) { for (const auto& entry : std::filesystem::directory_iterator(patch_path)) { const auto base_entry_path = base_path / entry.path().filename(); if (!std::filesystem::exists(base_entry_path)) { + const auto mod_entry_path = mod_path / entry.path().filename(); + if (std::filesystem::exists(mod_entry_path)) { + callback(mod_entry_path, !std::filesystem::is_directory(mod_entry_path)); + continue; + } + callback(entry.path(), !entry.is_directory()); + } + } + } + + // Pass 3: Any files that exist only in the mod directory (confirmed this can be valid) + if (std::filesystem::exists(mod_path)) { + for (const auto& entry : std::filesystem::directory_iterator(mod_path)) { + const auto base_entry_path = base_path / entry.path().filename(); + const auto patch_entry_path = patch_path / entry.path().filename(); + if (!std::filesystem::exists(base_entry_path) && + !std::filesystem::exists(patch_entry_path)) { callback(entry.path(), !entry.is_directory()); } } diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h index 0522c3d8a..9a782b19e 100644 --- a/src/core/file_sys/fs.h +++ b/src/core/file_sys/fs.h @@ -36,6 +36,13 @@ public: bool read_only; }; + enum class HostPathType { + Default, // Prioritizes Mod, then patch, then base + Base, + Patch, + Mod + }; + explicit MntPoints() = default; ~MntPoints() = default; @@ -45,7 +52,8 @@ public: void UnmountAll(); std::filesystem::path GetHostPath(std::string_view guest_directory, - bool* is_read_only = nullptr, bool force_base_path = false); + bool* is_read_only = nullptr, + HostPathType host_path = HostPathType::Default); using IterateDirectoryCallback = std::function; void IterateDirectory(std::string_view guest_directory,