| /* Simple test for some fts functions. | 
 |    Copyright (C) 2015-2016 Free Software Foundation, Inc. | 
 |    This file is part of the GNU C Library. | 
 |  | 
 |    The GNU C Library is free software; you can redistribute it and/or | 
 |    modify it under the terms of the GNU Lesser General Public | 
 |    License as published by the Free Software Foundation; either | 
 |    version 2.1 of the License, or (at your option) any later version. | 
 |  | 
 |    The GNU C Library is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |    Lesser General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU Lesser General Public | 
 |    License along with the GNU C Library; if not, see | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include <sys/types.h> | 
 | #include <sys/stat.h> | 
 | #include <fts.h> | 
 |  | 
 | #include <errno.h> | 
 | #include <error.h> | 
 | #include <string.h> | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include <unistd.h> | 
 |  | 
 | static void prepare (void); | 
 | static int do_test (void); | 
 | #define PREPARE(argc, argv)     prepare () | 
 | #define TEST_FUNCTION           do_test () | 
 | #include "../test-skeleton.c" | 
 |  | 
 | static char *fts_test_dir; | 
 |  | 
 | static void | 
 | make_dir (const char *dirname) | 
 | { | 
 |   char *name; | 
 |   if (asprintf (&name, "%s/%s", fts_test_dir, dirname) < 0) | 
 |     { | 
 |       puts ("out of memory"); | 
 |       exit (1); | 
 |     } | 
 |  | 
 |   if (mkdir (name, 0700) < 0) | 
 |     { | 
 |       printf ("cannot create dir \"%s\": %m\n", name); | 
 |       exit (1); | 
 |     } | 
 |  | 
 |   add_temp_file (name); | 
 | } | 
 |  | 
 | static void | 
 | make_file (const char *filename) | 
 | { | 
 |   char *name; | 
 |   if (asprintf (&name, "%s/%s", fts_test_dir, filename) < 0) | 
 |     { | 
 |       puts ("out of memory"); | 
 |       exit (1); | 
 |     } | 
 |  | 
 |   int fd = open (name, O_WRONLY | O_CREAT | O_EXCL, 0600); | 
 |   if (fd < 0) | 
 |     { | 
 |       printf ("cannot create file \"%s\": %m\n", name); | 
 |       exit (1); | 
 |     } | 
 |   close (fd); | 
 |  | 
 |   add_temp_file (name); | 
 | } | 
 |  | 
 | static void | 
 | prepare (void) | 
 | { | 
 |   char *dirbuf; | 
 |   char dir_name[] = "/tst-fts.XXXXXX"; | 
 |  | 
 |   if (asprintf (&dirbuf, "%s%s", test_dir, dir_name) < 0) | 
 |     { | 
 |       puts ("out of memory"); | 
 |       exit (1); | 
 |     } | 
 |  | 
 |   if (mkdtemp (dirbuf) == NULL) | 
 |     { | 
 |       puts ("cannot create temporary directory"); | 
 |       exit (1); | 
 |     } | 
 |  | 
 |   add_temp_file (dirbuf); | 
 |   fts_test_dir = dirbuf; | 
 |  | 
 |   make_file ("12"); | 
 |   make_file ("345"); | 
 |   make_file ("6789"); | 
 |  | 
 |   make_dir ("aaa"); | 
 |   make_file ("aaa/1234"); | 
 |   make_file ("aaa/5678"); | 
 |  | 
 |   make_dir ("bbb"); | 
 |   make_file ("bbb/1234"); | 
 |   make_file ("bbb/5678"); | 
 |   make_file ("bbb/90ab"); | 
 | } | 
 |  | 
 | /* Largest name wins, otherwise strcmp.  */ | 
 | static int | 
 | compare_ents (const FTSENT **ent1, const FTSENT **ent2) | 
 | { | 
 |   short len1 = (*ent1)->fts_namelen; | 
 |   short len2 = (*ent2)->fts_namelen; | 
 |   if (len1 != len2) | 
 |     return len1 - len2; | 
 |   else | 
 |     { | 
 |       const char *name1 = (*ent1)->fts_name; | 
 |       const char *name2 = (*ent2)->fts_name; | 
 |       return strcmp (name1, name2); | 
 |     } | 
 | } | 
 |  | 
 | /* Count the number of files seen as children.  */ | 
 | static int files = 0; | 
 |  | 
 | static void | 
 | children (FTS *fts) | 
 | { | 
 |   FTSENT *child = fts_children (fts, 0); | 
 |   if (child == NULL && errno != 0) | 
 |     { | 
 |       printf ("FAIL: fts_children: %m\n"); | 
 |       exit (1); | 
 |     } | 
 |  | 
 |   while (child != NULL) | 
 |     { | 
 |       short level = child->fts_level; | 
 |       const char *name = child->fts_name; | 
 |       if (child->fts_info == FTS_F || child->fts_info == FTS_NSOK) | 
 | 	{ | 
 | 	  files++; | 
 | 	  printf ("%*s%s\n", 2 * level, "", name); | 
 | 	} | 
 |       child = child->fts_link; | 
 |     } | 
 | } | 
 |  | 
 | /* Count the number of dirs seen in the test.  */ | 
 | static int dirs = 0; | 
 |  | 
 | static int | 
 | do_test (void) | 
 | { | 
 |   char *paths[2] = { fts_test_dir, NULL }; | 
 |   FTS *fts; | 
 |   fts = fts_open (paths, FTS_LOGICAL, &compare_ents); | 
 |   if (fts == NULL) | 
 |     { | 
 |       printf ("FAIL: fts_open: %m\n"); | 
 |       exit (1); | 
 |     } | 
 |  | 
 |   FTSENT *ent; | 
 |   while ((ent = fts_read (fts)) != NULL) | 
 |     { | 
 |       const char *name = ent->fts_name; | 
 |       short level = ent->fts_level; | 
 |       switch (ent->fts_info) | 
 | 	{ | 
 | 	case FTS_F: | 
 | 	  /* Don't show anything, children will have on parent dir.  */ | 
 | 	  break; | 
 |  | 
 | 	case FTS_D: | 
 | 	  printf ("%*s%s =>\n", 2 * level, "", name); | 
 | 	  children (fts); | 
 | 	  break; | 
 |  | 
 | 	case FTS_DP: | 
 | 	  dirs++; | 
 | 	  printf ("%*s<= %s\n", 2 * level, "", name); | 
 | 	  break; | 
 |  | 
 | 	case FTS_NS: | 
 | 	case FTS_ERR: | 
 | 	  printf ("FAIL: fts_read ent: %s\n", strerror (ent->fts_errno)); | 
 | 	  exit (1); | 
 | 	  break; | 
 |  | 
 | 	default: | 
 | 	  printf ("FAIL: unexpected fts_read ent %s\n", name); | 
 | 	  exit (1); | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |   /* fts_read returns NULL when done (and clears errno) | 
 |      or when an error occured (with errno set).  */ | 
 |   if (errno != 0) | 
 |     { | 
 |       printf ("FAIL: fts_read: %m\n"); | 
 |       exit (1); | 
 |     } | 
 |  | 
 |   if (fts_close (fts) != 0) | 
 |     { | 
 |       printf ("FAIL: fts_close: %m\n"); | 
 |       exit (1); | 
 |     } | 
 |  | 
 |   if (files != 8) | 
 |     { | 
 |       printf ("FAIL: Unexpected number of files: %d\n", files); | 
 |       return 1; | 
 |     } | 
 |  | 
 |   if (dirs != 3) | 
 |     { | 
 |       printf ("FAIL: Unexpected number of dirs: %d\n", dirs); | 
 |       return 1; | 
 |     } | 
 |  | 
 |   puts ("PASS"); | 
 |   return 0; | 
 | } |