aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dirtree.c26
1 files changed, 12 insertions, 14 deletions
diff --git a/lib/dirtree.c b/lib/dirtree.c
index f4cc620d..02f4b887 100644
--- a/lib/dirtree.c
+++ b/lib/dirtree.c
@@ -83,20 +83,18 @@ error:
char *dirtree_path(struct dirtree *node, int *plen)
{
+ struct dirtree *nn;
char *path;
- int len;
+ int len = plen ? *plen : 0;
- if (!node) {
- path = xmalloc(*plen);
- *plen = 0;
- return path;
- }
-
- len = (plen ? *plen : 0)+strlen(node->name)+1;
- path = dirtree_path(node->parent, &len);
- if (len && path[len-1] != '/') path[len++]='/';
- len = stpcpy(path+len, node->name) - path;
+ for (nn = node; nn; nn = nn->parent) if (*nn->name) len += strlen(nn->name)+1;
if (plen) *plen = len;
+ if (!len) return 0;
+ path = xmalloc(len)+len;
+ for (nn = node; nn; nn = nn->parent) if ((len = strlen(nn->name))) {
+ *--path = '/'*(nn != node);
+ memcpy(path -= len, nn->name, len);
+ }
return path;
}
@@ -121,11 +119,11 @@ struct dirtree *dirtree_handle_callback(struct dirtree *new,
flags = callback(new);
if (S_ISDIR(new->st.st_mode) && (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)))
- flags = dirtree_recurse(new, callback,
+ flags = dirtree_recurse(new, callback, !*new->name ? AT_FDCWD :
openat(dirtree_parentfd(new), new->name, O_CLOEXEC), flags);
- // If this had children, it was callback's job to free them already.
- if (!(flags & DIRTREE_SAVE)) {
+ // Free node that didn't request saving and has no saved children.
+ if (!new->child && !(flags & DIRTREE_SAVE)) {
free(new);
new = 0;
}