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