Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : * Copyright (C) 2008 Red Hat, Inc.
3 : : * Authors: Tomas Bzatek <tbzatek@redhat.com>
4 : : *
5 : : * SPDX-License-Identifier: LicenseRef-old-glib-tests
6 : : *
7 : : * This work is provided "as is"; redistribution and modification
8 : : * in whole or in part, in any medium, physical or electronic is
9 : : * permitted without restriction.
10 : : *
11 : : * This work is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 : : *
15 : : * In no event shall the authors or contributors be liable for any
16 : : * direct, indirect, incidental, special, exemplary, or consequential
17 : : * damages (including, but not limited to, procurement of substitute
18 : : * goods or services; loss of use, data, or profits; or business
19 : : * interruption) however caused and on any theory of liability, whether
20 : : * in contract, strict liability, or tort (including negligence or
21 : : * otherwise) arising in any way out of the use of this software, even
22 : : * if advised of the possibility of such damage.
23 : : */
24 : :
25 : : #include <glib/glib.h>
26 : : #include <glib/gstdio.h>
27 : : #include <gio/gio.h>
28 : : #include <errno.h>
29 : : #include <stdlib.h>
30 : : #include <stdio.h>
31 : : #include <unistd.h>
32 : : #include <sys/types.h>
33 : : #include <string.h>
34 : : #include <sys/stat.h>
35 : :
36 : : #define PATTERN_FILE_SIZE 0x10000
37 : : #define TEST_HANDLE_SPECIAL TRUE
38 : :
39 : : enum StructureExtraFlags
40 : : {
41 : : TEST_DELETE_NORMAL = 1 << 0,
42 : : TEST_DELETE_TRASH = 1 << 1,
43 : : TEST_DELETE_NON_EMPTY = 1 << 2,
44 : : TEST_DELETE_FAILURE = 1 << 3,
45 : : TEST_NOT_EXISTS = 1 << 4,
46 : : TEST_ENUMERATE_FILE = 1 << 5,
47 : : TEST_NO_ACCESS = 1 << 6,
48 : : TEST_COPY = 1 << 7,
49 : : TEST_MOVE = 1 << 8,
50 : : TEST_COPY_ERROR_RECURSE = 1 << 9,
51 : : TEST_ALREADY_EXISTS = 1 << 10,
52 : : TEST_TARGET_IS_FILE = 1 << 11,
53 : : TEST_CREATE = 1 << 12,
54 : : TEST_REPLACE = 1 << 13,
55 : : TEST_APPEND = 1 << 14,
56 : : TEST_OPEN = 1 << 15,
57 : : TEST_OVERWRITE = 1 << 16,
58 : : TEST_INVALID_SYMLINK = 1 << 17,
59 : : TEST_HIDDEN = 1 << 18,
60 : : TEST_DOT_HIDDEN = 1 << 19,
61 : : } G_GNUC_FLAG_ENUM;
62 : :
63 : : struct StructureItem
64 : : {
65 : : const char *filename;
66 : : const char *link_to;
67 : : GFileType file_type;
68 : : GFileCreateFlags create_flags;
69 : : guint32 mode;
70 : : gboolean handle_special;
71 : : enum StructureExtraFlags extra_flags;
72 : : };
73 : :
74 : : #define TEST_DIR_NO_ACCESS "dir_no-access"
75 : : #define TEST_DIR_NO_WRITE "dir_no-write"
76 : : #define TEST_DIR_TARGET "dir-target"
77 : : #define TEST_NAME_NOT_EXISTS "not_exists"
78 : : #define TEST_TARGET_FILE "target-file"
79 : :
80 : :
81 : : static const struct StructureItem sample_struct[] = {
82 : : /* filename link file_type create_flags mode | handle_special | extra_flags */
83 : : {"dir1", NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_DELETE_NON_EMPTY | TEST_REPLACE | TEST_OPEN},
84 : : {"dir1/subdir", NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_COPY_ERROR_RECURSE | TEST_APPEND},
85 : : {"dir2", NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_MOVE | TEST_CREATE},
86 : : {TEST_DIR_TARGET, NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_COPY_ERROR_RECURSE},
87 : : {TEST_DIR_NO_ACCESS, NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_PRIVATE, S_IRUSR + S_IWUSR + S_IRGRP + S_IWGRP + S_IROTH + S_IWOTH, 0, TEST_NO_ACCESS | TEST_OPEN},
88 : : {TEST_DIR_NO_WRITE, NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_PRIVATE, S_IRUSR + S_IXUSR + S_IRGRP + S_IXGRP + S_IROTH + S_IXOTH, 0, 0},
89 : : {TEST_TARGET_FILE, NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OPEN},
90 : : {"normal_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_ENUMERATE_FILE | TEST_CREATE | TEST_OVERWRITE},
91 : : {"normal_file-symlink", "normal_file", G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_ENUMERATE_FILE | TEST_COPY | TEST_OPEN},
92 : : {"executable_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, S_IRWXU + S_IRWXG + S_IRWXO, 0, TEST_DELETE_TRASH | TEST_COPY | TEST_OPEN | TEST_OVERWRITE | TEST_REPLACE},
93 : : {"private_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_PRIVATE, 0, 0, TEST_COPY | TEST_OPEN | TEST_OVERWRITE | TEST_APPEND},
94 : : {"normal_file2", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OVERWRITE | TEST_REPLACE},
95 : : {"readonly_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, S_IRUSR + S_IRGRP + S_IROTH, 0, TEST_DELETE_NORMAL | TEST_OPEN},
96 : : {"UTF_pr\xcc\x8ci\xcc\x81lis\xcc\x8c z",
97 : : NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_CREATE | TEST_OPEN | TEST_OVERWRITE},
98 : : {"dir_pr\xcc\x8ci\xcc\x81lis\xcc\x8c z",
99 : : NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_CREATE},
100 : : {"pattern_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_COPY | TEST_OPEN | TEST_APPEND},
101 : : {TEST_NAME_NOT_EXISTS, NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_NORMAL | TEST_NOT_EXISTS | TEST_COPY | TEST_OPEN},
102 : : {TEST_NAME_NOT_EXISTS, NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_TRASH | TEST_NOT_EXISTS | TEST_MOVE},
103 : : {"not_exists2", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_CREATE},
104 : : {"not_exists3", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_REPLACE},
105 : : {"not_exists4", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_APPEND},
106 : : {"dir_no-execute/file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_NORMAL | TEST_DELETE_FAILURE | TEST_NOT_EXISTS | TEST_OPEN},
107 : : {"lost_symlink", "nowhere", G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_DELETE_NORMAL | TEST_OPEN | TEST_INVALID_SYMLINK},
108 : : {"dir_hidden", NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, 0},
109 : : {"dir_hidden/.hidden", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, 0},
110 : : {"dir_hidden/.a-hidden-file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_HIDDEN},
111 : : {"dir_hidden/file-in-.hidden1", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_HIDDEN | TEST_DOT_HIDDEN},
112 : : {"dir_hidden/file-in-.hidden2", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_HIDDEN | TEST_DOT_HIDDEN},
113 : : };
114 : :
115 : : static gboolean test_suite;
116 : : static gboolean write_test;
117 : : static gboolean verbose;
118 : : static gboolean posix_compat;
119 : :
120 : : #ifdef G_OS_UNIX
121 : : /*
122 : : * check_cap_dac_override:
123 : : * @tmpdir: A temporary directory in which we can create and delete files
124 : : *
125 : : * Check whether the current process can bypass DAC permissions.
126 : : *
127 : : * Traditionally, "privileged" processes (those with effective uid 0)
128 : : * could do this (and bypass many other checks), and "unprivileged"
129 : : * processes could not.
130 : : *
131 : : * In Linux, the special powers of euid 0 are divided into many
132 : : * capabilities: see `capabilities(7)`. The one we are interested in
133 : : * here is `CAP_DAC_OVERRIDE`.
134 : : *
135 : : * We do this generically instead of actually looking at the capability
136 : : * bits, so that the right thing will happen on non-Linux Unix
137 : : * implementations, in particular if they have something equivalent to
138 : : * but not identical to Linux permissions.
139 : : *
140 : : * Returns: %TRUE if we have Linux `CAP_DAC_OVERRIDE` or equivalent
141 : : * privileges
142 : : */
143 : : static gboolean
144 : 73 : check_cap_dac_override (const char *tmpdir)
145 : : {
146 : : gchar *dac_denies_write;
147 : : gchar *inside;
148 : : gboolean have_cap;
149 : :
150 : 73 : dac_denies_write = g_build_filename (tmpdir, "dac-denies-write", NULL);
151 : 73 : inside = g_build_filename (dac_denies_write, "inside", NULL);
152 : :
153 : 73 : g_assert_no_errno (mkdir (dac_denies_write, S_IRWXU));
154 : 73 : g_assert_no_errno (chmod (dac_denies_write, 0));
155 : :
156 : 73 : if (mkdir (inside, S_IRWXU) == 0)
157 : : {
158 : 0 : g_test_message ("Looks like we have CAP_DAC_OVERRIDE or equivalent");
159 : 0 : g_assert_no_errno (rmdir (inside));
160 : 0 : have_cap = TRUE;
161 : : }
162 : : else
163 : : {
164 : 73 : int saved_errno = errno;
165 : :
166 : 73 : g_test_message ("We do not have CAP_DAC_OVERRIDE or equivalent");
167 : 73 : g_assert_cmpint (saved_errno, ==, EACCES);
168 : 73 : have_cap = FALSE;
169 : : }
170 : :
171 : 73 : g_assert_no_errno (chmod (dac_denies_write, S_IRWXU));
172 : 73 : g_assert_no_errno (rmdir (dac_denies_write));
173 : 73 : g_free (dac_denies_write);
174 : 73 : g_free (inside);
175 : 73 : return have_cap;
176 : : }
177 : : #endif
178 : :
179 : : static GFile *
180 : 10 : create_empty_file (GFile * parent, const char *filename,
181 : : GFileCreateFlags create_flags)
182 : : {
183 : : GFile *child;
184 : : GError *error;
185 : : GFileOutputStream *outs;
186 : :
187 : 10 : child = g_file_get_child (parent, filename);
188 : 10 : g_assert_nonnull (child);
189 : :
190 : 10 : error = NULL;
191 : 10 : outs = g_file_replace (child, NULL, FALSE, create_flags, NULL, &error);
192 : 10 : g_assert_no_error (error);
193 : 10 : g_assert_nonnull (outs);
194 : 10 : error = NULL;
195 : 10 : g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
196 : 10 : g_object_unref (outs);
197 : 10 : return child;
198 : : }
199 : :
200 : : static GFile *
201 : 8 : create_empty_dir (GFile * parent, const char *filename)
202 : : {
203 : : GFile *child;
204 : : gboolean res;
205 : : GError *error;
206 : :
207 : 8 : child = g_file_get_child (parent, filename);
208 : 8 : g_assert_nonnull (child);
209 : 8 : error = NULL;
210 : 8 : res = g_file_make_directory (child, NULL, &error);
211 : 8 : g_assert_true (res);
212 : 8 : g_assert_no_error (error);
213 : 8 : return child;
214 : : }
215 : :
216 : : static GFile *
217 : 2 : create_symlink (GFile * parent, const char *filename, const char *points_to)
218 : : {
219 : : GFile *child;
220 : : gboolean res;
221 : : GError *error;
222 : :
223 : 2 : child = g_file_get_child (parent, filename);
224 : 2 : g_assert_nonnull (child);
225 : 2 : error = NULL;
226 : 2 : res = g_file_make_symbolic_link (child, points_to, NULL, &error);
227 : 2 : g_assert_true (res);
228 : 2 : g_assert_no_error (error);
229 : 2 : return child;
230 : : }
231 : :
232 : : static void
233 : 1 : test_create_structure (gconstpointer test_data)
234 : : {
235 : : GFile *root;
236 : : GFile *child;
237 : : gboolean res;
238 : 1 : GError *error = NULL;
239 : : GFileOutputStream *outs;
240 : : GDataOutputStream *outds;
241 : : guint i;
242 : : struct StructureItem item;
243 : :
244 : 1 : g_assert_nonnull (test_data);
245 : 1 : g_test_message ("\n Going to create testing structure in '%s'...",
246 : : (char *) test_data);
247 : :
248 : 1 : root = g_file_new_for_commandline_arg ((char *) test_data);
249 : 1 : g_assert_nonnull (root);
250 : :
251 : : /* create root directory */
252 : 1 : g_file_make_directory (root, NULL, &error);
253 : 1 : g_assert_no_error (error);
254 : :
255 : : /* create any other items */
256 : 29 : for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
257 : : {
258 : 28 : item = sample_struct[i];
259 : 28 : if ((item.handle_special)
260 : 20 : || ((!posix_compat)
261 : 0 : && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK)))
262 : 8 : continue;
263 : :
264 : 20 : child = NULL;
265 : 20 : switch (item.file_type)
266 : : {
267 : 10 : case G_FILE_TYPE_REGULAR:
268 : 10 : g_test_message (" Creating file '%s'...", item.filename);
269 : 10 : child = create_empty_file (root, item.filename, item.create_flags);
270 : 10 : break;
271 : 8 : case G_FILE_TYPE_DIRECTORY:
272 : 8 : g_test_message (" Creating directory '%s'...", item.filename);
273 : 8 : child = create_empty_dir (root, item.filename);
274 : 8 : break;
275 : 2 : case G_FILE_TYPE_SYMBOLIC_LINK:
276 : 2 : g_test_message (" Creating symlink '%s' --> '%s'...", item.filename,
277 : : item.link_to);
278 : 2 : child = create_symlink (root, item.filename, item.link_to);
279 : 2 : break;
280 : 0 : case G_FILE_TYPE_UNKNOWN:
281 : : case G_FILE_TYPE_SPECIAL:
282 : : case G_FILE_TYPE_SHORTCUT:
283 : : case G_FILE_TYPE_MOUNTABLE:
284 : : default:
285 : 0 : break;
286 : : }
287 : 20 : g_assert_nonnull (child);
288 : :
289 : 20 : if ((item.mode > 0) && (posix_compat))
290 : : {
291 : : res =
292 : 4 : g_file_set_attribute_uint32 (child, G_FILE_ATTRIBUTE_UNIX_MODE,
293 : : item.mode,
294 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
295 : : NULL, &error);
296 : 4 : g_assert_true (res);
297 : 4 : g_assert_no_error (error);
298 : : }
299 : :
300 : 20 : if ((item.extra_flags & TEST_DOT_HIDDEN) == TEST_DOT_HIDDEN)
301 : : {
302 : : gchar *dir, *path, *basename;
303 : : FILE *f;
304 : :
305 : 2 : dir = g_path_get_dirname (item.filename);
306 : 2 : basename = g_path_get_basename (item.filename);
307 : 2 : path = g_build_filename (test_data, dir, ".hidden", NULL);
308 : :
309 : 2 : f = g_fopen (path, "ae");
310 : 2 : fprintf (f, "%s\n", basename);
311 : 2 : fclose (f);
312 : :
313 : 2 : g_free (dir);
314 : 2 : g_free (path);
315 : 2 : g_free (basename);
316 : : }
317 : :
318 : 20 : g_object_unref (child);
319 : : }
320 : :
321 : : /* create a pattern file */
322 : 1 : g_test_message (" Creating pattern file...");
323 : 1 : child = g_file_get_child (root, "pattern_file");
324 : 1 : g_assert_nonnull (child);
325 : :
326 : : outs =
327 : 1 : g_file_replace (child, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error);
328 : 1 : g_assert_no_error (error);
329 : :
330 : 1 : g_assert_nonnull (outs);
331 : 1 : outds = g_data_output_stream_new (G_OUTPUT_STREAM (outs));
332 : 1 : g_assert_nonnull (outds);
333 : 65537 : for (i = 0; i < PATTERN_FILE_SIZE; i++)
334 : : {
335 : 65536 : g_data_output_stream_put_byte (outds, i % 256, NULL, &error);
336 : 65536 : g_assert_no_error (error);
337 : : }
338 : :
339 : 1 : g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
340 : 1 : g_assert_no_error (error);
341 : 1 : g_object_unref (outds);
342 : 1 : g_object_unref (outs);
343 : 1 : g_object_unref (child);
344 : 1 : g_test_message (" done.");
345 : :
346 : 1 : g_object_unref (root);
347 : 1 : }
348 : :
349 : : static GFile *
350 : 30 : file_exists (GFile * parent, const char *filename, gboolean * result)
351 : : {
352 : : GFile *child;
353 : : gboolean res;
354 : :
355 : 30 : if (result)
356 : 30 : *result = FALSE;
357 : :
358 : 30 : child = g_file_get_child (parent, filename);
359 : 30 : g_assert_nonnull (child);
360 : 30 : res = g_file_query_exists (child, NULL);
361 : 30 : if (result)
362 : 30 : *result = res;
363 : :
364 : 30 : return child;
365 : : }
366 : :
367 : : static void
368 : 42 : test_attributes (struct StructureItem item, GFileInfo * info)
369 : : {
370 : : GFileType ftype;
371 : : guint32 mode;
372 : : const char *name, *display_name, *edit_name, *copy_name, *symlink_target;
373 : : gboolean utf8_valid;
374 : : gboolean has_attr;
375 : : gboolean is_symlink;
376 : : gboolean is_hidden;
377 : : gboolean can_read, can_write;
378 : :
379 : : /* standard::type */
380 : 42 : has_attr = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
381 : 42 : g_assert_true (has_attr);
382 : 42 : ftype = g_file_info_get_file_type (info);
383 : 42 : g_assert_cmpint (ftype, !=, G_FILE_TYPE_UNKNOWN);
384 : 42 : g_assert_cmpint (ftype, ==, item.file_type);
385 : :
386 : : /* unix::mode */
387 : 42 : if ((item.mode > 0) && (posix_compat))
388 : : {
389 : 8 : mode =
390 : 8 : g_file_info_get_attribute_uint32 (info,
391 : : G_FILE_ATTRIBUTE_UNIX_MODE) & 0xFFF;
392 : 8 : g_assert_cmpint (mode, ==, item.mode);
393 : : }
394 : :
395 : : /* access::can-read */
396 : 42 : if (item.file_type != G_FILE_TYPE_SYMBOLIC_LINK)
397 : : {
398 : : can_read =
399 : 38 : g_file_info_get_attribute_boolean (info,
400 : : G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
401 : 38 : g_assert_true (can_read);
402 : : }
403 : :
404 : : /* access::can-write */
405 : 42 : if ((write_test) && ((item.extra_flags & TEST_OVERWRITE) == TEST_OVERWRITE))
406 : : {
407 : : can_write =
408 : 10 : g_file_info_get_attribute_boolean (info,
409 : : G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
410 : 10 : g_assert_true (can_write);
411 : : }
412 : :
413 : : /* standard::name */
414 : 42 : name = g_file_info_get_name (info);
415 : 42 : g_assert_nonnull (name);
416 : :
417 : : /* standard::display-name */
418 : 42 : display_name = g_file_info_get_display_name (info);
419 : 42 : g_assert_nonnull (display_name);
420 : 42 : utf8_valid = g_utf8_validate (display_name, -1, NULL);
421 : 42 : g_assert_true (utf8_valid);
422 : :
423 : : /* standard::edit-name */
424 : 42 : edit_name = g_file_info_get_edit_name (info);
425 : 42 : if (edit_name)
426 : : {
427 : 42 : utf8_valid = g_utf8_validate (edit_name, -1, NULL);
428 : 42 : g_assert_true (utf8_valid);
429 : : }
430 : :
431 : : /* standard::copy-name */
432 : : copy_name =
433 : 42 : g_file_info_get_attribute_string (info,
434 : : G_FILE_ATTRIBUTE_STANDARD_COPY_NAME);
435 : 42 : if (copy_name)
436 : : {
437 : 42 : utf8_valid = g_utf8_validate (copy_name, -1, NULL);
438 : 42 : g_assert_true (utf8_valid);
439 : : }
440 : :
441 : : /* standard::is-symlink */
442 : 42 : if (posix_compat)
443 : : {
444 : 42 : is_symlink = g_file_info_get_is_symlink (info);
445 : 42 : g_assert_cmpint (is_symlink, ==,
446 : : item.file_type == G_FILE_TYPE_SYMBOLIC_LINK);
447 : : }
448 : :
449 : : /* standard::symlink-target */
450 : 42 : if ((item.file_type == G_FILE_TYPE_SYMBOLIC_LINK) && (posix_compat))
451 : : {
452 : 4 : symlink_target = g_file_info_get_symlink_target (info);
453 : 4 : g_assert_cmpstr (symlink_target, ==, item.link_to);
454 : : }
455 : :
456 : : /* standard::is-hidden */
457 : 42 : if ((item.extra_flags & TEST_HIDDEN) == TEST_HIDDEN)
458 : : {
459 : : is_hidden =
460 : 6 : g_file_info_get_attribute_boolean (info,
461 : : G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN);
462 : 6 : g_assert_true (is_hidden);
463 : : }
464 : :
465 : : /* unix::is-mountpoint */
466 : 42 : if (posix_compat)
467 : : {
468 : : gboolean is_mountpoint =
469 : 42 : g_file_info_get_attribute_boolean (info,
470 : : G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT);
471 : 42 : g_assert_false (is_mountpoint);
472 : : }
473 : 42 : }
474 : :
475 : : static void
476 : 1 : test_initial_structure (gconstpointer test_data)
477 : : {
478 : : GFile *root;
479 : : GFile *child;
480 : : gboolean res;
481 : : GError *error;
482 : : GFileInputStream *ins;
483 : : guint i;
484 : : GFileInfo *info;
485 : : guint32 size;
486 : : guchar *buffer;
487 : : gssize read, total_read;
488 : : struct StructureItem item;
489 : :
490 : 1 : g_assert_nonnull (test_data);
491 : 1 : g_test_message (" Testing sample structure in '%s'...", (char *) test_data);
492 : :
493 : 1 : root = g_file_new_for_commandline_arg ((char *) test_data);
494 : 1 : g_assert_nonnull (root);
495 : 1 : res = g_file_query_exists (root, NULL);
496 : 1 : g_assert_true (res);
497 : :
498 : : /* test the structure */
499 : 29 : for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
500 : : {
501 : 28 : item = sample_struct[i];
502 : 28 : if (((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
503 : 28 : || (item.handle_special))
504 : 8 : continue;
505 : :
506 : 20 : g_test_message (" Testing file '%s'...", item.filename);
507 : :
508 : 20 : child = file_exists (root, item.filename, &res);
509 : 20 : g_assert_nonnull (child);
510 : 20 : g_assert_true (res);
511 : :
512 : 20 : error = NULL;
513 : : info =
514 : 20 : g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
515 : : NULL, &error);
516 : 20 : g_assert_no_error (error);
517 : 20 : g_assert_nonnull (info);
518 : :
519 : 20 : test_attributes (item, info);
520 : :
521 : 20 : g_object_unref (child);
522 : 20 : g_object_unref (info);
523 : : }
524 : :
525 : : /* read and test the pattern file */
526 : 1 : g_test_message (" Testing pattern file...");
527 : 1 : child = file_exists (root, "pattern_file", &res);
528 : 1 : g_assert_nonnull (child);
529 : 1 : g_assert_true (res);
530 : :
531 : 1 : error = NULL;
532 : : info =
533 : 1 : g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
534 : : &error);
535 : 1 : g_assert_no_error (error);
536 : 1 : g_assert_nonnull (info);
537 : 1 : size = g_file_info_get_size (info);
538 : 1 : g_assert_cmpint (size, ==, PATTERN_FILE_SIZE);
539 : 1 : g_object_unref (info);
540 : :
541 : 1 : error = NULL;
542 : 1 : ins = g_file_read (child, NULL, &error);
543 : 1 : g_assert_nonnull (ins);
544 : 1 : g_assert_no_error (error);
545 : :
546 : 1 : buffer = g_malloc (PATTERN_FILE_SIZE);
547 : 1 : total_read = 0;
548 : :
549 : 2 : while (total_read < PATTERN_FILE_SIZE)
550 : : {
551 : 1 : error = NULL;
552 : : read =
553 : 1 : g_input_stream_read (G_INPUT_STREAM (ins), buffer + total_read,
554 : : PATTERN_FILE_SIZE, NULL, &error);
555 : 1 : g_assert_no_error (error);
556 : 1 : total_read += read;
557 : 1 : g_test_message (" read %"G_GSSIZE_FORMAT" bytes, total = %"G_GSSIZE_FORMAT" of %d.",
558 : : read, total_read, PATTERN_FILE_SIZE);
559 : : }
560 : 1 : g_assert_cmpint (total_read, ==, PATTERN_FILE_SIZE);
561 : :
562 : 1 : error = NULL;
563 : 1 : res = g_input_stream_close (G_INPUT_STREAM (ins), NULL, &error);
564 : 1 : g_assert_no_error (error);
565 : 1 : g_assert_true (res);
566 : :
567 : 65537 : for (i = 0; i < PATTERN_FILE_SIZE; i++)
568 : 65536 : g_assert_cmpint (*(buffer + i), ==, i % 256);
569 : :
570 : 1 : g_object_unref (ins);
571 : 1 : g_object_unref (child);
572 : 1 : g_free (buffer);
573 : 1 : g_object_unref (root);
574 : 1 : }
575 : :
576 : : static void
577 : 9 : traverse_recurse_dirs (GFile * parent, GFile * root)
578 : : {
579 : : gboolean res;
580 : : GError *error;
581 : : GFileEnumerator *enumerator;
582 : : GFileInfo *info;
583 : : GFile *descend;
584 : : char *relative_path;
585 : : guint i;
586 : : gboolean found;
587 : :
588 : 9 : g_assert_nonnull (root);
589 : :
590 : 9 : error = NULL;
591 : : enumerator =
592 : 9 : g_file_enumerate_children (parent, "*",
593 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
594 : : &error);
595 : 9 : g_assert_nonnull (enumerator);
596 : 9 : g_assert_no_error (error);
597 : :
598 : 9 : g_assert_true (g_file_enumerator_get_container (enumerator) == parent);
599 : :
600 : 9 : error = NULL;
601 : 9 : info = g_file_enumerator_next_file (enumerator, NULL, &error);
602 : 31 : while ((info) && (!error))
603 : : {
604 : 22 : descend = g_file_enumerator_get_child (enumerator, info);
605 : 22 : g_assert_nonnull (descend);
606 : 22 : relative_path = g_file_get_relative_path (root, descend);
607 : 22 : g_assert_nonnull (relative_path);
608 : :
609 : 22 : found = FALSE;
610 : 289 : for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
611 : : {
612 : 289 : if (strcmp (sample_struct[i].filename, relative_path) == 0)
613 : : {
614 : : /* test the attributes again */
615 : 22 : test_attributes (sample_struct[i], info);
616 : :
617 : 22 : found = TRUE;
618 : 22 : break;
619 : : }
620 : : }
621 : 22 : g_assert_true (found);
622 : :
623 : 22 : g_test_message (" Found file %s, relative to root: %s",
624 : : g_file_info_get_display_name (info), relative_path);
625 : :
626 : 22 : if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
627 : 8 : traverse_recurse_dirs (descend, root);
628 : :
629 : 22 : g_object_unref (descend);
630 : 22 : error = NULL;
631 : 22 : g_object_unref (info);
632 : 22 : g_free (relative_path);
633 : :
634 : 22 : info = g_file_enumerator_next_file (enumerator, NULL, &error);
635 : : }
636 : 9 : g_assert_no_error (error);
637 : :
638 : 9 : error = NULL;
639 : 9 : res = g_file_enumerator_close (enumerator, NULL, &error);
640 : 9 : g_assert_true (res);
641 : 9 : g_assert_no_error (error);
642 : 9 : g_assert_true (g_file_enumerator_is_closed (enumerator));
643 : :
644 : 9 : g_object_unref (enumerator);
645 : 9 : }
646 : :
647 : : static void
648 : 1 : test_traverse_structure (gconstpointer test_data)
649 : : {
650 : : GFile *root;
651 : : gboolean res;
652 : :
653 : 1 : g_assert_nonnull (test_data);
654 : 1 : g_test_message (" Traversing through the sample structure in '%s'...",
655 : : (char *) test_data);
656 : :
657 : 1 : root = g_file_new_for_commandline_arg ((char *) test_data);
658 : 1 : g_assert_nonnull (root);
659 : 1 : res = g_file_query_exists (root, NULL);
660 : 1 : g_assert_true (res);
661 : :
662 : 1 : traverse_recurse_dirs (root, root);
663 : :
664 : 1 : g_object_unref (root);
665 : 1 : }
666 : :
667 : :
668 : :
669 : :
670 : : static void
671 : 1 : test_enumerate (gconstpointer test_data)
672 : : {
673 : : GFile *root, *child;
674 : : gboolean res;
675 : : GError *error;
676 : : GFileEnumerator *enumerator;
677 : : GFileInfo *info;
678 : : guint i;
679 : : struct StructureItem item;
680 : :
681 : :
682 : 1 : g_assert_nonnull (test_data);
683 : 1 : g_test_message (" Test enumerate '%s'...", (char *) test_data);
684 : :
685 : 1 : root = g_file_new_for_commandline_arg ((char *) test_data);
686 : 1 : g_assert_nonnull (root);
687 : 1 : res = g_file_query_exists (root, NULL);
688 : 1 : g_assert_true (res);
689 : :
690 : :
691 : 29 : for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
692 : : {
693 : 28 : item = sample_struct[i];
694 : 28 : if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
695 : 0 : continue;
696 : :
697 : 28 : if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
698 : 22 : (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS)
699 : 1 : && posix_compat)
700 : 21 : || ((item.extra_flags & TEST_ENUMERATE_FILE) ==
701 : : TEST_ENUMERATE_FILE))
702 : : {
703 : 9 : g_test_message (" Testing file '%s'", item.filename);
704 : 9 : child = g_file_get_child (root, item.filename);
705 : 9 : g_assert_nonnull (child);
706 : 9 : error = NULL;
707 : : enumerator =
708 : 9 : g_file_enumerate_children (child, "*",
709 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
710 : : NULL, &error);
711 : :
712 : 9 : if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS)
713 : : {
714 : 6 : g_assert_null (enumerator);
715 : 6 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
716 : : }
717 : 9 : if ((item.extra_flags & TEST_ENUMERATE_FILE) == TEST_ENUMERATE_FILE)
718 : : {
719 : 2 : g_assert_null (enumerator);
720 : 2 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
721 : : }
722 : 9 : if ((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS)
723 : : {
724 : 1 : g_assert_nonnull (enumerator);
725 : :
726 : 1 : error = NULL;
727 : 1 : info = g_file_enumerator_next_file (enumerator, NULL, &error);
728 : 1 : g_assert_null (info);
729 : 1 : g_assert_no_error (error);
730 : : /* no items should be found, no error should be logged */
731 : : }
732 : :
733 : 9 : if (error)
734 : 8 : g_error_free (error);
735 : :
736 : 9 : if (enumerator)
737 : : {
738 : 1 : error = NULL;
739 : 1 : res = g_file_enumerator_close (enumerator, NULL, &error);
740 : 1 : g_assert_true (res);
741 : 1 : g_assert_no_error (error);
742 : :
743 : 1 : g_object_unref (enumerator);
744 : : }
745 : 9 : g_object_unref (child);
746 : : }
747 : : }
748 : 1 : g_object_unref (root);
749 : 1 : }
750 : :
751 : : static void
752 : 72 : do_copy_move (GFile * root, struct StructureItem item, const char *target_dir,
753 : : enum StructureExtraFlags extra_flags)
754 : : {
755 : : GFile *dst_dir, *src_file, *dst_file;
756 : : gboolean res;
757 : : GError *error;
758 : : #ifdef G_OS_UNIX
759 : 72 : gboolean have_cap_dac_override = check_cap_dac_override (g_file_peek_path (root));
760 : : #endif
761 : :
762 : 72 : g_test_message (" do_copy_move: '%s' --> '%s'", item.filename, target_dir);
763 : :
764 : 72 : dst_dir = g_file_get_child (root, target_dir);
765 : 72 : g_assert_nonnull (dst_dir);
766 : 72 : src_file = g_file_get_child (root, item.filename);
767 : 72 : g_assert_nonnull (src_file);
768 : 72 : dst_file = g_file_get_child (dst_dir, item.filename);
769 : 72 : g_assert_nonnull (dst_file);
770 : :
771 : 72 : error = NULL;
772 : 72 : if ((item.extra_flags & TEST_COPY) == TEST_COPY)
773 : : res =
774 : 70 : g_file_copy (src_file, dst_file,
775 : : G_FILE_COPY_NOFOLLOW_SYMLINKS |
776 : : ((extra_flags ==
777 : : TEST_OVERWRITE) ? G_FILE_COPY_OVERWRITE :
778 : : G_FILE_COPY_NONE), NULL, NULL, NULL, &error);
779 : : else
780 : : res =
781 : 2 : g_file_move (src_file, dst_file, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL,
782 : : NULL, NULL, &error);
783 : :
784 : 72 : if (error)
785 : 59 : g_test_message (" res = %d, error code %d = %s", res, error->code,
786 : 59 : error->message);
787 : :
788 : : /* copying file/directory to itself (".") */
789 : 72 : if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) &&
790 : : (extra_flags == TEST_ALREADY_EXISTS))
791 : : {
792 : 10 : g_assert_false (res);
793 : 10 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
794 : : }
795 : : /* target file is a file, overwrite is not set */
796 : 62 : else if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) &&
797 : : (extra_flags == TEST_TARGET_IS_FILE))
798 : : {
799 : 10 : g_assert_false (res);
800 : 10 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
801 : : }
802 : : /* source file is directory */
803 : 52 : else if ((item.extra_flags & TEST_COPY_ERROR_RECURSE) ==
804 : : TEST_COPY_ERROR_RECURSE)
805 : : {
806 : 8 : g_assert_false (res);
807 : 8 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE);
808 : : }
809 : : /* source or target path doesn't exist */
810 : 44 : else if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
811 : : (extra_flags == TEST_NOT_EXISTS))
812 : : {
813 : 15 : g_assert_false (res);
814 : 15 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
815 : : }
816 : : /* source or target path permission denied */
817 : 29 : else if (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS) ||
818 : : (extra_flags == TEST_NO_ACCESS))
819 : : {
820 : : /* This works for root, see bug #552912 */
821 : : #ifdef G_OS_UNIX
822 : 16 : if (have_cap_dac_override)
823 : : {
824 : 0 : g_test_message ("Unable to exercise g_file_copy() or g_file_move() "
825 : : "failing with EACCES: we probably have "
826 : : "CAP_DAC_OVERRIDE");
827 : 0 : g_assert_true (res);
828 : 0 : g_assert_no_error (error);
829 : : }
830 : : else
831 : : #endif
832 : : {
833 : 16 : g_assert_false (res);
834 : 16 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
835 : : }
836 : : }
837 : : /* no error should be found, all exceptions defined above */
838 : : else
839 : : {
840 : 13 : g_assert_true (res);
841 : 13 : g_assert_no_error (error);
842 : : }
843 : :
844 : 72 : if (error)
845 : 59 : g_error_free (error);
846 : :
847 : :
848 : 72 : g_object_unref (dst_dir);
849 : 72 : g_object_unref (src_file);
850 : 72 : g_object_unref (dst_file);
851 : 72 : }
852 : :
853 : : static void
854 : 1 : test_copy_move (gconstpointer test_data)
855 : : {
856 : : GFile *root;
857 : : gboolean res;
858 : : guint i;
859 : : struct StructureItem item;
860 : :
861 : 1 : g_assert_nonnull (test_data);
862 : 1 : root = g_file_new_for_commandline_arg ((char *) test_data);
863 : 1 : g_assert_nonnull (root);
864 : 1 : res = g_file_query_exists (root, NULL);
865 : 1 : g_assert_true (res);
866 : :
867 : :
868 : 29 : for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
869 : : {
870 : 28 : item = sample_struct[i];
871 : :
872 : 28 : if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
873 : 0 : continue;
874 : :
875 : 28 : if (((item.extra_flags & TEST_COPY) == TEST_COPY) ||
876 : 17 : ((item.extra_flags & TEST_MOVE) == TEST_MOVE))
877 : : {
878 : : /* test copy/move to a directory, expecting no errors if source files exist */
879 : 13 : do_copy_move (root, item, TEST_DIR_TARGET, 0);
880 : :
881 : : /* some files have been already moved so we can't count with them in the tests */
882 : 13 : if ((item.extra_flags & TEST_COPY) == TEST_COPY)
883 : : {
884 : : /* test overwrite for flagged files */
885 : 11 : if ((item.extra_flags & TEST_OVERWRITE) == TEST_OVERWRITE)
886 : : {
887 : 4 : do_copy_move (root, item, TEST_DIR_TARGET, TEST_OVERWRITE);
888 : : }
889 : : /* source = target, should return G_IO_ERROR_EXISTS */
890 : 11 : do_copy_move (root, item, ".", TEST_ALREADY_EXISTS);
891 : : /* target is file */
892 : 11 : do_copy_move (root, item, TEST_TARGET_FILE,
893 : : TEST_TARGET_IS_FILE);
894 : : /* target path is invalid */
895 : 11 : do_copy_move (root, item, TEST_NAME_NOT_EXISTS,
896 : : TEST_NOT_EXISTS);
897 : :
898 : : /* tests on POSIX-compatible filesystems */
899 : 11 : if (posix_compat)
900 : : {
901 : : /* target directory is not accessible (no execute flag) */
902 : 11 : do_copy_move (root, item, TEST_DIR_NO_ACCESS,
903 : : TEST_NO_ACCESS);
904 : : /* target directory is readonly */
905 : 11 : do_copy_move (root, item, TEST_DIR_NO_WRITE,
906 : : TEST_NO_ACCESS);
907 : : }
908 : : }
909 : : }
910 : : }
911 : 1 : g_object_unref (root);
912 : 1 : }
913 : :
914 : : /* Test that G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT is TRUE for / and for another
915 : : * known mountpoint. The FALSE case is tested for many directories and files by
916 : : * test_initial_structure(), via test_attributes().
917 : : */
918 : : static void
919 : 2 : test_unix_is_mountpoint (gconstpointer data)
920 : : {
921 : 2 : const gchar *path = data;
922 : 2 : GFile *file = g_file_new_for_path (path);
923 : : GFileInfo *info;
924 : : gboolean is_mountpoint;
925 : 2 : GError *error = NULL;
926 : :
927 : 2 : info = g_file_query_info (file, G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT,
928 : : G_FILE_QUERY_INFO_NONE, NULL, &error);
929 : 2 : g_assert_no_error (error);
930 : 2 : g_assert_nonnull (info);
931 : :
932 : : is_mountpoint =
933 : 2 : g_file_info_get_attribute_boolean (info,
934 : : G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT);
935 : 2 : g_assert_true (is_mountpoint);
936 : :
937 : 2 : g_clear_object (&info);
938 : 2 : g_clear_object (&file);
939 : 2 : }
940 : :
941 : : static void
942 : 1 : test_create (gconstpointer test_data)
943 : : {
944 : : GFile *root, *child;
945 : : gboolean res;
946 : : GError *error;
947 : : guint i;
948 : : struct StructureItem item;
949 : : GFileOutputStream *os;
950 : :
951 : 1 : g_assert_nonnull (test_data);
952 : :
953 : 1 : root = g_file_new_for_commandline_arg ((char *) test_data);
954 : 1 : g_assert_nonnull (root);
955 : 1 : res = g_file_query_exists (root, NULL);
956 : 1 : g_assert_true (res);
957 : :
958 : 29 : for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
959 : : {
960 : 28 : item = sample_struct[i];
961 : :
962 : 28 : if (((item.extra_flags & TEST_CREATE) == TEST_CREATE) ||
963 : 23 : ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE) ||
964 : 19 : ((item.extra_flags & TEST_APPEND) == TEST_APPEND))
965 : : {
966 : 13 : g_test_message (" test_create: '%s'", item.filename);
967 : :
968 : 13 : child = g_file_get_child (root, item.filename);
969 : 13 : g_assert_nonnull (child);
970 : 13 : error = NULL;
971 : 13 : os = NULL;
972 : :
973 : 13 : if ((item.extra_flags & TEST_CREATE) == TEST_CREATE)
974 : 5 : os = g_file_create (child, item.create_flags, NULL, &error);
975 : 8 : else if ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE)
976 : : os =
977 : 4 : g_file_replace (child, NULL, TRUE, item.create_flags, NULL,
978 : : &error);
979 : 4 : else if ((item.extra_flags & TEST_APPEND) == TEST_APPEND)
980 : 4 : os = g_file_append_to (child, item.create_flags, NULL, &error);
981 : :
982 : :
983 : 13 : if (error)
984 : 6 : g_test_message (" error code %d = %s", error->code, error->message);
985 : :
986 : 13 : if (((item.extra_flags & TEST_NOT_EXISTS) == 0) &&
987 : 10 : ((item.extra_flags & TEST_CREATE) == TEST_CREATE))
988 : : {
989 : 4 : g_assert_null (os);
990 : 4 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
991 : : }
992 : 9 : else if (item.file_type == G_FILE_TYPE_DIRECTORY)
993 : : {
994 : 2 : g_assert_null (os);
995 : 2 : if ((item.extra_flags & TEST_CREATE) == TEST_CREATE)
996 : 0 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
997 : : else
998 : 2 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
999 : : }
1000 : : else
1001 : : {
1002 : 7 : g_assert_nonnull (os);
1003 : 7 : g_assert_no_error (error);
1004 : : }
1005 : :
1006 : 13 : if (error)
1007 : 6 : g_error_free (error);
1008 : :
1009 : 13 : if (os)
1010 : : {
1011 : 7 : error = NULL;
1012 : : res =
1013 : 7 : g_output_stream_close (G_OUTPUT_STREAM (os), NULL, &error);
1014 : 7 : if (error)
1015 : 0 : g_test_message (" g_output_stream_close: error %d = %s",
1016 : 0 : error->code, error->message);
1017 : 7 : g_assert_true (res);
1018 : 7 : g_assert_no_error (error);
1019 : 7 : g_object_unref (os);
1020 : : }
1021 : 13 : g_object_unref (child);
1022 : : }
1023 : : }
1024 : 1 : g_object_unref (root);
1025 : 1 : }
1026 : :
1027 : : static void
1028 : 1 : test_open (gconstpointer test_data)
1029 : : {
1030 : : GFile *root, *child;
1031 : : gboolean res;
1032 : : GError *error;
1033 : : guint i;
1034 : : struct StructureItem item;
1035 : : GFileInputStream *input_stream;
1036 : :
1037 : 1 : g_assert_nonnull (test_data);
1038 : :
1039 : 1 : root = g_file_new_for_commandline_arg ((char *) test_data);
1040 : 1 : g_assert_nonnull (root);
1041 : 1 : res = g_file_query_exists (root, NULL);
1042 : 1 : g_assert_true (res);
1043 : :
1044 : 29 : for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
1045 : : {
1046 : 28 : item = sample_struct[i];
1047 : :
1048 : 28 : if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
1049 : 0 : continue;
1050 : :
1051 : 28 : if ((item.extra_flags & TEST_OPEN) == TEST_OPEN)
1052 : : {
1053 : 12 : g_test_message (" test_open: '%s'", item.filename);
1054 : :
1055 : 12 : child = g_file_get_child (root, item.filename);
1056 : 12 : g_assert_nonnull (child);
1057 : 12 : error = NULL;
1058 : 12 : input_stream = g_file_read (child, NULL, &error);
1059 : :
1060 : 12 : if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
1061 : 10 : ((item.extra_flags & TEST_INVALID_SYMLINK) ==
1062 : : TEST_INVALID_SYMLINK))
1063 : : {
1064 : 3 : g_assert_null (input_stream);
1065 : 3 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
1066 : : }
1067 : 9 : else if (item.file_type == G_FILE_TYPE_DIRECTORY)
1068 : : {
1069 : 2 : g_assert_null (input_stream);
1070 : 2 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
1071 : : }
1072 : : else
1073 : : {
1074 : 7 : g_assert_nonnull (input_stream);
1075 : 7 : g_assert_no_error (error);
1076 : : }
1077 : :
1078 : 12 : if (error)
1079 : 5 : g_error_free (error);
1080 : :
1081 : 12 : if (input_stream)
1082 : : {
1083 : 7 : error = NULL;
1084 : : res =
1085 : 7 : g_input_stream_close (G_INPUT_STREAM (input_stream), NULL,
1086 : : &error);
1087 : 7 : g_assert_true (res);
1088 : 7 : g_assert_no_error (error);
1089 : 7 : g_object_unref (input_stream);
1090 : : }
1091 : 12 : g_object_unref (child);
1092 : : }
1093 : : }
1094 : 1 : g_object_unref (root);
1095 : 1 : }
1096 : :
1097 : : static void
1098 : 1 : test_delete (gconstpointer test_data)
1099 : : {
1100 : : GFile *root;
1101 : : GFile *child;
1102 : : gboolean res;
1103 : : GError *error;
1104 : : guint i;
1105 : : struct StructureItem item;
1106 : : gchar *path;
1107 : :
1108 : 1 : g_assert_nonnull (test_data);
1109 : :
1110 : 1 : root = g_file_new_for_commandline_arg ((char *) test_data);
1111 : 1 : g_assert_nonnull (root);
1112 : 1 : res = g_file_query_exists (root, NULL);
1113 : 1 : g_assert_true (res);
1114 : :
1115 : 29 : for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
1116 : : {
1117 : 28 : item = sample_struct[i];
1118 : :
1119 : 28 : if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
1120 : 0 : continue;
1121 : :
1122 : 28 : if (((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL) ||
1123 : 21 : ((item.extra_flags & TEST_DELETE_TRASH) == TEST_DELETE_TRASH))
1124 : : {
1125 : 9 : child = file_exists (root, item.filename, &res);
1126 : 9 : g_assert_nonnull (child);
1127 : : /* we don't care about result here */
1128 : :
1129 : 9 : path = g_file_get_path (child);
1130 : 9 : g_test_message (" Deleting %s, path = %s", item.filename, path);
1131 : 9 : g_free (path);
1132 : :
1133 : 9 : error = NULL;
1134 : 9 : if ((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL)
1135 : 7 : res = g_file_delete (child, NULL, &error);
1136 : : else
1137 : 2 : res = g_file_trash (child, NULL, &error);
1138 : :
1139 : 9 : if ((item.extra_flags & TEST_DELETE_NON_EMPTY) ==
1140 : : TEST_DELETE_NON_EMPTY)
1141 : : {
1142 : 1 : g_assert_false (res);
1143 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_EMPTY);
1144 : : }
1145 : 9 : if ((item.extra_flags & TEST_DELETE_FAILURE) == TEST_DELETE_FAILURE)
1146 : : {
1147 : 1 : g_assert_false (res);
1148 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
1149 : : }
1150 : 9 : if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS)
1151 : : {
1152 : 3 : g_assert_false (res);
1153 : 3 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
1154 : : }
1155 : :
1156 : 9 : if (error)
1157 : : {
1158 : 6 : g_test_message (" result = %d, error = %s", res, error->message);
1159 : 6 : g_error_free (error);
1160 : : }
1161 : :
1162 : 9 : g_object_unref (child);
1163 : : }
1164 : : }
1165 : 1 : g_object_unref (root);
1166 : 1 : }
1167 : :
1168 : : static void
1169 : 1 : test_make_directory_with_parents (gconstpointer test_data)
1170 : : {
1171 : : GFile *root, *child, *grandchild, *greatgrandchild;
1172 : : gboolean res;
1173 : 1 : GError *error = NULL;
1174 : : #ifdef G_OS_UNIX
1175 : 1 : gboolean have_cap_dac_override = check_cap_dac_override (test_data);
1176 : : #endif
1177 : :
1178 : 1 : g_assert_nonnull (test_data);
1179 : :
1180 : 1 : root = g_file_new_for_commandline_arg ((char *) test_data);
1181 : 1 : g_assert_nonnull (root);
1182 : 1 : res = g_file_query_exists (root, NULL);
1183 : 1 : g_assert_true (res);
1184 : :
1185 : 1 : child = g_file_get_child (root, "a");
1186 : 1 : grandchild = g_file_get_child (child, "b");
1187 : 1 : greatgrandchild = g_file_get_child (grandchild, "c");
1188 : :
1189 : : /* Check that we can successfully make directory hierarchies of
1190 : : * depth 1, 2, or 3
1191 : : */
1192 : 1 : res = g_file_make_directory_with_parents (child, NULL, &error);
1193 : 1 : g_assert_true (res);
1194 : 1 : g_assert_no_error (error);
1195 : 1 : res = g_file_query_exists (child, NULL);
1196 : 1 : g_assert_true (res);
1197 : :
1198 : 1 : g_file_delete (child, NULL, NULL);
1199 : :
1200 : 1 : res = g_file_make_directory_with_parents (grandchild, NULL, &error);
1201 : 1 : g_assert_true (res);
1202 : 1 : g_assert_no_error (error);
1203 : 1 : res = g_file_query_exists (grandchild, NULL);
1204 : 1 : g_assert_true (res);
1205 : :
1206 : 1 : g_file_delete (grandchild, NULL, NULL);
1207 : 1 : g_file_delete (child, NULL, NULL);
1208 : :
1209 : 1 : res = g_file_make_directory_with_parents (greatgrandchild, NULL, &error);
1210 : 1 : g_assert_true (res);
1211 : 1 : g_assert_no_error (error);
1212 : 1 : res = g_file_query_exists (greatgrandchild, NULL);
1213 : 1 : g_assert_true (res);
1214 : :
1215 : 1 : g_file_delete (greatgrandchild, NULL, NULL);
1216 : 1 : g_file_delete (grandchild, NULL, NULL);
1217 : 1 : g_file_delete (child, NULL, NULL);
1218 : :
1219 : : /* Now test failure by trying to create a directory hierarchy
1220 : : * where a ancestor exists but is read-only
1221 : : */
1222 : :
1223 : : /* No obvious way to do this on Windows */
1224 : 1 : if (!posix_compat)
1225 : 0 : goto out;
1226 : :
1227 : : #ifdef G_OS_UNIX
1228 : : /* Permissions are ignored if we have CAP_DAC_OVERRIDE or equivalent,
1229 : : * and in particular if we're root */
1230 : 1 : if (have_cap_dac_override)
1231 : : {
1232 : 0 : g_test_skip ("Unable to exercise g_file_make_directory_with_parents "
1233 : : "failing with EACCES: we probably have "
1234 : : "CAP_DAC_OVERRIDE");
1235 : 0 : goto out;
1236 : : }
1237 : : #endif
1238 : :
1239 : 1 : g_file_make_directory (child, NULL, NULL);
1240 : 1 : g_assert_true (res);
1241 : :
1242 : 1 : res = g_file_set_attribute_uint32 (child,
1243 : : G_FILE_ATTRIBUTE_UNIX_MODE,
1244 : : S_IRUSR + S_IXUSR, /* -r-x------ */
1245 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
1246 : : NULL, NULL);
1247 : 1 : g_assert_true (res);
1248 : :
1249 : 1 : res = g_file_make_directory_with_parents (grandchild, NULL, &error);
1250 : 1 : g_assert_false (res);
1251 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
1252 : 1 : g_clear_error (&error);
1253 : :
1254 : 1 : res = g_file_make_directory_with_parents (greatgrandchild, NULL, &error);
1255 : 1 : g_assert_false (res);
1256 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
1257 : 1 : g_clear_error (&error);
1258 : :
1259 : 1 : out:
1260 : 1 : g_object_unref (greatgrandchild);
1261 : 1 : g_object_unref (grandchild);
1262 : 1 : g_object_unref (child);
1263 : 1 : g_object_unref (root);
1264 : 1 : }
1265 : :
1266 : :
1267 : : static void
1268 : 10 : cleanup_dir_recurse (GFile *parent, GFile *root)
1269 : : {
1270 : : gboolean res;
1271 : : GError *error;
1272 : : GFileEnumerator *enumerator;
1273 : : GFileInfo *info;
1274 : : GFile *descend;
1275 : : char *relative_path;
1276 : :
1277 : 10 : g_assert_nonnull (root);
1278 : :
1279 : : enumerator =
1280 : 10 : g_file_enumerate_children (parent, "*",
1281 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
1282 : : NULL);
1283 : 10 : if (! enumerator)
1284 : 1 : return;
1285 : :
1286 : 9 : error = NULL;
1287 : 9 : info = g_file_enumerator_next_file (enumerator, NULL, &error);
1288 : 42 : while ((info) && (!error))
1289 : : {
1290 : 33 : descend = g_file_enumerator_get_child (enumerator, info);
1291 : 33 : g_assert_nonnull (descend);
1292 : 33 : relative_path = g_file_get_relative_path (root, descend);
1293 : 33 : g_assert_nonnull (relative_path);
1294 : 33 : g_free (relative_path);
1295 : :
1296 : 33 : g_test_message (" deleting '%s'", g_file_info_get_display_name (info));
1297 : :
1298 : 33 : if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
1299 : 8 : cleanup_dir_recurse (descend, root);
1300 : :
1301 : 33 : error = NULL;
1302 : 33 : res = g_file_delete (descend, NULL, &error);
1303 : 33 : g_assert_true (res);
1304 : :
1305 : 33 : g_object_unref (descend);
1306 : 33 : error = NULL;
1307 : 33 : g_object_unref (info);
1308 : :
1309 : 33 : info = g_file_enumerator_next_file (enumerator, NULL, &error);
1310 : : }
1311 : 9 : g_assert_no_error (error);
1312 : :
1313 : 9 : error = NULL;
1314 : 9 : res = g_file_enumerator_close (enumerator, NULL, &error);
1315 : 9 : g_assert_true (res);
1316 : 9 : g_assert_no_error (error);
1317 : :
1318 : 9 : g_object_unref (enumerator);
1319 : : }
1320 : :
1321 : : static void
1322 : 2 : prep_clean_structure (gconstpointer test_data)
1323 : : {
1324 : : GFile *root;
1325 : :
1326 : 2 : g_assert_nonnull (test_data);
1327 : 2 : g_test_message (" Cleaning target testing structure in '%s'...",
1328 : : (char *) test_data);
1329 : :
1330 : 2 : root = g_file_new_for_commandline_arg ((char *) test_data);
1331 : 2 : g_assert_nonnull (root);
1332 : :
1333 : 2 : cleanup_dir_recurse (root, root);
1334 : :
1335 : 2 : g_file_delete (root, NULL, NULL);
1336 : :
1337 : 2 : g_object_unref (root);
1338 : 2 : }
1339 : :
1340 : : int
1341 : 1 : main (int argc, char *argv[])
1342 : : {
1343 : : static gboolean only_create_struct;
1344 : 1 : char *target_path = NULL;
1345 : : GError *error;
1346 : : GOptionContext *context;
1347 : : int retval;
1348 : :
1349 : : static GOptionEntry cmd_entries[] = {
1350 : : {"read-write", 'w', 0, G_OPTION_ARG_NONE, &write_test,
1351 : : "Perform write tests (incl. structure creation)", NULL},
1352 : : {"create-struct", 'c', 0, G_OPTION_ARG_NONE, &only_create_struct,
1353 : : "Only create testing structure (no tests)", NULL},
1354 : : {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL},
1355 : : {"posix", 'x', 0, G_OPTION_ARG_NONE, &posix_compat,
1356 : : "Test POSIX-specific features (unix permissions, symlinks)", NULL},
1357 : : G_OPTION_ENTRY_NULL
1358 : : };
1359 : :
1360 : 1 : test_suite = FALSE;
1361 : 1 : verbose = FALSE;
1362 : 1 : write_test = FALSE;
1363 : 1 : only_create_struct = FALSE;
1364 : 1 : target_path = NULL;
1365 : 1 : posix_compat = FALSE;
1366 : :
1367 : : /* strip all gtester-specific args */
1368 : 1 : g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
1369 : :
1370 : : /* no extra parameters specified, assume we're executed from glib test suite */
1371 : 1 : if (argc < 2)
1372 : : {
1373 : 1 : test_suite = TRUE;
1374 : 1 : verbose = TRUE;
1375 : 1 : write_test = TRUE;
1376 : 1 : only_create_struct = FALSE;
1377 : 1 : target_path = g_build_filename (g_get_tmp_dir (), "testdir_live-g-file", NULL);
1378 : : #ifdef G_PLATFORM_WIN32
1379 : : posix_compat = FALSE;
1380 : : #else
1381 : 1 : posix_compat = TRUE;
1382 : : #endif
1383 : : }
1384 : :
1385 : : /* add trailing args */
1386 : 1 : error = NULL;
1387 : 1 : context = g_option_context_new ("target_path");
1388 : 1 : g_option_context_add_main_entries (context, cmd_entries, NULL);
1389 : 1 : if (!g_option_context_parse (context, &argc, &argv, &error))
1390 : : {
1391 : 0 : g_printerr ("option parsing failed: %s\n", error->message);
1392 : 0 : return g_test_run ();
1393 : : }
1394 : :
1395 : : /* remaining arg should is the target path; we don't care of the extra args here */
1396 : 1 : if (argc >= 2)
1397 : 0 : target_path = g_strdup (argv[1]);
1398 : :
1399 : 1 : if (! target_path)
1400 : : {
1401 : 0 : g_printerr ("error: target path was not specified\n");
1402 : 0 : g_printerr ("%s", g_option_context_get_help (context, TRUE, NULL));
1403 : 0 : return g_test_run ();
1404 : : }
1405 : :
1406 : 1 : g_option_context_free (context);
1407 : :
1408 : : /* Write test - clean target directory first */
1409 : : /* this can be also considered as a test - enumerate + delete */
1410 : 1 : if (write_test || only_create_struct)
1411 : 1 : g_test_add_data_func ("/live-g-file/prep_clean_structure", target_path,
1412 : : prep_clean_structure);
1413 : :
1414 : : /* Write test - create new testing structure */
1415 : 1 : if (write_test || only_create_struct)
1416 : 1 : g_test_add_data_func ("/live-g-file/create_structure", target_path,
1417 : : test_create_structure);
1418 : :
1419 : : /* Read test - test the sample structure - expect defined attributes to be there */
1420 : 1 : if (!only_create_struct)
1421 : 1 : g_test_add_data_func ("/live-g-file/test_initial_structure", target_path,
1422 : : test_initial_structure);
1423 : :
1424 : : /* Read test - test traverse the structure - no special file should appear */
1425 : 1 : if (!only_create_struct)
1426 : 1 : g_test_add_data_func ("/live-g-file/test_traverse_structure", target_path,
1427 : : test_traverse_structure);
1428 : :
1429 : : /* Read test - enumerate */
1430 : 1 : if (!only_create_struct)
1431 : 1 : g_test_add_data_func ("/live-g-file/test_enumerate", target_path,
1432 : : test_enumerate);
1433 : :
1434 : : /* Read test - open (g_file_read()) */
1435 : 1 : if (!only_create_struct)
1436 : 1 : g_test_add_data_func ("/live-g-file/test_open", target_path, test_open);
1437 : :
1438 : 1 : if (posix_compat)
1439 : : {
1440 : 1 : g_test_add_data_func ("/live-g-file/test_unix_is_mountpoint/sysroot",
1441 : : "/",
1442 : : test_unix_is_mountpoint);
1443 : : #ifdef __linux__
1444 : 1 : g_test_add_data_func ("/live-g-file/test_unix_is_mountpoint/proc",
1445 : : "/proc",
1446 : : test_unix_is_mountpoint);
1447 : : #endif
1448 : : }
1449 : :
1450 : : /* Write test - create */
1451 : 1 : if (write_test && (!only_create_struct))
1452 : 1 : g_test_add_data_func ("/live-g-file/test_create", target_path,
1453 : : test_create);
1454 : :
1455 : : /* Write test - copy, move */
1456 : 1 : if (write_test && (!only_create_struct))
1457 : 1 : g_test_add_data_func ("/live-g-file/test_copy_move", target_path,
1458 : : test_copy_move);
1459 : :
1460 : : /* Write test - delete, trash */
1461 : 1 : if (write_test && (!only_create_struct))
1462 : 1 : g_test_add_data_func ("/live-g-file/test_delete", target_path,
1463 : : test_delete);
1464 : :
1465 : : /* Write test - make_directory_with_parents */
1466 : 1 : if (write_test && (!only_create_struct))
1467 : 1 : g_test_add_data_func ("/live-g-file/test_make_directory_with_parents", target_path,
1468 : : test_make_directory_with_parents);
1469 : :
1470 : 1 : if (write_test || only_create_struct)
1471 : 1 : g_test_add_data_func ("/live-g-file/final_clean", target_path,
1472 : : prep_clean_structure);
1473 : :
1474 : 1 : retval = g_test_run ();
1475 : :
1476 : 1 : g_free (target_path);
1477 : :
1478 : 1 : return retval;
1479 : : }
|