diff --git a/gio/gfile.c b/gio/gfile.c index 447da3cfb..43c5c3d74 100644 --- a/gio/gfile.c +++ b/gio/gfile.c @@ -4166,7 +4166,9 @@ g_file_delete_finish (GFile *file, * Sends @file to the "Trashcan", if possible. This is similar to * deleting it, but the user can recover it before emptying the trashcan. * Not all file systems support trashing, so this call can return the - * %G_IO_ERROR_NOT_SUPPORTED error. + * %G_IO_ERROR_NOT_SUPPORTED error. Since GLib 2.66, the `x-gvfs-notrash` unix + * mount option can be used to disable g_file_trash() support for certain + * mounts, the %G_IO_ERROR_NOT_SUPPORTED error will be returned in that case. * * If @cancellable is not %NULL, then the operation can be cancelled by * triggering the cancellable object from another thread. If the operation diff --git a/gio/glocalfile.c b/gio/glocalfile.c index e7481454e..cb0ecdafb 100644 --- a/gio/glocalfile.c +++ b/gio/glocalfile.c @@ -1858,6 +1858,52 @@ try_make_relative (const char *path, return g_strdup (path); } +static gboolean +ignore_trash_mount (GUnixMountEntry *mount) +{ + GUnixMountPoint *mount_point = NULL; + const gchar *mount_options; + gboolean retval = TRUE; + + if (g_unix_mount_is_system_internal (mount)) + return TRUE; + + mount_options = g_unix_mount_get_options (mount); + if (mount_options == NULL) + { + mount_point = g_unix_mount_point_at (g_unix_mount_get_mount_path (mount), + NULL); + if (mount_point != NULL) + mount_options = g_unix_mount_point_get_options (mount_point); + } + + if (mount_options == NULL || + strstr (mount_options, "x-gvfs-notrash") == NULL) + retval = FALSE; + + g_clear_pointer (&mount_point, g_unix_mount_point_free); + + return retval; +} + +static gboolean +ignore_trash_path (const gchar *topdir) +{ + GUnixMountEntry *mount; + gboolean retval = TRUE; + + mount = g_unix_mount_at (topdir, NULL); + if (mount == NULL) + goto out; + + retval = ignore_trash_mount (mount); + + out: + g_clear_pointer (&mount, g_unix_mount_free); + + return retval; +} + gboolean _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev) { @@ -1886,6 +1932,13 @@ _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev) if (topdir == NULL) return FALSE; + if (ignore_trash_path (topdir)) + { + g_free (topdir); + + return FALSE; + } + globaldir = g_build_filename (topdir, ".Trash", NULL); if (g_lstat (globaldir, &global_stat) == 0 && S_ISDIR (global_stat.st_mode) && @@ -2041,7 +2094,16 @@ g_local_file_trash (GFile *file, file, G_IO_ERROR_NOT_SUPPORTED); return FALSE; } - + + if (ignore_trash_path (topdir)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + _("Trashing on system internal mounts is not supported")); + g_free (topdir); + + return FALSE; + } + /* Try looking for global trash dir $topdir/.Trash/$uid */ globaldir = g_build_filename (topdir, ".Trash", NULL); if (g_lstat (globaldir, &global_stat) == 0 &&