diff options
author | Philip Withnall <philip@tecnocode.co.uk> | 2018-06-09 00:28:09 +0000 |
---|---|---|
committer | Philip Withnall <philip@tecnocode.co.uk> | 2018-06-09 00:28:09 +0000 |
commit | e22bffb522124ce6443ffef5a784510197ea9540 (patch) | |
tree | 504f7147a9f9b4a9b0e9c323f33299df576c3ff7 | |
parent | e3280675f51466cde58a5703633d682b566f2fd2 (diff) | |
parent | 1cbb5dd95fd188bb9c7a213b144e058163a10a7a (diff) | |
download | glib-e22bffb522124ce6443ffef5a784510197ea9540.tar.gz |
Merge branch 'wip/oholy/trashing-locations2' into 'master'
Resubmit of reverted trash related changes and tests
See merge request GNOME/glib!83
-rw-r--r-- | gio/glocalfile.c | 56 | ||||
-rw-r--r-- | gio/glocalfileinfo.c | 8 | ||||
-rw-r--r-- | gio/tests/Makefile.am | 1 | ||||
-rw-r--r-- | gio/tests/meson.build | 1 | ||||
-rw-r--r-- | gio/tests/trash.c | 103 |
5 files changed, 160 insertions, 9 deletions
diff --git a/gio/glocalfile.c b/gio/glocalfile.c index 3cd0137d6..1c8fa42e8 100644 --- a/gio/glocalfile.c +++ b/gio/glocalfile.c @@ -1677,16 +1677,20 @@ find_mountpoint_for (const char *file, } } -char * -_g_local_file_find_topdir_for (const char *file) +static char * +_g_local_file_find_topdir_for_internal (const char *file, dev_t file_dev) { char *dir; char *mountpoint = NULL; dev_t dir_dev; dir = get_parent (file, &dir_dev); - if (dir == NULL) - return NULL; + if (dir == NULL || dir_dev != file_dev) + { + g_free (dir); + + return NULL; + } mountpoint = find_mountpoint_for (dir, dir_dev); g_free (dir); @@ -1694,6 +1698,17 @@ _g_local_file_find_topdir_for (const char *file) return mountpoint; } +char * +_g_local_file_find_topdir_for (const char *file) +{ + GStatBuf file_stat; + + if (g_lstat (file, &file_stat) != 0) + return NULL; + + return _g_local_file_find_topdir_for_internal (file, file_stat.st_dev); +} + static char * get_unique_filename (const char *basename, int id) @@ -1769,6 +1784,7 @@ _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)) { @@ -1787,6 +1803,16 @@ _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)) + { + g_clear_pointer (&mount, g_unix_mount_free); + + 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) && @@ -1930,19 +1956,35 @@ 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); - topdir = _g_local_file_find_topdir_for (local->filename); + topdir = _g_local_file_find_topdir_for_internal (local->filename, + file_stat.st_dev); if (topdir == NULL) { g_set_io_error (error, _("Unable to find toplevel directory to trash %s"), - file, G_IO_ERROR_NOT_SUPPORTED); + file, ENOTSUP); return FALSE; } - + + mount = g_unix_mount_at (topdir, NULL); + if (mount == NULL || g_unix_mount_is_system_internal (mount)) + { + 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 && diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index df0352a8a..0ebfa15a0 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -924,9 +924,13 @@ get_access_rights (GFileAttributeMatcher *attribute_matcher, _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE, writable); + /* Trashing is supported only if the parent device is the same */ if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH)) - _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH, - writable && parent_info->has_trash_dir); + _g_file_info_set_attribute_boolean_by_id (info, + G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH, + writable && + parent_info->has_trash_dir && + parent_info->device == statbuf->st_dev); } } diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index 410f11d95..599823893 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -273,6 +273,7 @@ test_programs += \ unix-mounts \ unix-streams \ g-file-info-filesystem-readonly \ + trash \ $(NULL) test_extra_programs += \ diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 96229bd8b..83fadb6d7 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -123,6 +123,7 @@ if host_machine.system() != 'windows' 'unix-streams', 'g-file-info-filesystem-readonly', 'gschema-compile', + 'trash', ] # Uninstalled because of the check-for-executable logic in DesktopAppInfo diff --git a/gio/tests/trash.c b/gio/tests/trash.c new file mode 100644 index 000000000..ec9a9eca6 --- /dev/null +++ b/gio/tests/trash.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of the + * licence, or (at your option) any later version. + * + * This is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <glib.h> + +#ifndef G_OS_UNIX +#error This is a Unix-specific test +#endif + +#include <glib/gstdio.h> +#include <gio/gio.h> +#include <gio/gunixmounts.h> + +/* Test that g_file_trash() returns G_IO_ERROR_NOT_SUPPORTED for files on system mounts. */ +static void +test_trash_not_supported (void) +{ + GFile *file; + GFileIOStream *stream; + GUnixMountEntry *mount; + GFileInfo *info; + GError *error = NULL; + gboolean ret; + GStatBuf file_stat, home_stat; + + /* The test assumes that tmp file is located on system internal mount. */ + file = g_file_new_tmp ("test-trashXXXXXX", &stream, &error); + g_assert_no_error (error); + g_assert_cmpint (g_lstat (g_file_peek_path (file), &file_stat), ==, 0); + g_test_message ("File: %s (dev: %lu)", g_file_peek_path (file), file_stat.st_dev); + + g_assert_cmpint (g_stat (g_get_home_dir (), &home_stat), ==, 0); + g_test_message ("Home: %s (dev: %lu)", g_get_home_dir (), home_stat.st_dev); + + if (file_stat.st_dev == home_stat.st_dev) + { + g_test_skip ("The file has to be on another filesystem than the home trash to run this test"); + + g_object_unref (stream); + g_object_unref (file); + + return; + } + + mount = g_unix_mount_for (g_file_peek_path (file), NULL); + g_assert_true (mount == NULL || g_unix_mount_is_system_internal (mount)); + g_test_message ("Mount: %s", (mount != NULL) ? g_unix_mount_get_mount_path (mount) : "(null)"); + g_clear_pointer (&mount, g_unix_mount_free); + + /* g_file_trash() shouldn't be supported on system internal mounts, + * because those are not monitored by gvfsd-trash. + */ + ret = g_file_trash (file, NULL, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED); + g_test_message ("Error: %s", error->message); + g_assert_false (ret); + g_clear_error (&error); + + info = g_file_query_info (file, + G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, + &error); + g_assert_no_error (error); + + g_assert_false (g_file_info_get_attribute_boolean (info, + G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH)); + + g_io_stream_close (G_IO_STREAM (stream), NULL, &error); + g_assert_no_error (error); + + g_object_unref (info); + g_object_unref (stream); + g_object_unref (file); +} + +int +main (int argc, char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_bug_base ("htps://gitlab.gnome.org/GNOME/glib/issues/"); + g_test_bug ("251"); + + g_test_add_func ("/trash/not-supported", test_trash_not_supported); + + return g_test_run (); +} + |