08e4d12443e38ac52a8e1ec8dcb5d5ea038e2547
[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  * 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 <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28
29 #define DEFAULT_TEST_DIR                "testdir_live-g-file"
30
31 #define PATTERN_FILE_SIZE       0x10000
32 #define TEST_HANDLE_SPECIAL     TRUE
33
34 enum StructureExtraFlags
35 {
36   TEST_DELETE_NORMAL = 1 << 0,
37   TEST_DELETE_TRASH = 1 << 1,
38   TEST_DELETE_NON_EMPTY = 1 << 2,
39   TEST_DELETE_FAILURE = 1 << 3,
40   TEST_NOT_EXISTS = 1 << 4,
41   TEST_ENUMERATE_FILE = 1 << 5,
42   TEST_NO_ACCESS = 1 << 6,
43   TEST_COPY = 1 << 7,
44   TEST_MOVE = 1 << 8,
45   TEST_COPY_ERROR_RECURSE = 1 << 9,
46   TEST_ALREADY_EXISTS = 1 << 10,
47   TEST_TARGET_IS_FILE = 1 << 11,
48   TEST_CREATE = 1 << 12,
49   TEST_REPLACE = 1 << 13,
50   TEST_APPEND = 1 << 14,
51   TEST_OPEN = 1 << 15,
52   TEST_OVERWRITE = 1 << 16,
53   TEST_INVALID_SYMLINK = 1 << 17,
54 };
55
56 struct StructureItem
57 {
58   const char *filename;
59   const char *link_to;
60   GFileType file_type;
61   GFileCreateFlags create_flags;
62   guint32 mode;
63   gboolean handle_special;
64   enum StructureExtraFlags extra_flags;
65 };
66
67 #define TEST_DIR_NO_ACCESS              "dir_no-access"
68 #define TEST_DIR_NO_WRITE               "dir_no-write"
69 #define TEST_DIR_TARGET                 "dir-target"
70 #define TEST_NAME_NOT_EXISTS    "not_exists"
71 #define TEST_TARGET_FILE                "target-file"
72
73
74 static const struct StructureItem sample_struct[] = {
75 /*       filename                               link    file_type                               create_flags            mode | handle_special | extra_flags              */
76     {"dir1",                            NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_DELETE_NON_EMPTY | TEST_REPLACE | TEST_OPEN},
77     {"dir1/subdir",                     NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_COPY     | TEST_COPY_ERROR_RECURSE | TEST_APPEND},
78     {"dir2",                            NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_MOVE | TEST_CREATE},
79     {TEST_DIR_TARGET,           NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_COPY_ERROR_RECURSE},
80     {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},
81     {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},
82     {TEST_TARGET_FILE,          NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OPEN},
83         {"normal_file",                 NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_ENUMERATE_FILE | TEST_CREATE | TEST_OVERWRITE},
84         {"normal_file-symlink", "normal_file",  G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_ENUMERATE_FILE | TEST_COPY | TEST_OPEN},
85     {"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},
86     {"private_file",            NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_PRIVATE, 0, 0, TEST_COPY | TEST_OPEN | TEST_OVERWRITE | TEST_APPEND},
87     {"normal_file2",            NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OVERWRITE | TEST_REPLACE},
88     {"readonly_file",           NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, S_IRUSR + S_IRGRP + S_IROTH, 0, TEST_DELETE_NORMAL | TEST_OPEN},
89     {"UTF_pr\xcc\x8ci\xcc\x81lis\xcc\x8c z",
90                                                 NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_CREATE | TEST_OPEN | TEST_OVERWRITE},
91     {"dir_pr\xcc\x8ci\xcc\x81lis\xcc\x8c z",
92                                                 NULL,   G_FILE_TYPE_DIRECTORY,  G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_CREATE},
93     {"pattern_file",            NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_COPY | TEST_OPEN | TEST_APPEND},
94     {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},
95     {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},
96     {"not_exists2",                     NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_CREATE},
97     {"not_exists3",                     NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_REPLACE},
98     {"not_exists4",                     NULL,   G_FILE_TYPE_REGULAR,    G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_APPEND},
99     {"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},
100         {"lost_symlink",                "nowhere",      G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_DELETE_NORMAL | TEST_OPEN | TEST_INVALID_SYMLINK},
101   };
102
103 static gboolean write_test;
104 static gboolean verbose;
105 static gboolean posix_compat;
106
107 #define log(msg...) if (verbose)  g_print (msg)
108
109 static GFile *
110 create_empty_file (GFile * parent, const char *filename,
111                    GFileCreateFlags create_flags)
112 {
113   GFile *child;
114   gboolean res;
115   GError *error;
116   GFileOutputStream *outs;
117
118   child = g_file_get_child (parent, filename);
119   g_assert (child != NULL);
120
121   error = NULL;
122   outs = g_file_replace (child, NULL, FALSE, create_flags, NULL, &error);
123   g_assert_no_error (error);
124   g_assert (outs != NULL);
125   error = NULL;
126   res = g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
127   g_object_unref (outs);
128   return child;
129 }
130
131 static GFile *
132 create_empty_dir (GFile * parent, const char *filename)
133 {
134   GFile *child;
135   gboolean res;
136   GError *error;
137
138   child = g_file_get_child (parent, filename);
139   g_assert (child != NULL);
140   error = NULL;
141   res = g_file_make_directory (child, NULL, &error);
142   g_assert_cmpint (res, ==, TRUE);
143   g_assert_no_error (error);
144   return child;
145 }
146
147 static GFile *
148 create_symlink (GFile * parent, const char *filename, const char *points_to)
149 {
150   GFile *child;
151   gboolean res;
152   GError *error;
153
154   child = g_file_get_child (parent, filename);
155   g_assert (child != NULL);
156   error = NULL;
157   res = g_file_make_symbolic_link (child, points_to, NULL, &error);
158   g_assert_cmpint (res, ==, TRUE);
159   g_assert_no_error (error);
160   return child;
161 }
162
163 static void
164 test_create_structure (gconstpointer test_data)
165 {
166   GFile *root;
167   GFile *child;
168   gboolean res;
169   GError *error;
170   GFileOutputStream *outs;
171   GDataOutputStream *outds;
172   int i;
173   struct StructureItem item;
174
175   g_assert (test_data != NULL);
176   log ("\n  Going to create testing structure in '%s'...\n",
177        (char *) test_data);
178
179   root = g_file_new_for_commandline_arg ((char *) test_data);
180   g_assert (root != NULL);
181
182   /*  create root directory  */
183   res = g_file_make_directory (root, NULL, NULL);
184   /*  don't care about errors here  */
185
186   /*  create any other items  */
187   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
188     {
189       item = sample_struct[i];
190       if ((item.handle_special)
191           || ((!posix_compat)
192               && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK)))
193         continue;
194
195       child = NULL;
196       switch (item.file_type)
197         {
198         case G_FILE_TYPE_REGULAR:
199           log ("    Creating file '%s'...\n", item.filename);
200           child = create_empty_file (root, item.filename, item.create_flags);
201           break;
202         case G_FILE_TYPE_DIRECTORY:
203           log ("    Creating directory '%s'...\n", item.filename);
204           child = create_empty_dir (root, item.filename);
205           break;
206         case G_FILE_TYPE_SYMBOLIC_LINK:
207           log ("    Creating symlink '%s' --> '%s'...\n", item.filename,
208                item.link_to);
209           child = create_symlink (root, item.filename, item.link_to);
210           break;
211         default:
212           break;
213         }
214       g_assert (child != NULL);
215
216       if ((item.mode > 0) && (posix_compat))
217         {
218           error = NULL;
219           res =
220             g_file_set_attribute_uint32 (child, G_FILE_ATTRIBUTE_UNIX_MODE,
221                                          item.mode,
222                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
223                                          NULL, &error);
224           g_assert_cmpint (res, ==, TRUE);
225           g_assert_no_error (error);
226         }
227
228       g_object_unref (child);
229     }
230
231   /*  create a pattern file  */
232   log ("    Creating pattern file...");
233   child = g_file_get_child (root, "pattern_file");
234   g_assert (child != NULL);
235
236   error = NULL;
237   outs =
238     g_file_replace (child, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error);
239   g_assert_no_error (error);
240
241   g_assert (outs != NULL);
242   outds = g_data_output_stream_new (G_OUTPUT_STREAM (outs));
243   g_assert (outds != NULL);
244   for (i = 0; i < PATTERN_FILE_SIZE; i++)
245     {
246       error = NULL;
247       res = g_data_output_stream_put_byte (outds, i % 256, NULL, &error);
248       g_assert_no_error (error);
249     }
250   error = NULL;
251   res = g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error);
252   g_assert_no_error (error);
253   g_object_unref (outds);
254   g_object_unref (outs);
255   g_object_unref (child);
256   log (" done.\n");
257
258   g_object_unref (root);
259 }
260
261 static GFile *
262 file_exists (GFile * parent, const char *filename, gboolean * result)
263 {
264   GFile *child;
265   gboolean res;
266
267   if (result)
268     *result = FALSE;
269
270   child = g_file_get_child (parent, filename);
271   g_assert (child != NULL);
272   res = g_file_query_exists (child, NULL);
273   if (result)
274     *result = res;
275
276   return child;
277 }
278
279 static void
280 test_attributes (struct StructureItem item, GFileInfo * info)
281 {
282   GFileType ftype;
283   guint32 mode;
284   const char *name, *display_name, *edit_name, *copy_name, *symlink_target;
285   gboolean utf8_valid;
286   gboolean has_attr;
287   gboolean is_symlink;
288   gboolean can_read, can_write;
289
290   /*  standard::type  */
291   has_attr = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
292   g_assert_cmpint (has_attr, ==, TRUE);
293   ftype = g_file_info_get_file_type (info);
294   g_assert_cmpint (ftype, !=, G_FILE_TYPE_UNKNOWN);
295   g_assert_cmpint (ftype, ==, item.file_type);
296
297   /*  unix::mode  */
298   if ((item.mode > 0) && (posix_compat))
299     {
300       mode =
301         g_file_info_get_attribute_uint32 (info,
302                                           G_FILE_ATTRIBUTE_UNIX_MODE) & 0xFFF;
303       g_assert_cmpint (mode, ==, item.mode);
304     }
305
306   /*  access::can-read  */
307   if (item.file_type != G_FILE_TYPE_SYMBOLIC_LINK)
308     {
309       can_read =
310         g_file_info_get_attribute_boolean (info,
311                                            G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
312       g_assert_cmpint (can_read, ==, TRUE);
313     }
314
315   /*  access::can-write  */
316   if ((write_test) && ((item.extra_flags & TEST_OVERWRITE) == TEST_OVERWRITE))
317     {
318       can_write =
319         g_file_info_get_attribute_boolean (info,
320                                            G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
321       g_assert_cmpint (can_write, ==, TRUE);
322     }
323
324   /*  standard::name  */
325   name = g_file_info_get_name (info);
326   g_assert (name != NULL);
327
328   /*  standard::display-name  */
329   display_name = g_file_info_get_display_name (info);
330   g_assert (display_name != NULL);
331   utf8_valid = g_utf8_validate (display_name, -1, NULL);
332   g_assert_cmpint (utf8_valid, ==, TRUE);
333
334   /*  standard::edit-name  */
335   edit_name = g_file_info_get_edit_name (info);
336   if (edit_name)
337     {
338       utf8_valid = g_utf8_validate (edit_name, -1, NULL);
339       g_assert_cmpint (utf8_valid, ==, TRUE);
340     }
341
342   /*  standard::copy-name  */
343   copy_name =
344     g_file_info_get_attribute_string (info,
345                                       G_FILE_ATTRIBUTE_STANDARD_COPY_NAME);
346   if (copy_name)
347     {
348       utf8_valid = g_utf8_validate (copy_name, -1, NULL);
349       g_assert_cmpint (utf8_valid, ==, TRUE);
350     }
351
352   /*  standard::is-symlink  */
353   if (posix_compat)
354     {
355       is_symlink = g_file_info_get_is_symlink (info);
356       g_assert_cmpint (is_symlink, ==,
357                        item.file_type == G_FILE_TYPE_SYMBOLIC_LINK);
358     }
359
360   /*  standard::symlink-target  */
361   if ((item.file_type == G_FILE_TYPE_SYMBOLIC_LINK) && (posix_compat))
362     {
363       symlink_target = g_file_info_get_symlink_target (info);
364       g_assert_cmpstr (symlink_target, ==, item.link_to);
365     }
366 }
367
368 static void
369 test_initial_structure (gconstpointer test_data)
370 {
371   GFile *root;
372   GFile *child;
373   gboolean res;
374   GError *error;
375   GFileInputStream *ins;
376   int i;
377   GFileInfo *info;
378   guint32 size;
379   guchar *buffer;
380   gssize read, total_read;
381   struct StructureItem item;
382
383
384   g_assert (test_data != NULL);
385   log ("\n  Testing sample structure in '%s'...\n", (char *) test_data);
386
387   root = g_file_new_for_commandline_arg ((char *) test_data);
388   g_assert (root != NULL);
389   res = g_file_query_exists (root, NULL);
390   g_assert_cmpint (res, ==, TRUE);
391
392   /*  test the structure  */
393   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
394     {
395       item = sample_struct[i];
396       if (((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
397           || (item.handle_special))
398         continue;
399
400       log ("    Testing file '%s'...\n", item.filename);
401
402       child = file_exists (root, item.filename, &res);
403       g_assert (child != NULL);
404       g_assert_cmpint (res, ==, TRUE);
405
406       error = NULL;
407       info =
408         g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
409                            NULL, &error);
410       g_assert_no_error (error);
411       g_assert (info != NULL);
412
413       test_attributes (item, info);
414
415       g_object_unref (child);
416     }
417
418   /*  read and test the pattern file  */
419   log ("    Testing pattern file...\n");
420   child = file_exists (root, "pattern_file", &res);
421   g_assert (child != NULL);
422   g_assert_cmpint (res, ==, TRUE);
423
424   error = NULL;
425   info =
426     g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
427                        &error);
428   g_assert_no_error (error);
429   g_assert (info != NULL);
430   size = g_file_info_get_size (info);
431   g_assert_cmpint (size, ==, PATTERN_FILE_SIZE);
432
433   error = NULL;
434   ins = g_file_read (child, NULL, &error);
435   g_assert (ins != NULL);
436   g_assert_no_error (error);
437
438   buffer = g_malloc (PATTERN_FILE_SIZE);
439   total_read = 0;
440
441   while (total_read < PATTERN_FILE_SIZE)
442     {
443       error = NULL;
444       read =
445         g_input_stream_read (G_INPUT_STREAM (ins), buffer + total_read,
446                              PATTERN_FILE_SIZE, NULL, &error);
447       g_assert_no_error (error);
448       total_read += read;
449       log ("      read %d bytes, total = %d of %d.\n", read, total_read,
450            PATTERN_FILE_SIZE);
451     }
452   g_assert_cmpint (total_read, ==, PATTERN_FILE_SIZE);
453
454   error = NULL;
455   res = g_input_stream_close (G_INPUT_STREAM (ins), NULL, &error);
456   g_assert_no_error (error);
457   g_assert_cmpint (res, ==, TRUE);
458
459   for (i = 0; i < PATTERN_FILE_SIZE; i++)
460     g_assert_cmpint (*(buffer + i), ==, i % 256);
461
462   g_object_unref (ins);
463   g_object_unref (child);
464   g_free (buffer);
465   g_object_unref (root);
466 }
467
468 static void
469 traverse_recurse_dirs (GFile * parent, GFile * root)
470 {
471   gboolean res;
472   GError *error;
473   GFileEnumerator *enumerator;
474   GFileInfo *info;
475   GFile *descend;
476   char *relative_path;
477   int i;
478   gboolean found;
479
480   g_assert (root != NULL);
481
482   error = NULL;
483   enumerator =
484     g_file_enumerate_children (parent, "*",
485                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
486                                &error);
487   g_assert (enumerator != NULL);
488   g_assert_no_error (error);
489
490   error = NULL;
491   info = g_file_enumerator_next_file (enumerator, NULL, &error);
492   while ((info) && (!error))
493     {
494       descend = g_file_get_child (parent, g_file_info_get_name (info));
495       g_assert (descend != NULL);
496       relative_path = g_file_get_relative_path (root, descend);
497       g_assert (relative_path != NULL);
498
499       found = FALSE;
500       for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
501         {
502           if (strcmp (sample_struct[i].filename, relative_path) == 0)
503             {
504               /*  test the attributes again  */
505               test_attributes (sample_struct[i], info);
506
507               found = TRUE;
508               break;
509             }
510         }
511       g_assert_cmpint (found, ==, TRUE);
512
513       log ("  Found file %s, relative to root: %s\n",
514            g_file_info_get_display_name (info), relative_path);
515
516       if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
517         traverse_recurse_dirs (descend, root);
518
519       g_object_unref (descend);
520       error = NULL;
521       info = g_file_enumerator_next_file (enumerator, NULL, &error);
522     }
523   g_assert_no_error (error);
524
525   error = NULL;
526   res = g_file_enumerator_close (enumerator, NULL, &error);
527   g_assert_cmpint (res, ==, TRUE);
528   g_assert_no_error (error);
529 }
530
531 static void
532 test_traverse_structure (gconstpointer test_data)
533 {
534   GFile *root;
535   gboolean res;
536
537   g_assert (test_data != NULL);
538   log ("\n  Traversing through the sample structure in '%s'...\n",
539        (char *) test_data);
540
541   root = g_file_new_for_commandline_arg ((char *) test_data);
542   g_assert (root != NULL);
543   res = g_file_query_exists (root, NULL);
544   g_assert_cmpint (res, ==, TRUE);
545
546   traverse_recurse_dirs (root, root);
547
548   g_object_unref (root);
549 }
550
551
552
553
554 static void
555 test_enumerate (gconstpointer test_data)
556 {
557   GFile *root, *child;
558   gboolean res;
559   GError *error;
560   GFileEnumerator *enumerator;
561   GFileInfo *info;
562   int i;
563   struct StructureItem item;
564
565
566   g_assert (test_data != NULL);
567   log ("\n  Test enumerate '%s'...\n", (char *) test_data);
568
569   root = g_file_new_for_commandline_arg ((char *) test_data);
570   g_assert (root != NULL);
571   res = g_file_query_exists (root, NULL);
572   g_assert_cmpint (res, ==, TRUE);
573
574
575   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
576     {
577       item = sample_struct[i];
578       if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
579         continue;
580
581       if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
582           (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS)
583            && posix_compat)
584           || ((item.extra_flags & TEST_ENUMERATE_FILE) ==
585               TEST_ENUMERATE_FILE))
586         {
587           log ("    Testing file '%s'\n", item.filename);
588           child = g_file_get_child (root, item.filename);
589           g_assert (child != NULL);
590           error = NULL;
591           enumerator =
592             g_file_enumerate_children (child, "*",
593                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
594                                        NULL, &error);
595
596           if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS)
597             {
598               g_assert (enumerator == NULL);
599               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
600             }
601           if ((item.extra_flags & TEST_ENUMERATE_FILE) == TEST_ENUMERATE_FILE)
602             {
603               g_assert (enumerator == NULL);
604               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
605             }
606           if ((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS)
607             {
608               g_assert (enumerator != NULL);
609
610               error = NULL;
611               info = g_file_enumerator_next_file (enumerator, NULL, &error);
612               g_assert (info == NULL);
613               g_assert_no_error (error);
614               /*  no items should be found, no error should be logged  */
615             }
616
617           if (error)
618             g_error_free (error);
619
620           if (enumerator)
621             {
622               error = NULL;
623               res = g_file_enumerator_close (enumerator, NULL, &error);
624               g_assert_cmpint (res, ==, TRUE);
625               g_assert_no_error (error);
626             }
627           g_object_unref (child);
628         }
629     }
630   g_object_unref (root);
631 }
632
633 static void
634 do_copy_move (GFile * root, struct StructureItem item, const char *target_dir,
635               enum StructureExtraFlags extra_flags)
636 {
637   GFile *dst_dir, *src_file, *dst_file;
638   gboolean res;
639   GError *error;
640
641   log ("    do_copy_move: '%s' --> '%s'\n", item.filename, target_dir);
642
643   dst_dir = g_file_get_child (root, target_dir);
644   g_assert (dst_dir != NULL);
645   src_file = g_file_get_child (root, item.filename);
646   g_assert (src_file != NULL);
647   dst_file = g_file_get_child (dst_dir, item.filename);
648   g_assert (dst_file != NULL);
649
650   error = NULL;
651   if ((item.extra_flags & TEST_COPY) == TEST_COPY)
652     res =
653       g_file_copy (src_file, dst_file,
654                    G_FILE_COPY_NOFOLLOW_SYMLINKS |
655                    ((extra_flags ==
656                      TEST_OVERWRITE) ? G_FILE_COPY_OVERWRITE :
657                     G_FILE_COPY_NONE), NULL, NULL, NULL, &error);
658   else
659     res =
660       g_file_move (src_file, dst_file, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL,
661                    NULL, NULL, &error);
662
663   if (error)
664     log ("       res = %d, error code %d = %s\n", res, error->code,
665          error->message);
666
667   /*  copying file/directory to itself (".")  */
668   if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) &&
669       (extra_flags == TEST_ALREADY_EXISTS))
670     {
671       g_assert_cmpint (res, ==, FALSE);
672       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
673     }
674   /*  target file is a file, overwrite is not set  */
675   else if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) &&
676            (extra_flags == TEST_TARGET_IS_FILE))
677     {
678       g_assert_cmpint (res, ==, FALSE);
679       if (item.file_type == G_FILE_TYPE_DIRECTORY)
680         g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE);
681       else
682         g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY);
683     }
684   /*  source file is directory  */
685   else if ((item.extra_flags & TEST_COPY_ERROR_RECURSE) ==
686            TEST_COPY_ERROR_RECURSE)
687     {
688       g_assert_cmpint (res, ==, FALSE);
689       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE);
690     }
691   /*  source or target path doesn't exist  */
692   else if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
693            (extra_flags == TEST_NOT_EXISTS))
694     {
695       g_assert_cmpint (res, ==, FALSE);
696       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
697     }
698   /*  source or target path permission denied  */
699   else if (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS) ||
700            (extra_flags == TEST_NO_ACCESS))
701     {
702       g_assert_cmpint (res, ==, FALSE);
703       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED);
704     }
705   /*  no error should be found, all exceptions defined above  */
706   else
707     {
708       g_assert_cmpint (res, ==, TRUE);
709       g_assert_no_error (error);
710     }
711
712   if (error)
713     g_error_free (error);
714
715
716   g_object_unref (dst_dir);
717   g_object_unref (src_file);
718   g_object_unref (dst_file);
719 }
720
721 static void
722 test_copy_move (gconstpointer test_data)
723 {
724   GFile *root;
725   gboolean res;
726   int i;
727   struct StructureItem item;
728
729   log ("\n");
730
731   g_assert (test_data != NULL);
732   root = g_file_new_for_commandline_arg ((char *) test_data);
733   g_assert (root != NULL);
734   res = g_file_query_exists (root, NULL);
735   g_assert_cmpint (res, ==, TRUE);
736
737
738   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
739     {
740       item = sample_struct[i];
741
742       if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
743         continue;
744
745       if (((item.extra_flags & TEST_COPY) == TEST_COPY) ||
746           ((item.extra_flags & TEST_MOVE) == TEST_MOVE))
747         {
748           /*  test copy/move to a directory, expecting no errors if source files exist  */
749           do_copy_move (root, item, TEST_DIR_TARGET, 0);
750
751           /*  some files have been already moved so we can't count with them in the tests  */
752           if ((item.extra_flags & TEST_COPY) == TEST_COPY)
753             {
754               /*  test overwrite for flagged files  */
755               if ((item.extra_flags & TEST_OVERWRITE) == TEST_OVERWRITE)
756                 {
757                   do_copy_move (root, item, TEST_DIR_TARGET, TEST_OVERWRITE);
758                 }
759               /*  source = target, should return G_IO_ERROR_EXISTS  */
760               do_copy_move (root, item, ".", TEST_ALREADY_EXISTS);
761               /*  target is file  */
762               do_copy_move (root, item, TEST_TARGET_FILE,
763                             TEST_TARGET_IS_FILE);
764               /*  target path is invalid  */
765               do_copy_move (root, item, TEST_NAME_NOT_EXISTS,
766                             TEST_NOT_EXISTS);
767
768               /*  tests on POSIX-compatible filesystems  */
769               if (posix_compat)
770                 {
771                   /*  target directory is not accessible (no execute flag)  */
772                   do_copy_move (root, item, TEST_DIR_NO_ACCESS,
773                                 TEST_NO_ACCESS);
774                   /*  target directory is readonly  */
775                   do_copy_move (root, item, TEST_DIR_NO_WRITE,
776                                 TEST_NO_ACCESS);
777                 }
778             }
779         }
780     }
781   g_object_unref (root);
782 }
783
784 static void
785 test_create (gconstpointer test_data)
786 {
787   GFile *root, *child;
788   gboolean res;
789   GError *error;
790   int i;
791   struct StructureItem item;
792   GFileOutputStream *os;
793
794   g_assert (test_data != NULL);
795   log ("\n");
796
797   root = g_file_new_for_commandline_arg ((char *) test_data);
798   g_assert (root != NULL);
799   res = g_file_query_exists (root, NULL);
800   g_assert_cmpint (res, ==, TRUE);
801
802   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
803     {
804       item = sample_struct[i];
805
806       if (((item.extra_flags & TEST_CREATE) == TEST_CREATE) ||
807           ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE) ||
808           ((item.extra_flags & TEST_APPEND) == TEST_APPEND))
809         {
810           log ("  test_create: '%s'\n", item.filename);
811
812           child = g_file_get_child (root, item.filename);
813           g_assert (child != NULL);
814           error = NULL;
815           os = NULL;
816
817           if ((item.extra_flags & TEST_CREATE) == TEST_CREATE)
818             os = g_file_create (child, item.create_flags, NULL, &error);
819           else if ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE)
820             os =
821               g_file_replace (child, NULL, TRUE, item.create_flags, NULL,
822                               &error);
823           else if ((item.extra_flags & TEST_APPEND) == TEST_APPEND)
824             os = g_file_append_to (child, item.create_flags, NULL, &error);
825
826
827           if (error)
828             log ("       error code %d = %s\n", error->code, error->message);
829
830           if (((item.extra_flags & TEST_NOT_EXISTS) == 0) &&
831               ((item.extra_flags & TEST_CREATE) == TEST_CREATE))
832             {
833               g_assert (os == NULL);
834               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
835             }
836           else if (item.file_type == G_FILE_TYPE_DIRECTORY)
837             {
838               g_assert (os == NULL);
839               if ((item.extra_flags & TEST_CREATE) == TEST_CREATE)
840                 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
841               else
842                 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
843             }
844           else
845             {
846               g_assert (os != NULL);
847               g_assert_no_error (error);
848             }
849
850           if (error)
851             g_error_free (error);
852
853           if (os)
854             {
855               error = NULL;
856               res =
857                 g_output_stream_close (G_OUTPUT_STREAM (os), NULL, &error);
858               if (error)
859                 log ("         g_output_stream_close: error %d = %s\n",
860                      error->code, error->message);
861               g_assert_cmpint (res, ==, TRUE);
862               g_assert_no_error (error);
863             }
864           g_object_unref (child);
865         }
866     }
867   g_object_unref (root);
868 }
869
870 static void
871 test_open (gconstpointer test_data)
872 {
873   GFile *root, *child;
874   gboolean res;
875   GError *error;
876   int i;
877   struct StructureItem item;
878   GFileInputStream *input_stream;
879
880   g_assert (test_data != NULL);
881   log ("\n");
882
883   root = g_file_new_for_commandline_arg ((char *) test_data);
884   g_assert (root != NULL);
885   res = g_file_query_exists (root, NULL);
886   g_assert_cmpint (res, ==, TRUE);
887
888   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
889     {
890       item = sample_struct[i];
891
892       if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
893         continue;
894
895       if ((item.extra_flags & TEST_OPEN) == TEST_OPEN)
896         {
897           log ("  test_open: '%s'\n", item.filename);
898
899           child = g_file_get_child (root, item.filename);
900           g_assert (child != NULL);
901           error = NULL;
902           input_stream = g_file_read (child, NULL, &error);
903
904           if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) ||
905               ((item.extra_flags & TEST_INVALID_SYMLINK) ==
906                TEST_INVALID_SYMLINK))
907             {
908               g_assert (input_stream == NULL);
909               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
910             }
911           else if (item.file_type == G_FILE_TYPE_DIRECTORY)
912             {
913               g_assert (input_stream == NULL);
914               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
915             }
916           else
917             {
918               g_assert (input_stream != NULL);
919               g_assert_no_error (error);
920             }
921
922           if (error)
923             g_error_free (error);
924
925           if (input_stream)
926             {
927               error = NULL;
928               res =
929                 g_input_stream_close (G_INPUT_STREAM (input_stream), NULL,
930                                       &error);
931               g_assert_cmpint (res, ==, TRUE);
932               g_assert_no_error (error);
933             }
934           g_object_unref (child);
935         }
936     }
937   g_object_unref (root);
938 }
939
940 static void
941 test_delete (gconstpointer test_data)
942 {
943   GFile *root;
944   GFile *child;
945   gboolean res;
946   GError *error;
947   int i;
948   struct StructureItem item;
949
950   g_assert (test_data != NULL);
951   log ("\n");
952
953   root = g_file_new_for_commandline_arg ((char *) test_data);
954   g_assert (root != NULL);
955   res = g_file_query_exists (root, NULL);
956   g_assert_cmpint (res, ==, TRUE);
957
958   for (i = 0; i < G_N_ELEMENTS (sample_struct); i++)
959     {
960       item = sample_struct[i];
961
962       if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))
963         continue;
964
965       if (((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL) ||
966           ((item.extra_flags & TEST_DELETE_TRASH) == TEST_DELETE_TRASH))
967         {
968           child = file_exists (root, item.filename, &res);
969           g_assert (child != NULL);
970           /*  we don't care about result here  */
971
972           log ("  Deleting %s, path = %s\n", item.filename,
973                g_file_get_path (child));
974           error = NULL;
975           if ((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL)
976             res = g_file_delete (child, NULL, &error);
977           else
978             res = g_file_trash (child, NULL, &error);
979
980           if ((item.extra_flags & TEST_DELETE_NON_EMPTY) ==
981               TEST_DELETE_NON_EMPTY)
982             {
983               g_assert_cmpint (res, ==, FALSE);
984               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_EMPTY);
985             }
986           if ((item.extra_flags & TEST_DELETE_FAILURE) == TEST_DELETE_FAILURE)
987             {
988               g_assert_cmpint (res, ==, FALSE);
989               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
990             }
991           if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS)
992             {
993               g_assert_cmpint (res, ==, FALSE);
994               g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
995             }
996
997           if (error)
998             {
999               log ("      result = %d, error = %s\n", res, error->message);
1000               g_error_free (error);
1001             }
1002
1003           g_object_unref (child);
1004         }
1005     }
1006   g_object_unref (root);
1007 }
1008
1009
1010 static void
1011 cleanup_dir_recurse (GFile *parent, GFile *root)
1012 {
1013   gboolean res;
1014   GError *error;
1015   GFileEnumerator *enumerator;
1016   GFileInfo *info;
1017   GFile *descend;
1018   char *relative_path;
1019
1020   g_assert (root != NULL);
1021
1022   error = NULL;
1023   enumerator =
1024     g_file_enumerate_children (parent, "*",
1025                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL,
1026                                &error);
1027   if (! enumerator)
1028           return;
1029
1030   error = NULL;
1031   info = g_file_enumerator_next_file (enumerator, NULL, &error);
1032   while ((info) && (!error))
1033     {
1034       descend = g_file_get_child (parent, g_file_info_get_name (info));
1035       g_assert (descend != NULL);
1036       relative_path = g_file_get_relative_path (root, descend);
1037       g_assert (relative_path != NULL);
1038
1039       log ("    deleting '%s'\n", g_file_info_get_display_name (info));
1040
1041       if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
1042           cleanup_dir_recurse (descend, root);
1043       
1044       error = NULL;
1045       res = g_file_delete (descend, NULL, &error);
1046       g_assert_cmpint (res, ==, TRUE);
1047
1048       g_object_unref (descend);
1049       error = NULL;
1050       info = g_file_enumerator_next_file (enumerator, NULL, &error);
1051     }
1052   g_assert_no_error (error);
1053
1054   error = NULL;
1055   res = g_file_enumerator_close (enumerator, NULL, &error);
1056   g_assert_cmpint (res, ==, TRUE);
1057   g_assert_no_error (error);
1058 }
1059
1060 static void
1061 prep_clean_structure (gconstpointer test_data)
1062 {
1063   GFile *root;
1064   
1065   g_assert (test_data != NULL);
1066   log ("\n  Cleaning target testing structure in '%s'...\n",
1067        (char *) test_data);
1068
1069   root = g_file_new_for_commandline_arg ((char *) test_data);
1070   g_assert (root != NULL);
1071   
1072   cleanup_dir_recurse (root, root);
1073
1074   g_file_delete (root, NULL, NULL);
1075   
1076   g_object_unref (root);
1077 }
1078
1079 int
1080 main (int argc, char *argv[])
1081 {
1082   static gboolean only_create_struct;
1083   static char *target_path;
1084   GError *error;
1085   GOptionContext *context;
1086
1087   static GOptionEntry cmd_entries[] = {
1088     {"read-write", 'w', 0, G_OPTION_ARG_NONE, &write_test,
1089      "Perform write tests (incl. structure creation)", NULL},
1090     {"create-struct", 'c', 0, G_OPTION_ARG_NONE, &only_create_struct,
1091      "Only create testing structure (no tests)", NULL},
1092     {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL},
1093     {"posix", 'x', 0, G_OPTION_ARG_NONE, &posix_compat,
1094      "Test POSIX-specific features (unix permissions, symlinks)", NULL},
1095     {NULL}
1096   };
1097
1098   verbose = FALSE;
1099   write_test = FALSE;
1100   only_create_struct = FALSE;
1101   target_path = NULL;
1102   posix_compat = FALSE;
1103
1104   /*  strip all gtester-specific args  */
1105   g_type_init ();
1106   g_test_init (&argc, &argv, NULL);
1107
1108   /*  no extra parameters specified, assume we're executed from glib test suite  */ 
1109   if (argc < 2)
1110     {
1111           verbose = TRUE;
1112           write_test = TRUE;
1113           only_create_struct = FALSE;
1114           target_path = DEFAULT_TEST_DIR;
1115 #ifdef G_PLATFORM_WIN32
1116           posix_compat = FALSE;
1117 #else
1118           posix_compat = TRUE;
1119 #endif
1120     }
1121   
1122   /*  add trailing args  */
1123   error = NULL;
1124   context = g_option_context_new ("target_path");
1125   g_option_context_add_main_entries (context, cmd_entries, NULL);
1126   if (!g_option_context_parse (context, &argc, &argv, &error))
1127     {
1128       g_print ("option parsing failed: %s\n", error->message);
1129       return g_test_run ();
1130     }
1131
1132   /*  remaining arg should is the target path; we don't care of the extra args here  */ 
1133   if (argc >= 2)
1134     target_path = strdup (argv[1]);
1135   
1136   if (! target_path) 
1137     {
1138       g_print ("error: target path was not specified\n");
1139       g_print (g_option_context_get_help (context, TRUE, NULL));
1140       return g_test_run ();
1141     }
1142
1143   
1144   /*  Write test - clean target directory first  */
1145   /*    this can be also considered as a test - enumerate + delete  */ 
1146   if (write_test || only_create_struct)
1147     g_test_add_data_func ("/live-g-file/prep_clean_structure", target_path,
1148                   prep_clean_structure);
1149   
1150   /*  Write test - create new testing structure  */
1151   if (write_test || only_create_struct)
1152     g_test_add_data_func ("/live-g-file/create_structure", target_path,
1153                           test_create_structure);
1154
1155   /*  Read test - test the sample structure - expect defined attributes to be there  */
1156   if (!only_create_struct)
1157     g_test_add_data_func ("/live-g-file/test_initial_structure", target_path,
1158                           test_initial_structure);
1159
1160   /*  Read test - test traverse the structure - no special file should appear  */
1161   if (!only_create_struct)
1162     g_test_add_data_func ("/live-g-file/test_traverse_structure", target_path,
1163                           test_traverse_structure);
1164
1165   /*  Read test - enumerate  */
1166   if (!only_create_struct)
1167     g_test_add_data_func ("/live-g-file/test_enumerate", target_path,
1168                           test_enumerate);
1169
1170   /*  Read test - open (g_file_read())  */
1171   if (!only_create_struct)
1172     g_test_add_data_func ("/live-g-file/test_open", target_path, test_open);
1173
1174   /*  Write test - create  */
1175   if (write_test && (!only_create_struct))
1176     g_test_add_data_func ("/live-g-file/test_create", target_path,
1177                           test_create);
1178
1179   /*  Write test - copy, move  */
1180   if (write_test && (!only_create_struct))
1181     g_test_add_data_func ("/live-g-file/test_copy_move", target_path,
1182                           test_copy_move);
1183
1184   /*  Write test - delete, trash  */
1185   if (write_test && (!only_create_struct))
1186     g_test_add_data_func ("/live-g-file/test_delete", target_path,
1187                           test_delete);
1188
1189   if (write_test || only_create_struct)
1190     g_test_add_data_func ("/live-g-file/final_clean", target_path,
1191                   prep_clean_structure);
1192
1193   return g_test_run ();
1194
1195 }