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

source code of gtk/subprojects/glib/gio/tests/live-g-file.c