From 1c5bd20d80c6ac7ee56fa1f642c788d96df4bee8 Mon Sep 17 00:00:00 2001 From: Vishrut Sachan Date: Sat, 11 Apr 2026 02:13:16 +0530 Subject: [PATCH] ISO: Clean up orphaned cache entries after game list scan --- rpcs3/Loader/iso_cache.cpp | 28 ++++++++++++++++++++++++++++ rpcs3/Loader/iso_cache.h | 4 ++++ rpcs3/rpcs3qt/game_list_frame.cpp | 7 +++++++ rpcs3/rpcs3qt/game_list_frame.h | 1 + 4 files changed, 40 insertions(+) diff --git a/rpcs3/Loader/iso_cache.cpp b/rpcs3/Loader/iso_cache.cpp index e23c015b7e..1e9395e086 100644 --- a/rpcs3/Loader/iso_cache.cpp +++ b/rpcs3/Loader/iso_cache.cpp @@ -6,6 +6,8 @@ #include "util/fnv_hash.hpp" #include "Utilities/File.h" +#include + LOG_CHANNEL(iso_cache_log, "ISOCache"); namespace @@ -128,4 +130,30 @@ namespace iso_cache } } } + + void cleanup(const std::unordered_set& valid_iso_paths) + { + const std::string dir = get_cache_dir(); + + // Build a set of stems that should exist. + std::unordered_set valid_stems; + for (const std::string& path : valid_iso_paths) + { + valid_stems.insert(get_cache_stem(path)); + } + + // Delete any cache files whose stem is not in the valid set. + fs::dir cache_dir(dir); + fs::dir_entry entry{}; + while (cache_dir.read(entry)) + { + if (entry.name == "." || entry.name == "..") continue; + + const std::string stem = entry.name.substr(0, entry.name.find_last_of('.')); + if (valid_stems.find(stem) == valid_stems.end()) + { + fs::remove_file(dir + entry.name); + } + } + } } \ No newline at end of file diff --git a/rpcs3/Loader/iso_cache.h b/rpcs3/Loader/iso_cache.h index cd5a18a435..ca2f39e6a4 100644 --- a/rpcs3/Loader/iso_cache.h +++ b/rpcs3/Loader/iso_cache.h @@ -5,6 +5,7 @@ #include "util/types.hpp" #include +#include #include // Cached metadata extracted from an ISO during game list scanning. @@ -25,4 +26,7 @@ namespace iso_cache // Persists a populated cache entry to disk. void save(const std::string& iso_path, const iso_metadata_cache_entry& entry); + + // Remove cache entries for ISOs that are no longer in the scanned set. + void cleanup(const std::unordered_set& valid_iso_paths); } \ No newline at end of file diff --git a/rpcs3/rpcs3qt/game_list_frame.cpp b/rpcs3/rpcs3qt/game_list_frame.cpp index d2cdc6ea87..51806f5875 100644 --- a/rpcs3/rpcs3qt/game_list_frame.cpp +++ b/rpcs3/rpcs3qt/game_list_frame.cpp @@ -542,6 +542,9 @@ void game_list_frame::OnParsingFinished() { archive = std::make_unique(dir_or_elf); } + // Track this ISO path for cache cleanup after scan completes. + std::lock_guard lock(m_path_mutex); + m_scanned_iso_paths.insert(dir_or_elf); } const auto file_exists = [&archive, &cache_entry](const std::string& path) @@ -892,6 +895,9 @@ void game_list_frame::OnRefreshFinished() WaitAndAbortSizeCalcThreads(); WaitAndAbortRepaintThreads(); + // Remove cache entries for ISOs that are no longer present in the scanned paths. + iso_cache::cleanup(m_scanned_iso_paths); + for (auto&& g : m_games.pop_all()) { m_game_data.push_back(g); @@ -978,6 +984,7 @@ void game_list_frame::OnRefreshFinished() m_serials.clear(); m_path_list.clear(); m_path_entries.clear(); + m_scanned_iso_paths.clear(); Refresh(); diff --git a/rpcs3/rpcs3qt/game_list_frame.h b/rpcs3/rpcs3qt/game_list_frame.h index 637229bf60..b01dbd5a6e 100644 --- a/rpcs3/rpcs3qt/game_list_frame.h +++ b/rpcs3/rpcs3qt/game_list_frame.h @@ -181,6 +181,7 @@ private: std::vector m_path_entries; shared_mutex m_path_mutex; std::set m_path_list; + std::unordered_set m_scanned_iso_paths; QSet m_serials; QMutex m_games_mutex; lf_queue m_games;