From cf67a444c22d11074c15db77909f5e9145561ace Mon Sep 17 00:00:00 2001 From: Colin Clark Date: Tue, 9 Apr 2024 10:48:01 +0100 Subject: [PATCH] Bug fix: Collections and unmounted drives The bug: If a collection file is on the local filesystem The collection file contains references to files on a mounted drive The drive is unmounted The collection file is opened Geeqie sees that the files do not exist and deletes them from the collection file. The fix: If Geeqie does not find the file- If the file path prefix contains /home, /tmp or /usr it is assumed that the file was on the local drive and has been deleted by the user. It is ignored. If the file path prefix contains a mount path, it is assumed that the file was on a currently mounted drive and has been deleted. Otherwise it is assumed that the file is on a removable drive that is not currently mounted. The collection will not be opened. If this is not the case the user may need to use a text editor to remove the offending line from the collection file. Created problem: When a collection window contents have not been changed, but its geometry has, the geometry changes will not be saved. The user must make a minor positional change to any thumbnail to trigger a save. --- src/collect-io.cc | 68 +++++++++++++++++++++++++++++++++++++------- src/collect-table.cc | 3 ++ 2 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/collect-io.cc b/src/collect-io.cc index 31d4496f..5b9c5ba6 100644 --- a/src/collect-io.cc +++ b/src/collect-io.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -40,6 +41,7 @@ #include "secure-save.h" #include "thumb.h" #include "ui-fileops.h" +#include "ui-utildlg.h" #define GQ_COLLECTION_MARKER "#" GQ_APPNAME @@ -123,8 +125,7 @@ static gboolean collection_load_private(CollectionData *cd, const gchar *path, C pathl = path_from_utf8(path); - DEBUG_1("collection load: append=%d flush=%d only_geometry=%d path=%s", - append, flush, only_geometry, pathl); + DEBUG_1("collection load: append=%d flush=%d only_geometry=%d path=%s", append, flush, only_geometry, pathl); /* load it */ f = fopen(pathl, "r"); @@ -161,8 +162,7 @@ static gboolean collection_load_private(CollectionData *cd, const gchar *path, C has_official_header = TRUE; limit_failures = FALSE; } - else if (strncmp(p, "#geometry:", 10 ) == 0 && - scan_geometry(p + 10, cd->window)) + else if (strncmp(p, "#geometry:", 10 ) == 0 && scan_geometry(p + 10, cd->window)) { has_geometry_header = TRUE; cd->window_read = TRUE; @@ -236,15 +236,64 @@ static gboolean collection_load_private(CollectionData *cd, const gchar *path, C changed |= collect_manager_process_action(entry, &buffer2); valid = (buffer2[0] == G_DIR_SEPARATOR && collection_add_check(cd, file_data_new_simple(buffer2), FALSE, TRUE)); - if (!valid) DEBUG_1("collection invalid file: %s", buffer2); + if (!valid) + { + log_printf("Warning: Collection: %s Invalid file: %s", cd->name, buffer2); + DEBUG_1("collection invalid file: %s", buffer2); + } total++; if (!valid) { + /* If the file path has the prefix home, tmp or usr it was on the local file system and has been deleted. Ignore it. */ + if (!g_str_has_prefix(buffer2, "/home") && !g_str_has_prefix(buffer2, "/tmp") && !g_str_has_prefix(buffer2, "/usr")) + { + /* The file was on a mounted drive and either has been deleted or the drive is not mounted */ + struct mntent *mount_entry; + FILE *mount_entries; + gboolean found = FALSE; + + mount_entries = setmntent("/proc/mounts", "r"); + if (mount_entries == nullptr) + { + /* It is assumed this will never fail */ + perror("setmntent"); + exit(1); + } + + while (nullptr != (mount_entry = getmntent(mount_entries))) + { + if (g_strcmp0(mount_entry->mnt_dir, G_DIR_SEPARATOR_S) != 0) + { + if (g_str_has_prefix(buffer2, mount_entry->mnt_dir)) + { + log_printf("%s was a file on a mounted filesystem but has been deleted: %s", buffer2, cd->name); + found = TRUE; + break; + } + } + } + endmntent(mount_entries); + + if (!found) + { + log_printf("%s is a file on an unmounted filesystem: %s", buffer2, cd->path); + gchar *text = g_strdup_printf(_("This Collection cannot be opened because it contains a link to a file on a drive which is not yet mounted.\n\nCollection: %s\nFile: %s\n"), cd->path, buffer2); + warning_dialog(_("Cannot open Collection"), text, GQ_ICON_DIALOG_WARNING, nullptr); + g_free(text); + + collection_window_close_by_collection(cd); + success = FALSE; + break; + } + } + else + { + log_printf("%s was a file on local filesystem but has been deleted: %s", buffer2, cd->name); + } + fail++; - if (limit_failures && - fail > GQ_COLLECTION_FAIL_MIN && - fail * 100 / total > GQ_COLLECTION_FAIL_PERCENT) + if (limit_failures && fail > GQ_COLLECTION_FAIL_MIN && fail * 100 / total > GQ_COLLECTION_FAIL_PERCENT) { log_printf("%d invalid filenames in unofficial collection file, closing: %s\n", fail, path); success = FALSE; @@ -257,8 +306,7 @@ static gboolean collection_load_private(CollectionData *cd, const gchar *path, C g_string_free(extended_filename_buffer, TRUE); - DEBUG_1("collection files: total = %d fail = %d official=%d gqview=%d geometry=%d", - total, fail, has_official_header, has_gqview_header, has_geometry_header); + DEBUG_1("collection files: total = %d fail = %d official=%d gqview=%d geometry=%d", total, fail, has_official_header, has_gqview_header, has_geometry_header); fclose(f); if (only_geometry) return has_geometry_header; diff --git a/src/collect-table.cc b/src/collect-table.cc index 7f47ff75..ee39fb90 100644 --- a/src/collect-table.cc +++ b/src/collect-table.cc @@ -2644,6 +2644,8 @@ static void collection_table_destroy(GtkWidget *, gpointer data) /* If there is no unsaved data, save the window geometry */ + /** @FIXME This code interferes with the code detecting files on unmounted drives. See collection_load_private() in collect-io,cc. If the user wants to save the geometry of an unchanged Collection, just slightly move one of the thumbnails. */ +/* if (!ct->cd->changed) { if (!collection_save(ct->cd, ct->cd->path)) @@ -2651,6 +2653,7 @@ static void collection_table_destroy(GtkWidget *, gpointer data) log_printf("failed saving to collection path: %s\n", ct->cd->path); } } +*/ if (ct->popup) { -- 2.20.1