From dca3bdf817b06681811791e7a4592167557f82ff Mon Sep 17 00:00:00 2001 From: jay Date: Sat, 8 Jan 2005 14:12:51 +0000 Subject: [PATCH] We now understand but do not implement -execdir (a *BSD invention, and a very useful security enhancement) and -okdir (the obvious companion to it) --- find/defs.h | 2 ++ find/find.c | 37 +++++++++++++++++++++++++++- find/parser.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- find/pred.c | 27 +++++++++++++++++++-- 4 files changed, 132 insertions(+), 12 deletions(-) diff --git a/find/defs.h b/find/defs.h index 11f3331..4b35142 100644 --- a/find/defs.h +++ b/find/defs.h @@ -373,6 +373,7 @@ boolean pred_ctime PARAMS((char *pathname, struct stat *stat_buf, struct predica boolean pred_delete PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_empty PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_exec PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); +boolean pred_execdir PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_false PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_fls PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_fprint PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); @@ -396,6 +397,7 @@ boolean pred_newer PARAMS((char *pathname, struct stat *stat_buf, struct predica boolean pred_nogroup PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_nouser PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_ok PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); +boolean pred_okdir PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_open PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_or PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); boolean pred_path PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)); diff --git a/find/find.c b/find/find.c index 6ca30a4..f3dfb5f 100644 --- a/find/find.c +++ b/find/find.c @@ -280,7 +280,7 @@ main (int argc, char **argv) #endif bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); - atexit(close_stdout); + atexit (close_stdout); if (isatty(0)) { @@ -1115,6 +1115,33 @@ process_path (char *pathname, char *name, boolean leaf, char *parent) return 1; } +/* Examine the predicate list for instances of -execdir or -okdir + * which have been terminated with '+' (build argument list) rather + * than ';' (singles only). If there are any, run them (this will + * have no effect if there are no arguments waiting. + */ +static void +complete_pending_execdirs(void) +{ + struct predicate *p; + for (p=eval_tree; p; p=p->pred_next) + { + if (p->pred_func == pred_execdir + || p->pred_func == pred_okdir) + { + /* It's an exec-family predicate. p->args.exec_val is valid. */ + if (p->args.exec_vec.multiple) + { + /* This one was terminated by '+' + * and so might have some left... Run it. + * Set state.exit_status if there are any problems. + */ + } + } + } +} + + /* Scan directory PATHNAME and recurse through process_path for each entry. PATHLEN is the length of PATHNAME. @@ -1256,6 +1283,14 @@ process_dir (char *pathname, char *name, int pathlen, struct stat *statp, char * process_path (cur_path, cur_name, false, pathname); state.curdepth--; } + + + /* We're about to leave the directory. If there are any -execdir argument lists + * which have been built but have not yet been processed, do them now + * because they must be done in the same directory. + */ + complete_pending_execdirs(); + #if USE_SAFE_CHDIR if (strcmp (name, ".")) { diff --git a/find/parser.c b/find/parser.c index 1420658..9007aab 100644 --- a/find/parser.c +++ b/find/parser.c @@ -73,6 +73,7 @@ static boolean parse_d PARAMS((char *argv[], int *arg_ptr)); static boolean parse_depth PARAMS((char *argv[], int *arg_ptr)); static boolean parse_empty PARAMS((char *argv[], int *arg_ptr)); static boolean parse_exec PARAMS((char *argv[], int *arg_ptr)); +static boolean parse_execdir PARAMS((char *argv[], int *arg_ptr)); static boolean parse_false PARAMS((char *argv[], int *arg_ptr)); static boolean parse_fls PARAMS((char *argv[], int *arg_ptr)); static boolean parse_fprintf PARAMS((char *argv[], int *arg_ptr)); @@ -104,6 +105,7 @@ static boolean parse_nogroup PARAMS((char *argv[], int *arg_ptr)); static boolean parse_nouser PARAMS((char *argv[], int *arg_ptr)); static boolean parse_nowarn PARAMS((char *argv[], int *arg_ptr)); static boolean parse_ok PARAMS((char *argv[], int *arg_ptr)); +static boolean parse_okdir PARAMS((char *argv[], int *arg_ptr)); boolean parse_open PARAMS((char *argv[], int *arg_ptr)); static boolean parse_or PARAMS((char *argv[], int *arg_ptr)); static boolean parse_path PARAMS((char *argv[], int *arg_ptr)); @@ -194,6 +196,7 @@ static struct parser_table const parse_table[] = {ARG_OPTION, "depth", parse_depth}, {ARG_TEST, "empty", parse_empty}, /* GNU */ {ARG_ACTION, "exec", parse_exec}, + {ARG_ACTION, "execdir", parse_execdir}, /* *BSD, GNU */ {ARG_TEST, "false", parse_false}, /* GNU */ {ARG_ACTION, "fls", parse_fls}, /* GNU */ {ARG_POSITIONAL_OPTION, "follow", parse_follow}, /* GNU, Unix */ @@ -233,6 +236,7 @@ static struct parser_table const parse_table[] = {ARG_PUNCTUATION, "o", parse_or}, {ARG_PUNCTUATION, "or", parse_or}, /* GNU */ {ARG_ACTION, "ok", parse_ok}, + {ARG_ACTION, "okdir", parse_okdir}, /* GNU (-execdir is BSD) */ {ARG_TEST, "path", parse_path}, /* GNU, HP-UX, GNU prefers wholename */ {ARG_TEST, "perm", parse_perm}, {ARG_ACTION, "print", parse_print}, @@ -564,6 +568,12 @@ parse_exec (char **argv, int *arg_ptr) } static boolean +parse_execdir (char **argv, int *arg_ptr) +{ + return (insert_exec_ok (pred_execdir, argv, arg_ptr)); +} + +static boolean parse_false (char **argv, int *arg_ptr) { struct predicate *our_pred; @@ -1101,6 +1111,12 @@ parse_ok (char **argv, int *arg_ptr) return (insert_exec_ok (pred_ok, argv, arg_ptr)); } +static boolean +parse_okdir (char **argv, int *arg_ptr) +{ + return (insert_exec_ok (pred_okdir, argv, arg_ptr)); +} + boolean parse_open (char **argv, int *arg_ptr) { @@ -1823,20 +1839,38 @@ insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr) int num_paths; /* Number of args with path replacements. */ int path_pos; /* Index in array of path replacements. */ int vec_pos; /* Index in array of args. */ + int saw_braces; /* True if previous arg was '{}'. */ + int plusflag; /* Saw '+' */ + struct predicate *our_pred; struct exec_val *execp; /* Pointer for efficiency. */ if ((argv == NULL) || (argv[*arg_ptr] == NULL)) return (false); + plusflag = 0; + /* Count the number of args with path replacements, up until the ';'. */ start = *arg_ptr; - for (end = start, num_paths = 0; + for (end = start, num_paths = 0, saw_braces=0; (argv[end] != NULL) && ((argv[end][0] != ';') || (argv[end][1] != '\0')); end++) - if (strstr (argv[end], "{}")) - num_paths++; + { + if (argv[end][0] == '+' && argv[end][1] == 0 && saw_braces) + { + /* A '+' following '{}' is also a terminator. */ + plusflag = 1; + break; + } + + saw_braces = 0; + if (strstr (argv[end], "{}")) + { + saw_braces = 1; + num_paths++; + } + } /* Fail if no command given or no semicolon found. */ if ((end == start) || (argv[end] == NULL)) { @@ -1844,6 +1878,10 @@ insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr) return (false); } + if (plusflag) + error(1,0, "The \"-exec ...{} +\" action is not yet supported."); + + our_pred = insert_primary (func); our_pred->side_effects = true; our_pred->no_default_print = true; @@ -1851,21 +1889,43 @@ insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr) execp->paths = (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1)); execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1)); + execp->multiple = plusflag ? true : false; + /* Record the positions of all args, and the args with path replacements. */ - for (end = start, path_pos = vec_pos = 0; + for (end = start, path_pos = vec_pos = 0, saw_braces=0; (argv[end] != NULL) && ((argv[end][0] != ';') || (argv[end][1] != '\0')); end++) { register char *p; + + if ('+' == argv[end][0] && 0 == argv[end][1]) + { + if (saw_braces) + { + /* last arg was "{}" and this one is "+". + * this signals the end of the argument list. + */ + break; + } + else + { + /* This is just an "ordinary" "+". Pass it through. */ + } + } execp->paths[path_pos].count = 0; + saw_braces = 0; for (p = argv[end]; *p; ++p) - if (p[0] == '{' && p[1] == '}') - { - execp->paths[path_pos].count++; - ++p; - } + { + if (p[0] == '{' && p[1] == '}') + { + saw_braces = 1; + execp->paths[path_pos].count++; + ++p; + } + } + if (execp->paths[path_pos].count) { execp->paths[path_pos].offset = vec_pos; diff --git a/find/pred.c b/find/pred.c index bf124f6..147b690 100644 --- a/find/pred.c +++ b/find/pred.c @@ -164,6 +164,7 @@ struct pred_assoc pred_table[] = {pred_delete, "delete "}, {pred_empty, "empty "}, {pred_exec, "exec "}, + {pred_execdir, "execdir "}, {pred_false, "false "}, {pred_fprint, "fprint "}, {pred_fprint0, "fprint0 "}, @@ -186,6 +187,7 @@ struct pred_assoc pred_table[] = {pred_nogroup, "nogroup "}, {pred_nouser, "nouser "}, {pred_ok, "ok "}, + {pred_okdir, "okdir "}, {pred_open, "( "}, {pred_or, "or "}, {pred_path, "path "}, @@ -450,8 +452,8 @@ pred_empty (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) return (false); } -boolean -pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +static boolean +old_impl_pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { int i; int path_pos; @@ -492,6 +494,19 @@ pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) } boolean +pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +{ + return old_impl_pred_exec(pathname, stat_buf, pred_ptr); +} + +boolean +pred_execdir (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +{ + error(1, 0, "-execdir is not yet implemented."); + /* return old_impl_pred_exec(pathname, stat_buf, pred_ptr); */ +} + +boolean pred_false (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { (void) &pathname; @@ -1085,6 +1100,14 @@ pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) return (false); } + +boolean +pred_okdir (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +{ + error(1, 0, "-okdir is not yet implemented."); + return false; +} + boolean pred_open (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { -- 2.11.4.GIT