diff --git a/chgrp.c b/chgrp.c index 2adf60d..8cd4c60 100644 --- a/chgrp.c +++ b/chgrp.c @@ -8,14 +8,13 @@ #include "fs.h" #include "util.h" -static struct stat st; static int hflag = 0; static int Rflag = 0; static gid_t gid = -1; static int ret = 0; static void -chgrp(const char *path, void *data, struct recursor *r) +chgrp(const char *path, struct stat *st, void *data, struct recursor *r) { char *chownf_name; int (*chownf)(const char *, uid_t, gid_t); @@ -28,10 +27,10 @@ chgrp(const char *path, void *data, struct recursor *r) chownf = chown; } - if (chownf(path, st.st_uid, gid) < 0) { + if (st && chownf(path, st->st_uid, gid) < 0) { weprintf("%s %s:", chownf_name, path); ret = 1; - } else if (Rflag) { + } else if (Rflag && st && S_ISDIR(st->st_mode)) { recurse(path, NULL, r); } } @@ -76,14 +75,8 @@ main(int argc, char *argv[]) } gid = gr->gr_gid; - for (argc--, argv++; *argv; argc--, argv++) { - if (stat(*argv, &st) < 0) { - weprintf("stat %s:", *argv); - ret = 1; - continue; - } - chgrp(*argv, NULL, &r); - } + for (argc--, argv++; *argv; argc--, argv++) + recurse(*argv, NULL, &r); return ret || recurse_status; } diff --git a/chmod.c b/chmod.c index 1cfa6b3..991a0b3 100644 --- a/chmod.c +++ b/chmod.c @@ -10,23 +10,17 @@ static mode_t mask = 0; static int ret = 0; static void -chmodr(const char *path, void *data, struct recursor *r) +chmodr(const char *path, struct stat *st, void *data, struct recursor *r) { - struct stat st; mode_t m; - if (stat(path, &st) < 0) { - weprintf("stat %s:", path); - ret = 1; - return; - } - - m = parsemode(modestr, st.st_mode, mask); + m = parsemode(modestr, st ? st->st_mode : 0, mask); if (chmod(path, m) < 0) { weprintf("chmod %s:", path); ret = 1; - } else if (Rflag) + } else if (Rflag && st && S_ISDIR(st->st_mode)) { recurse(path, NULL, r); + } } static void @@ -82,7 +76,7 @@ done: usage(); for (--argc, ++argv; *argv; argc--, argv++) - chmodr(*argv, NULL, &r); + recurse(*argv, NULL, &r); return ret || recurse_status; } diff --git a/chown.c b/chown.c index bc2bb1f..5bc1e99 100644 --- a/chown.c +++ b/chown.c @@ -17,7 +17,7 @@ static gid_t gid = -1; static int ret = 0; static void -chownpwgr(const char *path, void *data, struct recursor *r) +chownpwgr(const char *path, struct stat *st, void *data, struct recursor *r) { char *chownf_name; int (*chownf)(const char *, uid_t, gid_t); @@ -33,7 +33,7 @@ chownpwgr(const char *path, void *data, struct recursor *r) if (chownf(path, uid, gid) < 0) { weprintf("%s %s:", chownf_name, path); ret = 1; - } else if (Rflag) { + } else if (Rflag && st && S_ISDIR(st->st_mode)) { recurse(path, NULL, r); } } @@ -99,7 +99,7 @@ main(int argc, char *argv[]) } } for (argc--, argv++; *argv; argc--, argv++) - chownpwgr(*argv, NULL, &r); + recurse(*argv, NULL, &r); return ret || recurse_status; } diff --git a/du.c b/du.c index 6ecebc9..b20201a 100644 --- a/du.c +++ b/du.c @@ -17,7 +17,6 @@ static size_t blksize = 512; static int aflag = 0; static int sflag = 0; static int hflag = 0; -static int ret = 0; static void printpath(size_t n, const char *path) @@ -35,25 +34,16 @@ nblks(blkcnt_t blocks) } void -du(const char *path, void *total, struct recursor *r) +du(const char *path, struct stat *st, void *total, struct recursor *r) { - struct stat st; size_t subtotal = 0; - if (lstat(path, &st) < 0) { - if (!(r->depth) || errno != ENOENT) - weprintf("stat %s:", path); - if (!(r->depth)) - ret = 1; - return; - } - - if (S_ISDIR(st.st_mode)) + if (st && S_ISDIR(st->st_mode)) recurse(path, &subtotal, r); - *((size_t *)total) += subtotal + nblks(st.st_blocks); + *((size_t *)total) += subtotal + nblks(st ? st->st_blocks : 0); - if (!sflag && r->depth <= maxdepth && (S_ISDIR(st.st_mode) || aflag)) - printpath(subtotal + nblks(st.st_blocks), path); + if (!sflag && r->depth <= maxdepth && r->depth && st && (S_ISDIR(st->st_mode) || aflag)) + printpath(subtotal + nblks(st->st_blocks), path); } static void @@ -109,16 +99,14 @@ main(int argc, char *argv[]) blksize = 1024; if (!argc) { - du(".", &n, &r); - if (sflag && !ret) - printpath(nblks(n), "."); + recurse(".", &n, &r); + printpath(nblks(n), "."); } else { for (; *argv; argc--, argv++) { - du(argv[0], &n, &r); - if (sflag && !ret) - printpath(n, argv[0]); + recurse(*argv, &n, &r); + printpath(n, *argv); } } - return ret || recurse_status; + return recurse_status; } diff --git a/fs.h b/fs.h index 853996d..91b130f 100644 --- a/fs.h +++ b/fs.h @@ -1,4 +1,5 @@ /* See LICENSE file for copyright and license details. */ +#include #include struct history { @@ -8,7 +9,7 @@ struct history { }; struct recursor { - void (*fn)(const char *, void *, struct recursor *); + void (*fn)(const char *, struct stat *st, void *, struct recursor *); struct history *hist; int depth; int follow; @@ -36,4 +37,4 @@ extern int recurse_status; void recurse(const char *, void *, struct recursor *); int cp(const char *, const char *, int); -void rm(const char *, void *, struct recursor *); +void rm(const char *, struct stat *st, void *, struct recursor *); diff --git a/libutil/recurse.c b/libutil/recurse.c index c4e8043..c7f67d3 100644 --- a/libutil/recurse.c +++ b/libutil/recurse.c @@ -33,24 +33,23 @@ recurse(const char *path, void *data, struct recursor *r) } if (statf(path, &st) < 0) { - if (errno != ENOENT) { - weprintf("%s %s:", statf_name, path); - recurse_status = 1; - } + weprintf("%s %s:", statf_name, path); + recurse_status = 1; return; } - if (!S_ISDIR(st.st_mode)) + if (!S_ISDIR(st.st_mode)) { + (r->fn)(path, &st, data, r); return; + } new = emalloc(sizeof(struct history)); - new->prev = r->hist; r->hist = new; new->dev = st.st_dev; new->ino = st.st_ino; for (h = new->prev; h; h = h->prev) - if (h->dev == st.st_dev && h->ino == st.st_ino) + if (h->ino == st.st_ino && h->dev == st.st_dev) return; if (!(dp = opendir(path))) { @@ -70,17 +69,27 @@ recurse(const char *path, void *data, struct recursor *r) if (path[strlen(path) - 1] != '/') estrlcat(subpath, "/", sizeof(subpath)); estrlcat(subpath, d->d_name, sizeof(subpath)); - if ((r->flags & SAMEDEV) && statf(subpath, &dst) < 0) { - if (errno != ENOENT) { - weprintf("%s %s:", statf_name, subpath); - recurse_status = 1; - } - } else if (!((r->flags & SAMEDEV) && dst.st_dev != st.st_dev)) { + if (statf(subpath, &dst) < 0) { + weprintf("%s %s:", statf_name, subpath); + recurse_status = 1; + } else if ((r->flags & SAMEDEV) && dst.st_dev != st.st_dev) { + continue; + } else { r->depth++; - (r->fn)(subpath, data, r); + (r->fn)(subpath, &dst, data, r); r->depth--; } } + if (!r->depth) { + (r->fn)(path, &st, data, r); + + for (; r->hist; ) { + h = r->hist; + r->hist = r->hist->prev; + free(h); + } + } + closedir(dp); } diff --git a/libutil/rm.c b/libutil/rm.c index 01b3763..09bf3b9 100644 --- a/libutil/rm.c +++ b/libutil/rm.c @@ -1,4 +1,6 @@ /* See LICENSE file for copyright and license details. */ +#include + #include #include @@ -10,9 +12,9 @@ int rm_rflag = 0; int rm_status = 0; void -rm(const char *path, void *data, struct recursor *r) +rm(const char *path, struct stat *st, void *data, struct recursor *r) { - if (rm_rflag) + if (rm_rflag && st && S_ISDIR(st->st_mode)) recurse(path, NULL, r); if (remove(path) < 0) { if (!rm_fflag) diff --git a/mv.c b/mv.c index 148b4bc..404a310 100644 --- a/mv.c +++ b/mv.c @@ -21,7 +21,7 @@ mv(const char *s1, const char *s2, int depth) cp_HLPflag = 'P'; rm_rflag = 1; cp(s1, s2, depth); - rm(s1, NULL, &r); + rm(s1, NULL, NULL, &r); return (mv_status = cp_status || rm_status); } mv_status = 1; diff --git a/rm.c b/rm.c index 17d75ed..e72abe8 100644 --- a/rm.c +++ b/rm.c @@ -33,7 +33,7 @@ main(int argc, char *argv[]) } for (; *argv; argc--, argv++) - rm(*argv, NULL, &r); + recurse(*argv, NULL, &r); return rm_status || recurse_status; } diff --git a/tar.c b/tar.c index b966b15..965f87e 100644 --- a/tar.c +++ b/tar.c @@ -235,10 +235,12 @@ print(char * fname, int l, char b[BLKSIZ]) } static void -c(const char *path, void *data, struct recursor *r) +c(const char *path, struct stat *st, void *data, struct recursor *r) { archive(path); - recurse(path, NULL, r); + + if (st && S_ISDIR(st->st_mode)) + recurse(path, NULL, r); } static void @@ -318,7 +320,7 @@ main(int argc, char *argv[]) tarfile = stdout; } chdir(dir); - c(argv[0], NULL, &r); + recurse(argv[0], NULL, &r); break; case 't': case 'x':