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