diff --git a/chgrp.c b/chgrp.c index 17a23f9..da483d2 100644 --- a/chgrp.c +++ b/chgrp.c @@ -14,7 +14,7 @@ static gid_t gid = -1; static int ret = 0; static void -chgrp(const char *path, int depth) +chgrp(const char *path, int depth, void *data) { char *chownf_name; int (*chownf)(const char *, uid_t, gid_t); @@ -31,7 +31,7 @@ chgrp(const char *path, int depth) weprintf("%s %s:", chownf_name, path); ret = 1; } else if (Rflag) { - recurse(path, chgrp, depth); + recurse(path, chgrp, depth, NULL); } } @@ -80,7 +80,7 @@ main(int argc, char *argv[]) ret = 1; continue; } - chgrp(*argv, 0); + chgrp(*argv, 0, NULL); } return ret; diff --git a/chmod.c b/chmod.c index f7ab866..fcbf65a 100644 --- a/chmod.c +++ b/chmod.c @@ -9,7 +9,7 @@ static mode_t mask = 0; static int ret = 0; static void -chmodr(const char *path, int depth) +chmodr(const char *path, int depth, void *data) { 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, depth, NULL); } static void @@ -80,7 +80,7 @@ done: usage(); for (--argc, ++argv; *argv; argc--, argv++) - chmodr(*argv, 0); + chmodr(*argv, 0, NULL); return ret; } diff --git a/chown.c b/chown.c index 417944b..8d7ff16 100644 --- a/chown.c +++ b/chown.c @@ -16,7 +16,7 @@ static gid_t gid = -1; static int ret = 0; static void -chownpwgr(const char *path, int depth) +chownpwgr(const char *path, int depth, void *data) { char *chownf_name; int (*chownf)(const char *, uid_t, gid_t); @@ -33,7 +33,7 @@ chownpwgr(const char *path, int depth) weprintf("%s %s:", chownf_name, path); ret = 1; } else if (Rflag) { - recurse(path, chownpwgr, depth); + recurse(path, chownpwgr, depth, NULL); } } @@ -97,7 +97,7 @@ main(int argc, char *argv[]) } } for (argc--, argv++; *argv; argc--, argv++) - chownpwgr(*argv, 0); + chownpwgr(*argv, 0, NULL); return ret; } diff --git a/du.c b/du.c index 56b4b9f..0c46629 100644 --- a/du.c +++ b/du.c @@ -2,140 +2,56 @@ #include #include -#include +#include +#include #include -#include #include -#include -#include +#include #include "util.h" -static size_t blksize = 512; -static char file[PATH_MAX]; -static size_t depth = -1; -static size_t curdepth = 0; +static size_t maxdepth = SIZE_MAX; +static size_t blksize = 512; static int aflag = 0; -static int dflag = 0; static int sflag = 0; -static int kflag = 0; static int hflag = 0; -static int xflag = 0; -static int HLPflag = 'P'; - -static char * -xrealpath(const char *pathname, char *resolved) -{ - char *r; - - r = realpath(pathname, resolved); - if (!r) - eprintf("realpath: %s:", pathname); - return r; -} +static int ret = 0; static void -print(size_t n, char *path) +printpath(size_t n, const char *path) { if (hflag) printf("%s\t%s\n", humansize(n * blksize), path); else - printf("%lu\t%s\n", n, path); -} - -static char * -push(const char *path) -{ - char *cwd; - - cwd = agetcwd(); - if (chdir(path) < 0) - weprintf("chdir: %s:", path); - return cwd; -} - -static void -pop(char *path) -{ - if (chdir(path) < 0) - weprintf("chdir: %s:", path); - free(path); + printf("%zu\t%s\n", n, path); } static size_t -nblks(struct stat *st) +nblks(blkcnt_t blocks) { - return (512 * st->st_blocks + blksize - 1) / blksize; + return (512 * blocks + blksize - 1) / blksize; } -static size_t -du(const char *path, char follow) +void +du(const char *path, int depth, void *total) { - struct dirent *dent; - struct stat pst, st; - DIR *dp; - size_t n = 0, m, t; - int r; - char *cwd; + struct stat st; + size_t subtotal = 0; - if (lstat(path, &pst) < 0) - eprintf("stat: %s:", path); - n = nblks(&pst); - - if (!(S_ISDIR(pst.st_mode) || - (follow != 'P' && S_ISLNK(pst.st_mode) && - stat(path, &pst) == 0 && S_ISDIR(pst.st_mode)))) - goto done; - - follow = follow == 'H' ? 'P' : follow; - - dp = opendir(path); - if (!dp) { - weprintf("opendir %s:", path); - goto done; + if (lstat(path, &st) < 0) { + if (!depth || errno != ENOENT) + weprintf("stat %s:", path); + if (!depth) + ret = 1; + return; } - cwd = push(path); - while ((dent = readdir(dp))) { - if (strcmp(dent->d_name, ".") == 0 || - strcmp(dent->d_name, "..") == 0) - continue; - if (lstat(dent->d_name, &st) < 0) - eprintf("stat: %s:", dent->d_name); - if (xflag && st.st_dev != pst.st_dev) - continue; - if (S_ISDIR(st.st_mode) || - (follow != 'P' && S_ISLNK(st.st_mode) && - stat(dent->d_name, &st) == 0 && S_ISDIR(st.st_mode))) { - t = curdepth; - curdepth++; - n += du(dent->d_name, follow); - curdepth = t; - continue; - } - m = nblks(&st); - n += m; - if (aflag && !sflag) { - if (S_ISLNK(st.st_mode)) { - r = snprintf(file, sizeof(file), "%s/%s", - cwd, dent->d_name); - if (r >= sizeof(file) || r < 0) - eprintf("path too long\n"); - } else { - xrealpath(dent->d_name, file); - } - if (!dflag || (depth != -1 && curdepth < depth)) - print(m, file); - } - } - pop(cwd); - closedir(dp); + recurse(path, du, depth, &subtotal); + *((size_t *)total) += subtotal + nblks(st.st_blocks); -done: - if (!sflag && (!dflag || (depth != -1 && curdepth <= depth))) - print(n, xrealpath(path, file)); - return n; + if (!sflag && depth <= maxdepth && (S_ISDIR(st.st_mode) || aflag)) + printpath(subtotal + nblks(st.st_blocks), path); } static void @@ -147,7 +63,8 @@ usage(void) int main(int argc, char *argv[]) { - size_t n; + int kflag = 0, dflag = 0; + size_t n = 0; char *bsize; ARGBEGIN { @@ -156,24 +73,24 @@ main(int argc, char *argv[]) break; case 'd': dflag = 1; - depth = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX)); - break; - case 's': - sflag = 1; - break; - case 'k': - kflag = 1; + maxdepth = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX)); break; case 'h': hflag = 1; break; + case 'k': + kflag = 1; + break; + case 's': + sflag = 1; + break; + case 'x': + recurse_samedev = 1; + break; case 'H': case 'L': case 'P': - HLPflag = ARGC(); - break; - case 'x': - xflag = 1; + recurse_follow = ARGC(); break; default: usage(); @@ -184,22 +101,21 @@ main(int argc, char *argv[]) bsize = getenv("BLOCKSIZE"); if (bsize) - blksize = estrtonum(bsize, 0, LONG_MAX); - + blksize = estrtonum(bsize, 0, MIN(LLONG_MAX, SIZE_MAX)); if (kflag) blksize = 1024; - if (argc < 1) { - n = du(".", HLPflag); - if (sflag) - print(n, xrealpath(".", file)); + if (!argc) { + du(".", 0, &n); + if (sflag && !ret) + printpath(nblks(n), "."); } else { - for (; argc > 0; argc--, argv++) { - curdepth = 0; - n = du(argv[0], HLPflag); - if (sflag) - print(n, xrealpath(argv[0], file)); + for (; *argv; argc--, argv++) { + du(argv[0], 0, &n); + if (sflag && !ret) + printpath(n, argv[0]); } } - return 0; + + return ret; } diff --git a/fs.h b/fs.h index 53cc39a..d826625 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 *, int, void *); diff --git a/libutil/recurse.c b/libutil/recurse.c index f7b1f61..3c30a7e 100644 --- a/libutil/recurse.c +++ b/libutil/recurse.c @@ -1,5 +1,6 @@ /* See LICENSE file for copyright and license details. */ #include +#include #include #include #include @@ -10,21 +11,28 @@ #include "../util.h" -int recurse_follow = 'P'; +int recurse_follow = 'P'; +int recurse_samedev = 0; void -recurse(const char *path, void (*fn)(const char *, int), int depth) +recurse(const char *path, void (*fn)(const char *, int, void *), int depth, void *data) { struct dirent *d; - struct stat lst, st; + struct stat lst, st, dst; 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 (lstat(path, &lst) < 0) { + if (errno != ENOENT) + weprintf("lstat %s:", path); + return; + } + if (stat(path, &st) < 0) { + if (errno != ENOENT) + weprintf("stat %s:", path); + return; + } 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; @@ -36,9 +44,13 @@ recurse(const char *path, void (*fn)(const char *, int), int depth) while ((d = readdir(dp))) { if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) 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); + buf = emalloc(len + (path[len - 1] != '/') + strlen(d->d_name) + 1); + sprintf(buf, "%s%s%s", path, (path[len - 1] == '/') ? "" : "/", d->d_name); + if (recurse_samedev && lstat(buf, &dst) < 0) { + if (errno != ENOENT) + weprintf("stat %s:", buf); + } else if (!(recurse_samedev && dst.st_dev != lst.st_dev)) + fn(buf, depth + 1, data); free(buf); } diff --git a/libutil/rm.c b/libutil/rm.c index 60c97c1..88ac788 100644 --- a/libutil/rm.c +++ b/libutil/rm.c @@ -10,10 +10,10 @@ int rm_rflag = 0; int rm_status = 0; void -rm(const char *path, int depth) +rm(const char *path, int depth, void *data) { if (rm_rflag) - recurse(path, rm, depth); + recurse(path, rm, depth, NULL); if (remove(path) < 0) { if (!rm_fflag) weprintf("remove %s:", path); diff --git a/mv.c b/mv.c index 6734ee9..78e58c7 100644 --- a/mv.c +++ b/mv.c @@ -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, 0, NULL); return (mv_status = cp_status || rm_status); } mv_status = 1; diff --git a/rm.c b/rm.c index 3b539e6..6738ef1 100644 --- a/rm.c +++ b/rm.c @@ -31,7 +31,7 @@ main(int argc, char *argv[]) } for (; *argv; argc--, argv++) - rm(*argv, 0); + rm(*argv, 0, NULL); return rm_status; } diff --git a/tar.c b/tar.c index 8c6fdac..d423d63 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, int depth, void *data) { archive(path); - recurse(path, c, depth); + recurse(path, c, depth, NULL); } static void @@ -316,7 +316,7 @@ main(int argc, char *argv[]) tarfile = stdout; } chdir(dir); - c(argv[0], 0); + c(argv[0], 0, NULL); break; case 't': case 'x': diff --git a/util.h b/util.h index c400a50..2beae2d 100644 --- a/util.h +++ b/util.h @@ -66,7 +66,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); +extern int recurse_samedev; +void recurse(const char *, void (*)(const char *, int, void *), int, void *); #undef strtonum long long strtonum(const char *, long long, long long, const char **); long long enstrtonum(int, const char *, long long, long long);