aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dirtree.c17
-rw-r--r--lib/lib.h1
-rw-r--r--toys/chgrp.c17
3 files changed, 23 insertions, 12 deletions
diff --git a/lib/dirtree.c b/lib/dirtree.c
index 418e8eb1..01e0ea8c 100644
--- a/lib/dirtree.c
+++ b/lib/dirtree.c
@@ -78,6 +78,23 @@ int dirtree_notdotdot(struct dirtree *catch)
return DIRTREE_SAVE|DIRTREE_RECURSE;
}
+// depth first recursion
+int dirtree_comeagain(struct dirtree *try, int recurse)
+{
+ int ret = dirtree_notdotdot(try);
+ if (ret) {
+ if (S_ISDIR(try->st.st_mode)) {
+ if (!try->extra) {
+ try->extra = xdup(try->data);
+ if (recurse) return DIRTREE_COMEAGAIN;
+ }
+ } else try->extra = openat(try->parent ? try->parent->data : AT_FDCWD,
+ try->name, 0);
+ }
+
+ return ret;
+}
+
// Handle callback for a node in the tree. Returns saved node(s) or NULL.
//
// By default, allocates a tree of struct dirtree, not following symlinks
diff --git a/lib/lib.h b/lib/lib.h
index 5a184ccf..88810b1f 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -74,6 +74,7 @@ struct dirtree {
struct dirtree *dirtree_add_node(int dirfd, char *name);
char *dirtree_path(struct dirtree *node, int *plen);
int dirtree_notdotdot(struct dirtree *catch);
+int dirtree_comeagain(struct dirtree *try, int recurse);
struct dirtree *handle_callback(struct dirtree *new,
int (*callback)(struct dirtree *node));
void dirtree_recurse(struct dirtree *node,
diff --git a/toys/chgrp.c b/toys/chgrp.c
index 5cf43896..935e1781 100644
--- a/toys/chgrp.c
+++ b/toys/chgrp.c
@@ -40,19 +40,12 @@ DEFINE_GLOBALS(
static int do_chgrp(struct dirtree *node)
{
- int fd, ret = 1, flags = toys.optflags;
+ int ret, flags = toys.optflags;
- if (!dirtree_notdotdot(node)) return 0;
+ ret = dirtree_comeagain(node, flags & FLAG_R);
+ if (!ret || ret == DIRTREE_COMEAGAIN) return ret;
- // Handle recursion, and make it depth first
- if (S_ISDIR(node->st.st_mode)) {
- if (!node->extra) node->extra = dup(node->data);
- if ((flags & FLAG_R) && node->data != -1) return DIRTREE_COMEAGAIN;
- fd = node->extra;
- } else fd = openat(node->parent ? node->parent->data : AT_FDCWD,
- node->name, 0);
-
- if (fd != -1) ret = fchown(fd, -1, TT.group);
+ if (node->extra != -1) ret = fchown(node->extra, -1, TT.group);
if (ret || (flags & FLAG_v)) {
char *path = dirtree_path(node, 0);
@@ -62,7 +55,7 @@ static int do_chgrp(struct dirtree *node)
perror_msg("changing group of '%s' to '%s'", path, TT.group_name);
free(path);
}
- close(fd);
+ close(node->extra);
toys.exitval |= ret;
return 0;