1 /*
2 * Copyright (C) 2018 Red Hat, Inc.
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 *
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of the
9 * licence, or (at your option) any later version.
10 *
11 * This is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 * License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <glib.h>
21
22 #ifndef G_OS_UNIX
23 #error This is a Unix-specific test
24 #endif
25
26 #include <glib/gstdio.h>
27 #include <gio/gio.h>
28 #include <gio/gunixmounts.h>
29
30 /* Test that g_file_trash() returns G_IO_ERROR_NOT_SUPPORTED for files on system mounts. */
31 static void
32 test_trash_not_supported (void)
33 {
34 GFile *file;
35 GFileIOStream *stream;
36 GUnixMountEntry *mount;
37 GFileInfo *info;
38 GError *error = NULL;
39 gboolean ret;
40 gchar *parent_dirname;
41 GStatBuf parent_stat, home_stat;
42
43 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/251");
44
45 /* The test assumes that tmp file is located on system internal mount. */
46 file = g_file_new_tmp ("test-trashXXXXXX", &stream, &error);
47 parent_dirname = g_path_get_dirname (g_file_peek_path (file));
48 g_assert_no_error (error);
49 g_assert_cmpint (g_stat (parent_dirname, &parent_stat), ==, 0);
50 g_test_message ("File: %s (parent st_dev: %" G_GUINT64_FORMAT ")",
51 g_file_peek_path (file), (guint64) parent_stat.st_dev);
52
53 g_assert_cmpint (g_stat (g_get_home_dir (), &home_stat), ==, 0);
54 g_test_message ("Home: %s (st_dev: %" G_GUINT64_FORMAT ")",
55 g_get_home_dir (), (guint64) home_stat.st_dev);
56
57 if (parent_stat.st_dev == home_stat.st_dev)
58 {
59 g_test_skip ("The file has to be on another filesystem than the home trash to run this test");
60
61 g_free (parent_dirname);
62 g_object_unref (stream);
63 g_object_unref (file);
64
65 return;
66 }
67
68 mount = g_unix_mount_for (g_file_peek_path (file), NULL);
69 g_assert_true (mount == NULL || g_unix_mount_is_system_internal (mount));
70 g_test_message ("Mount: %s", (mount != NULL) ? g_unix_mount_get_mount_path (mount) : "(null)");
71 g_clear_pointer (&mount, g_unix_mount_free);
72
73 /* g_file_trash() shouldn't be supported on system internal mounts,
74 * because those are not monitored by gvfsd-trash.
75 */
76 ret = g_file_trash (file, NULL, &error);
77 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
78 g_test_message ("Error: %s", error->message);
79 g_assert_false (ret);
80 g_clear_error (&error);
81
82 info = g_file_query_info (file,
83 G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
84 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
85 NULL,
86 &error);
87 g_assert_no_error (error);
88
89 g_assert_false (g_file_info_get_attribute_boolean (info,
90 G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH));
91
92 g_io_stream_close (G_IO_STREAM (stream), NULL, &error);
93 g_assert_no_error (error);
94
95 g_free (parent_dirname);
96 g_object_unref (info);
97 g_object_unref (stream);
98 g_object_unref (file);
99 }
100
101 /* Test that symlinks are properly expaned when looking for topdir (e.g. for trash folder). */
102 static void
103 test_trash_symlinks (void)
104 {
105 GFile *symlink;
106 GUnixMountEntry *target_mount, *tmp_mount, *symlink_mount, *target_over_symlink_mount;
107 gchar *target, *tmp, *target_over_symlink;
108 GError *error = NULL;
109
110 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1522");
111
112 target = g_build_filename (g_get_home_dir (), ".local", NULL);
113
114 if (!g_file_test (target, G_FILE_TEST_IS_DIR))
115 {
116 g_test_skip_printf ("Directory '%s' does not exist", target);
117 g_free (target);
118 return;
119 }
120
121 target_mount = g_unix_mount_for (target, NULL);
122
123 if (target_mount == NULL)
124 {
125 g_test_skip_printf ("Unable to determine mount point for %s", target);
126 g_free (target);
127 return;
128 }
129
130 g_assert_nonnull (target_mount);
131 g_test_message ("Target: %s (mount: %s)", target, g_unix_mount_get_mount_path (target_mount));
132
133 tmp = g_dir_make_tmp ("test-trashXXXXXX", &error);
134 g_assert_no_error (error);
135 g_assert_nonnull (tmp);
136 tmp_mount = g_unix_mount_for (tmp, NULL);
137
138 if (tmp_mount == NULL)
139 {
140 g_test_skip_printf ("Unable to determine mount point for %s", tmp);
141 g_unix_mount_free (target_mount);
142 g_free (target);
143 g_free (tmp);
144 return;
145 }
146
147 g_assert_nonnull (tmp_mount);
148 g_test_message ("Tmp: %s (mount: %s)", tmp, g_unix_mount_get_mount_path (tmp_mount));
149
150 if (g_unix_mount_compare (target_mount, tmp_mount) == 0)
151 {
152 g_test_skip ("The tmp has to be on another mount than the home to run this test");
153
154 g_unix_mount_free (tmp_mount);
155 g_free (tmp);
156 g_unix_mount_free (target_mount);
157 g_free (target);
158
159 return;
160 }
161
162 symlink = g_file_new_build_filename (tmp, "symlink", NULL);
163 g_file_make_symbolic_link (symlink, g_get_home_dir (), NULL, &error);
164 g_assert_no_error (error);
165
166 symlink_mount = g_unix_mount_for (g_file_peek_path (symlink), NULL);
167 g_assert_nonnull (symlink_mount);
168 g_test_message ("Symlink: %s (mount: %s)", g_file_peek_path (symlink), g_unix_mount_get_mount_path (symlink_mount));
169
170 g_assert_cmpint (g_unix_mount_compare (symlink_mount, tmp_mount), ==, 0);
171
172 target_over_symlink = g_build_filename (g_file_peek_path (symlink),
173 ".local",
174 NULL);
175 target_over_symlink_mount = g_unix_mount_for (target_over_symlink, NULL);
176 g_assert_nonnull (symlink_mount);
177 g_test_message ("Target over symlink: %s (mount: %s)", target_over_symlink, g_unix_mount_get_mount_path (target_over_symlink_mount));
178
179 g_assert_cmpint (g_unix_mount_compare (target_over_symlink_mount, target_mount), ==, 0);
180
181 g_unix_mount_free (target_over_symlink_mount);
182 g_unix_mount_free (symlink_mount);
183 g_free (target_over_symlink);
184 g_object_unref (symlink);
185 g_unix_mount_free (tmp_mount);
186 g_free (tmp);
187 g_unix_mount_free (target_mount);
188 g_free (target);
189 }
190
191 int
192 main (int argc, char *argv[])
193 {
194 g_test_init (&argc, &argv, NULL);
195
196 g_test_add_func ("/trash/not-supported", test_trash_not_supported);
197 g_test_add_func ("/trash/symlinks", test_trash_symlinks);
198
199 return g_test_run ();
200 }