diff options
author | Rob Landley <rob@landley.net> | 2015-05-09 18:11:22 -0500 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2015-05-09 18:11:22 -0500 |
commit | aab9164df395a4b0878b0ad930a5ec8a806a58e9 (patch) | |
tree | ae36c520e5ebeaf616755792f67c9e09ff1bbf9f /lib | |
parent | a913d92bad6550e005a3ffac71a82586042171b5 (diff) | |
download | toybox-aab9164df395a4b0878b0ad930a5ec8a806a58e9.tar.gz |
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).
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dirtree.c | 41 | ||||
-rw-r--r-- | lib/lib.h | 5 |
2 files changed, 27 insertions, 19 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; } @@ -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); |