[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 1/2] Fix Savannah bug 27563 (-L breaks -execdir).
From: |
James Youngman |
Subject: |
[PATCH 1/2] Fix Savannah bug 27563 (-L breaks -execdir). |
Date: |
Sun, 11 Apr 2010 17:05:20 +0100 |
* find/pred.c (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.
Signed-off-by: James Youngman <address@hidden>
---
ChangeLog | 20 +++++++++++
find/pred.c | 108 +++++++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 99 insertions(+), 29 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index b19dcfa..28cab09 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2010-04-11 James Youngman <address@hidden>
+
+ Fix Savannah bug #27563, -L breaks -execdir.
+ * find/pred.c (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 <address@hidden>
Fix Savannah bug #19593, -execdir .... {} + has suboptimal performance
diff --git a/find/pred.c b/find/pred.c
index e2e8dfb..3173398 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -507,6 +507,24 @@ pred_empty (const char *pathname, struct stat *stat_buf,
struct predicate *pred_
}
+/* Initialise exec->wd_for_exec.
+
+ We save in exec->wd_for_exec the directory whose path relative to
+ cwd_df is dir.
+ */
+static bool
+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;
+ set_cloexec_flag (execp->wd_for_exec->desc, true);
+ return true;
+}
+
+
static bool
record_exec_dir (struct exec_val *execp)
{
@@ -517,30 +535,45 @@ 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;
- set_cloexec_flag (execp->wd_for_exec->desc, true);
+ /* 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 bool
-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
@@ -554,15 +587,30 @@ 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
{
- /* For the others (-exec, -ok), the parder should
+ /* 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);
+ target = pathname;
+ prefix = NULL;
+ pfxlen = 0u;
}
if (execp->multiple)
@@ -573,7 +621,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);
@@ -583,7 +631,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
{
@@ -596,7 +644,7 @@ new_impl_pred_exec (const char *pathname,
execp->replace_vec[i],
strlen (execp->replace_vec[i]),
prefix, pfxlen,
- pathname, len,
+ target, strlen (target),
0);
}
@@ -605,31 +653,35 @@ new_impl_pred_exec (const char *pathname,
if (WIFEXITED(execp->last_child_status))
{
if (0 == WEXITSTATUS(execp->last_child_status))
- return true; /* The child succeeded. */
+ result = true; /* The child succeeded. */
else
- return false;
+ result = false;
}
else
{
- return false;
+ result = false;
}
}
+ if (target != pathname)
+ {
+ assert (local);
+ free (target);
+ }
+ return result;
}
bool
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);
}
bool
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);
}
bool
@@ -1530,7 +1582,7 @@ bool
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;
}
@@ -1538,10 +1590,8 @@ pred_ok (const char *pathname, struct stat *stat_buf,
struct predicate *pred_ptr
bool
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.7.0