mirror of
https://github.com/drakmor/ShadowMountPlus.git
synced 2026-10-22 06:32:25 -05:00
Fix cross-root image duplicate remount loops
This commit is contained in:
1 parent
091dffbfcb
commit
c2ddd8005d
3 files changed
+55
-13
No files matched your search
@@ -29,6 +29,8 @@ bool sm_image_index_visit_ready_titles(
|
||||
sm_image_index_title_visitor_t visitor, const void *visitor_ctx);
|
||||
// Return true when a title is mapped to an existing backing image.
|
||||
bool sm_image_index_has_source_for_title(const char *title_id);
|
||||
// Validate a title against a complete index with an unchanged regular source.
|
||||
bool sm_image_index_source_has_title(const char *path, const char *title_id);
|
||||
// Start a new fingerprint generation before mounting an image.
|
||||
void sm_image_index_begin_scan(const char *path, const struct stat *st);
|
||||
// Associate a discovered mounted game with its outer backing image. Returns
|
||||
|
||||
+36
-6
@@ -324,6 +324,36 @@ static void begin_scan_locked(const char *path, const struct stat *st) {
|
||||
g_image_index_dirty = true;
|
||||
}
|
||||
|
||||
// Caller holds g_image_index_mutex. A retained link alone cannot prove that a
|
||||
// replaced image still contains the same title.
|
||||
static bool indexed_source_has_title(const char *path, const char *title_id) {
|
||||
int entry_index = find_entry(path);
|
||||
if (entry_index < 0 || !g_image_index[entry_index].complete)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < MAX_IMAGE_TITLES; ++i) {
|
||||
if (g_image_titles[i].valid &&
|
||||
g_image_titles[i].image_index == (uint16_t)entry_index &&
|
||||
strcmp(g_image_titles[i].title_id, title_id) == 0) {
|
||||
struct stat st;
|
||||
return stat(path, &st) == 0 && S_ISREG(st.st_mode) &&
|
||||
stamp_matches(&g_image_index[entry_index], &st);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sm_image_index_source_has_title(const char *path, const char *title_id) {
|
||||
if (!path || !title_id || path[0] == '\0' || title_id[0] == '\0')
|
||||
return false;
|
||||
|
||||
pthread_mutex_lock(&g_image_index_mutex);
|
||||
load_index();
|
||||
bool found = indexed_source_has_title(path, title_id);
|
||||
pthread_mutex_unlock(&g_image_index_mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool cached_titles_ready(int entry_index,
|
||||
const struct AppDbTitleList *app_db_titles,
|
||||
bool app_db_titles_ready) {
|
||||
@@ -334,18 +364,18 @@ static bool cached_titles_ready(int entry_index,
|
||||
continue;
|
||||
}
|
||||
const char *title_id = g_image_titles[i].title_id;
|
||||
if (!is_installed(title_id) || !has_appmeta_data(title_id))
|
||||
if ((app_db_titles_ready &&
|
||||
!app_db_title_list_contains(app_db_titles, title_id)) ||
|
||||
!is_installed(title_id) || !has_appmeta_data(title_id)) {
|
||||
return false;
|
||||
}
|
||||
char runtime_path[MAX_PATH];
|
||||
char linked_image[MAX_PATH];
|
||||
if (!read_mount_link(title_id, runtime_path, sizeof(runtime_path)) ||
|
||||
!is_under_image_mount_base(runtime_path) ||
|
||||
!read_mount_image_link(title_id, linked_image, sizeof(linked_image)) ||
|
||||
strcmp(linked_image, image_path) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (app_db_titles_ready &&
|
||||
!app_db_title_list_contains(app_db_titles, title_id)) {
|
||||
(strcmp(linked_image, image_path) != 0 &&
|
||||
!indexed_source_has_title(linked_image, title_id))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+17
-7
@@ -68,10 +68,11 @@ static void note_found_indexed_title(const char *title_id, const void *ctx) {
|
||||
char linked_image[MAX_PATH];
|
||||
if (!image_path ||
|
||||
!read_mount_link(title_id, runtime_path, sizeof(runtime_path)) ||
|
||||
!read_mount_image_link(title_id, linked_image, sizeof(linked_image)) ||
|
||||
strcmp(linked_image, image_path) != 0) {
|
||||
!read_mount_image_link(title_id, linked_image, sizeof(linked_image))) {
|
||||
return;
|
||||
}
|
||||
if (strcmp(linked_image, image_path) != 0)
|
||||
notify_duplicate_title_once(title_id, image_path, linked_image);
|
||||
cache_game_entry(runtime_path, title_id, "");
|
||||
}
|
||||
|
||||
@@ -338,11 +339,20 @@ static existing_directory_result_t handle_existing_directory_candidate(
|
||||
}
|
||||
|
||||
if (installed && appmeta_present && has_tracked_path &&
|
||||
strcmp(tracked_path, full_path) != 0 &&
|
||||
is_data_mounted(info->title_id)) {
|
||||
(void)strlcpy(preferred_existing_path_out, tracked_path, MAX_PATH);
|
||||
cache_game_entry(tracked_path, info->title_id, info->title_name);
|
||||
return EXISTING_DIRECTORY_PREFER_CACHED;
|
||||
strcmp(tracked_path, full_path) != 0) {
|
||||
char linked_image[MAX_PATH];
|
||||
// Runtime layers are normally released between scans. Keep the selected
|
||||
// image while its fingerprint still proves that it contains this title.
|
||||
bool linked_source_valid =
|
||||
is_under_image_mount_base(tracked_path) &&
|
||||
read_mount_image_link(info->title_id, linked_image,
|
||||
sizeof(linked_image)) &&
|
||||
sm_image_index_source_has_title(linked_image, info->title_id);
|
||||
if (linked_source_valid || is_data_mounted(info->title_id)) {
|
||||
(void)strlcpy(preferred_existing_path_out, tracked_path, MAX_PATH);
|
||||
cache_game_entry(tracked_path, info->title_id, info->title_name);
|
||||
return EXISTING_DIRECTORY_PREFER_CACHED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_app_db && is_title_install_pending(info->title_id))
|
||||
|
||||
Reference in new issue
Block a user