* modules/fts-tests, tests/test-fts.c: New files. --- ChangeLog | 5 ++ modules/fts-tests | 13 +++++ tests/test-fts.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 modules/fts-tests create mode 100644 tests/test-fts.c
diff --git a/ChangeLog b/ChangeLog index 43401d2ad..05ac15d93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-07-24 Paul Eggert <egg...@cs.ucla.edu> + + fts-tests: new module + * modules/fts-tests, tests/test-fts.c: New files. + 2017-07-23 Bruno Haible <br...@clisp.org> Rename module 'strftime' to 'nstrftime'. diff --git a/modules/fts-tests b/modules/fts-tests new file mode 100644 index 000000000..115bf669a --- /dev/null +++ b/modules/fts-tests @@ -0,0 +1,13 @@ +Files: +tests/test-fts.c + +Depends-on: +errno +remove +unlinkat + +configure.ac: + +Makefile.am: +TESTS += test-fts +check_PROGRAMS += test-fts diff --git a/tests/test-fts.c b/tests/test-fts.c new file mode 100644 index 000000000..2ce72c96a --- /dev/null +++ b/tests/test-fts.c @@ -0,0 +1,142 @@ +/* Test the fts function. + Copyright 2017 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <fts_.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#define BASE "t-fts.tmp" +static char *const argv[2] = { BASE, 0 }; + +static void +perror_exit (char const *message, int status) +{ + perror (message); + exit (status); +} + +/* Remove BASE and all files under it. */ +static void +remove_tree (void) +{ + FTSENT *e; + FTS *ftsp = fts_open (argv, FTS_NOSTAT | FTS_PHYSICAL | FTS_CWDFD, 0); + if (ftsp) + { + while ((e = fts_read (ftsp))) + { + int status = 0; + switch (e->fts_info) + { + case FTS_DP: + status = unlinkat (ftsp->fts_cwd_fd, e->fts_accpath, + AT_REMOVEDIR); + break; + + case FTS_F: case FTS_NSOK: + status = unlinkat (ftsp->fts_cwd_fd, e->fts_accpath, 0); + break; + } + if (status != 0) + perror_exit (e->fts_path, 1); + } + if (fts_close (ftsp) != 0) + perror_exit ("fts_close", 2); + } + else if (errno != ENOENT) + perror_exit (BASE, 3); +} + +int +main (void) +{ + FTS *ftsp; + FTSENT *e; + char buf[sizeof BASE + 100]; + int i; + enum { needles = 4 }; + int needles_seen = 0; + struct stat st; + + remove_tree (); + + /* Create directories BASE, BASE/d, BASE/d/1, BASE/d/2, ..., BASE/d/65536, + to stress-test fts. Stop if directory creation fails due to + EMFILE problems, or if BASE/d's link count no longer matches the + Unix tradition. See: + https://bugzilla.kernel.org/show_bug.cgi?id=196405 + for more info. */ + if (mkdir (BASE, 0777) != 0) + perror_exit (BASE, 4); + if (mkdir (BASE "/d", 0777) != 0) + perror_exit (BASE "/d", 5); + for (i = 1; i <= 65536; i++) + { + sprintf (buf, "%s/d/%i", BASE, i); + if (mkdir (buf, 0777) != 0) + { + if (errno != EMFILE || i <= needles) + perror_exit (buf, 77); + break; + } + if (needles < i && stat (BASE "/d", &st) == 0 && st.st_nlink != i + 2) + break; + } + + /* Create empty files BASE/d/1/needle etc. */ + for (i = 1; i <= needles; i++) + { + int fd; + sprintf (buf, "%s/d/%d/needle", BASE, i); + fd = open (buf, O_WRONLY | O_CREAT, 0666); + if (fd < 0 || close (fd) != 0) + perror_exit (buf, 77); + } + + /* Use fts to look for the needles. */ + ftsp = fts_open (argv, FTS_SEEDOT | FTS_NOSTAT | FTS_PHYSICAL | FTS_CWDFD, 0); + if (!ftsp) + perror_exit (BASE, 6); + while ((e = fts_read (ftsp))) + needles_seen += strcmp (e->fts_name, "needle") == 0; + fflush (stdout); + if (errno) + perror_exit ("fts_read", 7); + + /* Report an error if we did not find the needles. */ + if (needles_seen != needles) + { + fprintf (stderr, "%d needles found (should be %d)\n", + needles_seen, needles); + return 1; + } + + remove_tree (); + if (stat (BASE, &st) == 0) + { + fprintf (stderr, "fts could not remove directory\n"); + return 1; + } + return 0; +} -- 2.13.3