Branch data Line data Source code
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 : : #include <fcntl.h>
30 : :
31 : : /* Test that g_file_trash() returns G_IO_ERROR_NOT_SUPPORTED for files on system mounts. */
32 : : static void
33 : 1 : test_trash_not_supported (void)
34 : : {
35 : : GFile *file;
36 : : GFileIOStream *stream;
37 : : GUnixMountEntry *mount;
38 : : GFileInfo *info;
39 : 1 : GError *error = NULL;
40 : : gboolean ret;
41 : : gchar *parent_dirname;
42 : : GStatBuf parent_stat, home_stat;
43 : :
44 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/251");
45 : :
46 : : /* The test assumes that tmp file is located on system internal mount. */
47 : 1 : file = g_file_new_tmp ("test-trashXXXXXX", &stream, &error);
48 : 1 : parent_dirname = g_path_get_dirname (g_file_peek_path (file));
49 : 1 : g_assert_no_error (error);
50 : 1 : g_assert_cmpint (g_stat (parent_dirname, &parent_stat), ==, 0);
51 : 1 : g_test_message ("File: %s (parent st_dev: %" G_GUINT64_FORMAT ")",
52 : 1 : g_file_peek_path (file), (guint64) parent_stat.st_dev);
53 : :
54 : 1 : g_assert_cmpint (g_stat (g_get_home_dir (), &home_stat), ==, 0);
55 : 1 : g_test_message ("Home: %s (st_dev: %" G_GUINT64_FORMAT ")",
56 : 1 : g_get_home_dir (), (guint64) home_stat.st_dev);
57 : :
58 : 1 : if (parent_stat.st_dev == home_stat.st_dev)
59 : : {
60 : 1 : g_test_skip ("The file has to be on another filesystem than the home trash to run this test");
61 : :
62 : 1 : g_free (parent_dirname);
63 : 1 : g_object_unref (stream);
64 : 1 : g_object_unref (file);
65 : :
66 : 1 : return;
67 : : }
68 : :
69 : 0 : mount = g_unix_mount_entry_for (g_file_peek_path (file), NULL);
70 : 0 : g_assert_true (mount == NULL || g_unix_mount_entry_is_system_internal (mount));
71 : 0 : g_test_message ("Mount: %s", (mount != NULL) ? g_unix_mount_entry_get_mount_path (mount) : "(null)");
72 : 0 : g_clear_pointer (&mount, g_unix_mount_entry_free);
73 : :
74 : : /* g_file_trash() shouldn't be supported on system internal mounts,
75 : : * because those are not monitored by gvfsd-trash.
76 : : */
77 : 0 : ret = g_file_trash (file, NULL, &error);
78 : 0 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
79 : 0 : g_test_message ("Error: %s", error->message);
80 : 0 : g_assert_false (ret);
81 : 0 : g_clear_error (&error);
82 : :
83 : 0 : info = g_file_query_info (file,
84 : : G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH,
85 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
86 : : NULL,
87 : : &error);
88 : 0 : g_assert_no_error (error);
89 : :
90 : 0 : g_assert_false (g_file_info_get_attribute_boolean (info,
91 : : G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH));
92 : :
93 : 0 : g_io_stream_close (G_IO_STREAM (stream), NULL, &error);
94 : 0 : g_assert_no_error (error);
95 : :
96 : 0 : g_free (parent_dirname);
97 : 0 : g_object_unref (info);
98 : 0 : g_object_unref (stream);
99 : 0 : g_object_unref (file);
100 : : }
101 : :
102 : : /* Test that symlinks are properly expaned when looking for topdir (e.g. for trash folder). */
103 : : static void
104 : 1 : test_trash_symlinks (void)
105 : : {
106 : : GFile *symlink;
107 : : GUnixMountEntry *target_mount, *tmp_mount, *symlink_mount, *target_over_symlink_mount;
108 : : gchar *target, *tmp, *target_over_symlink;
109 : 1 : GError *error = NULL;
110 : :
111 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1522");
112 : :
113 : 1 : target = g_build_filename (g_get_home_dir (), ".local", NULL);
114 : :
115 : 1 : if (!g_file_test (target, G_FILE_TEST_IS_DIR))
116 : : {
117 : 0 : g_test_skip_printf ("Directory '%s' does not exist", target);
118 : 0 : g_free (target);
119 : 1 : return;
120 : : }
121 : :
122 : 1 : target_mount = g_unix_mount_entry_for (target, NULL);
123 : :
124 : 1 : if (target_mount == NULL)
125 : : {
126 : 0 : g_test_skip_printf ("Unable to determine mount point for %s", target);
127 : 0 : g_free (target);
128 : 0 : return;
129 : : }
130 : :
131 : 1 : g_assert_nonnull (target_mount);
132 : 1 : g_test_message ("Target: %s (mount: %s)", target, g_unix_mount_entry_get_mount_path (target_mount));
133 : :
134 : 1 : tmp = g_dir_make_tmp ("test-trashXXXXXX", &error);
135 : 1 : g_assert_no_error (error);
136 : 1 : g_assert_nonnull (tmp);
137 : 1 : tmp_mount = g_unix_mount_entry_for (tmp, NULL);
138 : :
139 : 1 : if (tmp_mount == NULL)
140 : : {
141 : 0 : g_test_skip_printf ("Unable to determine mount point for %s", tmp);
142 : 0 : g_unix_mount_entry_free (target_mount);
143 : 0 : g_free (target);
144 : 0 : g_free (tmp);
145 : 0 : return;
146 : : }
147 : :
148 : 1 : g_assert_nonnull (tmp_mount);
149 : 1 : g_test_message ("Tmp: %s (mount: %s)", tmp, g_unix_mount_entry_get_mount_path (tmp_mount));
150 : :
151 : 1 : if (g_unix_mount_entry_compare (target_mount, tmp_mount) == 0)
152 : : {
153 : 1 : g_test_skip ("The tmp has to be on another mount than the home to run this test");
154 : :
155 : 1 : g_unix_mount_entry_free (tmp_mount);
156 : 1 : g_free (tmp);
157 : 1 : g_unix_mount_entry_free (target_mount);
158 : 1 : g_free (target);
159 : :
160 : 1 : return;
161 : : }
162 : :
163 : 0 : symlink = g_file_new_build_filename (tmp, "symlink", NULL);
164 : 0 : g_file_make_symbolic_link (symlink, g_get_home_dir (), NULL, &error);
165 : 0 : g_assert_no_error (error);
166 : :
167 : 0 : symlink_mount = g_unix_mount_entry_for (g_file_peek_path (symlink), NULL);
168 : 0 : g_assert_nonnull (symlink_mount);
169 : 0 : g_test_message ("Symlink: %s (mount: %s)", g_file_peek_path (symlink), g_unix_mount_entry_get_mount_path (symlink_mount));
170 : :
171 : 0 : g_assert_cmpint (g_unix_mount_entry_compare (symlink_mount, tmp_mount), ==, 0);
172 : :
173 : 0 : target_over_symlink = g_build_filename (g_file_peek_path (symlink),
174 : : ".local",
175 : : NULL);
176 : 0 : target_over_symlink_mount = g_unix_mount_entry_for (target_over_symlink, NULL);
177 : 0 : g_assert_nonnull (symlink_mount);
178 : 0 : g_test_message ("Target over symlink: %s (mount: %s)", target_over_symlink, g_unix_mount_entry_get_mount_path (target_over_symlink_mount));
179 : :
180 : 0 : g_assert_cmpint (g_unix_mount_entry_compare (target_over_symlink_mount, target_mount), ==, 0);
181 : :
182 : 0 : g_unix_mount_entry_free (target_over_symlink_mount);
183 : 0 : g_unix_mount_entry_free (symlink_mount);
184 : 0 : g_free (target_over_symlink);
185 : 0 : g_object_unref (symlink);
186 : 0 : g_unix_mount_entry_free (tmp_mount);
187 : 0 : g_free (tmp);
188 : 0 : g_unix_mount_entry_free (target_mount);
189 : 0 : g_free (target);
190 : : }
191 : :
192 : : /* Test that long filename are handled correctly */
193 : : static void
194 : 1 : test_trash_long_filename (void)
195 : : {
196 : 1 : const gchar *long_filename = "test_trash_long_filename_aaaaaaaaaaaaaaaaaaaaaaaaa" \
197 : : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
198 : : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
199 : : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
200 : : "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
201 : : "aaaaa"; /* 255 bytes */
202 : : gchar *filepath;
203 : : int fd;
204 : : GFile *file;
205 : 1 : GError *error = NULL;
206 : :
207 : : /* The test assumes that test file is located on ext fs. */
208 : 1 : filepath = g_build_filename (g_get_home_dir (), long_filename, NULL);
209 : 1 : fd = g_open (filepath, O_CREAT | O_RDONLY, 0666);
210 : 1 : if (fd == -1)
211 : : {
212 : 0 : g_test_skip ("Failed to create test file");
213 : 0 : g_free (filepath);
214 : 0 : return;
215 : : }
216 : 1 : (void) g_close (fd, NULL);
217 : 1 : file = g_file_new_for_path (filepath);
218 : 1 : g_file_trash (file, NULL, &error);
219 : 1 : g_unlink (filepath);
220 : 1 : g_assert_no_error (error);
221 : :
222 : : /* Delete trashed version of test file */
223 : : {
224 : : GFileEnumerator *enumerator;
225 : : GFile *trash;
226 : :
227 : 1 : trash = g_file_new_for_uri ("trash:///");
228 : 1 : enumerator = g_file_enumerate_children (trash,
229 : : G_FILE_ATTRIBUTE_STANDARD_NAME ","
230 : : G_FILE_ATTRIBUTE_TRASH_ORIG_PATH,
231 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
232 : : NULL, NULL);
233 : :
234 : 1 : if (enumerator)
235 : : {
236 : : GFileInfo *info;
237 : :
238 : 0 : while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL)
239 : : {
240 : 0 : const char *origpath = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH);
241 : :
242 : 0 : if (strcmp (filepath, origpath) == 0)
243 : : {
244 : 0 : GFile *item = g_file_get_child (trash, g_file_info_get_name (info));
245 : 0 : g_file_delete (item, NULL, NULL);
246 : 0 : g_object_unref (item);
247 : 0 : g_object_unref (info);
248 : 0 : break;
249 : : }
250 : :
251 : 0 : g_object_unref (info);
252 : : }
253 : :
254 : 0 : g_file_enumerator_close (enumerator, NULL, NULL);
255 : 0 : g_object_unref (enumerator);
256 : : }
257 : 1 : g_object_unref (trash);
258 : : }
259 : :
260 : 1 : g_free (filepath);
261 : 1 : g_object_unref (file);
262 : 1 : g_clear_error (&error);
263 : : }
264 : :
265 : : int
266 : 1 : main (int argc, char *argv[])
267 : : {
268 : 1 : g_test_init (&argc, &argv, NULL);
269 : :
270 : 1 : g_test_add_func ("/trash/not-supported", test_trash_not_supported);
271 : 1 : g_test_add_func ("/trash/symlinks", test_trash_symlinks);
272 : 1 : g_test_add_func ("/trash/long-filename", test_trash_long_filename);
273 : :
274 : 1 : return g_test_run ();
275 : : }
|