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