Merge branch 'wip/oholy/x-gvfs-notrash' into 'master'

Add support to ignore trash for certain mounts

See merge request GNOME/glib!1549
This commit is contained in:
Philip Withnall 2020-08-05 13:25:05 +00:00
commit 1c08f55c6d
5 changed files with 101 additions and 14 deletions

View File

@ -1572,6 +1572,7 @@ g_unix_mount_point_guess_symbolic_icon
g_unix_mount_point_guess_name
g_unix_mount_point_guess_can_eject
g_unix_mount_points_get
g_unix_mount_point_at
g_unix_mounts_get
g_unix_mount_at
g_unix_mount_for

View File

@ -4134,7 +4134,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

View File

@ -1777,6 +1777,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)
{
@ -1787,7 +1833,6 @@ _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev)
char uid_str[32];
GStatBuf global_stat, trash_stat;
gboolean res;
GUnixMountEntry *mount;
if (g_once_init_enter (&home_dev_set))
{
@ -1806,17 +1851,13 @@ _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev)
if (topdir == NULL)
return FALSE;
mount = g_unix_mount_at (topdir, NULL);
if (mount == NULL || g_unix_mount_is_system_internal (mount))
if (ignore_trash_path (topdir))
{
g_clear_pointer (&mount, g_unix_mount_free);
g_free (topdir);
return FALSE;
}
g_clear_pointer (&mount, g_unix_mount_free);
globaldir = g_build_filename (topdir, ".Trash", NULL);
if (g_lstat (globaldir, &global_stat) == 0 &&
S_ISDIR (global_stat.st_mode) &&
@ -1982,7 +2023,6 @@ g_local_file_trash (GFile *file,
{
uid_t uid;
char uid_str[32];
GUnixMountEntry *mount;
uid = geteuid ();
g_snprintf (uid_str, sizeof (uid_str), "%lu", (unsigned long)uid);
@ -1996,20 +2036,15 @@ g_local_file_trash (GFile *file,
return FALSE;
}
mount = g_unix_mount_at (topdir, NULL);
if (mount == NULL || g_unix_mount_is_system_internal (mount))
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_clear_pointer (&mount, g_unix_mount_free);
g_free (topdir);
return FALSE;
}
g_clear_pointer (&mount, g_unix_mount_free);
/* Try looking for global trash dir $topdir/.Trash/$uid */
globaldir = g_build_filename (topdir, ".Trash", NULL);
if (g_lstat (globaldir, &global_stat) == 0 &&

View File

@ -1660,6 +1660,52 @@ g_unix_mount_points_get (guint64 *time_read)
return _g_get_unix_mount_points ();
}
/**
* g_unix_mount_point_at:
* @mount_path: (type filename): path for a possible unix mount point.
* @time_read: (out) (optional): guint64 to contain a timestamp.
*
* Gets a #GUnixMountPoint for a given mount path. If @time_read is set, it
* will be filled with a unix timestamp for checking if the mount points have
* changed since with g_unix_mount_points_changed_since().
*
* If more mount points have the same mount path, the last matching mount point
* is returned.
*
* Returns: (transfer full) (nullable): a #GUnixMountPoint, or %NULL if no match
* is found.
*
* Since: 2.66
**/
GUnixMountPoint *
g_unix_mount_point_at (const char *mount_path,
guint64 *time_read)
{
GList *mount_points, *l;
GUnixMountPoint *mount_point, *found;
mount_points = g_unix_mount_points_get (time_read);
found = NULL;
for (l = mount_points; l != NULL; l = l->next)
{
mount_point = l->data;
if (strcmp (mount_path, mount_point->mount_path) == 0)
{
if (found != NULL)
g_unix_mount_point_free (found);
found = mount_point;
}
else
g_unix_mount_point_free (mount_point);
}
g_list_free (mount_points);
return found;
}
/**
* g_unix_mounts_changed_since:
* @time: guint64 to contain a timestamp.

View File

@ -132,6 +132,9 @@ GIcon * g_unix_mount_point_guess_symbolic_icon (GUnixMountPoint *mount
GLIB_AVAILABLE_IN_ALL
GList * g_unix_mount_points_get (guint64 *time_read);
GLIB_AVAILABLE_IN_2_66
GUnixMountPoint *g_unix_mount_point_at (const char *mount_path,
guint64 *time_read);
GLIB_AVAILABLE_IN_ALL
GList * g_unix_mounts_get (guint64 *time_read);
GLIB_AVAILABLE_IN_ALL