aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2015-05-09 18:11:22 -0500
committerRob Landley <rob@landley.net>2015-05-09 18:11:22 -0500
commitaab9164df395a4b0878b0ad930a5ec8a806a58e9 (patch)
treeae36c520e5ebeaf616755792f67c9e09ff1bbf9f
parenta913d92bad6550e005a3ffac71a82586042171b5 (diff)
downloadtoybox-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).
-rw-r--r--lib/dirtree.c41
-rw-r--r--lib/lib.h5
-rw-r--r--toys/pending/diff.c4
-rw-r--r--toys/pending/tar.c5
-rw-r--r--toys/posix/chgrp.c15
-rw-r--r--toys/posix/cp.c4
-rw-r--r--toys/posix/du.c20
-rw-r--r--toys/posix/find.c9
-rw-r--r--toys/posix/ls.c6
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;