From aff2fc0e6cce3a569afdd12bfe4837bcae6bd26e Mon Sep 17 00:00:00 2001 From: Roman Tarasov Date: Sat, 14 Mar 2026 20:08:29 +0300 Subject: [PATCH] Remove stale duplicate-tracking entries when sources disappear --- include/sm_title_state.h | 2 ++ src/sm_game_cache.c | 30 +++++++++++++++++++++--------- src/sm_image.c | 1 + src/sm_title_state.c | 6 ++++++ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/include/sm_title_state.h b/include/sm_title_state.h index fffbf49..de88181 100644 --- a/include/sm_title_state.h +++ b/include/sm_title_state.h @@ -13,6 +13,8 @@ void mark_register_attempted(const char *title_id); // Notify once about duplicate title IDs from different paths. void notify_duplicate_title_once(const char *title_id, const char *path_a, const char *path_b); +// Clear the one-shot duplicate notification state for a title. +void clear_duplicate_title_notification(const char *title_id); // Return the number of failed install/remount attempts for a title. uint8_t get_failed_mount_attempts(const char *title_id); // Clear failed install/remount attempts for a title. diff --git a/src/sm_game_cache.c b/src/sm_game_cache.c index b2c734d..4ff94ca 100644 --- a/src/sm_game_cache.c +++ b/src/sm_game_cache.c @@ -2,6 +2,7 @@ #include "sm_game_cache.h" #include "sm_limits.h" #include "sm_log.h" +#include "sm_title_state.h" struct GameCache { char path[MAX_PATH]; @@ -12,6 +13,24 @@ struct GameCache { static struct GameCache g_game_cache[MAX_PENDING]; +static void clear_game_cache_slot(int index, const char *reason) { + if (index < 0 || index >= MAX_PENDING || !g_game_cache[index].valid) + return; + + if (reason && reason[0] != '\0') { + if (g_game_cache[index].title_id[0] != '\0') + log_debug(" [CACHE] %s: %s (%s)", reason, g_game_cache[index].title_id, + g_game_cache[index].path); + else + log_debug(" [CACHE] %s: %s", reason, g_game_cache[index].path); + } + + if (g_game_cache[index].title_id[0] != '\0') + clear_duplicate_title_notification(g_game_cache[index].title_id); + + memset(&g_game_cache[index], 0, sizeof(g_game_cache[index])); +} + void cache_game_entry(const char *path, const char *title_id, const char *title_name) { for (int k = 0; k < MAX_PENDING; k++) { @@ -33,14 +52,7 @@ void prune_game_cache(void) { continue; if (access(g_game_cache[k].path, F_OK) == 0) continue; - - if (g_game_cache[k].title_id[0] != '\0') - log_debug(" [CACHE] source removed: %s (%s)", g_game_cache[k].title_id, - g_game_cache[k].path); - else - log_debug(" [CACHE] source removed: %s", g_game_cache[k].path); - - memset(&g_game_cache[k], 0, sizeof(g_game_cache[k])); + clear_game_cache_slot(k, "source removed"); } } @@ -77,6 +89,6 @@ void clear_cached_game(const char *path) { continue; if (strcmp(g_game_cache[k].path, path) != 0) continue; - memset(&g_game_cache[k], 0, sizeof(g_game_cache[k])); + clear_game_cache_slot(k, "removed from duplicate tracking"); } } diff --git a/src/sm_image.c b/src/sm_image.c index a3dfdf3..6dcf089 100644 --- a/src/sm_image.c +++ b/src/sm_image.c @@ -698,6 +698,7 @@ bool unmount_image(const char *file_path, int unit_id, attach_backend_t backend) // Remove mount.lnk and unmount /system_ex/app/ that point to this // source before unmounting the virtual disk itself. cleanup_mount_links(mount_point, true); + clear_cached_game(mount_point); // Unmount stacked layers (unionfs over image fs). for (int i = 0; i < MAX_LAYERED_UNMOUNT_ATTEMPTS; i++) { diff --git a/src/sm_title_state.c b/src/sm_title_state.c index d9fb76e..5e367da 100644 --- a/src/sm_title_state.c +++ b/src/sm_title_state.c @@ -137,6 +137,12 @@ void notify_duplicate_title_once(const char *title_id, const char *path_a, notify_system("Duplicate %s detected:\n%s\n%s", title_id, path_a, path_b); } +void clear_duplicate_title_notification(const char *title_id) { + struct TitleStateEntry *entry = find_title_state(title_id); + if (entry) + entry->duplicate_notified_once = false; +} + uint8_t get_failed_mount_attempts(const char *title_id) { struct TitleStateEntry *entry = find_title_state(title_id); return entry ? entry->mount_reg_attempts : 0;