From aab9164df395a4b0878b0ad930a5ec8a806a58e9 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 9 May 2015 18:11:22 -0500 Subject: Add DIRTREE_SHUTUP to disable dirtree warnings if file vanishes out from under traversal. Pass through full flag set in dirtree_add_node(), add dirtree_start() wrapper to provide symlink-only behavior (avoiding a lot of DIRTREE_SYMFOLLOW*!!(logic) repeated in callers). --- lib/dirtree.c | 41 +++++++++++++++++++++++------------------ lib/lib.h | 5 ++++- toys/pending/diff.c | 4 +--- toys/pending/tar.c | 5 ++--- toys/posix/chgrp.c | 15 ++++++--------- toys/posix/cp.c | 4 ++-- toys/posix/du.c | 20 ++++++-------------- toys/posix/find.c | 9 +++------ toys/posix/ls.c | 6 +++--- 9 files changed, 50 insertions(+), 59 deletions(-) diff --git a/lib/dirtree.c b/lib/dirtree.c index 60ce56b8..1e898161 100644 --- a/lib/dirtree.c +++ b/lib/dirtree.c @@ -24,22 +24,21 @@ int dirtree_notdotdot(struct dirtree *catch) // (This doesn't open directory filehandles yet so as not to exhaust the // filehandle space on large trees, dirtree_handle_callback() does that.) -struct dirtree *dirtree_add_node(struct dirtree *parent, char *name, - int symfollow) +struct dirtree *dirtree_add_node(struct dirtree *parent, char *name, int flags) { struct dirtree *dt = NULL; struct stat st; - char buf[4096]; int len = 0, linklen = 0; if (name) { // open code this because haven't got node to call dirtree_parentfd() on yet int fd = parent ? parent->data : AT_FDCWD; - if (fstatat(fd, name, &st, symfollow ? 0 : AT_SYMLINK_NOFOLLOW)) goto error; + if (fstatat(fd, name, &st, AT_SYMLINK_NOFOLLOW*!(flags&DIRTREE_SYMFOLLOW))) + goto error; if (S_ISLNK(st.st_mode)) { - if (0>(linklen = readlinkat(fd, name, buf, 4095))) goto error; - buf[linklen++]=0; + if (0>(linklen = readlinkat(fd, name, libbuf, 4095))) goto error; + libbuf[linklen++]=0; } len = strlen(name); } @@ -50,7 +49,7 @@ struct dirtree *dirtree_add_node(struct dirtree *parent, char *name, strcpy(dt->name, name); if (linklen) { - dt->symlink = memcpy(len+(char *)dt, buf, linklen); + dt->symlink = memcpy(len+(char *)dt, libbuf, linklen); dt->data = --linklen; } } @@ -58,7 +57,7 @@ struct dirtree *dirtree_add_node(struct dirtree *parent, char *name, return dt; error: - if (notdotdot(name)) { + if (!(flags&DIRTREE_SHUTUP) && notdotdot(name)) { char *path = parent ? dirtree_path(parent, 0) : ""; perror_msg("%s%s%s", path, parent ? "/" : "", name); @@ -111,13 +110,13 @@ int dirtree_parentfd(struct dirtree *node) struct dirtree *dirtree_handle_callback(struct dirtree *new, int (*callback)(struct dirtree *node)) { - int flags, dir = S_ISDIR(new->st.st_mode); + int flags; + if (!new) return 0; if (!callback) callback = dirtree_notdotdot; - flags = callback(new); - if (dir) { + if (S_ISDIR(new->st.st_mode)) { if (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)) { new->data = openat(dirtree_parentfd(new), new->name, O_CLOEXEC); flags = dirtree_recurse(new, callback, flags); @@ -144,9 +143,11 @@ int dirtree_recurse(struct dirtree *node, DIR *dir; if (node->data == -1 || !(dir = fdopendir(node->data))) { - char *path = dirtree_path(node, 0); - perror_msg("No %s", path); - free(path); + if (!(flags & DIRTREE_SHUTUP)) { + char *path = dirtree_path(node, 0); + perror_msg("No %s", path); + free(path); + } close(node->data); return flags; @@ -157,8 +158,7 @@ int dirtree_recurse(struct dirtree *node, // The extra parentheses are to shut the stupid compiler up. while ((entry = readdir(dir))) { - if (!(new = dirtree_add_node(node, entry->d_name, flags&DIRTREE_SYMFOLLOW))) - continue; + if (!(new = dirtree_add_node(node, entry->d_name, flags))) continue; new = dirtree_handle_callback(new, callback); if (new == DIRTREE_ABORTVAL) break; if (new) { @@ -179,14 +179,19 @@ int dirtree_recurse(struct dirtree *node, return flags; } +// Create dirtree root +struct dirtree *dirtree_start(char *name, int symfollow) +{ + return dirtree_add_node(0, name, DIRTREE_SYMFOLLOW*!!symfollow); +} + // Create dirtree from path, using callback to filter nodes. // If callback == NULL allocate a tree of struct dirtree nodes and return // pointer to root node. -// symfollow is just for the top of tree, callback return code controls children struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node)) { - struct dirtree *root = dirtree_add_node(0, path, 0); + struct dirtree *root = dirtree_start(path, 0); return root ? dirtree_handle_callback(root, callback) : DIRTREE_ABORTVAL; } diff --git a/lib/lib.h b/lib/lib.h index be4051eb..03a05703 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -50,6 +50,8 @@ void get_optflags(void); #define DIRTREE_COMEAGAIN 4 // Follow symlinks to directories #define DIRTREE_SYMFOLLOW 8 +// Don't warn about failure to stat +#define DIRTREE_SHUTUP 16 // Don't look at any more files in this directory. #define DIRTREE_ABORT 256 @@ -65,7 +67,8 @@ struct dirtree { char name[]; }; -struct dirtree *dirtree_add_node(struct dirtree *p, char *name, int symfollow); +struct dirtree *dirtree_start(char *name, int symfollow); +struct dirtree *dirtree_add_node(struct dirtree *p, char *name, int flags); char *dirtree_path(struct dirtree *node, int *plen); int dirtree_notdotdot(struct dirtree *catch); int dirtree_parentfd(struct dirtree *node); diff --git a/toys/pending/diff.c b/toys/pending/diff.c index 1b3f80bb..80238614 100644 --- a/toys/pending/diff.c +++ b/toys/pending/diff.c @@ -768,7 +768,6 @@ void diff_main(void) struct stat st[2]; int j = 0, k = 1, start[2] = {1, 1}; char *files[2]; - struct dirtree *root; for (j = 0; j < 2; j++) { files[j] = toys.optargs[j]; @@ -799,8 +798,7 @@ void diff_main(void) if (S_ISDIR(st[0].st_mode) && S_ISDIR(st[1].st_mode)) { for (j = 0; j < 2; j++) { memset(&dir[j], 0, sizeof(dir)); - root = dirtree_add_node(0, files[j], 1); - if (root) dirtree_handle_callback(root, list_dir); + dirtree_handle_callback(dirtree_start(files[j], 1), list_dir); dir[j].nr_elm = TT.size; //size updated in list_dir qsort(&(dir[j].list[1]), (TT.size - 1), sizeof(char*), cmp); diff --git a/toys/pending/tar.c b/toys/pending/tar.c index f44465cc..c8b6dff8 100644 --- a/toys/pending/tar.c +++ b/toys/pending/tar.c @@ -788,9 +788,8 @@ void tar_main(void) for (tmp = TT.inc; tmp; tmp = tmp->next) { TT.handle = tar_hdl; //recurse thru dir and add files to archive - struct dirtree *root = dirtree_add_node(0,tmp->arg,toys.optflags & FLAG_h); - - if (root) dirtree_handle_callback(root, add_to_tar); + dirtree_handle_callback(dirtree_start(tmp->arg, toys.optflags & FLAG_h), + add_to_tar); } memset(toybuf, 0, 1024); writeall(tar_hdl->src_fd, toybuf, 1024); diff --git a/toys/posix/chgrp.c b/toys/posix/chgrp.c index fb82adbd..6b95c6ad 100644 --- a/toys/posix/chgrp.c +++ b/toys/posix/chgrp.c @@ -49,12 +49,11 @@ static int do_chgrp(struct dirtree *node) // Depth first search if (!dirtree_notdotdot(node)) return 0; if ((flags & FLAG_R) && !node->again && S_ISDIR(node->st.st_mode)) - return DIRTREE_COMEAGAIN|((flags&FLAG_L) ? DIRTREE_SYMFOLLOW : 0); + return DIRTREE_COMEAGAIN|(DIRTREE_SYMFOLLOW*!!(flags&FLAG_L)); fd = dirtree_parentfd(node); ret = fchownat(fd, node->name, TT.owner, TT.group, - (flags&(FLAG_L|FLAG_H)) || !(flags&(FLAG_h|FLAG_R)) - ? 0 : AT_SYMLINK_NOFOLLOW); + AT_SYMLINK_NOFOLLOW*(!(flags&(FLAG_L|FLAG_H)) && (flags&(FLAG_h|FLAG_R)))); if (ret || (flags & FLAG_v)) { char *path = dirtree_path(node, 0); @@ -74,7 +73,7 @@ static int do_chgrp(struct dirtree *node) void chgrp_main(void) { - int ischown = toys.which->name[2] == 'o', hl = toys.optflags&(FLAG_H|FLAG_L); + int ischown = toys.which->name[2] == 'o'; char **s, *own; TT.owner = TT.group = -1; @@ -94,11 +93,9 @@ void chgrp_main(void) if (TT.group_name && *TT.group_name) TT.group = xgetgrnamid(TT.group_name)->gr_gid; - for (s=toys.optargs+1; *s; s++) { - struct dirtree *new = dirtree_add_node(0, *s, hl); - if (new) dirtree_handle_callback(new, do_chgrp); - else toys.exitval = 1; - } + for (s=toys.optargs+1; *s; s++) + dirtree_handle_callback(dirtree_start(*s, toys.optflags&(FLAG_H|FLAG_L)), + do_chgrp);; if (CFG_TOYBOX_FREE && ischown) free(own); } diff --git a/toys/posix/cp.c b/toys/posix/cp.c index 2959f67c..df8269f3 100644 --- a/toys/posix/cp.c +++ b/toys/posix/cp.c @@ -340,9 +340,9 @@ void cp_main(void) // Skip nonexistent sources if (rc) { - int symfollow = toys.optflags & (FLAG_H|FLAG_L); + int symfollow = DIRTREE_SYMFOLLOW*!!(toys.optflags & (FLAG_H|FLAG_L)); - if (errno != EXDEV || !(new = dirtree_add_node(0, src, symfollow))) + if (errno != EXDEV || !(new = dirtree_start(src, symfollow))) perror_msg("bad '%s'", src); else dirtree_handle_callback(new, TT.callback); } diff --git a/toys/posix/du.c b/toys/posix/du.c index 00a7f68a..0dea495c 100644 --- a/toys/posix/du.c +++ b/toys/posix/du.c @@ -104,7 +104,8 @@ static int seen_inode(void **list, struct stat *st) // dirtree callback, comput/display size of node static int do_du(struct dirtree *node) { - if (node->parent && !dirtree_notdotdot(node)) return 0; + if (!node->parent) TT.st_dev = node->st.st_dev; + else if (!dirtree_notdotdot(node)) return 0; // detect swiching filesystems if ((toys.optflags & FLAG_x) && (TT.st_dev != node->st.st_dev)) @@ -146,21 +147,12 @@ static int do_du(struct dirtree *node) void du_main(void) { - char *noargs[] = {".", 0}; - struct dirtree *root; - - if (!toys.optc) toys.optargs = noargs; + char *noargs[] = {".", 0}, **args; // Loop over command line arguments, recursing through children - while (*toys.optargs) { - root = dirtree_add_node(0, *toys.optargs, toys.optflags & (FLAG_H|FLAG_L)); - - if (root) { - TT.st_dev = root->st.st_dev; - dirtree_handle_callback(root, do_du); - } - toys.optargs++; - } + for (args = toys.optc ? toys.optargs : noargs; *args; args++) + dirtree_handle_callback(dirtree_start(*args, + DIRTREE_SYMFOLLOW*!!(toys.optflags & (FLAG_H|FLAG_L))), do_du); if (toys.optflags & FLAG_c) print(TT.total*512, 0); if (CFG_TOYBOX_FREE) seen_inode(TT.inodes, 0); diff --git a/toys/posix/find.c b/toys/posix/find.c index 69e370d4..73502b4a 100644 --- a/toys/posix/find.c +++ b/toys/posix/find.c @@ -531,12 +531,9 @@ void find_main(void) do_find(0); // Loop through paths - for (i = 0; i < len; i++) { - struct dirtree *new; - - new = dirtree_add_node(0, ss[i], toys.optflags&(FLAG_H|FLAG_L)); - if (new) dirtree_handle_callback(new, do_find); - } + for (i = 0; i < len; i++) + dirtree_handle_callback(dirtree_start(ss[i], toys.optflags&(FLAG_H|FLAG_L)), + do_find); if (CFG_TOYBOX_FREE) { close(TT.topdir); diff --git a/toys/posix/ls.c b/toys/posix/ls.c index 5dd6bc50..3e5d3910 100644 --- a/toys/posix/ls.c +++ b/toys/posix/ls.c @@ -540,10 +540,10 @@ void ls_main(void) // Iterate through command line arguments, collecting directories and files. // Non-absolute paths are relative to current directory. - TT.files = dirtree_add_node(0, 0, 0); + TT.files = dirtree_start(0, 0); for (s = *toys.optargs ? toys.optargs : noargs; *s; s++) { - dt = dirtree_add_node(0, *s, !(toys.optflags & (FLAG_l|FLAG_d|FLAG_F)) - || (toys.optflags & (FLAG_L|FLAG_H))); + dt = dirtree_start(*s, !(toys.optflags&(FLAG_l|FLAG_d|FLAG_F)) || + (toys.optflags&(FLAG_L|FLAG_H))); if (!dt) { toys.exitval = 1; -- cgit v1.2.3