From fec3fd1f8ac1db9ed87b79bd3eb5e38aa835e881 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 26 Jul 2014 13:30:40 -0500 Subject: Move DIRTREE_COMEAGAIN second callback up to when the filehandle is still open, and add dir->again variable to distinguish second call instead of checking for -1 filehandle. --- lib/dirtree.c | 15 +++++++++------ lib/lib.h | 7 ++++--- toys/other/lsattr.c | 2 +- toys/other/switch_root.c | 2 +- toys/posix/chgrp.c | 2 +- toys/posix/cp.c | 2 +- toys/posix/du.c | 4 ++-- toys/posix/rm.c | 4 ++-- 8 files changed, 21 insertions(+), 17 deletions(-) diff --git a/lib/dirtree.c b/lib/dirtree.c index 7ad699e1..8445ca40 100644 --- a/lib/dirtree.c +++ b/lib/dirtree.c @@ -116,8 +116,7 @@ struct dirtree *dirtree_handle_callback(struct dirtree *new, if (dir) { if (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)) { new->data = openat(dirtree_parentfd(new), new->name, O_CLOEXEC); - dirtree_recurse(new, callback, flags & DIRTREE_SYMFOLLOW); - if (flags & DIRTREE_COMEAGAIN) flags = callback(new); + flags = dirtree_recurse(new, callback, flags); } } @@ -133,8 +132,8 @@ struct dirtree *dirtree_handle_callback(struct dirtree *new, // Recursively read/process children of directory node (with dirfd in data), // filtering through callback(). -void dirtree_recurse(struct dirtree *node, - int (*callback)(struct dirtree *node), int symfollow) +int dirtree_recurse(struct dirtree *node, + int (*callback)(struct dirtree *node), int flags) { struct dirtree *new, **ddt = &(node->child); struct dirent *entry; @@ -146,7 +145,7 @@ void dirtree_recurse(struct dirtree *node, free(path); close(node->data); - return; + return flags; } // according to the fddir() man page, the filehandle in the DIR * can still @@ -154,7 +153,7 @@ void 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, symfollow))) + if (!(new = dirtree_add_node(node, entry->d_name, flags&DIRTREE_SYMFOLLOW))) continue; new = dirtree_handle_callback(new, callback); if (new == DIRTREE_ABORTVAL) break; @@ -164,9 +163,13 @@ void dirtree_recurse(struct dirtree *node, } } + if (flags & DIRTREE_COMEAGAIN) flags = callback(node); + // This closes filehandle as well, so note it closedir(dir); node->data = -1; + + return flags; } // Create dirtree from path, using callback to filter nodes. diff --git a/lib/lib.h b/lib/lib.h index 11a1018c..34c78a26 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -60,7 +60,8 @@ struct dirtree { long extra; // place for user to store their stuff (can be pointer) struct stat st; char *symlink; - int data; // dirfd for directory, linklen for symlink, -1 = comeagain + int data; // dirfd for directory, linklen for symlink + char again; char name[]; }; @@ -70,8 +71,8 @@ int dirtree_notdotdot(struct dirtree *catch); int dirtree_parentfd(struct dirtree *node); struct dirtree *dirtree_handle_callback(struct dirtree *new, int (*callback)(struct dirtree *node)); -void dirtree_recurse(struct dirtree *node, - int (*callback)(struct dirtree *node), int symfollow); +int dirtree_recurse(struct dirtree *node, int (*callback)(struct dirtree *node), + int symfollow); struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node)); // help.c diff --git a/toys/other/lsattr.c b/toys/other/lsattr.c index 937ea608..39945ef0 100644 --- a/toys/other/lsattr.c +++ b/toys/other/lsattr.c @@ -140,7 +140,7 @@ static int retell_dir(struct dirtree *root) { char *fpath = NULL; - if (root->data == -1) { + if (root->again) { xputc('\n'); return 0; } diff --git a/toys/other/switch_root.c b/toys/other/switch_root.c index 1dfa20de..0861c70e 100644 --- a/toys/other/switch_root.c +++ b/toys/other/switch_root.c @@ -32,7 +32,7 @@ static int del_node(struct dirtree *node) if (node->st.st_dev == TT.rootdev && dirtree_notdotdot(node)) { int flag = 0; if (S_ISDIR(node->st.st_mode)) { - if (node->data != -1) return DIRTREE_COMEAGAIN; + if (!node->again) return DIRTREE_COMEAGAIN; flag = AT_REMOVEDIR; } unlinkat(dirtree_parentfd(node), node->name, flag); diff --git a/toys/posix/chgrp.c b/toys/posix/chgrp.c index c53ea21d..24af46ac 100644 --- a/toys/posix/chgrp.c +++ b/toys/posix/chgrp.c @@ -44,7 +44,7 @@ static int do_chgrp(struct dirtree *node) // Depth first search if (!dirtree_notdotdot(node)) return 0; - if ((flags & FLAG_R) && node->data != -1 && S_ISDIR(node->st.st_mode)) + if ((flags & FLAG_R) && !node->again && S_ISDIR(node->st.st_mode)) return DIRTREE_COMEAGAIN|((flags&FLAG_L) ? DIRTREE_SYMFOLLOW : 0); fd = dirtree_parentfd(node); diff --git a/toys/posix/cp.c b/toys/posix/cp.c index 283ee978..aecd1870 100644 --- a/toys/posix/cp.c +++ b/toys/posix/cp.c @@ -84,7 +84,7 @@ int cp_node(struct dirtree *try) if (!dirtree_notdotdot(try)) return 0; // If returning from COMEAGAIN, jump straight to -p logic at end. - if (S_ISDIR(try->st.st_mode) && try->data == -1) { + if (S_ISDIR(try->st.st_mode) && try->again) { fdout = try->extra; err = 0; } else { diff --git a/toys/posix/du.c b/toys/posix/du.c index 2bfa7e41..22a26d3a 100644 --- a/toys/posix/du.c +++ b/toys/posix/du.c @@ -111,12 +111,12 @@ static int do_du(struct dirtree *node) return 0; // Don't count hard links twice - if (!(toys.optflags & FLAG_l) && node->data != -1) + if (!(toys.optflags & FLAG_l) && !node->again) if (seen_inode(&TT.inodes, &node->st)) return 0; // Collect child info before printing directory size if (S_ISDIR(node->st.st_mode)) { - if (node->data != -1) { + if (!node->again) { TT.depth++; return DIRTREE_COMEAGAIN | (DIRTREE_SYMFOLLOW*!!(toys.optflags & FLAG_L)); } else TT.depth--; diff --git a/toys/posix/rm.c b/toys/posix/rm.c index 15359cb1..2f40106f 100644 --- a/toys/posix/rm.c +++ b/toys/posix/rm.c @@ -37,7 +37,7 @@ static int do_rm(struct dirtree *try) // This is either the posix section 2(b) prompt or the section 3 prompt. if (!(flags & FLAG_f) && (!S_ISLNK(try->st.st_mode) && faccessat(fd, try->name, W_OK, 0))) or++; - if (!(dir && try->data == -1) && ((or && isatty(0)) || (flags & FLAG_i))) { + if (!(dir && try->again) && ((or && isatty(0)) || (flags & FLAG_i))) { char *s = dirtree_path(try, 0); fprintf(stderr, "rm %s%s", or ? "ro " : "", dir ? "dir " : ""); or = yesno(s, 0); @@ -52,7 +52,7 @@ static int do_rm(struct dirtree *try) if (toys.optflags & FLAG_f) wfchmodat(fd, try->name, 0600); else goto skip; } - if (try->data != -1) return DIRTREE_COMEAGAIN; + if (!try->again) return DIRTREE_COMEAGAIN; using = AT_REMOVEDIR; if (try->symlink) goto skip; if (flags & FLAG_i) { -- cgit v1.2.3