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 ++++- 2 files changed, 27 insertions(+), 19 deletions(-) (limited to 'lib') 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); -- cgit v1.2.3