From 4ab0357974351c8b5088b01e3e4e9de79eb156a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Tyrychtr?= Date: Thu, 18 Sep 2025 15:11:47 +0000 Subject: [PATCH] gio-tool-trash: Report error when emptying the trash This adds error reporting and proper exit code when emptying the trash fails for some (mainly permission) related error. Fixes #3785. --- gio/gio-tool-trash.c | 80 +++++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 19 deletions(-) diff --git a/gio/gio-tool-trash.c b/gio/gio-tool-trash.c index 454869e78..4f01a8001 100644 --- a/gio/gio-tool-trash.c +++ b/gio/gio-tool-trash.c @@ -40,14 +40,16 @@ static const GOptionEntry entries[] = { G_OPTION_ENTRY_NULL }; -static void -delete_trash_file (GFile *file, gboolean del_file, gboolean del_children) +static gboolean +delete_trash_file (GFile *file, gboolean del_file, gboolean del_children, GError **error) { GFileInfo *info; GFile *child; GFileEnumerator *enumerator; + GError *local_error = NULL; + gboolean success = TRUE; - g_return_if_fail (g_file_has_uri_scheme (file, "trash")); + g_return_val_if_fail (g_file_has_uri_scheme (file, "trash"), FALSE); if (del_children) { @@ -56,30 +58,65 @@ delete_trash_file (GFile *file, gboolean del_file, gboolean del_children) G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, - NULL); - if (enumerator) + &local_error); + if (!enumerator) { - while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL) + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + while ((info = g_file_enumerator_next_file (enumerator, NULL, &local_error)) != NULL) + { + child = g_file_get_child (file, g_file_info_get_name (info)); + + /* The g_file_delete operation works differently for locations + * provided by the trash backend as it prevents modifications of + * trashed items. For that reason, it is enough to call + * g_file_delete on top-level items only. + */ + if (!delete_trash_file (child, TRUE, FALSE, &local_error)) { - child = g_file_get_child (file, g_file_info_get_name (info)); - - /* The g_file_delete operation works differently for locations - * provided by the trash backend as it prevents modifications of - * trashed items. For that reason, it is enough to call - * g_file_delete on top-level items only. - */ - delete_trash_file (child, TRUE, FALSE); - g_object_unref (child); g_object_unref (info); + success = FALSE; + break; } - g_file_enumerator_close (enumerator, NULL, NULL); - g_object_unref (enumerator); + + g_object_unref (child); + g_object_unref (info); } + + if (local_error) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + success = FALSE; + } + + if (!g_file_enumerator_close (enumerator, NULL, &local_error)) + { + if (success) + g_propagate_error (error, g_steal_pointer (&local_error)); + else + g_clear_error (&local_error); + success = FALSE; + } + + g_object_unref (enumerator); + + if (!success) + return FALSE; } if (del_file) - g_file_delete (file, NULL, NULL); + { + if (!g_file_delete (file, NULL, &local_error)) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + } + + return TRUE; } static gboolean @@ -297,7 +334,12 @@ handle_trash (int argc, char *argv[], gboolean do_help) else if (empty) { file = g_file_new_for_uri ("trash:"); - delete_trash_file (file, FALSE, TRUE); + if (!delete_trash_file (file, FALSE, TRUE, &error)) + { + print_file_error (file, error->message); + g_clear_error (&error); + retval = 1; + } g_object_unref (file); }