root/maint/gnulib/tests/test-fts.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. perror_exit
  2. fts_dealloc
  3. remove_tree
  4. main

   1 /* Test the fts function.
   2    Copyright 2017-2021 Free Software Foundation, Inc.
   3 
   4    This program is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 3 of the License, or
   7    (at your option) any later version.
   8 
   9    This program 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.  See the
  12    GNU General Public License for more details.
  13 
  14    You should have received a copy of the GNU General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 #include <config.h>
  18 
  19 #include <fts_.h>
  20 
  21 #include <errno.h>
  22 #include <fcntl.h>
  23 #include <stdio.h>
  24 #include <stdlib.h>
  25 #include <string.h>
  26 #include <sys/stat.h>
  27 #include <unistd.h>
  28 
  29 #define BASE "t-fts.tmp"
  30 static char base[] = BASE; /* Not const, since argv needs non-const.  */
  31 static char const base_d[] = BASE "/d";
  32 static char *const argv[2] = { base, 0 };
  33 
  34 static void
  35 perror_exit (char const *message, int status)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37   perror (message);
  38   exit (status);
  39 }
  40 
  41 /* alloc/dealloc to ensure structures initialized appropriately.  */
  42 static void
  43 fts_dealloc (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  44 {
  45   static char dir[] = "./";
  46   static char *const curr_dir[2] = { dir, 0 };
  47   FTS *ftsp = fts_open (curr_dir, FTS_NOSTAT | FTS_PHYSICAL | FTS_CWDFD, 0);
  48   if (ftsp)
  49     {
  50       if (fts_close (ftsp) != 0)
  51         perror_exit ("fts_close", 9);
  52     }
  53   else
  54     perror_exit (base, 10);
  55 }
  56 
  57 /* Remove BASE and all files under it.  */
  58 static void
  59 remove_tree (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61   FTSENT *e;
  62   FTS *ftsp = fts_open (argv, FTS_NOSTAT | FTS_PHYSICAL | FTS_CWDFD, 0);
  63   if (ftsp)
  64     {
  65       while ((e = fts_read (ftsp)))
  66         {
  67           int status = 0;
  68           switch (e->fts_info)
  69             {
  70             case FTS_DP:
  71               status = unlinkat (ftsp->fts_cwd_fd, e->fts_accpath,
  72                                  AT_REMOVEDIR);
  73               break;
  74 
  75             case FTS_F: case FTS_NSOK:
  76               status = unlinkat (ftsp->fts_cwd_fd, e->fts_accpath, 0);
  77               break;
  78             }
  79           if (status != 0)
  80             perror_exit (e->fts_path, 1);
  81         }
  82       if (fts_close (ftsp) != 0)
  83         perror_exit ("fts_close", 2);
  84     }
  85   else if (errno != ENOENT)
  86     perror_exit (base, 3);
  87 }
  88 
  89 int
  90 main (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92   FTS *ftsp;
  93   FTSENT *e;
  94   char buf[sizeof BASE + 100];
  95   int i;
  96   enum { needles = 4 };
  97   int needles_seen = 0;
  98   struct stat st;
  99 
 100   remove_tree ();
 101 
 102   /* Create directories BASE, BASE/d, BASE/d/1, BASE/d/2, ..., BASE/d/65536,
 103      to stress-test fts.  Stop if directory creation fails due to
 104      EMFILE or EMLINK problems, or if BASE/d's link count no longer matches the
 105      Unix tradition.  See:
 106      https://bugzilla.kernel.org/show_bug.cgi?id=196405
 107      for more info.  */
 108   if (mkdir (BASE, 0777) != 0)
 109     perror_exit (base, 4);
 110   if (mkdir (base_d, 0777) != 0)
 111     perror_exit (base_d, 5);
 112   for (i = 1; i <= 65536; i++)
 113     {
 114       sprintf (buf, "%s/d/%i", base, i);
 115       if (mkdir (buf, 0777) != 0)
 116         {
 117           if (errno == EMFILE || errno == EMLINK)
 118             break;
 119           if (i <= needles)
 120             perror_exit (buf, 77);
 121           break;
 122         }
 123       if (needles < i && stat (base_d, &st) == 0 && st.st_nlink != i + 2)
 124         break;
 125     }
 126 
 127   /* Create empty files BASE/d/1/needle etc.  */
 128   for (i = 1; i <= needles; i++)
 129     {
 130       int fd;
 131       sprintf (buf, "%s/d/%d/needle", base, i);
 132       fd = open (buf, O_WRONLY | O_CREAT, 0666);
 133       if (fd < 0 || close (fd) != 0)
 134         perror_exit (buf, 77);
 135     }
 136 
 137   /* Use fts to look for the needles.  */
 138   ftsp = fts_open (argv, FTS_SEEDOT | FTS_NOSTAT | FTS_PHYSICAL | FTS_CWDFD, 0);
 139   if (!ftsp)
 140     perror_exit (base, 6);
 141   while ((e = fts_read (ftsp)))
 142     needles_seen += strcmp (e->fts_name, "needle") == 0;
 143   int fts_read_errno = errno;
 144   fflush (stdout);
 145   if (fts_read_errno)
 146     {
 147       errno = fts_read_errno;
 148       perror_exit ("fts_read", 7);
 149     }
 150   if (fts_close (ftsp) != 0)
 151     perror_exit (base, 8);
 152 
 153   /* Report an error if we did not find the needles.  */
 154   if (needles_seen != needles)
 155     {
 156       fprintf (stderr, "%d needles found (should be %d)\n",
 157                needles_seen, needles);
 158       return 1;
 159     }
 160 
 161   remove_tree ();
 162   if (stat (base, &st) == 0)
 163     {
 164       fprintf (stderr, "fts could not remove directory\n");
 165       return 1;
 166     }
 167 
 168   fts_dealloc ();
 169 
 170   return 0;
 171 }

/* [previous][next][first][last][top][bottom][index][help] */