Compare commits

...

9 Commits
rawhide ... f13

Author SHA1 Message Date
Fedora Release Engineering c3ae861b86 dist-git conversion 2010-07-28 14:26:28 +00:00
Kamil Dudka 46e433431a - fix Savannah bug #29949 2010-06-01 10:40:42 +00:00
Kamil Dudka e1f9543c9d eliminate the offset in some patches 2010-05-10 16:16:43 +00:00
Kamil Dudka 593142936c - mention -xautofs in the output of --help (#590166) 2010-05-10 15:17:21 +00:00
Kamil Dudka 55a9f8670e trivial follow-up 2010-05-06 20:45:58 +00:00
Kamil Dudka 8244b13d4a trivial follow-up 2010-05-06 14:27:36 +00:00
Kamil Dudka e6446fceb3 - backport of patches for upstream bugs #19593 and #27563 (rhbz #493143) 2010-05-06 13:13:26 +00:00
Kamil Dudka fc6b56efa1 fix mistakenly stated bug ID in the ChangeLog 2010-03-30 12:08:51 +00:00
Jesse Keating 4f3893e494 Initialize branch F-13 for findutils 2010-02-17 01:19:43 +00:00
11 changed files with 1761 additions and 32 deletions

View File

View File

@ -1,21 +0,0 @@
# Makefile for source rpm: findutils
# $Id: Makefile,v 1.2 2007/10/15 18:45:12 notting Exp $
NAME := findutils
SPECFILE = $(firstword $(wildcard *.spec))
define find-makefile-common
for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$d/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done
endef
MAKEFILE_COMMON := $(shell $(find-makefile-common))
ifeq ($(MAKEFILE_COMMON),)
# attempt a checkout
define checkout-makefile-common
test -f CVS/Root && { cvs -Q -d $$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2
endef
MAKEFILE_COMMON := $(shell $(checkout-makefile-common))
endif
include $(MAKEFILE_COMMON)

View File

@ -1,3 +1,13 @@
NEWS | 6 +++
doc/find.texi | 17 +++++++
find/Makefile.am | 2 +-
find/defs.h | 6 +++
find/find.1 | 4 ++
find/parser.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
find/pred.c | 47 ++++++++++++++++++++
find/tree.c | 2 +
8 files changed, 209 insertions(+), 3 deletions(-)
diff --git a/NEWS b/NEWS
index d00862f..6b8b725 100644
--- a/NEWS
@ -130,7 +140,7 @@ index f9c61a3..27ad1da 100644
A `%' character followed by any other character is discarded, but the
other character is printed (don't rely on this, as further format
diff --git a/find/parser.c b/find/parser.c
index 036ddb8..6b09eee 100644
index 411fd96..3f237eb 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -53,6 +53,8 @@
@ -323,7 +333,7 @@ index 036ddb8..6b09eee 100644
parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
{
options.stay_on_filesystem = true;
@@ -2815,7 +2934,7 @@ insert_fprintf (struct format_val *vec,
@@ -2812,7 +2931,7 @@ insert_fprintf (struct format_val *vec,
if (*scan2 == '.')
for (scan2++; ISDIGIT (*scan2); scan2++)
/* Do nothing. */ ;
@ -332,7 +342,7 @@ index 036ddb8..6b09eee 100644
{
segmentp = make_segment (segmentp, format, scan2 - format,
KIND_FORMAT, *scan2, 0,
@@ -2945,6 +3064,11 @@ make_segment (struct segment **segment,
@@ -2942,6 +3061,11 @@ make_segment (struct segment **segment,
*fmt++ = 's';
break;

View File

@ -1,3 +1,11 @@
doc/find.texi | 4 ++++
find/defs.h | 3 +++
find/find.1 | 3 +++
find/ftsfind.c | 6 ++++++
find/parser.c | 11 ++++++++++-
find/util.c | 1 +
6 files changed, 27 insertions(+), 1 deletions(-)
diff --git a/doc/find.texi b/doc/find.texi
index f1feba3..8037c63 100644
--- a/doc/find.texi
@ -59,7 +67,7 @@ index b59d896..838b81f 100644
{
/* this is the preorder visit, but user said -depth */
diff --git a/find/parser.c b/find/parser.c
index 534b670..036ddb8 100644
index 534b670..411fd96 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -150,6 +150,7 @@ static boolean parse_user PARAMS((const struct parser_table*, char *arg
@ -78,17 +86,23 @@ index 534b670..036ddb8 100644
PARSE_TEST ("xtype", xtype), /* GNU */
#ifdef UNIMPLEMENTED_UNIX
/* It's pretty ugly for find to know about archive formats.
@@ -2560,6 +2562,16 @@ parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
@@ -1117,7 +1119,7 @@ operators (decreasing precedence; -and is implicit where no others are given):\n
positional options (always true): -daystart -follow -regextype\n\n\
normal options (always true, specified before other expressions):\n\
-depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\
- --version -xdev -ignore_readdir_race -noignore_readdir_race\n"));
+ --version -xautofs -xdev -ignore_readdir_race -noignore_readdir_race\n"));
puts (_("\
tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
-cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\
@@ -2560,6 +2562,13 @@ parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
}
static boolean
+parse_xautofs (const struct parser_table* entry, char **argv, int *arg_ptr)
+{
+ (void) argv;
+ (void) arg_ptr;
+ (void) entry;
+ options.bypass_autofs = true;
+ return true;
+ return parse_noop(entry, argv, arg_ptr);
+}
+
+static boolean

View File

@ -0,0 +1,192 @@
ChangeLog | 16 +++++++
find/testsuite/Makefile.am | 3 +
find/testsuite/config/unix.exp | 9 ++++
find/testsuite/find.gnu/execdir-multiple.exp | 55 ++++++++++++++++++++++++++
find/testsuite/find.gnu/execdir-multiple.xo | 24 +++++++++++
find/testsuite/find.gnu/execdir-pwd1.exp | 20 +++++++++
6 files changed, 127 insertions(+), 0 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index be93846..34552d5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2010-04-10 James Youngman <jay@gnu.org>
+
+ Add a test which checks $CWD for find -execdir {} +/;
+ * find/testsuite/find.gnu/execdir-multiple.exp: New test; verifies
+ that for -execdir +, all the execs occur with the correct working
+ directory.
+ * find/testsuite/find.gnu/execdir-multiple.xo: Expected output for
+ this test.
+ * find/testsuite/Makefile.am (EXTRA_DIST_EXP): Add the new test.
+ (EXTRA_DIST_XO): Add the expected output file.
+ * find/testsuite/config/unix.exp (mkdir): Create proc "mkdir"
+ which creates a directory.
+ * find/testsuite/find.gnu/execdir-pwd1.exp: New test.
+ * find/testsuite/Makefile.am (EXTRA_DIST_EXP): Add
+ execdir-pwd1.exp.
+
2009-05-16 James Youngman <jay@gnu.org>
Apply typo fix from <petrosyan@gmail.com> (tiny change).
diff --git a/find/testsuite/Makefile.am b/find/testsuite/Makefile.am
index dca30e6..1447132 100644
--- a/find/testsuite/Makefile.am
+++ b/find/testsuite/Makefile.am
@@ -14,6 +14,7 @@ find.gnu/depth.xo \
find.gnu/depth-d.xo \
find.gnu/empty.xo \
find.gnu/execdir-hier.xo \
+find.gnu/execdir-multiple.xo \
find.gnu/execdir-one.xo \
find.gnu/execdir-root-only.xo \
find.gnu/exec-many-rtn-failure.xo \
@@ -114,8 +115,10 @@ find.gnu/depth-d.exp \
find.gnu/empty.exp \
find.gnu/execdir-hier.exp \
find.gnu/execdir-in-unreadable.exp \
+find.gnu/execdir-multiple.exp \
find.gnu/execdir-one.exp \
find.gnu/execdir-pwd.exp \
+find.gnu/execdir-pwd1.exp \
find.gnu/execdir-root-only.exp \
find.gnu/exec-many-rtn-failure.exp \
find.gnu/exec-many-rtn-success.exp \
diff --git a/find/testsuite/config/unix.exp b/find/testsuite/config/unix.exp
index 087aeb2..968eb9d 100644
--- a/find/testsuite/config/unix.exp
+++ b/find/testsuite/config/unix.exp
@@ -259,6 +259,15 @@ proc touch args {
}
}
+proc mkdir { dirname } {
+ # Not all versions of Tcl offer 'file mkdir'.
+ set failed [ catch "file mkdir $dirname" result ]
+ if $failed {
+ # Fall back on the external command.
+ send_log "file mkdir does not work, falling back on exec mkdir\n"
+ exec mkdir "$dirname"
+ }
+}
proc safe_path [ ] {
diff --git a/find/testsuite/find.gnu/execdir-multiple.exp b/find/testsuite/find.gnu/execdir-multiple.exp
new file mode 100644
index 0000000..6d4bd66
--- /dev/null
+++ b/find/testsuite/find.gnu/execdir-multiple.exp
@@ -0,0 +1,55 @@
+# tests for -execdir ... \+
+
+# Create 4 empty files in each of 6 directories.
+# Also create a shell script in each of those 6 directories.
+# Run a find command which runs the shell script for each empty file.
+# Check to make sure that each file is mentioned exactly once, and that
+# the command was run with the correct working directory.
+#
+# The output is a sequence of lines of this form:
+#
+# cwd ./basename
+#
+# cmd is the basename of the current directory at the time the command
+# is run by -execidr. ./basename is the name of the file that was matched
+# (that is, it's the value passed in {}).
+
+# $body is the body of a shell script we use for testing.
+# It prints a series of lines of the form described above.
+# One line is printed for each command-line argument.
+set body {#! /bin/sh
+set -e
+here=`pwd`
+d=`basename $here`
+
+for arg;
+do
+ echo "$d" "$arg"
+done | LC_ALL=C sort
+}
+
+
+if { [ safe_path ] } {
+ global SKIP_OLD
+
+ exec rm -rf tmp
+ mkdir tmp
+
+ # Put a copy of our shell script in each
+ # directory, plus some files.
+ foreach dir { a b c d e f } {
+ mkdir "tmp/$dir"
+ set script_name "tmp/$dir/runme"
+ set f [open "$script_name" "w" 0700 ]
+ puts $f "$body"
+ close $f
+ foreach item { one two three four } {
+ touch "tmp/$dir/$item"
+ }
+ }
+
+ set SKIP_OLD 1
+ find_start p {tmp -type f -empty -execdir sh ./runme \{\} + } ""
+ set SKIP_OLD 0
+ exec rm -rf tmp
+}
diff --git a/find/testsuite/find.gnu/execdir-multiple.xo b/find/testsuite/find.gnu/execdir-multiple.xo
new file mode 100644
index 0000000..a4f93d9
--- /dev/null
+++ b/find/testsuite/find.gnu/execdir-multiple.xo
@@ -0,0 +1,24 @@
+a ./one
+a ./two
+a ./three
+a ./four
+b ./one
+b ./two
+b ./three
+b ./four
+c ./one
+c ./two
+c ./three
+c ./four
+d ./one
+d ./two
+d ./three
+d ./four
+e ./one
+e ./two
+e ./three
+e ./four
+f ./one
+f ./two
+f ./three
+f ./four
diff --git a/find/testsuite/find.gnu/execdir-pwd1.exp b/find/testsuite/find.gnu/execdir-pwd1.exp
new file mode 100644
index 0000000..e9863ac
--- /dev/null
+++ b/find/testsuite/find.gnu/execdir-pwd1.exp
@@ -0,0 +1,20 @@
+# tests for working directory of -execdir {} \;
+if { [ safe_path ] } {
+ global SKIP_OLD
+
+ exec rm -rf tmp
+ exec mkdir tmp
+
+ # Create an empty shell script.
+ exec touch tmp/foo
+ exec chmod +x tmp/foo
+
+ # The -execdir should find the "foo" in the current directory.
+ # If not, the find command is probably executing the command
+ # built up by -execdir in the wrong directory.
+
+ set SKIP_OLD 1
+ find_start p {tmp -name foo -execdir sh ./foo \{\} \; } ""
+ set SKIP_OLD 0
+ exec rm -rf tmp
+}

View File

@ -0,0 +1,945 @@
ChangeLog | 83 +++++++++++++++++++++++++++++++++++++++++++++
find/defs.h | 14 ++++----
find/find.c | 69 +++++--------------------------------
find/finddata.c | 12 +-----
find/ftsfind.c | 49 ++-------------------------
find/parser.c | 35 ++++++------------
find/pred.c | 92 +++++++++++++++++++++++++++++++++-----------------
find/util.c | 89 +++++++++++++++++++++++++++++++++++++++---------
import-gnulib.config | 1 +
lib/dircallback.c | 36 +++++++++++++++++++-
lib/dircallback.h | 5 ++-
lib/listfile.c | 2 +-
12 files changed, 291 insertions(+), 196 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 34552d5..fefc1b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,88 @@
2010-04-10 James Youngman <jay@gnu.org>
+ Exec predicates now store which directory they want to run in.
+ * lib/dircallback.c (run_in_dirfd): New name for old run_in_dir
+ function.
+ (run_in_dir): Like the old function of the same name, but now
+ takes an argument const struct saved_cwd *.
+ * lib/dircallback.h: Update declarations of run_in_dirfd and
+ run_in_dir.
+ * find/util.c: Include dircallback.h, xalloc.h, save-cwd.h.
+ (do_complete_pending_execdirs): Remove dir_fd parameter, since the
+ per-predicate data structures now indicate what directory they
+ need to be run in. Instead of calling bc_do_exec directly, use a
+ callback 'exec_cb' that uses run_in_dir (which now takes a
+ saved_cwd* parameter instead of a file descriptor).
+ (do_exec): Called by do_complete_pending_execdirs, and simply uses
+ run_in_dir to call exec_cb, restoring the working directory
+ afterward.
+ (record_initial_cwd): New function, initialises the global
+ variable initial_wd.
+ (cleanup_initial_cwd): New function, cleans up the global variable
+ initial_wd.
+ (cleanup): Call cleanup_initial_cwd.
+ (get_start_dirfd): Remove.
+ (is_exec_in_local_dir): New function; true for predicates -execdir
+ and -okdir.
+ * find/pred.c: Include save-cwd.h.
+ (record_exec_dir): New function, sets the value of
+ execp->wd_for_exec if needed.
+ (new_impl_pred_exec): Remove the obsolete dir_fd parameter. Call
+ record_exec_dir.
+ (pred_exec): Don't pass the dir_fd parameter.
+ (pred_execdir): Likewise.
+ (pred_ok): Likewise.
+ (pred_okdir): Likewise.
+ (can_access): Call run_in_dirfd rather than run_in_dir (the
+ function was renamed).
+ (prep_child_for_exec): Remove dir_fd parameter; don't fchdir to
+ that. Call restore_cwd instead (passing a saved_cwd* parameter
+ which replaced dir_fd).
+ (launch): Remove references to execp->use_current_dir.
+ (launch): Change references to execp->dir_fd to execp->wd_for_exec.
+ * find/parser.c: Correct indentiation of declaration of
+ insert_exec_ok and remove the obsolete dir_fd parameter.
+ (parse_exec): Don't pass the dir_fd parameter to insert_exec_ok.
+ (parse_execdir): Likewise.
+ (parse_ok): Likewise.
+ (parse_okdir): Likewise.
+ (insert_exec_ok): Remove obsolete dir_fd paramter. Initialise
+ execp->wd_for_exec, either to NULL (for -*dir) or to the
+ initial_wd.
+ * find/ftsfind.c: Remove get_current_dirfd. Remove
+ complete_execdirs_cb.
+ (consider_visiting): Call complete_pending_execdirs directly.
+ (main): Call record_initial_cwd to record the initial working
+ directory, early on. Don't initialise starting_dir or
+ starting_desc, they have been removed.
+ * find/finddata.c: Include save-cwd.h. Remove starting_dir and
+ starting_desc. Add new global variable initial_wd. It is a struct
+ saved_wd* and represents find's initial working directory.
+ * find/find.c: Include save-cwd.h.
+ (main): Call record_initial_cwd in order to initialise the
+ global variable initial_wd Don't set starting_desc and
+ starting_dir, since those variables have been removed.
+ (safely_chdir): Don't pass an fd to complete_pending_execdirs.
+ (chdir_back): Remove the safety check (since we are using fchdir
+ and in any case no longer have all the data that the existing
+ wd_sanity_check function wants).
+ (do_process_top_dir): Don't pass an fd to
+ complete_pending_execdirs.
+ (process_dir): Likewise.
+ * find/defs.h (struct exec_val): Remove use_current_dir and
+ dir_fd. Replace with wd_for_exec, which is a struct saved_wd*.
+ (get_start_dirfd): Remove prototype.
+ (get_current_dirfd): Remove prototype.
+ (complete_pending_execdirs): No longer takes dir_fd parameter.
+ (record_initial_cwd): Add prototype.
+ (is_exec_in_local_dir): Add prototype.
+ (options): Declare.
+ (initial_wd): Add declaration. It is a struct saved_wd* and
+ represents find's initial working directory.
+ (starting_dir): Remove declaration of global variable.
+ (starting_desc): Remove declaration of global variable.
+ * import-gnulib.config (modules): Import module save-cwd.
+
Add a test which checks $CWD for find -execdir {} +/;
* find/testsuite/find.gnu/execdir-multiple.exp: New test; verifies
that for -execdir +, all the execs occur with the correct working
diff --git a/find/defs.h b/find/defs.h
index 36d428d..b4c1339 100644
--- a/find/defs.h
+++ b/find/defs.h
@@ -196,9 +196,8 @@ struct exec_val
struct buildcmd_state state;
char **replace_vec; /* Command arguments (for ";" style) */
int num_args;
- boolean use_current_dir; /* If nonzero, don't chdir to start dir */
boolean close_stdin; /* If true, close stdin in the child. */
- int dir_fd; /* The directory to do the exec in. */
+ struct saved_cwd *wd_for_exec;/* What directory to perform the exec in. */
};
/* The format string for a -printf or -fprintf is chopped into one or
@@ -337,8 +336,6 @@ struct predicate
/* find.c, ftsfind.c */
boolean is_fts_enabled(int *ftsoptions);
-int get_start_dirfd(void);
-int get_current_dirfd(void);
/* find library function declarations. */
@@ -493,8 +490,11 @@ struct predicate *insert_primary_withpred PARAMS((const struct parser_table *ent
void usage PARAMS((FILE *fp, int status, char *msg));
extern boolean check_nofollow(void);
void complete_pending_execs(struct predicate *p);
-void complete_pending_execdirs(int dir_fd); /* Passing dir_fd is an unpleasant CodeSmell. */
+void complete_pending_execdirs(void);
const char *safely_quote_err_filename (int n, char const *arg);
+void record_initial_cwd (void);
+boolean is_exec_in_local_dir(const PRED_FUNC pred_func);
+
void fatal_file_error(const char *name) ATTRIBUTE_NORETURN;
void nonfatal_file_error(const char *name);
@@ -660,10 +660,10 @@ struct state
};
/* finddata.c */
+extern struct options options;
extern struct state state;
-extern char const *starting_dir;
-extern int starting_desc;
extern char *program_name;
+extern struct saved_cwd *initial_wd;
#endif
diff --git a/find/find.c b/find/find.c
index 171988f..badcf3c 100644
--- a/find/find.c
+++ b/find/find.c
@@ -52,6 +52,7 @@
#include "quotearg.h"
#include "xgetcwd.h"
#include "error.h"
+#include "save-cwd.h"
#ifdef HAVE_LOCALE_H
#include <locale.h>
@@ -131,6 +132,8 @@ main (int argc, char **argv)
program_name = argv[0];
state.exit_status = 0;
+ record_initial_cwd ();
+
/* Set the option defaults before we do the locale
* initialisation as check_nofollow() needs to be executed in the
* POSIX locale.
@@ -183,23 +186,6 @@ main (int argc, char **argv)
}
- starting_desc = open (".", O_RDONLY
-#if defined O_LARGEFILE
- |O_LARGEFILE
-#endif
- );
- if (0 <= starting_desc && fchdir (starting_desc) != 0)
- {
- close (starting_desc);
- starting_desc = -1;
- }
-
- if (starting_desc < 0)
- {
- starting_dir = xgetcwd ();
- if (! starting_dir)
- error (1, errno, _("cannot get current directory"));
- }
set_stat_placeholders(&starting_stat_buf);
if ((*options.xstat) (".", &starting_stat_buf) != 0)
error (1, errno, _("cannot stat current directory"));
@@ -876,7 +862,7 @@ safely_chdir(const char *dest,
* processed, do them now because they must be done in the same
* directory.
*/
- complete_pending_execdirs(get_current_dirfd());
+ complete_pending_execdirs ();
#if !defined(O_NOFOLLOW)
options.open_nofollow_available = false;
@@ -911,45 +897,10 @@ safely_chdir(const char *dest,
static void
chdir_back (void)
{
- struct stat stat_buf;
- boolean dummy;
-
- if (starting_desc < 0)
- {
- if (options.debug_options & DebugSearch)
- fprintf(stderr, "chdir_back(): chdir(\"%s\")\n", starting_dir);
-
-#ifdef STAT_MOUNTPOINTS
- /* We will need the mounted device list. Get it now if we don't
- * already have it.
- */
- if (NULL == mounted_devices)
- init_mounted_dev_list(1);
-#endif
-
- if (chdir (starting_dir) != 0)
- fatal_file_error(starting_dir);
-
- wd_sanity_check(starting_dir,
- program_name,
- starting_dir,
- starting_stat_buf.st_dev,
- starting_stat_buf.st_ino,
- &stat_buf, 0, __LINE__,
- TraversingUp,
- FATAL_IF_SANITY_CHECK_FAILS,
- &dummy);
- }
- else
- {
- if (options.debug_options & DebugSearch)
- fprintf(stderr, "chdir_back(): chdir(<starting-point>)\n");
+ if (options.debug_options & DebugSearch)
+ fprintf (stderr, "chdir_back(): chdir to start point\n");
- if (fchdir (starting_desc) != 0)
- {
- fatal_file_error(starting_dir);
- }
- }
+ restore_cwd (initial_wd);
}
/* Move to the parent of a given directory and then call a function,
@@ -1038,7 +989,7 @@ static void do_process_top_dir(char *pathname,
(void) pstat;
process_path (pathname, base, false, ".", mode);
- complete_pending_execdirs(get_current_dirfd());
+ complete_pending_execdirs ();
}
static void do_process_predicate(char *pathname,
@@ -1326,7 +1277,7 @@ process_dir (char *pathname, char *name, int pathlen, const struct stat *statp,
* yet been processed, do them now because they must be done in
* the same directory.
*/
- complete_pending_execdirs(get_current_dirfd());
+ complete_pending_execdirs ();
if (strcmp (name, "."))
{
@@ -1464,7 +1415,7 @@ process_dir (char *pathname, char *name, int pathlen, const struct stat *statp,
* yet been processed, do them now because they must be done in
* the same directory.
*/
- complete_pending_execdirs(get_current_dirfd());
+ complete_pending_execdirs ();
if (strcmp (name, "."))
{
diff --git a/find/finddata.c b/find/finddata.c
index 373eb38..dcc8261 100644
--- a/find/finddata.c
+++ b/find/finddata.c
@@ -19,6 +19,7 @@
#include <config.h>
#include "defs.h"
+#include "save-cwd.h"
/* Name this program was run with. */
@@ -26,13 +27,4 @@ char *program_name;
struct options options;
struct state state;
-
-/* The full path of the initial working directory, or "." if
- STARTING_DESC is nonnegative. */
-char const *starting_dir = ".";
-
-/* A file descriptor open to the initial working directory.
- Doing it this way allows us to work when the i.w.d. has
- unreadable parents. */
-int starting_desc;
-
+struct saved_cwd *initial_wd = NULL;
diff --git a/find/ftsfind.c b/find/ftsfind.c
index 838b81f..9945abd 100644
--- a/find/ftsfind.c
+++ b/find/ftsfind.c
@@ -98,24 +98,6 @@ static int ftsoptions = FTS_NOSTAT|FTS_TIGHT_CYCLE_CHECK;
static int prev_depth = INT_MIN; /* fts_level can be < 0 */
static int curr_fd = -1;
-int get_current_dirfd(void)
-{
- if (ftsoptions & FTS_CWDFD)
- {
- assert (curr_fd != -1);
- assert ( (AT_FDCWD == curr_fd) || (curr_fd >= 0) );
-
- if (AT_FDCWD == curr_fd)
- return starting_desc;
- else
- return curr_fd;
- }
- else
- {
- return AT_FDCWD;
- }
-}
-
static void left_dir(void)
{
if (ftsoptions & FTS_CWDFD)
@@ -324,15 +306,6 @@ symlink_loop(const char *name)
}
-static int
-complete_execdirs_cb(void *context)
-{
- (void) context;
- /* By the tme this callback is called, the current directory is correct. */
- complete_pending_execdirs(AT_FDCWD);
- return 0;
-}
-
static void
show_outstanding_execdirs(FILE *fp)
{
@@ -566,7 +539,7 @@ consider_visiting(FTS *p, FTSENT *ent)
if (state.execdirs_outstanding)
{
show_outstanding_execdirs(stderr);
- run_in_dir(p->fts_cwd_fd, complete_execdirs_cb, NULL);
+ complete_pending_execdirs ();
}
if (ent->fts_info == FTS_DP)
@@ -670,6 +643,8 @@ main (int argc, char **argv)
state.execdirs_outstanding = false;
state.cwd_dir_fd = AT_FDCWD;
+ record_initial_cwd ();
+
/* Set the option defaults before we do the locale initialisation as
* check_nofollow() needs to be executed in the POSIX locale.
*/
@@ -719,24 +694,6 @@ main (int argc, char **argv)
}
- starting_desc = open (".", O_RDONLY
-#if defined O_LARGEFILE
- |O_LARGEFILE
-#endif
- );
- if (0 <= starting_desc && fchdir (starting_desc) != 0)
- {
- close (starting_desc);
- starting_desc = -1;
- }
- if (starting_desc < 0)
- {
- starting_dir = xgetcwd ();
- if (! starting_dir)
- error (1, errno, _("cannot get current directory"));
- }
-
-
process_all_startpoints(argc-end_of_leading_options, argv+end_of_leading_options);
/* If "-exec ... {} +" has been used, there may be some
diff --git a/find/parser.c b/find/parser.c
index 3f237eb..b96d317 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -181,7 +181,6 @@ static struct segment **make_segment PARAMS((struct segment **segment,
struct predicate *pred));
static boolean insert_exec_ok PARAMS((const char *action,
const struct parser_table *entry,
- int dir_fd,
char *argv[],
int *arg_ptr));
static boolean get_comp_type PARAMS((const char **str,
@@ -928,13 +927,13 @@ parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
static boolean
parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
{
- return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
+ return insert_exec_ok ("-exec", entry, argv, arg_ptr);
}
static boolean
parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
{
- return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
+ return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
}
static boolean
@@ -1790,13 +1789,13 @@ parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
static boolean
parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
{
- return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
+ return insert_exec_ok ("-ok", entry, argv, arg_ptr);
}
static boolean
parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
{
- return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
+ return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
}
boolean
@@ -3158,11 +3157,10 @@ check_path_safety(const char *action, char **argv)
/* handles both exec and ok predicate */
static boolean
-new_insert_exec_ok (const char *action,
- const struct parser_table *entry,
- int dir_fd,
- char **argv,
- int *arg_ptr)
+insert_exec_ok (const char *action,
+ const struct parser_table *entry,
+ char **argv,
+ int *arg_ptr)
{
int start, end; /* Indexes in ARGV of start & end of cmd. */
int i; /* Index into cmd args */
@@ -3183,6 +3181,7 @@ new_insert_exec_ok (const char *action,
our_pred->need_type = our_pred->need_stat = false;
execp = &our_pred->args.exec_vec;
+ execp->wd_for_exec = NULL;
if ((func != pred_okdir) && (func != pred_ok))
{
@@ -3202,13 +3201,14 @@ new_insert_exec_ok (const char *action,
if ((func == pred_execdir) || (func == pred_okdir))
{
+ execp->wd_for_exec = NULL;
options.ignore_readdir_race = false;
check_path_safety(action, argv);
- execp->use_current_dir = true;
}
else
{
- execp->use_current_dir = false;
+ assert (NULL != initial_wd);
+ execp->wd_for_exec = initial_wd;
}
our_pred->args.exec_vec.multiple = 0;
@@ -3361,17 +3361,6 @@ new_insert_exec_ok (const char *action,
-static boolean
-insert_exec_ok (const char *action,
- const struct parser_table *entry,
- int dir_fd,
- char **argv,
- int *arg_ptr)
-{
- return new_insert_exec_ok(action, entry, dir_fd, argv, arg_ptr);
-}
-
-
/* Get a timestamp and comparison type.
diff --git a/find/pred.c b/find/pred.c
index 7c34119..d057d48 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -47,6 +47,7 @@
#include "dircallback.h"
#include "error.h"
#include "verify.h"
+#include "save-cwd.h"
#include <selinux/selinux.h>
@@ -502,8 +503,30 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_
return (false);
}
+
static boolean
-new_impl_pred_exec (int dir_fd, const char *pathname,
+record_exec_dir (struct exec_val *execp)
+{
+ if (!execp->wd_for_exec)
+ {
+ /* working directory not already known, so must be a *dir variant,
+ and this must be the first arg we added. However, this may
+ be -execdir foo {} \; (i.e. not multiple). */
+ assert (!execp->state.todo);
+
+ /* Record the WD. */
+ execp->wd_for_exec = xmalloc (sizeof (*execp->wd_for_exec));
+ execp->wd_for_exec->name = NULL;
+ execp->wd_for_exec->desc = openat (state.cwd_dir_fd, ".", O_RDONLY);
+ if (execp->wd_for_exec->desc < 0)
+ return false;
+ }
+ return true;
+}
+
+
+static boolean
+new_impl_pred_exec (const char *pathname,
struct stat *stat_buf,
struct predicate *pred_ptr,
const char *prefix, size_t pfxlen)
@@ -512,7 +535,32 @@ new_impl_pred_exec (int dir_fd, const char *pathname,
size_t len = strlen(pathname);
(void) stat_buf;
- execp->dir_fd = dir_fd;
+
+ if (is_exec_in_local_dir (pred_ptr->pred_func))
+ {
+ /* For -execdir/-okdir predicates, the parser did not fill in
+ the wd_for_exec member of sturct exec_val. So for those
+ predicates, we do so now.
+ */
+ if (!record_exec_dir (execp))
+ {
+ error (EXIT_FAILURE, errno,
+ _("Failed to save working directory in order to "
+ "run a command on %s"),
+ safely_quote_err_filename (0, pathname));
+ /*NOTREACHED*/
+ }
+ }
+ else
+ {
+ /* For the others (-exec, -ok), the parser should
+ have set wd_for_exec to initial_wd, indicating
+ that the exec should take place from find's initial
+ working directory.
+ */
+ assert (execp->wd_for_exec == initial_wd);
+ }
+
if (execp->multiple)
{
/* Push the argument onto the current list.
@@ -558,8 +606,7 @@ new_impl_pred_exec (int dir_fd, const char *pathname,
boolean
pred_exec (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
- return new_impl_pred_exec(get_start_dirfd(),
- pathname, stat_buf, pred_ptr, NULL, 0);
+ return new_impl_pred_exec(pathname, stat_buf, pred_ptr, NULL, 0);
}
boolean
@@ -567,8 +614,7 @@ pred_execdir (const char *pathname, struct stat *stat_buf, struct predicate *pre
{
const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
(void) &pathname;
- return new_impl_pred_exec (get_current_dirfd(),
- state.rel_pathname, stat_buf, pred_ptr,
+ return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
prefix, (prefix ? 2 : 0));
}
@@ -1460,8 +1506,7 @@ boolean
pred_ok (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
- return new_impl_pred_exec (get_start_dirfd(),
- pathname, stat_buf, pred_ptr, NULL, 0);
+ return new_impl_pred_exec (pathname, stat_buf, pred_ptr, NULL, 0);
else
return false;
}
@@ -1471,8 +1516,7 @@ pred_okdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_
{
const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
- return new_impl_pred_exec (get_current_dirfd(),
- state.rel_pathname, stat_buf, pred_ptr,
+ return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
prefix, (prefix ? 2 : 0));
else
return false;
@@ -1573,7 +1617,7 @@ can_access(int access_type)
args.filename = state.rel_pathname;
args.access_type = access_type;
args.cb_errno = 0;
- return 0 == run_in_dir(state.cwd_dir_fd, access_callback, &args);
+ return 0 == run_in_dirfd (state.cwd_dir_fd, access_callback, &args);
}
@@ -1912,7 +1956,7 @@ pred_context (const char *pathname, struct stat *stat_buf,
static boolean
-prep_child_for_exec (boolean close_stdin, int dir_fd)
+prep_child_for_exec (boolean close_stdin, const struct saved_cwd *wd)
{
boolean ok = true;
if (close_stdin)
@@ -1948,17 +1992,10 @@ prep_child_for_exec (boolean close_stdin, int dir_fd)
* announcement of a call to stat() anyway, as we're about to exec
* something.
*/
- if (dir_fd != AT_FDCWD)
+ if (0 != restore_cwd (wd))
{
- assert (dir_fd >= 0);
- if (0 != fchdir(dir_fd))
- {
- /* If we cannot execute our command in the correct directory,
- * we should not execute it at all.
- */
- error(0, errno, _("Failed to change directory"));
- ok = false;
- }
+ error (0, errno, _("Failed to change directory"));
+ ok = false;
}
return ok;
}
@@ -1974,13 +2011,6 @@ launch (const struct buildcmd_control *ctl,
static int first_time = 1;
const struct exec_val *execp = buildstate->usercontext;
- if (!execp->use_current_dir)
- {
- assert (starting_desc >= 0);
- assert (execp->dir_fd == starting_desc);
- }
-
-
/* Null terminate the arg list. */
bc_push_arg (ctl, buildstate, (char *) NULL, 0, NULL, 0, false);
@@ -2001,8 +2031,8 @@ launch (const struct buildcmd_control *ctl,
if (child_pid == 0)
{
/* We are the child. */
- assert (starting_desc >= 0);
- if (!prep_child_for_exec(execp->close_stdin, execp->dir_fd))
+ assert (NULL != execp->wd_for_exec);
+ if (!prep_child_for_exec (execp->close_stdin, execp->wd_for_exec))
{
_exit(1);
}
diff --git a/find/util.c b/find/util.c
index d3cb467..da4fc62 100644
--- a/find/util.c
+++ b/find/util.c
@@ -36,6 +36,9 @@
#include "error.h"
#include "verify.h"
#include "openat.h"
+#include "dircallback.h"
+#include "xalloc.h"
+#include "save-cwd.h"
#if ENABLE_NLS
# include <libintl.h>
@@ -282,6 +285,26 @@ check_nofollow(void)
#endif
+static int
+exec_cb (void *context)
+{
+ struct exec_val *execp = context;
+ launch (&execp->ctl, &execp->state);
+ return 0;
+}
+
+static void
+do_exec (struct exec_val *execp)
+{
+ run_in_dir (execp->wd_for_exec, exec_cb, execp);
+ if (execp->wd_for_exec != initial_wd)
+ {
+ free_cwd (execp->wd_for_exec);
+ free (execp->wd_for_exec);
+ execp->wd_for_exec = NULL;
+ }
+}
+
/* Examine the predicate list for instances of -execdir or -okdir
* which have been terminated with '+' (build argument list) rather
@@ -289,14 +312,14 @@ check_nofollow(void)
* have no effect if there are no arguments waiting).
*/
static void
-do_complete_pending_execdirs(struct predicate *p, int dir_fd)
+do_complete_pending_execdirs(struct predicate *p)
{
if (NULL == p)
return;
assert (state.execdirs_outstanding);
- do_complete_pending_execdirs(p->pred_left, dir_fd);
+ do_complete_pending_execdirs(p->pred_left);
if (pred_is(p, pred_execdir) || pred_is(p, pred_okdir))
{
@@ -311,25 +334,24 @@ do_complete_pending_execdirs(struct predicate *p, int dir_fd)
if (execp->state.todo)
{
/* There are not-yet-executed arguments. */
- launch (&execp->ctl, &execp->state);
+ do_exec (execp);
}
}
}
- do_complete_pending_execdirs(p->pred_right, dir_fd);
+ do_complete_pending_execdirs(p->pred_right);
}
void
-complete_pending_execdirs(int dir_fd)
+complete_pending_execdirs (void)
{
if (state.execdirs_outstanding)
{
- do_complete_pending_execdirs(get_eval_tree(), dir_fd);
+ do_complete_pending_execdirs(get_eval_tree());
state.execdirs_outstanding = false;
}
}
-
/* Examine the predicate list for instances of -exec which have been
* terminated with '+' (build argument list) rather than ';' (singles
@@ -365,6 +387,37 @@ complete_pending_execs(struct predicate *p)
complete_pending_execs(p->pred_right);
}
+
+void
+record_initial_cwd (void)
+{
+ initial_wd = xmalloc (sizeof (*initial_wd));
+ if (0 != save_cwd (initial_wd))
+ {
+ error (EXIT_FAILURE, errno,
+ _("failed to save initial working directory"));
+ }
+}
+
+static void
+cleanup_initial_cwd (void)
+{
+ if (0 == restore_cwd (initial_wd))
+ {
+ free_cwd (initial_wd);
+ free (initial_wd);
+ initial_wd = NULL;
+ }
+ else
+ {
+ /* since we may already be in atexit, die with _exit(). */
+ error (0, errno,
+ _("failed to restore initial working directory"));
+ _exit (EXIT_FAILURE);
+ }
+}
+
+
static void
traverse_tree(struct predicate *tree,
@@ -424,9 +477,11 @@ cleanup(void)
if (eval_tree)
{
traverse_tree(eval_tree, complete_pending_execs);
- complete_pending_execdirs(get_current_dirfd());
+ complete_pending_execdirs ();
traverse_tree(eval_tree, flush_and_close_output_files);
}
+
+ cleanup_initial_cwd ();
}
/* Savannah bug #16378 manifests as an assertion failure in pred_type()
@@ -963,15 +1018,6 @@ set_option_defaults(struct options *p)
}
-/* get_start_dirfd
- *
- * Returns the fd for the directory we started in.
- */
-int get_start_dirfd(void)
-{
- return starting_desc;
-}
-
/* apply_predicate
*
*/
@@ -997,6 +1043,15 @@ apply_predicate(const char *pathname, struct stat *stat_buf, struct predicate *p
}
}
+/* is_exec_in_local_dir
+ *
+ */
+bool
+is_exec_in_local_dir (const PRED_FUNC pred_func)
+{
+ return pred_execdir == pred_func || pred_okdir == pred_func;
+}
+
/* safely_quote_err_filename
*
diff --git a/import-gnulib.config b/import-gnulib.config
index f2e8998..b1f0851 100644
--- a/import-gnulib.config
+++ b/import-gnulib.config
@@ -67,6 +67,7 @@ quotearg
realloc
regex
rpmatch
+save-cwd
savedir
stat-macros
stat-time
diff --git a/lib/dircallback.c b/lib/dircallback.c
index 5dbf3b3..f96fccc 100644
--- a/lib/dircallback.c
+++ b/lib/dircallback.c
@@ -54,7 +54,41 @@
int
-run_in_dir (int dir_fd, int (*callback)(void*), void *usercontext)
+run_in_dir (const struct saved_cwd *there,
+ int (*callback)(void*), void *usercontext)
+{
+ int err = -1;
+ int saved_errno = 0;
+ struct saved_cwd here;
+ if (0 == save_cwd (&here))
+ {
+ if (0 == restore_cwd (there))
+ {
+ err = callback(usercontext);
+ saved_errno = (err < 0 ? errno : 0);
+ }
+ else
+ {
+ openat_restore_fail (errno);
+ }
+
+ if (restore_cwd (&here) != 0)
+ openat_restore_fail (errno);
+
+ free_cwd (&here);
+ }
+ else
+ {
+ openat_save_fail (errno);
+ }
+ if (saved_errno)
+ errno = saved_errno;
+ return err;
+}
+
+
+int
+run_in_dirfd (int dir_fd, int (*callback)(void*), void *usercontext)
{
if (dir_fd == AT_FDCWD)
{
diff --git a/lib/dircallback.h b/lib/dircallback.h
index 41ea282..3234113 100644
--- a/lib/dircallback.h
+++ b/lib/dircallback.h
@@ -19,6 +19,9 @@
#if !defined DIRCALLBACK_H
# define DIRCALLBACK_H
-int run_in_dir (int dir_fd, int (*callback)(void*), void *usercontext);
+struct saved_cwd;
+
+int run_in_dirfd (int fd, int (*callback)(void*), void *usercontext);
+int run_in_dir (struct saved_cwd*, int (*callback)(void*), void *usercontext);
#endif
diff --git a/lib/listfile.c b/lib/listfile.c
index ca9eae2..b5bee54 100644
--- a/lib/listfile.c
+++ b/lib/listfile.c
@@ -424,7 +424,7 @@ get_link_name_at (const char *name, int dir_fd, char *relname)
args.result = NULL;
args.name = name;
args.relname = relname;
- if (0 == run_in_dir(dir_fd, get_link_name_cb, &args))
+ if (0 == run_in_dirfd (dir_fd, get_link_name_cb, &args))
return args.result;
else
return NULL;

View File

@ -0,0 +1,107 @@
ChangeLog | 10 ++++++++++
NEWS | 15 +++++++++++++++
find/ftsfind.c | 37 +++++++++++++++++++------------------
3 files changed, 44 insertions(+), 18 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index fefc1b8..98d7962 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
2010-04-10 James Youngman <jay@gnu.org>
+ Fix Savannah bug #19593, -execdir .... {} + has suboptimal performance
+ * find/ftsfind.c (consider_visiting): Don't call
+ complete_pending_execdirs for every file we visit.
+ (find): Instead, call complete_pending_execdirs every time we
+ see a file which isn't at the same nesting level as the previous
+ file we saw. This is an improvement but not optimal (since
+ descending into a subdirectory will cause us to issue an exec
+ before we've finished with the current directory).
+ * NEWS: Mention this change.
+
Exec predicates now store which directory they want to run in.
* lib/dircallback.c (run_in_dirfd): New name for old run_in_dir
function.
diff --git a/NEWS b/NEWS
index 6b8b725..569ff51 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,20 @@
GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
+* Major changes in release 4.4.3-git, YYYY-MM-DD
+
+** Bug Fixes
+
+#19593: -execdir .... {} + has suboptimal performance (see below)
+
+** Performance changes
+
+The find program will once again build argument lists longer than 1
+with "-execdir ...+". The upper limit of 1 argument for execdir was
+introduced as a workaround in findutils-4.3.4. The limit is now
+removed, but find still does not issue the maximum possible number of
+arguments, since an exec will occur each time find encounters a
+subdirectory (if at least one argument is pending).
+
* Major changes in release 4.4.2, 2009-11-26
** Functional Enhancements to find
diff --git a/find/ftsfind.c b/find/ftsfind.c
index 9945abd..3c9ae1d 100644
--- a/find/ftsfind.c
+++ b/find/ftsfind.c
@@ -524,24 +524,6 @@ consider_visiting(FTS *p, FTSENT *ent)
visit(p, ent, &statbuf);
}
- /* XXX: if we allow a build-up of pending arguments for "-execdir foo {} +"
- * we need to execute them in the same directory as we found the item.
- * If we are trying to do "find a -execdir echo {} +", we will need to
- * echo
- * a while in the original working directory
- * b while in a
- * c while in b (just before leaving b)
- *
- * These restrictions are hard to satisfy while using fts(). The reason is
- * that it doesn't tell us just before we leave a directory. For the moment,
- * we punt and don't allow the arguments to build up.
- */
- if (state.execdirs_outstanding)
- {
- show_outstanding_execdirs(stderr);
- complete_pending_execdirs ();
- }
-
if (ent->fts_info == FTS_DP)
{
/* we're leaving a directory. */
@@ -591,8 +573,27 @@ find(char *arg)
}
else
{
+ int level = INT_MIN;
+
while ( (ent=fts_read(p)) != NULL )
{
+ if (state.execdirs_outstanding)
+ {
+ /* If we changed level, perform any outstanding
+ * execdirs. If we see a sequence of directory entries
+ * like this: fffdfffdfff, we could build a command line
+ * of 9 files, but this simple-minded implementation
+ * builds a command line for only 3 files at a time
+ * (since fts descends into the directories).
+ */
+ if ((int)ent->fts_level != level)
+ {
+ show_outstanding_execdirs (stderr);
+ complete_pending_execdirs ();
+ }
+ }
+ level = (int)ent->fts_level;
+
state.have_stat = false;
state.have_type = false;
state.type = 0;

View File

@ -0,0 +1,277 @@
ChangeLog | 21 +++++++++
NEWS | 2 +
find/pred.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
3 files changed, 132 insertions(+), 24 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 98d7962..8e5d0ce 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2010-04-11 James Youngman <jay@gnu.org>
+
+ Fix Savannah bug #27563, -L breaks -execdir.
+ * find/pred.c (mdir_name): New function, taken from newer gnulib.
+ (initialise_wd_for_exec): New function, factoring out part of the body
+ of record_exec_dir.
+ (record_exec_dir): If state.rel_pathname contains a /, extract the
+ directory part and initialise execp->wd_for_exec to point at that
+ directory.
+ (impl_pred_exec): Rename new_impl_pred_exec to impl_pred_exec.
+ Drop the prefix and pfxlen parameters. Compute the base name of
+ the target and pass that to the bc_push_arg function instead of
+ state.rel_pathname. Deal with state.rel_pathname being an
+ absolute path (e.g. find / -execdir...). Introduce a new
+ variable, result, allowing us to free the buffer used for the base
+ name in the return path.
+ (pred_exec): Don't pass the prefix and the prefix length any more.
+ (pred_execdir): Likewise.
+ (pred_ok): Likewise.
+ (pred_okdir): Likewise.
+
2010-04-10 James Youngman <jay@gnu.org>
Fix Savannah bug #19593, -execdir .... {} + has suboptimal performance
diff --git a/NEWS b/NEWS
index 569ff51..c8eb0bc 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
** Bug Fixes
+#27563: -L breaks -execdir
+
#19593: -execdir .... {} + has suboptimal performance (see below)
** Performance changes
diff --git a/find/pred.c b/find/pred.c
index d057d48..cf25184 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -504,6 +504,57 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_
}
+/* In general, we can't use the builtin `dirname' function if available,
+ since it has different meanings in different environments.
+ In some environments the builtin `dirname' modifies its argument.
+
+ Return the leading directories part of FILE, allocated with malloc.
+ Works properly even if there are trailing slashes (by effectively
+ ignoring them). Return NULL on failure.
+
+ If lstat (FILE) would succeed, then { chdir (dir_name (FILE));
+ lstat (base_name (FILE)); } will access the same file. Likewise,
+ if the sequence { chdir (dir_name (FILE));
+ rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE
+ to "foo" in the same directory FILE was in. */
+
+static char *
+mdir_name (char const *file)
+{
+ size_t length = dir_len (file);
+ bool append_dot = (length == 0
+ || (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
+ && length == FILE_SYSTEM_PREFIX_LEN (file)
+ && file[2] != '\0' && ! ISSLASH (file[2])));
+ char *dir = malloc (length + append_dot + 1);
+ if (!dir)
+ return NULL;
+ memcpy (dir, file, length);
+ if (append_dot)
+ dir[length++] = '.';
+ dir[length] = '\0';
+ return dir;
+}
+
+
+/* Initialise exec->wd_for_exec.
+
+ We save in exec->wd_for_exec the directory whose path relative to
+ cwd_df is dir.
+ */
+static boolean
+initialise_wd_for_exec (struct exec_val *execp, int cwd_fd, const char *dir)
+{
+ execp->wd_for_exec = xmalloc (sizeof (*execp->wd_for_exec));
+ execp->wd_for_exec->name = NULL;
+ execp->wd_for_exec->desc = openat (cwd_fd, dir, O_RDONLY);
+ if (execp->wd_for_exec->desc < 0)
+ return false;
+
+ return true;
+}
+
+
static boolean
record_exec_dir (struct exec_val *execp)
{
@@ -514,29 +565,46 @@ record_exec_dir (struct exec_val *execp)
be -execdir foo {} \; (i.e. not multiple). */
assert (!execp->state.todo);
- /* Record the WD. */
- execp->wd_for_exec = xmalloc (sizeof (*execp->wd_for_exec));
- execp->wd_for_exec->name = NULL;
- execp->wd_for_exec->desc = openat (state.cwd_dir_fd, ".", O_RDONLY);
- if (execp->wd_for_exec->desc < 0)
- return false;
+ /* Record the WD. If we're using -L or fts chooses to do so for
+ any other reason, state.cwd_dir_fd may in fact not be the
+ directory containing the target file. When this happens,
+ rel_path will contain directory components (since it is the
+ path from state.cwd_dir_fd to the target file).
+
+ We deal with this by extracting any directory part and using
+ that to adjust what goes into execp->wd_for_exec.
+ */
+ if (strchr (state.rel_pathname, '/'))
+ {
+ char *dir = mdir_name (state.rel_pathname);
+ bool result = initialise_wd_for_exec (execp, state.cwd_dir_fd, dir);
+ free (dir);
+ return result;
+ }
+ else
+ {
+ return initialise_wd_for_exec (execp, state.cwd_dir_fd, ".");
+ }
}
return true;
}
static boolean
-new_impl_pred_exec (const char *pathname,
- struct stat *stat_buf,
- struct predicate *pred_ptr,
- const char *prefix, size_t pfxlen)
+impl_pred_exec (const char *pathname,
+ struct stat *stat_buf,
+ struct predicate *pred_ptr)
{
struct exec_val *execp = &pred_ptr->args.exec_vec;
- size_t len = strlen(pathname);
+ char *target;
+ bool result;
+ const bool local = is_exec_in_local_dir (pred_ptr->pred_func);
+ char *prefix;
+ size_t pfxlen;
(void) stat_buf;
- if (is_exec_in_local_dir (pred_ptr->pred_func))
+ if (local)
{
/* For -execdir/-okdir predicates, the parser did not fill in
the wd_for_exec member of sturct exec_val. So for those
@@ -550,6 +618,18 @@ new_impl_pred_exec (const char *pathname,
safely_quote_err_filename (0, pathname));
/*NOTREACHED*/
}
+ target = base_name (state.rel_pathname);
+ if ('/' == target[0])
+ {
+ /* find / execdir ls -d {} \; */
+ prefix = NULL;
+ pfxlen = 0;
+ }
+ else
+ {
+ prefix = "./";
+ pfxlen = 2u;
+ }
}
else
{
@@ -559,6 +639,9 @@ new_impl_pred_exec (const char *pathname,
working directory.
*/
assert (execp->wd_for_exec == initial_wd);
+ target = (char *) pathname;
+ prefix = NULL;
+ pfxlen = 0u;
}
if (execp->multiple)
@@ -569,7 +652,7 @@ new_impl_pred_exec (const char *pathname,
*/
bc_push_arg(&execp->ctl,
&execp->state,
- pathname, len+1,
+ target, strlen (target)+1,
prefix, pfxlen,
0);
@@ -579,7 +662,7 @@ new_impl_pred_exec (const char *pathname,
/* POSIX: If the primary expression is punctuated by a plus
* sign, the primary shall always evaluate as true
*/
- return true;
+ result = true;
}
else
{
@@ -592,30 +675,34 @@ new_impl_pred_exec (const char *pathname,
execp->replace_vec[i],
strlen(execp->replace_vec[i]),
prefix, pfxlen,
- pathname, len,
+ target, strlen (target),
0);
}
/* Actually invoke the command. */
- return execp->ctl.exec_callback(&execp->ctl,
+ result = execp->ctl.exec_callback(&execp->ctl,
&execp->state);
}
+ if (target != pathname)
+ {
+ assert (local);
+ free (target);
+ }
+ return result;
}
boolean
pred_exec (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
- return new_impl_pred_exec(pathname, stat_buf, pred_ptr, NULL, 0);
+ return impl_pred_exec(pathname, stat_buf, pred_ptr);
}
boolean
pred_execdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
- const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
(void) &pathname;
- return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
- prefix, (prefix ? 2 : 0));
+ return impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr);
}
boolean
@@ -1506,7 +1593,7 @@ boolean
pred_ok (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
- return new_impl_pred_exec (pathname, stat_buf, pred_ptr, NULL, 0);
+ return impl_pred_exec (pathname, stat_buf, pred_ptr);
else
return false;
}
@@ -1514,10 +1601,8 @@ pred_ok (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr
boolean
pred_okdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
- const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
- return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
- prefix, (prefix ? 2 : 0));
+ return impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr);
else
return false;
}

View File

@ -0,0 +1,103 @@
ChangeLog | 11 +++++++++++
find/testsuite/Makefile.am | 4 ++++
find/testsuite/find.gnu/sv-bug-27563-execdir.exp | 6 ++++++
find/testsuite/find.gnu/sv-bug-27563-execdir.xo | 1 +
find/testsuite/find.posix/sv-bug-27563-exec.exp | 6 ++++++
find/testsuite/find.posix/sv-bug-27563-exec.xo | 1 +
6 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 8e5d0ce..5702e66 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
2010-04-11 James Youngman <jay@gnu.org>
+ Add a test case for Savannah bug 27563 (-L breaks -execdir).
+ * find/testsuite/Makefile.am (EXTRA_DIST_EXP): Add
+ find.gnu/sv-bug-27563-execdir.exp and
+ find.posix/sv-bug-27563-exec.exp.
+ (EXTRA_DIST_XO): Add find.gnu/sv-bug-27563-execdir.xo and
+ find.posix/sv-bug-27563-exec.xo.
+ * find/testsuite/find.gnu/sv-bug-27563-execdir.exp: New test.
+ * find/testsuite/find.posix/sv-bug-27563-exec.exp: New test.
+ * find/testsuite/find.gnu/sv-bug-27563-execdir.xo: Expected output.
+ * find/testsuite/find.posix/sv-bug-27563-exec.xo: Expected output.
+
Fix Savannah bug #27563, -L breaks -execdir.
* find/pred.c (mdir_name): New function, taken from newer gnulib.
(initialise_wd_for_exec): New function, factoring out part of the body
diff --git a/find/testsuite/Makefile.am b/find/testsuite/Makefile.am
index 1447132..aa32d4b 100644
--- a/find/testsuite/Makefile.am
+++ b/find/testsuite/Makefile.am
@@ -63,6 +63,7 @@ find.gnu/samefile-same.xo \
find.gnu/samefile-symlink.xo \
find.gnu/sv-bug-17782.xo \
find.gnu/sv-bug-18222.xo \
+find.gnu/sv-bug-27563-execdir.xo \
find.gnu/true.xo \
find.gnu/wholename.xo \
find.gnu/xtype-symlink.xo \
@@ -78,6 +79,7 @@ find.posix/grouping.xo \
find.posix/links.xo \
find.posix/sv-bug-11175.xo \
find.posix/sv-bug-12181.xo \
+find.posix/sv-bug-27563-exec.xo \
find.posix/depth1.xo \
find.posix/mtime0.xo \
find.posix/sizes.xo \
@@ -179,6 +181,7 @@ find.gnu/sv-bug-17490.exp \
find.gnu/sv-bug-17782.exp \
find.gnu/sv-bug-18222.exp \
find.gnu/sv-bug-24169.exp \
+find.gnu/sv-bug-27563-execdir.exp \
find.gnu/quit.exp \
find.gnu/used-invarg.exp \
find.gnu/used-missing.exp \
@@ -199,6 +202,7 @@ find.posix/links.exp \
find.posix/mtime0.exp \
find.posix/sv-bug-11175.exp \
find.posix/sv-bug-12181.exp \
+find.posix/sv-bug-27563-exec.exp \
find.posix/depth1.exp \
find.posix/sizes.exp \
find.posix/name.exp \
diff --git a/find/testsuite/find.gnu/sv-bug-27563-execdir.exp b/find/testsuite/find.gnu/sv-bug-27563-execdir.exp
new file mode 100644
index 0000000..c67fc88
--- /dev/null
+++ b/find/testsuite/find.gnu/sv-bug-27563-execdir.exp
@@ -0,0 +1,6 @@
+# tests for Savannah bug 27563 (result of find -L -exec ls {} \;)
+exec rm -rf tmp
+exec mkdir tmp
+exec touch tmp/yyyy
+find_start p {-L tmp -name yyyy -execdir ls \{\} \; }
+exec rm -rf tmp
diff --git a/find/testsuite/find.gnu/sv-bug-27563-execdir.xo b/find/testsuite/find.gnu/sv-bug-27563-execdir.xo
new file mode 100644
index 0000000..285260b
--- /dev/null
+++ b/find/testsuite/find.gnu/sv-bug-27563-execdir.xo
@@ -0,0 +1 @@
+./yyyy
diff --git a/find/testsuite/find.posix/sv-bug-27563-exec.exp b/find/testsuite/find.posix/sv-bug-27563-exec.exp
new file mode 100644
index 0000000..d18b0c1
--- /dev/null
+++ b/find/testsuite/find.posix/sv-bug-27563-exec.exp
@@ -0,0 +1,6 @@
+# tests for Savannah bug 27563 (result of find -L -exec ls {} \;)
+exec rm -rf tmp
+exec mkdir tmp
+exec touch tmp/yyyy
+find_start p {-L tmp -name yyyy -exec ls \{\} \; }
+exec rm -rf tmp
diff --git a/find/testsuite/find.posix/sv-bug-27563-exec.xo b/find/testsuite/find.posix/sv-bug-27563-exec.xo
new file mode 100644
index 0000000..cd491dd
--- /dev/null
+++ b/find/testsuite/find.posix/sv-bug-27563-exec.xo
@@ -0,0 +1 @@
+tmp/yyyy

View File

@ -0,0 +1,70 @@
ChangeLog | 9 +++++++++
NEWS | 2 ++
find/pred.c | 10 ++++------
find/testsuite/find.gnu/execdir-multiple.exp | 1 +
4 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 5702e66..97b1b7c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2010-05-24 Kamil Dudka <kdudka@redhat.com>
+
+ Fix Savannah bug #29949, -execdir does not change working directory
+ * find/pred.c (record_exec_dir): Do not throw the execdir when not
+ working in the cumulative mode.
+ * find/testsuite/find.gnu/execdir-multiple.exp: Add a test-case for
+ the bug #29949.
+ * NEWS: Mention this bugfix.
+
2010-04-11 James Youngman <jay@gnu.org>
Add a test case for Savannah bug 27563 (-L breaks -execdir).
diff --git a/NEWS b/NEWS
index c8eb0bc..2ba2111 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
** Bug Fixes
+#29949: find -execdir does not change working directory
+
#27563: -L breaks -execdir
#19593: -execdir .... {} + has suboptimal performance (see below)
diff --git a/find/pred.c b/find/pred.c
index cf25184..cac74d1 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -558,13 +558,11 @@ initialise_wd_for_exec (struct exec_val *execp, int cwd_fd, const char *dir)
static boolean
record_exec_dir (struct exec_val *execp)
{
- if (!execp->wd_for_exec)
+ /* working directory not already known, so must be a *dir variant,
+ and this must be the first arg we added. However, this may
+ be -execdir foo {} \; (i.e. not multiple). */
+ if (!execp->state.todo)
{
- /* working directory not already known, so must be a *dir variant,
- and this must be the first arg we added. However, this may
- be -execdir foo {} \; (i.e. not multiple). */
- assert (!execp->state.todo);
-
/* Record the WD. If we're using -L or fts chooses to do so for
any other reason, state.cwd_dir_fd may in fact not be the
directory containing the target file. When this happens,
diff --git a/find/testsuite/find.gnu/execdir-multiple.exp b/find/testsuite/find.gnu/execdir-multiple.exp
index 6d4bd66..495b93b 100644
--- a/find/testsuite/find.gnu/execdir-multiple.exp
+++ b/find/testsuite/find.gnu/execdir-multiple.exp
@@ -49,6 +49,7 @@ if { [ safe_path ] } {
}
set SKIP_OLD 1
+ find_start p {tmp -type f -empty -execdir sh ./runme \{\} \; } ""
find_start p {tmp -type f -empty -execdir sh ./runme \{\} + } ""
set SKIP_OLD 0
exec rm -rf tmp

View File

@ -1,7 +1,7 @@
Summary: The GNU versions of find utilities (find and xargs)
Name: findutils
Version: 4.4.2
Release: 6%{?dist}
Release: 8%{?dist}
Epoch: 1
License: GPLv3+
Group: Applications/File
@ -30,6 +30,24 @@ Patch5: findutils-4.4.2-selinux.patch
# the following patch will be no longer needed
Patch6: findutils-4.4.2-selinux-gnulib.patch
# backport of upstream commit 41896c730790d6afa9feabc867aaa14198873a76
Patch7: findutils-4.5.8-0001-41896c7.patch
# backport of upstream commit 7dc70069a3095a42eadb22b24cb9260c243aff8f
Patch8: findutils-4.5.8-0002-7dc7006.patch
# backport of upstream commit 27a7e451b84808408bf23b3f8a0363acb36e1a96
Patch9: findutils-4.5.8-0003-27a7e45.patch
# backport of upstream commit e1d0a991e96ee164d74579efc027b09336e50c79
Patch10: findutils-4.5.8-0004-e1d0a99.patch
# backport of upstream commit a1f54022d1913a92ccb728211127d5c238397eb6
Patch11: findutils-4.5.8-0005-a1f5402.patch
# Fix Savannah bug #29949, -execdir does not change working directory
Patch12: findutils-4.5.8-0006-Fix-Savannah-bug-29949.patch
Requires(post): /sbin/install-info
Requires(preun): /sbin/install-info
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@ -56,6 +74,13 @@ useful for finding things on your system.
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
autoreconf
%build
@ -112,11 +137,18 @@ rm -rf $RPM_BUILD_ROOT
%{_infodir}/find-maint.info.gz
%changelog
* Tue Jun 01 2010 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-8
- fix Savannah bug #29949
* Mon May 10 2010 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-7
- backport of patches for upstream bugs #19593 and #27563 (rhbz #493143)
- mention -xautofs in the output of --help (#590166)
* Thu Nov 26 2009 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-6
- update SELinux patch to the latest upstream (gnulib based) version
* Wed Nov 18 2009 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-5
- do not fail silently on a remount during traverse (#501848)
- do not fail silently on a remount during traverse (#538536)
* Tue Oct 20 2009 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-4
- make it possible to recognize an autofs filesystem by find