Paul Eggert
2017-07-25 07:28:01 UTC
* 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 <***@cs.ucla.edu>
+
+ fts-tests: new module
+ * modules/fts-tests, tests/test-fts.c: New files.
+
2017-07-23 Bruno Haible <***@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;
+}
---
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 <***@cs.ucla.edu>
+
+ fts-tests: new module
+ * modules/fts-tests, tests/test-fts.c: New files.
+
2017-07-23 Bruno Haible <***@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
2.13.3