From fb47200334ffbea949da76697fee09539ef9dfc8 Mon Sep 17 00:00:00 2001 From: Michael Webster Date: Wed, 28 Aug 2024 10:48:39 -0400 Subject: [PATCH] Fix blocking when listing or entering a network location with an inaccessible host. A mounted network directory with a down host will cause stat to block for 10 seconds before reporting failure. In nemo, if that location is bookmarked, it can cause multiple freezes at startup. --- This is not a perfect fix - I don't think one is possible at the application level. Nemo will now check if a target's path is descended from a mounted network connection, and skip any operation involving stat. pros: - Nemo will no longer freeze at startup due a 'dangling' network mount. - Clicking on the bookmark will no longer freeze, but if the folder hasn't been explicitly accessed yet, there will be a delay of about 10s, then an error popup. Subsequent clicks will cause the error immediately. - Navigating to the folder's parent directory will *always* cause a 10s delay in loading that folder. The file list will not include the bad directory. con: - The places-sidebar will always show any bookmarked network folder as available/online (no triangle warning icon), whether actually available or not. ref: #3270 (maybe?), #3436, #1378. --- libnemo-private/nemo-action.c | 6 +- libnemo-private/nemo-bookmark.c | 3 +- libnemo-private/nemo-file-utilities.c | 86 ++++++++++++++++++++++++++- libnemo-private/nemo-file-utilities.h | 4 ++ 4 files changed, 94 insertions(+), 5 deletions(-) diff --git a/libnemo-private/nemo-action.c b/libnemo-private/nemo-action.c index e21d0003c..e2292d9e0 100644 --- a/libnemo-private/nemo-action.c +++ b/libnemo-private/nemo-action.c @@ -952,7 +952,7 @@ nemo_action_new (const gchar *name, const gchar *prg_name = reverse ? deps[i] + 1 : deps[i]; if (g_path_is_absolute (prg_name)) { - if (g_file_test (prg_name, G_FILE_TEST_EXISTS)) { + if ((!nemo_path_is_network_safe (prg_name)) && g_file_test (prg_name, G_FILE_TEST_EXISTS)) { found = TRUE; } } else { @@ -1657,7 +1657,7 @@ get_is_dir (NemoFile *file) GFile *f = nemo_file_get_location (file); - if (g_file_is_native (f)) { + if (g_file_is_native (f) && (!nemo_location_is_network_safe (f))) { gchar *path; path = g_file_get_path (f); @@ -1958,7 +1958,7 @@ get_visibility (NemoAction *action, f = nemo_file_get_location (file); if (g_file_is_native (f)) { - mount = g_file_find_enclosing_mount (f, NULL, NULL); + mount = nemo_get_mount_for_location_safe (f); nemo_file_set_mount (file, mount); } diff --git a/libnemo-private/nemo-bookmark.c b/libnemo-private/nemo-bookmark.c index 879fd806a..f4f07be89 100644 --- a/libnemo-private/nemo-bookmark.c +++ b/libnemo-private/nemo-bookmark.c @@ -743,7 +743,8 @@ nemo_bookmark_uri_get_exists (NemoBookmark *bookmark) path_name = g_file_get_path (bookmark->details->location); - if (g_file_is_native (bookmark->details->location) && g_file_test (path_name, G_FILE_TEST_EXISTS)) { + if (g_file_is_native (bookmark->details->location) && + (!nemo_location_is_network_safe (bookmark->details->location)) && g_file_test (path_name, G_FILE_TEST_EXISTS)) { exists = TRUE; } else { g_signal_emit_by_name (bookmark, "location-mounted", bookmark->details->location, &exists); diff --git a/libnemo-private/nemo-file-utilities.c b/libnemo-private/nemo-file-utilities.c index c63eaf698..04549d735 100644 --- a/libnemo-private/nemo-file-utilities.c +++ b/libnemo-private/nemo-file-utilities.c @@ -1714,7 +1714,91 @@ nemo_user_is_root (void) return elevated; } -/* End copied section */ +static gint +sort_by_length (GMount *a, GMount *b) +{ + g_autoptr(GFile) a_root = g_mount_get_root (a); + g_autoptr(GFile) b_root = g_mount_get_root (b); + g_autofree gchar *a_uri = g_file_get_uri (a_root); + g_autofree gchar *b_uri = g_file_get_uri (b_root); + gint a_len = g_utf8_strlen (a_uri, -1); + gint b_len = g_utf8_strlen (b_uri, -1); + + return b_len - a_len; +} + +GMount * +nemo_get_mount_for_location_safe (GFile *location) +{ + GVolumeMonitor *monitor; + GList *mounts = NULL; + GList *mount_iter; + GMount *ret = NULL; + + + monitor = g_volume_monitor_get (); + mounts = g_volume_monitor_get_mounts (monitor); + + mounts = g_list_sort (mounts, (GCompareFunc) sort_by_length); + + for (mount_iter = mounts; mount_iter != NULL; mount_iter = mount_iter->next) { + GMount *mount = G_MOUNT (mount_iter->data); + GFile *mount_location = g_mount_get_root (mount); + gchar *mount_root_uri = g_file_get_uri (mount_location); + gchar *location_uri = g_file_get_uri (location); + + if (g_str_has_prefix (location_uri, mount_root_uri)) { + // Add a ref for our match, as it will lose one when the list is freed. + ret = g_object_ref (mount); + } + + g_free (mount_root_uri); + g_free (location_uri); + g_object_unref (mount_location); + + if (ret != NULL) + break; + } + + g_list_free_full (mounts, (GDestroyNotify) g_object_unref); + g_object_unref (monitor); + + return ret; +} + +gboolean +nemo_location_is_network_safe (GFile *location) +{ + GVolume *volume; + GMount *mount; + gboolean is_network = FALSE; + + mount = nemo_get_mount_for_location_safe (location); + if (mount != NULL) { + volume = g_mount_get_volume (mount); + if (volume != NULL) { + g_autofree gchar *identifier = g_volume_get_identifier (volume, "class"); + + if (g_strcmp0 (identifier, "network") == 0) { + is_network = TRUE; + } + + g_object_unref (volume); + } + + g_object_unref (mount); + } + + return is_network; +} + +gboolean +nemo_path_is_network_safe (const gchar *path) +{ + g_autoptr(GFile) location = g_file_new_for_path (path); + + return nemo_location_is_network_safe (location); +} #if !defined (NEMO_OMIT_SELF_CHECK) diff --git a/libnemo-private/nemo-file-utilities.h b/libnemo-private/nemo-file-utilities.h index fb8ea4c9a..5862acda0 100644 --- a/libnemo-private/nemo-file-utilities.h +++ b/libnemo-private/nemo-file-utilities.h @@ -118,4 +118,8 @@ gchar *nemo_get_best_guess_file_mimetype (const gchar *filename, gboolean nemo_treating_root_as_normal (void); gboolean nemo_user_is_root (void); + +GMount *nemo_get_mount_for_location_safe (GFile *location); +gboolean nemo_location_is_network_safe (GFile *location); +gboolean nemo_path_is_network_safe (const gchar *path); #endif /* NEMO_FILE_UTILITIES_H */