On Tue May 18 2010 00:41:00 Kamil Dudka wrote:
> Sorry for not catching this. Unfortunately 'make distcheck' does not work
> by me without the patches either:
>
> $ git checkout a242875ae63167ee29c3f626741c56266be3bc92
> $ git clean -xfd
> $ ./import-gnulib.sh
> $ ./configure
> $ make distcheck
Perhaps my mistake as well. It seems like I have to run 'make' before
'make distcheck' to get it passed.
> > (after performing the obvious fixup to the NEWS file)
>
> So the NEWS entries should be appended to 4.4.3-git, right?
>
> > Could you take another look, please?
The revisited patches are attached. I've tried 'make distcheck' after
application of each individual patch. All of them passed. Please let
me know if there are still some outstanding issues.
Kamil
[0001-Add-a-test-which-checks-CWD-for-find-execdir.patch]
From b704cdeddf0a4bf193416df65848300b128db5ef Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@...>
Date: Tue, 18 May 2010 12:49:27 +0200
Subject: [PATCH 1/5] 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.
---
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(-)
create mode 100644 find/testsuite/find.gnu/execdir-multiple.exp
create mode 100644 find/testsuite/find.gnu/execdir-multiple.xo
create mode 100644 find/testsuite/find.gnu/execdir-pwd1.exp
diff --git a/ChangeLog b/ChangeLog
index 3c9f62e..460ec1c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2010-04-10 James Youngman <jay@...>
+
+ 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.
+
2010-04-06 James Youngman <jay@...>
* po/nl.po: Updated Dutch translation.
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
+}
--
1.6.6.1
[0002-Exec-predicates-now-store-which-directory-they-want-.patch]
From a2f7afcd9d4942323ca46cc2c3c048188b4d8092 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@...>
Date: Tue, 18 May 2010 12:58:34 +0200
Subject: [PATCH 2/5] 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.
---
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 460ec1c..e0a4573 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,88 @@
2010-04-10 James Youngman <jay@...>
+ 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 4539fd9..6115b3c 100644
--- a/find/defs.h
+++ b/find/defs.h
@@ -195,9 +195,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
@@ -335,8 +334,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);
@@ -654,10 +654,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 b59d896..cc54c9f 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)
{
@@ -560,7 +533,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)
@@ -664,6 +637,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.
*/
@@ -713,24 +688,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 08758ee..4344c56 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -177,7 +177,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,
@@ -844,13 +843,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
@@ -1734,13 +1733,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
@@ -3083,11 +3082,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 */
@@ -3108,6 +3106,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))
{
@@ -3127,13 +3126,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;
@@ -3286,17 +3286,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 b1f48a0..3d74f7a 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"
#if ENABLE_NLS
# include <libintl.h>
@@ -499,8 +500,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)
@@ -509,7 +532,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.
@@ -555,8 +603,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
@@ -564,8 +611,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));
}
@@ -1433,8 +1479,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;
}
@@ -1444,8 +1489,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;
@@ -1546,7 +1590,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);
}
@@ -1865,7 +1909,7 @@ pred_xtype (const char *pathname, struct stat *stat_buf, struct predicate *pred_
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)
@@ -1901,17 +1945,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;
}
@@ -1927,13 +1964,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);
@@ -1954,8 +1984,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 cc9a3eb..56bf488 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>
@@ -290,6 +293,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
@@ -297,14 +320,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))
{
@@ -319,25 +342,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
@@ -373,6 +395,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,
@@ -432,9 +485,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()
@@ -970,15 +1025,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
*
*/
@@ -1004,6 +1050,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;
--
1.6.6.1
[0003-Fix-Savannah-bug-19593-execdir-.-has-suboptimal-perf.patch]
From 1f0f557cdccdfcdd671b90bcdaaca7c686df19cf Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@...>
Date: Tue, 18 May 2010 13:03:48 +0200
Subject: [PATCH 3/5] 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.
---
ChangeLog | 10 ++++++++++
NEWS | 11 +++++++++++
find/ftsfind.c | 37 +++++++++++++++++++------------------
3 files changed, 40 insertions(+), 18 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index e0a4573..432a6bb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
2010-04-10 James Youngman <jay@...>
+ 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 853fade..b46fdd3 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,17 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
-uid, -used, -atime, -mtime, -ctime.
#27017: find -D opt / -fstype ext3 -print , -quit coredumps
+#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).
+
** Translations
Updated the Dutch, Polish, French, Czech, Indonesian, Chinese
diff --git a/find/ftsfind.c b/find/ftsfind.c
index cc54c9f..26392ce 100644
--- a/find/ftsfind.c
+++ b/find/ftsfind.c
@@ -518,24 +518,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. */
@@ -585,8 +567,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;
--
1.6.6.1
[0004-Fix-Savannah-bug-27563-L-breaks-execdir.patch]
From d4d5d5d2075882a109bb6df8f124a80a21765473 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@...>
Date: Tue, 18 May 2010 13:07:45 +0200
Subject: [PATCH 4/5] 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.
---
ChangeLog | 21 +++++++++
NEWS | 3 +
find/pred.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
3 files changed, 133 insertions(+), 24 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 432a6bb..ac10eb9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2010-04-11 James Youngman <jay@...>
+
+ 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@...>
Fix Savannah bug #19593, -execdir .... {} + has suboptimal performance
diff --git a/NEWS b/NEWS
index b46fdd3..a57ca21 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,9 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
#28824: Corrected error message for "-ctime x".
Likewise for -gid, -inum, -links, -mmin, -cmin, -amin,
-uid, -used, -atime, -mtime, -ctime.
+
+#27563: -L breaks -execdir
+
#27017: find -D opt / -fstype ext3 -print , -quit coredumps
#19593: -execdir .... {} + has suboptimal performance (see below)
diff --git a/find/pred.c b/find/pred.c
index 3d74f7a..d98c4dc 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -501,6 +501,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)
{
@@ -511,29 +562,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
@@ -547,6 +615,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
{
@@ -556,6 +636,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)
@@ -566,7 +649,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);
@@ -576,7 +659,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
{
@@ -589,30 +672,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
@@ -1479,7 +1566,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;
}
@@ -1487,10 +1574,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;
}
--
1.6.6.1
[0005-Add-a-test-case-for-Savannah-bug-27563-L-breaks-exec.patch]
From d9433317aee2e9cca5339b9f8eff2b8f4b43a166 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <kdudka@...>
Date: Tue, 18 May 2010 13:10:10 +0200
Subject: [PATCH 5/5] 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.
---
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(-)
create mode 100644 find/testsuite/find.gnu/sv-bug-27563-execdir.exp
create mode 100644 find/testsuite/find.gnu/sv-bug-27563-execdir.xo
create mode 100644 find/testsuite/find.posix/sv-bug-27563-exec.exp
create mode 100644 find/testsuite/find.posix/sv-bug-27563-exec.xo
diff --git a/ChangeLog b/ChangeLog
index ac10eb9..0143974 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
2010-04-11 James Youngman <jay@...>
+ 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
--
1.6.6.1
_______________________________________________
Findutils-patches mailing list
Findutils-patches@...
http://lists.gnu.org/mailman/listinfo/findutils-patches