* gnulib-local/lib/fts.c.diff: incorporated from a patch by Kamil Dudka <kdu...@redhat.com>. This patch introduces an FTS_NOLEAF option to fts. * gnulib-local/lib/fts_.h.diff: Likewise. * find/ftsfind.c (ftsoptions): point out that is_fts_enabled reflects the settings made in the initialization of ftsoptions, not the modifications made later to it (e.g. FTS_NOLEAF). (find): Set fts_options |= FTS_NOLEAF when the -noleaf option was specified. With -D search, the debugging output now shows the options passed to fts_open. (is_fts_enabled): Point out that the result doesn't reflect any dynamic changes to ftsoptions (e.g. FTS_NOLEAF). * Makefile.am (EXTRA_DIST): Distribute fts.c.diff and fts_.h.diff in gnulib-local/lib. These diffs will be applied to the gnulib sources by gnulib-tool (hence, the gnulib code shipped in the source tarball will already include these patches). * find/parser.c (parse_version): For the FTS feature, indicate whether FTS_NOLEAF is available (but not whether it was used; for that you have to use the command-line flag -D search). --- Makefile.am | 4 +++- find/ftsfind.c | 12 ++++++++++++ find/parser.c | 12 ++++++++++++ gnulib-local/lib/fts.c.diff | 23 +++++++++++++++++++++++ gnulib-local/lib/fts_.h.diff | 24 ++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 gnulib-local/lib/fts.c.diff create mode 100644 gnulib-local/lib/fts_.h.diff
diff --git a/Makefile.am b/Makefile.am index c31e7f03..030a4d58 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,9 @@ AM_CFLAGS = $(WARN_CFLAGS) EXTRA_DIST = COPYING ChangeLog TODO config.h.in stamp-h.in \ THANKS bootstrap \ - tool-versions.txt README-hacking + tool-versions.txt README-hacking \ + gnulib-local/lib/fts.c.diff \ + gnulib-local/lib/fts_.h.diff DISTCLEANFILES = tool-versions.txt diff --git a/find/ftsfind.c b/find/ftsfind.c index f9b03e2d..7bb6c145 100644 --- a/find/ftsfind.c +++ b/find/ftsfind.c @@ -72,6 +72,7 @@ /* FTS_TIGHT_CYCLE_CHECK tries to work around Savannah bug #17877 * (but actually using it doesn't fix the bug). */ +/* The --version output will reflect only flags set here (via is_fts_enabled). */ static int ftsoptions = FTS_NOSTAT|FTS_TIGHT_CYCLE_CHECK|FTS_CWDFD|FTS_VERBATIM; static int prev_depth = INT_MIN; /* fts_level can be < 0 */ @@ -545,6 +546,13 @@ find (char *arg) if (options.stay_on_filesystem) ftsoptions |= FTS_XDEV; + if (options.no_leaf_check) + ftsoptions |= FTS_NOLEAF; + + if (options.debug_options & DebugSearch) + fprintf (stderr, "calling fts_open with options %#x\n", + (unsigned)ftsoptions); + p = fts_open (arglist, ftsoptions, NULL); if (NULL == p) { @@ -742,6 +750,10 @@ main (int argc, char **argv) return state.exit_status; } +/* The result of is_fts_enabled will reflect only flags set in + ftsoptions directly. However, ftsoptions is dynamically modified + as the command line is parsed. The effect of this is that --version + cannot reflect thse dynamic options. */ bool is_fts_enabled (int *fts_options) { diff --git a/find/parser.c b/find/parser.c index 855ed1f8..bbe17641 100644 --- a/find/parser.c +++ b/find/parser.c @@ -2552,6 +2552,8 @@ parse_version (const struct parser_table* entry, char **argv, int *arg_ptr) } flags = 0; + /* See function header for is_fts_enabled for limitations on the + interpretation of its result. */ if (is_fts_enabled (&flags)) { int nflags = 0; @@ -2565,8 +2567,18 @@ parse_version (const struct parser_table* entry, char **argv, int *arg_ptr) printf (","); } printf ("FTS_CWDFD"); + ++nflags; has_features = true; } +#if defined(FTS_NOLEAF) + if (nflags) + { + printf (","); + } + printf ("FTS_NOLEAF=%#x", (unsigned)FTS_NOLEAF); + ++nflags; + has_features = true; +#endif printf (") "); } diff --git a/gnulib-local/lib/fts.c.diff b/gnulib-local/lib/fts.c.diff new file mode 100644 index 00000000..fa36cf2a --- /dev/null +++ b/gnulib-local/lib/fts.c.diff @@ -0,0 +1,23 @@ +The flag is needed to implement the -noleaf option of find. +* lib/fts.c (link_count_optimize_ok): Implement the FTS_NOLEAF flag. +* lib/fts_.h (FTS_NOLEAF): New macro, shifted conflicting constants. +--- + lib/fts.c | 4 ++++ + lib/fts_.h | 12 +++++++++--- + 2 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/lib/fts.c b/lib/fts.c +index ea73675..76bbc06 100644 +--- a/lib/fts.c ++++ b/lib/fts.c +@@ -781,6 +781,10 @@ link_count_optimize_ok (FTSENT const *p) + bool opt_ok; + struct LCO_ent *t2; + ++ if (ISSET(FTS_NOLEAF)) ++ /* leaf optimization explicitly disabled by the FTS_NOLEAF flag */ ++ return false; ++ + /* If we're not in CWDFD mode, don't bother with this optimization, + since the caller is not serious about performance. */ + if (!ISSET(FTS_CWDFD)) diff --git a/gnulib-local/lib/fts_.h.diff b/gnulib-local/lib/fts_.h.diff new file mode 100644 index 00000000..ff9fe666 --- /dev/null +++ b/gnulib-local/lib/fts_.h.diff @@ -0,0 +1,24 @@ +diff --git a/lib/fts_.h b/lib/fts_.h +index b9a3f12..1a500fc 100644 +--- a/lib/fts_.h ++++ b/lib/fts_.h +@@ -155,10 +155,16 @@ typedef struct { + from input path names during fts_open initialization. */ + # define FTS_VERBATIM 0x1000 + +-# define FTS_OPTIONMASK 0x1fff /* valid user option mask */ ++ /* Disable leaf optimization (which eliminates stat() calls during traversal, ++ based on the count of nested directories stored in stat.st_nlink of each ++ directory). Note that the optimization is by default enabled only for ++ selected file systems, and only if the FTS_CWDFD flag is set. */ ++# define FTS_NOLEAF 0x2000 + +-# define FTS_NAMEONLY 0x2000 /* (private) child names only */ +-# define FTS_STOP 0x4000 /* (private) unrecoverable error */ ++# define FTS_OPTIONMASK 0x3fff /* valid user option mask */ ++ ++# define FTS_NAMEONLY 0x4000 /* (private) child names only */ ++# define FTS_STOP 0x8000 /* (private) unrecoverable error */ + int fts_options; /* fts_open options, global flags */ + + /* Map a directory's device number to a boolean. The boolean is -- 2.11.0