• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
38 enum 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 
62 struct 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 
80 static 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 
114 static gboolean test_suite;
115 static gboolean write_test;
116 static gboolean verbose;
117 static 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  */
142 static gboolean
check_cap_dac_override(const char * tmpdir)143 check_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 (tmpdir, "dac-denies-write", NULL);
150   inside = g_build_filename (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 (inside, S_IRWXU) == 0)
156     {
157       g_test_message ("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 ("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 (dac_denies_write);
173   g_free (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 */
log(const g_char * format,...)183 static 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 
192 static GFile *
create_empty_file(GFile * parent,const char * filename,GFileCreateFlags create_flags)193 create_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 (parent, filename);
201   g_assert_nonnull (child);
202 
203   error = NULL;
204   outs = g_file_replace (child, NULL, FALSE, create_flags, NULL, &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);
209   g_object_unref (outs);
210   return child;
211 }
212 
213 static GFile *
create_empty_dir(GFile * parent,const char * filename)214 create_empty_dir (GFile * parent, const char *filename)
215 {
216   GFile *child;
217   gboolean res;
218   GError *error;
219 
220   child = g_file_get_child (parent, filename);
221   g_assert_nonnull (child);
222   error = NULL;
223   res = g_file_make_directory (child, NULL, &error);
224   g_assert_true (res);
225   g_assert_no_error (error);
226   return child;
227 }
228 
229 static GFile *
create_symlink(GFile * parent,const char * filename,const char * points_to)230 create_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 (parent, filename);
237   g_assert_nonnull (child);
238   error = NULL;
239   res = g_file_make_symbolic_link (child, points_to, NULL, &error);
240   g_assert_true (res);
241   g_assert_no_error (error);
242   return child;
243 }
244 
245 static void
test_create_structure(gconstpointer test_data)246 test_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 ((char *) test_data);
262   g_assert_nonnull (root);
263 
264   /*  create root directory  */
265   g_file_make_directory (root, NULL, &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 (root, item.filename, item.create_flags);
283 	  break;
284 	case G_FILE_TYPE_DIRECTORY:
285 	  log ("    Creating directory '%s'...\n", item.filename);
286 	  child = create_empty_dir (root, 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 (root, item.filename, 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 (child, G_FILE_ATTRIBUTE_UNIX_MODE,
306 					 item.mode,
307 					 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
308 					 NULL, &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 (item.filename);
319 	  basename = g_path_get_basename (item.filename);
320 	  path = g_build_filename (test_data, dir, ".hidden", NULL);
321 
322 	  f = fopen (path, "a");
323 	  fprintf (f, "%s\n", basename);
324 	  fclose (f);
325 
326 	  g_free (dir);
327 	  g_free (path);
328 	  g_free (basename);
329 	}
330 
331       g_object_unref (child);
332     }
333 
334   /*  create a pattern file  */
335   log ("    Creating pattern file...");
336   child = g_file_get_child (root, "pattern_file");
337   g_assert_nonnull (child);
338 
339   outs =
340     g_file_replace (child, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &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 (outds, i % 256, NULL, &error);
349       g_assert_no_error (error);
350     }
351 
352   g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
353   g_assert_no_error (error);
354   g_object_unref (outds);
355   g_object_unref (outs);
356   g_object_unref (child);
357   log (" done.\n");
358 
359   g_object_unref (root);
360 }
361 
362 static GFile *
file_exists(GFile * parent,const char * filename,gboolean * result)363 file_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 (parent, filename);
372   g_assert_nonnull (child);
373   res = g_file_query_exists (child, NULL);
374   if (result)
375     *result = res;
376 
377   return child;
378 }
379 
380 static void
test_attributes(struct StructureItem item,GFileInfo * info)381 test_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 (display_name, -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 (edit_name, -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 (copy_name, -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 
488 static void
test_initial_structure(gconstpointer test_data)489 test_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 ((char *) test_data);
507   g_assert_nonnull (root);
508   res = g_file_query_exists (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 (root, item.filename, &res);
522       g_assert_nonnull (child);
523       g_assert_true (res);
524 
525       error = NULL;
526       info =
527 	g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
528 			   NULL, &error);
529       g_assert_no_error (error);
530       g_assert_nonnull (info);
531 
532       test_attributes (item, info);
533 
534       g_object_unref (child);
535       g_object_unref (info);
536     }
537 
538   /*  read and test the pattern file  */
539   log ("    Testing pattern file...\n");
540   child = file_exists (root, "pattern_file", &res);
541   g_assert_nonnull (child);
542   g_assert_true (res);
543 
544   error = NULL;
545   info =
546     g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
547 		       &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 (info);
553 
554   error = NULL;
555   ins = g_file_read (child, NULL, &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 + total_read,
567 			     PATTERN_FILE_SIZE, NULL, &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);
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 (ins);
584   g_object_unref (child);
585   g_free (buffer);
586   g_object_unref (root);
587 }
588 
589 static void
traverse_recurse_dirs(GFile * parent,GFile * root)590 traverse_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 (parent, "*",
606 			       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
607 			       &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);
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 (root, 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 (sample_struct[i].filename, relative_path) == 0)
626 	    {
627 	      /*  test the attributes again  */
628 	      test_attributes (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 (descend, root);
641 
642       g_object_unref (descend);
643       error = NULL;
644       g_object_unref (info);
645       g_free (relative_path);
646 
647       info = g_file_enumerator_next_file (enumerator, NULL, &error);
648     }
649   g_assert_no_error (error);
650 
651   error = NULL;
652   res = g_file_enumerator_close (enumerator, NULL, &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 (enumerator);
658 }
659 
660 static void
test_traverse_structure(gconstpointer test_data)661 test_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 ((char *) test_data);
671   g_assert_nonnull (root);
672   res = g_file_query_exists (root, NULL);
673   g_assert_true (res);
674 
675   traverse_recurse_dirs (root, root);
676 
677   g_object_unref (root);
678 }
679 
680 
681 
682 
683 static void
test_enumerate(gconstpointer test_data)684 test_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 ((char *) test_data);
699   g_assert_nonnull (root);
700   res = g_file_query_exists (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 (root, item.filename);
718 	  g_assert_nonnull (child);
719 	  error = NULL;
720 	  enumerator =
721 	    g_file_enumerate_children (child, "*",
722 				       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
723 				       NULL, &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);
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);
753 	      g_assert_true (res);
754 	      g_assert_no_error (error);
755 
756               g_object_unref (enumerator);
757 	    }
758 	  g_object_unref (child);
759 	}
760     }
761   g_object_unref (root);
762 }
763 
764 static void
do_copy_move(GFile * root,struct StructureItem item,const char * target_dir,enum StructureExtraFlags extra_flags)765 do_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 (g_file_peek_path (root));
773 #endif
774 
775   log ("    do_copy_move: '%s' --> '%s'\n", item.filename, target_dir);
776 
777   dst_dir = g_file_get_child (root, target_dir);
778   g_assert_nonnull (dst_dir);
779   src_file = g_file_get_child (root, item.filename);
780   g_assert_nonnull (src_file);
781   dst_file = g_file_get_child (dst_dir, 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 (src_file, dst_file,
788 		   G_FILE_COPY_NOFOLLOW_SYMLINKS |
789 		   ((extra_flags ==
790 		     TEST_OVERWRITE) ? G_FILE_COPY_OVERWRITE :
791 		    G_FILE_COPY_NONE), NULL, NULL, NULL, &error);
792   else
793     res =
794       g_file_move (src_file, dst_file, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL,
795 		   NULL, NULL, &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 ("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 (dst_dir);
862   g_object_unref (src_file);
863   g_object_unref (dst_file);
864 }
865 
866 static void
test_copy_move(gconstpointer test_data)867 test_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 ((char *) test_data);
878   g_assert_nonnull (root);
879   res = g_file_query_exists (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, 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, TEST_OVERWRITE);
903 		}
904 	      /*  source = target, should return G_IO_ERROR_EXISTS  */
905 	      do_copy_move (root, item, ".", TEST_ALREADY_EXISTS);
906 	      /*  target is file  */
907 	      do_copy_move (root, item, TEST_TARGET_FILE,
908 			    TEST_TARGET_IS_FILE);
909 	      /*  target path is invalid  */
910 	      do_copy_move (root, item, TEST_NAME_NOT_EXISTS,
911 			    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 				TEST_NO_ACCESS);
919 		  /*  target directory is readonly  */
920 		  do_copy_move (root, item, TEST_DIR_NO_WRITE,
921 				TEST_NO_ACCESS);
922 		}
923 	    }
924 	}
925     }
926   g_object_unref (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  */
933 static void
test_unix_is_mountpoint(gconstpointer data)934 test_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                             G_FILE_QUERY_INFO_NONE, NULL, &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 
956 static void
test_create(gconstpointer test_data)957 test_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 ((char *) test_data);
970   g_assert_nonnull (root);
971   res = g_file_query_exists (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 (root, 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 (child, item.create_flags, NULL, &error);
991 	  else if ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE)
992 	    os =
993 	      g_file_replace (child, NULL, TRUE, item.create_flags, NULL,
994 			      &error);
995 	  else if ((item.extra_flags & TEST_APPEND) == TEST_APPEND)
996 	    os = g_file_append_to (child, item.create_flags, NULL, &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);
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 (os);
1036 	    }
1037 	  g_object_unref (child);
1038 	}
1039     }
1040   g_object_unref (root);
1041 }
1042 
1043 static void
test_open(gconstpointer test_data)1044 test_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 ((char *) test_data);
1057   g_assert_nonnull (root);
1058   res = g_file_query_exists (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 (root, item.filename);
1073 	  g_assert_nonnull (child);
1074 	  error = NULL;
1075 	  input_stream = g_file_read (child, NULL, &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);
1104 	      g_assert_true (res);
1105 	      g_assert_no_error (error);
1106               g_object_unref (input_stream);
1107 	    }
1108 	  g_object_unref (child);
1109 	}
1110     }
1111   g_object_unref (root);
1112 }
1113 
1114 static void
test_delete(gconstpointer test_data)1115 test_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 ((char *) test_data);
1129   g_assert_nonnull (root);
1130   res = g_file_query_exists (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 (root, item.filename, &res);
1144 	  g_assert_nonnull (child);
1145 	  /*  we don't care about result here  */
1146 
1147           path = g_file_get_path (child);
1148 	  log ("  Deleting %s, path = %s\n", item.filename, path);
1149           g_free (path);
1150 
1151 	  error = NULL;
1152 	  if ((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL)
1153 	    res = g_file_delete (child, NULL, &error);
1154 	  else
1155 	    res = g_file_trash (child, NULL, &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 (child);
1181 	}
1182     }
1183   g_object_unref (root);
1184 }
1185 
1186 static void
test_make_directory_with_parents(gconstpointer test_data)1187 test_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 (test_data);
1194 #endif
1195 
1196   g_assert_nonnull (test_data);
1197 
1198   root = g_file_new_for_commandline_arg ((char *) test_data);
1199   g_assert_nonnull (root);
1200   res = g_file_query_exists (root, NULL);
1201   g_assert_true (res);
1202 
1203   child = g_file_get_child (root, "a");
1204   grandchild = g_file_get_child (child, "b");
1205   greatgrandchild = g_file_get_child (grandchild, "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 (child, NULL, &error);
1211   g_assert_true (res);
1212   g_assert_no_error (error);
1213   res = g_file_query_exists (child, NULL);
1214   g_assert_true (res);
1215 
1216   g_file_delete (child, NULL, NULL);
1217 
1218   res = g_file_make_directory_with_parents (grandchild, NULL, &error);
1219   g_assert_true (res);
1220   g_assert_no_error (error);
1221   res = g_file_query_exists (grandchild, NULL);
1222   g_assert_true (res);
1223 
1224   g_file_delete (grandchild, NULL, NULL);
1225   g_file_delete (child, NULL, NULL);
1226 
1227   res = g_file_make_directory_with_parents (greatgrandchild, NULL, &error);
1228   g_assert_true (res);
1229   g_assert_no_error (error);
1230   res = g_file_query_exists (greatgrandchild, NULL);
1231   g_assert_true (res);
1232 
1233   g_file_delete (greatgrandchild, NULL, NULL);
1234   g_file_delete (grandchild, NULL, NULL);
1235   g_file_delete (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 ("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 (child, NULL, NULL);
1258   g_assert_true (res);
1259 
1260   res = g_file_set_attribute_uint32 (child,
1261                                      G_FILE_ATTRIBUTE_UNIX_MODE,
1262                                      S_IRUSR + S_IXUSR, /* -r-x------ */
1263                                      G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
1264                                      NULL, NULL);
1265   g_assert_true (res);
1266 
1267   res = g_file_make_directory_with_parents (grandchild, NULL, &error);
1268   g_assert_false (res);
1269   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
1270   g_clear_error (&error);
1271 
1272   res = g_file_make_directory_with_parents (greatgrandchild, NULL, &error);
1273   g_assert_false (res);
1274   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
1275   g_clear_error (&error);
1276 
1277 out:
1278   g_object_unref (greatgrandchild);
1279   g_object_unref (grandchild);
1280   g_object_unref (child);
1281   g_object_unref (root);
1282 }
1283 
1284 
1285 static void
cleanup_dir_recurse(GFile * parent,GFile * root)1286 cleanup_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 (parent, "*",
1299 			       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);
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 (root, descend);
1311       g_assert_nonnull (relative_path);
1312       g_free (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 (descend, root);
1318 
1319       error = NULL;
1320       res = g_file_delete (descend, NULL, &error);
1321       g_assert_true (res);
1322 
1323       g_object_unref (descend);
1324       error = NULL;
1325       g_object_unref (info);
1326 
1327       info = g_file_enumerator_next_file (enumerator, NULL, &error);
1328     }
1329   g_assert_no_error (error);
1330 
1331   error = NULL;
1332   res = g_file_enumerator_close (enumerator, NULL, &error);
1333   g_assert_true (res);
1334   g_assert_no_error (error);
1335 
1336   g_object_unref (enumerator);
1337 }
1338 
1339 static void
prep_clean_structure(gconstpointer test_data)1340 prep_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 ((char *) test_data);
1349   g_assert_nonnull (root);
1350 
1351   cleanup_dir_recurse (root, root);
1352 
1353   g_file_delete (root, NULL, NULL);
1354 
1355   g_object_unref (root);
1356 }
1357 
1358 int
main(int argc,char * argv[])1359 main (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, &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 ("target_path");
1405   g_option_context_add_main_entries (context, cmd_entries, NULL);
1406   if (!g_option_context_parse (context, &argc, &argv, &error))
1407     {
1408       g_printerr ("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 (argv[1]);
1415 
1416   if (! target_path)
1417     {
1418       g_printerr ("error: target path was not specified\n");
1419       g_printerr ("%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 ("/live-g-file/prep_clean_structure", target_path,
1429     	  	  prep_clean_structure);
1430 
1431   /*  Write test - create new testing structure  */
1432   if (write_test || only_create_struct)
1433     g_test_add_data_func ("/live-g-file/create_structure", target_path,
1434 			  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 ("/live-g-file/test_initial_structure", target_path,
1439 			  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 ("/live-g-file/test_traverse_structure", target_path,
1444 			  test_traverse_structure);
1445 
1446   /*  Read test - enumerate  */
1447   if (!only_create_struct)
1448     g_test_add_data_func ("/live-g-file/test_enumerate", target_path,
1449 			  test_enumerate);
1450 
1451   /*  Read test - open (g_file_read())  */
1452   if (!only_create_struct)
1453     g_test_add_data_func ("/live-g-file/test_open", target_path, test_open);
1454 
1455   if (posix_compat)
1456     {
1457       g_test_add_data_func ("/live-g-file/test_unix_is_mountpoint/sysroot",
1458                             "/",
1459                             test_unix_is_mountpoint);
1460 #ifdef __linux__
1461       g_test_add_data_func ("/live-g-file/test_unix_is_mountpoint/proc",
1462                             "/proc",
1463                             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 ("/live-g-file/test_create", target_path,
1470 			  test_create);
1471 
1472   /*  Write test - copy, move  */
1473   if (write_test && (!only_create_struct))
1474     g_test_add_data_func ("/live-g-file/test_copy_move", target_path,
1475 			  test_copy_move);
1476 
1477   /*  Write test - delete, trash  */
1478   if (write_test && (!only_create_struct))
1479     g_test_add_data_func ("/live-g-file/test_delete", target_path,
1480 			  test_delete);
1481 
1482   /*  Write test - make_directory_with_parents */
1483   if (write_test && (!only_create_struct))
1484     g_test_add_data_func ("/live-g-file/test_make_directory_with_parents", target_path,
1485 			  test_make_directory_with_parents);
1486 
1487   if (write_test || only_create_struct)
1488     g_test_add_data_func ("/live-g-file/final_clean", target_path,
1489     	  	  prep_clean_structure);
1490 
1491   return g_test_run ();
1492 
1493 }
1494