mkdir-p: Depend on 'mkdir'.
[gnulib.git] / tests / test-fts.c
blob79eaeae8e142bc8928caa9337eb3db48d577f171
1 /* Test the fts function.
2 Copyright 2017-2018 Free Software Foundation, Inc.
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.
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.
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/>. */
17 #include <config.h>
19 #include <fts_.h>
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>
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 };
34 static void
35 perror_exit (char const *message, int status)
37 perror (message);
38 exit (status);
41 /* alloc/dealloc to ensure structures initialized appropriately. */
42 static void
43 fts_dealloc (void)
45 static char dir[] = "./";
46 static char *const curr_dir[2] = { dir, 0 };
47 FTSENT *e;
48 FTS *ftsp = fts_open (curr_dir, FTS_NOSTAT | FTS_PHYSICAL | FTS_CWDFD, 0);
49 if (ftsp)
51 if (fts_close (ftsp) != 0)
52 perror_exit ("fts_close", 9);
54 else
55 perror_exit (base, 10);
58 /* Remove BASE and all files under it. */
59 static void
60 remove_tree (void)
62 FTSENT *e;
63 FTS *ftsp = fts_open (argv, FTS_NOSTAT | FTS_PHYSICAL | FTS_CWDFD, 0);
64 if (ftsp)
66 while ((e = fts_read (ftsp)))
68 int status = 0;
69 switch (e->fts_info)
71 case FTS_DP:
72 status = unlinkat (ftsp->fts_cwd_fd, e->fts_accpath,
73 AT_REMOVEDIR);
74 break;
76 case FTS_F: case FTS_NSOK:
77 status = unlinkat (ftsp->fts_cwd_fd, e->fts_accpath, 0);
78 break;
80 if (status != 0)
81 perror_exit (e->fts_path, 1);
83 if (fts_close (ftsp) != 0)
84 perror_exit ("fts_close", 2);
86 else if (errno != ENOENT)
87 perror_exit (base, 3);
90 int
91 main (void)
93 FTS *ftsp;
94 FTSENT *e;
95 char buf[sizeof BASE + 100];
96 int i;
97 enum { needles = 4 };
98 int needles_seen = 0;
99 struct stat st;
101 remove_tree ();
103 /* Create directories BASE, BASE/d, BASE/d/1, BASE/d/2, ..., BASE/d/65536,
104 to stress-test fts. Stop if directory creation fails due to
105 EMFILE problems, or if BASE/d's link count no longer matches the
106 Unix tradition. See:
107 https://bugzilla.kernel.org/show_bug.cgi?id=196405
108 for more info. */
109 if (mkdir (BASE, 0777) != 0)
110 perror_exit (base, 4);
111 if (mkdir (base_d, 0777) != 0)
112 perror_exit (base_d, 5);
113 for (i = 1; i <= 65536; i++)
115 sprintf (buf, "%s/d/%i", base, i);
116 if (mkdir (buf, 0777) != 0)
118 if (errno != EMFILE || i <= needles)
119 perror_exit (buf, 77);
120 break;
122 if (needles < i && stat (base_d, &st) == 0 && st.st_nlink != i + 2)
123 break;
126 /* Create empty files BASE/d/1/needle etc. */
127 for (i = 1; i <= needles; i++)
129 int fd;
130 sprintf (buf, "%s/d/%d/needle", base, i);
131 fd = open (buf, O_WRONLY | O_CREAT, 0666);
132 if (fd < 0 || close (fd) != 0)
133 perror_exit (buf, 77);
136 /* Use fts to look for the needles. */
137 ftsp = fts_open (argv, FTS_SEEDOT | FTS_NOSTAT | FTS_PHYSICAL | FTS_CWDFD, 0);
138 if (!ftsp)
139 perror_exit (base, 6);
140 while ((e = fts_read (ftsp)))
141 needles_seen += strcmp (e->fts_name, "needle") == 0;
142 int fts_read_errno = errno;
143 fflush (stdout);
144 if (fts_read_errno)
146 errno = fts_read_errno;
147 perror_exit ("fts_read", 7);
149 if (fts_close (ftsp) != 0)
150 perror_exit (base, 8);
152 /* Report an error if we did not find the needles. */
153 if (needles_seen != needles)
155 fprintf (stderr, "%d needles found (should be %d)\n",
156 needles_seen, needles);
157 return 1;
160 remove_tree ();
161 if (stat (base, &st) == 0)
163 fprintf (stderr, "fts could not remove directory\n");
164 return 1;
167 fts_dealloc ();
169 return 0;