summaryrefslogtreecommitdiff
path: root/tree-walk.c
diff options
context:
space:
mode:
Diffstat (limited to 'tree-walk.c')
-rw-r--r--tree-walk.c62
1 files changed, 54 insertions, 8 deletions
diff --git a/tree-walk.c b/tree-walk.c
index 142205ddc3..02e2aed773 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -62,7 +62,7 @@ void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1)
static int entry_compare(struct name_entry *a, struct name_entry *b)
{
- return base_name_compare(
+ return df_name_compare(
a->path, tree_entry_len(a->path, a->sha1), a->mode,
b->path, tree_entry_len(b->path, b->sha1), b->mode);
}
@@ -104,12 +104,48 @@ int tree_entry(struct tree_desc *desc, struct name_entry *entry)
return 1;
}
-void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback)
+void setup_traverse_info(struct traverse_info *info, const char *base)
{
+ int pathlen = strlen(base);
+ static struct traverse_info dummy;
+
+ memset(info, 0, sizeof(*info));
+ if (pathlen && base[pathlen-1] == '/')
+ pathlen--;
+ info->pathlen = pathlen ? pathlen + 1 : 0;
+ info->name.path = base;
+ info->name.sha1 = (void *)(base + pathlen + 1);
+ if (pathlen)
+ info->prev = &dummy;
+}
+
+char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
+{
+ int len = tree_entry_len(n->path, n->sha1);
+ int pathlen = info->pathlen;
+
+ path[pathlen + len] = 0;
+ for (;;) {
+ memcpy(path + pathlen, n->path, len);
+ if (!pathlen)
+ break;
+ path[--pathlen] = '/';
+ n = &info->name;
+ len = tree_entry_len(n->path, n->sha1);
+ info = info->prev;
+ pathlen -= len;
+ }
+ return path;
+}
+
+int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
+{
+ int ret = 0;
struct name_entry *entry = xmalloc(n*sizeof(*entry));
for (;;) {
unsigned long mask = 0;
+ unsigned long dirmask = 0;
int i, last;
last = -1;
@@ -134,25 +170,35 @@ void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callb
mask = 0;
}
mask |= 1ul << i;
+ if (S_ISDIR(entry[i].mode))
+ dirmask |= 1ul << i;
last = i;
}
if (!mask)
break;
+ dirmask &= mask;
/*
- * Update the tree entries we've walked, and clear
- * all the unused name-entries.
+ * Clear all the unused name-entries.
*/
for (i = 0; i < n; i++) {
- if (mask & (1ul << i)) {
- update_tree_entry(t+i);
+ if (mask & (1ul << i))
continue;
- }
entry_clear(entry + i);
}
- callback(n, mask, entry, base);
+ ret = info->fn(n, mask, dirmask, entry, info);
+ if (ret < 0)
+ break;
+ if (ret)
+ mask &= ret;
+ ret = 0;
+ for (i = 0; i < n; i++) {
+ if (mask & (1ul << i))
+ update_tree_entry(t + i);
+ }
}
free(entry);
+ return ret;
}
static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char *result, unsigned *mode)