(root)/
glibc-2.38/
io/
tst-fts.c
       1  /* Simple test for some fts functions.
       2     Copyright (C) 2015-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <sys/types.h>
      20  #include <sys/stat.h>
      21  #include <fts.h>
      22  
      23  #include <errno.h>
      24  #include <error.h>
      25  #include <string.h>
      26  #include <stdio.h>
      27  #include <stdlib.h>
      28  #include <unistd.h>
      29  
      30  static void prepare (void);
      31  static int do_test (void);
      32  #define PREPARE(argc, argv)     prepare ()
      33  #define TEST_FUNCTION           do_test ()
      34  #include "../test-skeleton.c"
      35  
      36  static char *fts_test_dir;
      37  
      38  static void
      39  make_dir (const char *dirname)
      40  {
      41    char *name;
      42    if (asprintf (&name, "%s/%s", fts_test_dir, dirname) < 0)
      43      {
      44        puts ("out of memory");
      45        exit (1);
      46      }
      47  
      48    if (mkdir (name, 0700) < 0)
      49      {
      50        printf ("cannot create dir \"%s\": %m\n", name);
      51        exit (1);
      52      }
      53  
      54    add_temp_file (name);
      55  }
      56  
      57  static void
      58  make_file (const char *filename)
      59  {
      60    char *name;
      61    if (asprintf (&name, "%s/%s", fts_test_dir, filename) < 0)
      62      {
      63        puts ("out of memory");
      64        exit (1);
      65      }
      66  
      67    int fd = open (name, O_WRONLY | O_CREAT | O_EXCL, 0600);
      68    if (fd < 0)
      69      {
      70        printf ("cannot create file \"%s\": %m\n", name);
      71        exit (1);
      72      }
      73    close (fd);
      74  
      75    add_temp_file (name);
      76  }
      77  
      78  static void
      79  prepare (void)
      80  {
      81    char *dirbuf;
      82    char dir_name[] = "/tst-fts.XXXXXX";
      83  
      84    if (asprintf (&dirbuf, "%s%s", test_dir, dir_name) < 0)
      85      {
      86        puts ("out of memory");
      87        exit (1);
      88      }
      89  
      90    if (mkdtemp (dirbuf) == NULL)
      91      {
      92        puts ("cannot create temporary directory");
      93        exit (1);
      94      }
      95  
      96    add_temp_file (dirbuf);
      97    fts_test_dir = dirbuf;
      98  
      99    make_file ("12");
     100    make_file ("345");
     101    make_file ("6789");
     102  
     103    make_dir ("aaa");
     104    make_file ("aaa/1234");
     105    make_file ("aaa/5678");
     106  
     107    make_dir ("bbb");
     108    make_file ("bbb/1234");
     109    make_file ("bbb/5678");
     110    make_file ("bbb/90ab");
     111  }
     112  
     113  /* Largest name wins, otherwise strcmp.  */
     114  static int
     115  compare_ents (const FTSENT **ent1, const FTSENT **ent2)
     116  {
     117    short len1 = (*ent1)->fts_namelen;
     118    short len2 = (*ent2)->fts_namelen;
     119    if (len1 != len2)
     120      return len1 - len2;
     121    else
     122      {
     123        const char *name1 = (*ent1)->fts_name;
     124        const char *name2 = (*ent2)->fts_name;
     125        return strcmp (name1, name2);
     126      }
     127  }
     128  
     129  /* Count the number of files seen as children.  */
     130  static int files = 0;
     131  
     132  static void
     133  children (FTS *fts)
     134  {
     135    FTSENT *child = fts_children (fts, 0);
     136    if (child == NULL && errno != 0)
     137      {
     138        printf ("FAIL: fts_children: %m\n");
     139        exit (1);
     140      }
     141  
     142    while (child != NULL)
     143      {
     144        short level = child->fts_level;
     145        const char *name = child->fts_name;
     146        if (child->fts_info == FTS_F || child->fts_info == FTS_NSOK)
     147  	{
     148  	  files++;
     149  	  printf ("%*s%s\n", 2 * level, "", name);
     150  	}
     151        child = child->fts_link;
     152      }
     153  }
     154  
     155  /* Count the number of dirs seen in the test.  */
     156  static int dirs = 0;
     157  
     158  static int
     159  do_test (void)
     160  {
     161    char *paths[2] = { fts_test_dir, NULL };
     162    FTS *fts;
     163    fts = fts_open (paths, FTS_LOGICAL, &compare_ents);
     164    if (fts == NULL)
     165      {
     166        printf ("FAIL: fts_open: %m\n");
     167        exit (1);
     168      }
     169  
     170    FTSENT *ent;
     171    while ((ent = fts_read (fts)) != NULL)
     172      {
     173        const char *name = ent->fts_name;
     174        short level = ent->fts_level;
     175        switch (ent->fts_info)
     176  	{
     177  	case FTS_F:
     178  	  /* Don't show anything, children will have on parent dir.  */
     179  	  break;
     180  
     181  	case FTS_D:
     182  	  printf ("%*s%s =>\n", 2 * level, "", name);
     183  	  children (fts);
     184  	  break;
     185  
     186  	case FTS_DP:
     187  	  dirs++;
     188  	  printf ("%*s<= %s\n", 2 * level, "", name);
     189  	  break;
     190  
     191  	case FTS_NS:
     192  	case FTS_ERR:
     193  	  printf ("FAIL: fts_read ent: %s\n", strerror (ent->fts_errno));
     194  	  exit (1);
     195  	  break;
     196  
     197  	default:
     198  	  printf ("FAIL: unexpected fts_read ent %s\n", name);
     199  	  exit (1);
     200  	  break;
     201  	}
     202      }
     203    /* fts_read returns NULL when done (and clears errno)
     204       or when an error occurred (with errno set).  */
     205    if (errno != 0)
     206      {
     207        printf ("FAIL: fts_read: %m\n");
     208        exit (1);
     209      }
     210  
     211    if (fts_close (fts) != 0)
     212      {
     213        printf ("FAIL: fts_close: %m\n");
     214        exit (1);
     215      }
     216  
     217    if (files != 8)
     218      {
     219        printf ("FAIL: Unexpected number of files: %d\n", files);
     220        return 1;
     221      }
     222  
     223    if (dirs != 3)
     224      {
     225        printf ("FAIL: Unexpected number of dirs: %d\n", dirs);
     226        return 1;
     227      }
     228  
     229    puts ("PASS");
     230    return 0;
     231  }