From 520535d0b39b60764767fc556d7d059a8b9091c2 Mon Sep 17 00:00:00 2001 From: Evan Gates Date: Fri, 6 Mar 2015 12:31:38 -0800 Subject: [PATCH] work on recurse 1) add loop detection to recurse 2) call the correct stat function in recurse instead of both stat and lstat 3) split out readdir loop into applydir useful for avoiding redundant stat calls and when extra logic is needed (as in find) 4) use applydir in find instead of doing it manually (still need to finish const propagation, hit a wall in my understanding) --- chgrp.c | 6 ++--- chmod.c | 6 ++--- chown.c | 6 ++--- cp.c | 2 +- find.c | 77 +++++++++++++++---------------------------------------- fs.h | 2 +- libutil/cp.c | 2 +- libutil/recurse.c | 44 ++++++++++++++++++++++--------- libutil/rm.c | 6 ++--- mv.c | 4 +-- rm.c | 4 +-- tar.c | 6 ++--- util.h | 12 ++++++++- 13 files changed, 85 insertions(+), 92 deletions(-) diff --git a/chgrp.c b/chgrp.c index 0ca2466..8b3ee65 100644 --- a/chgrp.c +++ b/chgrp.c @@ -15,14 +15,14 @@ static char *chownf_name = "chown"; static int (*chownf)(const char *, uid_t, gid_t) = chown; static void -chgrp(const char *path, int depth) +chgrp(const char *path, Rhist *hist) { if (chownf(path, st.st_uid, gid) < 0) { weprintf("%s %s:", chownf_name, path); status = 1; } if (Rflag) - recurse(path, chgrp, depth); + recurse(path, chgrp, hist); } static void @@ -76,7 +76,7 @@ main(int argc, char *argv[]) status = 1; continue; } - chgrp(*argv, 0); + chgrp(*argv, NULL); } return status; } diff --git a/chmod.c b/chmod.c index 2436721..7210944 100644 --- a/chmod.c +++ b/chmod.c @@ -9,7 +9,7 @@ static mode_t mask = 0; static int ret = 0; void -chmodr(const char *path, int depth) +chmodr(const char *path, Rhist *hist) { struct stat st; mode_t m; @@ -25,7 +25,7 @@ chmodr(const char *path, int depth) weprintf("chmod %s:", path); ret = 1; } else if (Rflag) - recurse(path, chmodr, depth); + recurse(path, chmodr, hist); } static void @@ -80,7 +80,7 @@ done: usage(); for (--argc, ++argv; *argv; argc--, argv++) - chmodr(*argv, 0); + chmodr(*argv, NULL); return ret; } diff --git a/chown.c b/chown.c index cd76f9c..0378d66 100644 --- a/chown.c +++ b/chown.c @@ -16,14 +16,14 @@ static char *chownf_name = "chown"; static int (*chownf)(const char *, uid_t, gid_t) = chown; static void -chownpwgr(const char *path, int depth) +chownpwgr(const char *path, Rhist *hist) { if (chownf(path, uid, gid) < 0) { weprintf("%s %s:", chownf_name, path); ret = 1; } if (rflag) - recurse(path, chownpwgr, depth); + recurse(path, chownpwgr, hist); } static void @@ -97,7 +97,7 @@ main(int argc, char *argv[]) } } for (; argc > 0; argc--, argv++) - chownpwgr(argv[0], 0); + chownpwgr(argv[0], NULL); return ret; } diff --git a/cp.c b/cp.c index 4bba1b5..6144e5c 100644 --- a/cp.c +++ b/cp.c @@ -1,8 +1,8 @@ /* See LICENSE file for copyright and license details. */ #include -#include "fs.h" #include "util.h" +#include "fs.h" static void usage(void) diff --git a/find.c b/find.c index b0f3e31..3db08f9 100644 --- a/find.c +++ b/find.c @@ -24,7 +24,7 @@ typedef union { /* Argument passed into a primary's function */ typedef struct { - char *path; + const char *path; struct stat *st; Extra extra; } Arg; @@ -69,7 +69,7 @@ typedef struct { } Permarg; typedef struct { - char ***braces; + const char ***braces; char **argv; } Okarg; @@ -88,7 +88,7 @@ typedef struct { typedef struct { union { struct { - char ***braces; /* NULL terminated list of pointers into argv where {} were */ + const char ***braces; /* NULL terminated list of pointers into argv where {} were */ } s; /* semicolon */ struct { size_t arglen; /* number of bytes in argv before files are added */ @@ -102,15 +102,6 @@ typedef struct { char isplus; /* -exec + instead of -exec ; */ } Execarg; -/* used to find loops while recursing through directory structure */ -typedef struct Findhist Findhist; -struct Findhist { - Findhist *next; - char *path; - dev_t dev; - ino_t ino; -}; - /* Primaries */ static int pri_name (Arg *arg); static int pri_path (Arg *arg); @@ -160,7 +151,7 @@ static Pri_info *find_primary(char *name); static Op_info *find_op(char *name); static void parse(int argc, char **argv); static int eval(Tok *tok, Arg *arg); -static void find(char *path, Findhist *hist); +static void find(const char *path, Rhist *hist); static void usage(void); /* for comparisons with Narg */ @@ -230,7 +221,9 @@ static struct { static int pri_name(Arg *arg) { - return !fnmatch((char *)arg->extra.p, basename(arg->path), 0); + char path[strlen(arg->path) + 1]; + strcpy(path, arg->path); + return !fnmatch((char *)arg->extra.p, basename(path), 0); } static int @@ -350,7 +343,8 @@ pri_exec(Arg *arg) int status; size_t len; pid_t pid; - char **sp, ***brace; + char **sp; + const char ***brace; Execarg *e = arg->extra.p; if (e->isplus) { @@ -410,7 +404,8 @@ pri_ok(Arg *arg) { int status; pid_t pid; - char ***brace, reply, buf[256]; + const char ***brace; + char reply, buf[256]; Okarg *o = arg->extra.p; fprintf(stderr, "%s: %s ?", *o->argv, arg->path); @@ -569,10 +564,12 @@ get_size_arg(char *argv[], Extra *extra) return argv; } +/* FIXME: still have const problems at *braces++ = arg; */ static char ** get_exec_arg(char *argv[], Extra *extra) { - char **arg, **new, ***braces; + char **arg, **new; + const char ***braces; int nbraces = 0; Execarg *e = extra->p = emalloc(sizeof(*e)); @@ -614,10 +611,12 @@ get_exec_arg(char *argv[], Extra *extra) return arg; } +/* FIXME: still have const problems at *braces++ = arg; */ static char ** get_ok_arg(char *argv[], Extra *extra) { - char **arg, ***braces; + char **arg; + const char ***braces; int nbraces = 0; Okarg *o = extra->p = emalloc(sizeof(*o)); @@ -919,15 +918,12 @@ eval(Tok *tok, Arg *arg) /* evaluate path, if it's a directory iterate through directory entries and * recurse + * FIXME: can I move more of this into recurse() correctly? */ static void -find(char *path, Findhist *hist) +find(const char *path, Rhist *hist) { struct stat st; - DIR *dir; - struct dirent *de; - Findhist *f, cur; - size_t len = strlen(path) + 2; /* null and '/' */ Arg arg = { path, &st, { NULL } }; if ((gflags.l || (gflags.h && !hist) ? stat(path, &st) : lstat(path, &st)) < 0) { @@ -950,40 +946,7 @@ find(char *path, Findhist *hist) (gflags.xdev && hist && st.st_dev != hist->dev)) return; - for (f = hist; f; f = f->next) { - if (f->dev == st.st_dev && f->ino == st.st_ino) { - weprintf("loop detected '%s' is '%s'\n", path, f->path); - return; - } - } - cur.next = hist; - cur.path = path; - cur.dev = st.st_dev; - cur.ino = st.st_ino; - - if (!(dir = opendir(path))) { - weprintf("failed to opendir %s:", path); - /* should we just ignore this since we hit an error? */ - if (gflags.depth) - eval(root, &arg); - return; - } - - /* FIXME: check errno to see if we are done or encountered an error? */ - while ((de = readdir(dir))) { - size_t pathcap = len + strlen(de->d_name); - char pathbuf[pathcap], *p; - - if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) - continue; - - p = pathbuf + strlcpy(pathbuf, path, pathcap); - if (*--p != '/') - strlcat(pathbuf, "/", pathcap); - strlcat(pathbuf, de->d_name, pathcap); - find(pathbuf, &cur); - } - closedir(dir); /* check return value? */ + applydir(path, &st, find, hist); if (gflags.depth) eval(root, &arg); diff --git a/fs.h b/fs.h index 53cc39a..91c6942 100644 --- a/fs.h +++ b/fs.h @@ -12,4 +12,4 @@ extern int rm_rflag; extern int rm_status; int cp(const char *, const char *, int); -void rm(const char *, int); +void rm(const char *, Rhist *); diff --git a/libutil/cp.c b/libutil/cp.c index e58716e..73f3543 100644 --- a/libutil/cp.c +++ b/libutil/cp.c @@ -11,9 +11,9 @@ #include #include -#include "../fs.h" #include "../text.h" #include "../util.h" +#include "../fs.h" int cp_aflag = 0; int cp_fflag = 0; diff --git a/libutil/recurse.c b/libutil/recurse.c index f7b1f61..a63d90f 100644 --- a/libutil/recurse.c +++ b/libutil/recurse.c @@ -13,24 +13,44 @@ int recurse_follow = 'P'; void -recurse(const char *path, void (*fn)(const char *, int), int depth) +recurse(const char *path, void (*fn)(const char *, Rhist *), Rhist *hist) { + + struct stat st; + int (*statf)(const char *, struct stat *) = + (recurse_follow == 'P' || (recurse_follow == 'H' && hist)) ? lstat : stat; + + if (statf(path, &st) < 0) { + weprintf("%s %s:", statf == stat ? "stat" : "lstat", path); + return; + } + if (!S_ISDIR(st.st_mode)) + return; + + applydir(path, &st, fn, hist); +} + +void +applydir(const char *path, struct stat *st, void (*fn)(const char *, Rhist *), Rhist *hist) +{ + Rhist *h, cur; struct dirent *d; - struct stat lst, st; DIR *dp; size_t len; char *buf; - if (lstat(path, &lst) < 0) - eprintf("lstat %s:", path); - if (stat(path, &st) < 0) - eprintf("stat %s:", path); - if (!S_ISDIR(lst.st_mode) && !(S_ISLNK(lst.st_mode) && S_ISDIR(st.st_mode) && - !(recurse_follow == 'P' || (recurse_follow == 'H' && depth > 0)))) - return; + for (h = hist; h; h = h->next) { + if (h->ino == st->st_ino && h->dev == st->st_dev) { + weprintf("loop detected: %s is %s\n", h->path, path); + return; + } + } + cur = (Rhist){ hist, path, st->st_dev, st->st_ino }; - if (!(dp = opendir(path))) - eprintf("opendir %s:", path); + if (!(dp = opendir(path))) { + weprintf("opendir %s:", path); + return; + } len = strlen(path); while ((d = readdir(dp))) { @@ -38,7 +58,7 @@ recurse(const char *path, void (*fn)(const char *, int), int depth) continue; buf = emalloc(len + (path[len] != '/') + strlen(d->d_name) + 1); sprintf(buf, "%s%s%s", path, (path[len] == '/') ? "" : "/", d->d_name); - fn(buf, depth + 1); + fn(buf, &cur); free(buf); } diff --git a/libutil/rm.c b/libutil/rm.c index 60c97c1..f55ee7a 100644 --- a/libutil/rm.c +++ b/libutil/rm.c @@ -2,18 +2,18 @@ #include #include -#include "../fs.h" #include "../util.h" +#include "../fs.h" int rm_fflag = 0; int rm_rflag = 0; int rm_status = 0; void -rm(const char *path, int depth) +rm(const char *path, Rhist *hist) { if (rm_rflag) - recurse(path, rm, depth); + recurse(path, rm, hist); if (remove(path) < 0) { if (!rm_fflag) weprintf("remove %s:", path); diff --git a/mv.c b/mv.c index 6734ee9..d9f0c88 100644 --- a/mv.c +++ b/mv.c @@ -4,8 +4,8 @@ #include #include -#include "fs.h" #include "util.h" +#include "fs.h" static int mv_status = 0; @@ -19,7 +19,7 @@ mv(const char *s1, const char *s2, int depth) cp_HLPflag = 'P'; rm_rflag = 1; cp(s1, s2, depth); - rm(s1, 0); + rm(s1, NULL); return (mv_status = cp_status || rm_status); } mv_status = 1; diff --git a/rm.c b/rm.c index 3b539e6..2958a2a 100644 --- a/rm.c +++ b/rm.c @@ -1,6 +1,6 @@ /* See LICENSE file for copyright and license details. */ -#include "fs.h" #include "util.h" +#include "fs.h" static void usage(void) @@ -31,7 +31,7 @@ main(int argc, char *argv[]) } for (; *argv; argc--, argv++) - rm(*argv, 0); + rm(*argv, NULL); return rm_status; } diff --git a/tar.c b/tar.c index e0e6240..31b52bd 100644 --- a/tar.c +++ b/tar.c @@ -234,10 +234,10 @@ print(char * fname, int l, char b[BLKSIZ]) } static void -c(const char *path, int depth) +c(const char *path, Rhist *hist) { archive(path); - recurse(path, c, depth); + recurse(path, c, hist); } static void @@ -316,7 +316,7 @@ main(int argc, char *argv[]) tarfile = stdout; } chdir(dir); - c(argv[0], 0); + c(argv[0], NULL); break; case 't': case 'x': diff --git a/util.h b/util.h index 2fec2d9..16c3af6 100644 --- a/util.h +++ b/util.h @@ -1,5 +1,6 @@ /* See LICENSE file for copyright and license details. */ #include +#include #include #include @@ -18,6 +19,14 @@ #define LEN(x) (sizeof (x) / sizeof *(x)) +typedef struct Rhist Rhist; +struct Rhist { + Rhist *next; + const char *path; + dev_t dev; + ino_t ino; +}; + extern char *argv0; char *agetcwd(void); @@ -63,7 +72,8 @@ char *humansize(double); mode_t parsemode(const char *, mode_t, mode_t); void putword(const char *); extern int recurse_follow; -void recurse(const char *, void (*)(const char *, int), int); +void recurse(const char *, void (*)(const char *, Rhist *), Rhist *); +void applydir(const char *, struct stat *, void (*)(const char *, Rhist *), Rhist *); #undef strtonum long long strtonum(const char *, long long, long long, const char **); long long enstrtonum(int, const char *, long long, long long); -- 2.3.1