--- chgrp.c | 2 +- chmod.c | 4 +- chown.c | 2 +- du.c | 2 +- fs.h | 5 +- libutil/recurse.c | 141 ++++++++++++++++++++++++---------------------- libutil/rm.c | 2 +- tar.c | 4 +- 8 files changed, 85 insertions(+), 77 deletions(-) diff --git a/chgrp.c b/chgrp.c index 4042a0d..6be7e1d 100644 --- a/chgrp.c +++ b/chgrp.c _AT_@ -24,7 +24,7 @@ chgrp(int dirfd, const char *name, struct stat *st, void *data, struct recursor weprintf("chown %s:", r->path); ret = 1; } else if (S_ISDIR(st->st_mode)) { - recurse(dirfd, name, NULL, r); + recursedir(dirfd, name, NULL, r); } } diff --git a/chmod.c b/chmod.c index c79488b..58f995b 100644 --- a/chmod.c +++ b/chmod.c _AT_@ -19,7 +19,7 @@ chmodr(int dirfd, const char *name, struct stat *st, void *data, struct recursor weprintf("chmod %s:", r->path); ret = 1; } else if (S_ISDIR(st->st_mode)) { - recurse(dirfd, name, NULL, r); + recursedir(dirfd, name, NULL, r); } } _AT_@ -32,7 +32,7 @@ usage(void) int main(int argc, char *argv[]) { - struct recursor r = { .fn = chmodr, .maxdepth = 1, .follow = 'H', .flags = DIRFIRST }; + struct recursor r = { .fn = chmodr, .maxdepth = 1, .follow = 'H' }; size_t i; argv0 = *argv, argv0 ? (argc--, argv++) : (void *)0; diff --git a/chown.c b/chown.c index 71628eb..27dd3a7 100644 --- a/chown.c +++ b/chown.c _AT_@ -28,7 +28,7 @@ chownpwgr(int dirfd, const char *name, struct stat *st, void *data, struct recur weprintf("chown %s:", r->path); ret = 1; } else if (S_ISDIR(st->st_mode)) { - recurse(dirfd, name, NULL, r); + recursedir(dirfd, name, NULL, r); } } diff --git a/du.c b/du.c index 1815a02..6388159 100644 --- a/du.c +++ b/du.c _AT_@ -42,7 +42,7 @@ du(int dirfd, const char *path, struct stat *st, void *data, struct recursor *r) subtotal = nblks(st->st_blocks); if (S_ISDIR(st->st_mode)) - recurse(dirfd, path, &subtotal, r); + recursedir(dirfd, path, &subtotal, r); *total += subtotal; if (!r->depth) diff --git a/fs.h b/fs.h index 00ecd3b..9ee3c5d 100644 --- a/fs.h +++ b/fs.h _AT_@ -18,12 +18,12 @@ struct recursor { int maxdepth; int follow; int flags; + dev_t dev; }; enum { SAMEDEV = 1 << 0, - DIRFIRST = 1 << 1, - SILENT = 1 << 2, + SILENT = 1 << 1, }; extern int cp_aflag; _AT_@ -41,6 +41,7 @@ extern int rm_status; extern int recurse_status; void recurse(int, const char *, void *, struct recursor *); +void recursedir(int, const char *, void *, struct recursor *); int cp(const char *, const char *, int); void rm(int, const char *, struct stat *st, void *, struct recursor *); diff --git a/libutil/recurse.c b/libutil/recurse.c index e66efaf..0403e16 100644 --- a/libutil/recurse.c +++ b/libutil/recurse.c _AT_@ -15,22 +15,37 @@ int recurse_status = 0; +/* returns 0 if we have seen this directory, 1 otherwise */ +static int +histadd(struct recursor *r, struct stat *st) +{ + struct history *h; + + if (S_ISDIR(st->st_mode)) { + for (h = r->hist; h; h = h->prev) { + if (h->ino == st->st_ino && h->dev == st->st_dev) + return 0; + } + h = emalloc(sizeof(struct history)); + h->prev = r->hist; + r->hist = h; + h->dev = st->st_dev; + h->ino = st->st_ino; + } + return 1; +} + void recurse(int dirfd, const char *name, void *data, struct recursor *r) { - struct dirent *d; - struct history *new, *h; - struct stat st, dst; - DIR *dp; - int flags = 0, fd; - size_t pathlen = r->pathlen; - - if (dirfd == AT_FDCWD) - pathlen = estrlcpy(r->path, name, sizeof(r->path)); + struct history *h; + struct stat st; + int flags = 0; - if (r->follow == 'P' || (r->follow == 'H' && r->depth)) + if (r->follow == 'P') flags |= AT_SYMLINK_NOFOLLOW; - + if (!r->pathlen) + r->pathlen = estrlcpy(r->path, name, sizeof(r->path)); if (fstatat(dirfd, name, &st, flags) < 0) { if (!(r->flags & SILENT)) { weprintf("stat %s:", r->path); _AT_@ -38,71 +53,63 @@ recurse(int dirfd, const char *name, void *data, struct recursor *r) } return; } - if (!S_ISDIR(st.st_mode)) { - r->fn(dirfd, name, &st, data, r); - return; - } + r->dev = st.st_dev; + histadd(r, &st); + r->fn(dirfd, name, &st, data, r); - new = emalloc(sizeof(struct history)); - new->prev = r->hist; - r->hist = new; - new->dev = st.st_dev; - new->ino = st.st_ino; + while (r->hist) { + h = r->hist; + r->hist = r->hist->prev; + free(h); + } +} - for (h = new->prev; h; h = h->prev) - if (h->ino == st.st_ino && h->dev == st.st_dev) - return; +void +recursedir(int dirfd, const char *name, void *data, struct recursor *r) +{ + struct dirent *d; + struct stat st; + DIR *dp; + int flags = 0, fd; + size_t pathlen = r->pathlen; - if (!r->depth && (r->flags & DIRFIRST)) - r->fn(dirfd, name, &st, data, r); + if (r->maxdepth && r->depth + 1 >= r->maxdepth) + return; - if (!r->maxdepth || r->depth + 1 < r->maxdepth) { - fd = openat(dirfd, name, O_RDONLY | O_CLOEXEC | O_DIRECTORY); - if (fd < 0) { - weprintf("open %s:", r->path); + fd = openat(dirfd, name, O_RDONLY | O_CLOEXEC | O_DIRECTORY); + if (fd < 0) { + weprintf("open %s:", r->path); + recurse_status = 1; + } + if (!(dp = fdopendir(fd))) { + if (!(r->flags & SILENT)) { + weprintf("fdopendir:"); recurse_status = 1; } - if (!(dp = fdopendir(fd))) { + return; + } + if (r->path[pathlen - 1] != '/') + r->path[pathlen++] = '/'; + if (r->follow == 'P' || r->follow == 'H') + flags |= AT_SYMLINK_NOFOLLOW; + while ((d = readdir(dp))) { + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + r->pathlen = pathlen + estrlcpy(r->path + pathlen, d->d_name, sizeof(r->path) - pathlen); + if (fstatat(fd, d->d_name, &st, flags) < 0) { if (!(r->flags & SILENT)) { - weprintf("fdopendir:"); + weprintf("stat %s:", r->path); recurse_status = 1; } - return; - } - if (r->path[pathlen - 1] != '/') - r->path[pathlen++] = '/'; - if (r->follow == 'H') - flags |= AT_SYMLINK_NOFOLLOW; - while ((d = readdir(dp))) { - if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) - continue; - r->pathlen = pathlen + estrlcpy(r->path + pathlen, d->d_name, sizeof(r->path) - pathlen); - if (fstatat(fd, d->d_name, &dst, flags) < 0) { - if (!(r->flags & SILENT)) { - weprintf("stat %s:", r->path); - recurse_status = 1; - } - } else if ((r->flags & SAMEDEV) && dst.st_dev != st.st_dev) { - continue; - } else { - r->depth++; - r->fn(fd, d->d_name, &dst, data, r); - r->depth--; - } - } - r->path[pathlen - 1] = '\0'; - r->pathlen = pathlen - 1; - closedir(dp); - } - - if (!r->depth) { - if (!(r->flags & DIRFIRST)) - r->fn(dirfd, name, &st, data, r); - - while (r->hist) { - h = r->hist; - r->hist = r->hist->prev; - free(h); + } else if ((r->flags & SAMEDEV) && st.st_dev != r->dev) { + continue; + } else if (histadd(r, &st)) { + r->depth++; + r->fn(fd, d->d_name, &st, data, r); + r->depth--; } } + r->path[pathlen - 1] = '\0'; + r->pathlen = pathlen - 1; + closedir(dp); } diff --git a/libutil/rm.c b/libutil/rm.c index 8d4be08..4891756 100644 --- a/libutil/rm.c +++ b/libutil/rm.c _AT_@ -15,7 +15,7 @@ void rm(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r) { if (!r->maxdepth && S_ISDIR(st->st_mode)) { - recurse(dirfd, name, NULL, r); + recursedir(dirfd, name, NULL, r); if (unlinkat(dirfd, name, AT_REMOVEDIR) < 0) { if (!(r->flags & SILENT)) diff --git a/tar.c b/tar.c index b74c134..9937c96 100644 --- a/tar.c +++ b/tar.c _AT_@ -375,7 +375,7 @@ c(int dirfd, const char *name, struct stat *st, void *data, struct recursor *r) puts(r->path); if (S_ISDIR(st->st_mode)) - recurse(dirfd, name, NULL, r); + recursedir(dirfd, name, NULL, r); } static void _AT_@ -514,7 +514,7 @@ usage(void) int main(int argc, char *argv[]) { - struct recursor r = { .fn = c, .follow = 'P', .flags = DIRFIRST }; + struct recursor r = { .fn = c, .follow = 'P' }; struct stat st; char *file = NULL, *dir = ".", mode = '\0'; int fd; -- 2.27.0Received on Tue Jun 23 2020 - 11:30:51 CEST
This archive was generated by hypermail 2.3.0 : Tue Jun 23 2020 - 11:36:33 CEST