X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=tree-walk.c;h=02e2aed7737207225f1b96eed774a1b75dd6d8d9;hb=191a8e32b38c7ff0dd884df7bd323b7a5bd4336c;hp=a4a4e2a9892fb10df32b113ca8b05848d11aff78;hpb=94b9816c5ce5bfc8bf4a8baf2128fa2d429a6898;p=git.git diff --git a/tree-walk.c b/tree-walk.c index a4a4e2a98..02e2aed77 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -2,6 +2,50 @@ #include "tree-walk.h" #include "tree.h" +static const char *get_mode(const char *str, unsigned int *modep) +{ + unsigned char c; + unsigned int mode = 0; + + if (*str == ' ') + return NULL; + + while ((c = *str++) != ' ') { + if (c < '0' || c > '7') + return NULL; + mode = (mode << 3) + (c - '0'); + } + *modep = mode; + return str; +} + +static void decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned long size) +{ + const char *path; + unsigned int mode, len; + + if (size < 24 || buf[size - 21]) + die("corrupt tree file"); + + path = get_mode(buf, &mode); + if (!path || !*path) + die("corrupt tree file"); + len = strlen(path) + 1; + + /* Initialize the descriptor entry */ + desc->entry.path = path; + desc->entry.mode = mode; + desc->entry.sha1 = (const unsigned char *)(path + len); +} + +void init_tree_desc(struct tree_desc *desc, const void *buffer, unsigned long size) +{ + desc->buffer = buffer; + desc->size = size; + if (size) + decode_tree_entry(desc, buffer, size); +} + void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1) { unsigned long size = 0; @@ -12,16 +56,15 @@ void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1) if (!buf) die("unable to read tree %s", sha1_to_hex(sha1)); } - desc->size = size; - desc->buf = buf; + init_tree_desc(desc, buf, size); return buf; } static int entry_compare(struct name_entry *a, struct name_entry *b) { - return base_name_compare( - a->path, a->pathlen, a->mode, - b->path, b->pathlen, b->mode); + 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); } static void entry_clear(struct name_entry *a) @@ -31,89 +74,78 @@ static void entry_clear(struct name_entry *a) static void entry_extract(struct tree_desc *t, struct name_entry *a) { - a->sha1 = tree_entry_extract(t, &a->path, &a->mode); - a->pathlen = tree_entry_len(a->path, a->sha1); + *a = t->entry; } void update_tree_entry(struct tree_desc *desc) { - const void *buf = desc->buf; + const void *buf = desc->buffer; + const unsigned char *end = desc->entry.sha1 + 20; unsigned long size = desc->size; - int len = strlen(buf) + 1 + 20; + unsigned long len = end - (const unsigned char *)buf; if (size < len) die("corrupt tree file"); - desc->buf = (char *) buf + len; - desc->size = size - len; + buf = end; + size -= len; + desc->buffer = buf; + desc->size = size; + if (size) + decode_tree_entry(desc, buf, size); } -static const char *get_mode(const char *str, unsigned int *modep) +int tree_entry(struct tree_desc *desc, struct name_entry *entry) { - unsigned char c; - unsigned int mode = 0; + if (!desc->size) + return 0; - while ((c = *str++) != ' ') { - if (c < '0' || c > '7') - return NULL; - mode = (mode << 3) + (c - '0'); - } - *modep = mode; - return str; + *entry = desc->entry; + update_tree_entry(desc); + return 1; } -const unsigned char *tree_entry_extract(struct tree_desc *desc, const char **pathp, unsigned int *modep) +void setup_traverse_info(struct traverse_info *info, const char *base) { - const void *tree = desc->buf; - unsigned long size = desc->size; - int len = strlen(tree)+1; - const unsigned char *sha1 = (unsigned char *) tree + len; - const char *path; - unsigned int mode; + int pathlen = strlen(base); + static struct traverse_info dummy; - path = get_mode(tree, &mode); - if (!path || size < len + 20) - die("corrupt tree file"); - *pathp = path; - *modep = canon_mode(mode); - return sha1; + 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; } -int tree_entry(struct tree_desc *desc, struct name_entry *entry) +char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n) { - const void *tree = desc->buf; - const char *path; - unsigned long len, size = desc->size; - - if (!size) - return 0; - - path = get_mode(tree, &entry->mode); - if (!path) - die("corrupt tree file"); - - entry->path = path; - len = strlen(path); - entry->pathlen = len; + int len = tree_entry_len(n->path, n->sha1); + int pathlen = info->pathlen; - path += len + 1; - entry->sha1 = (const unsigned char *) path; - - path += 20; - len = path - (char *) tree; - if (len > size) - die("corrupt tree file"); - - desc->buf = path; - desc->size = size - len; - return 1; + 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; } -void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback) +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; @@ -138,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) @@ -198,10 +240,11 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch { int retval; void *tree; + unsigned long size; struct tree_desc t; unsigned char root[20]; - tree = read_object_with_reference(tree_sha1, tree_type, &t.size, root); + tree = read_object_with_reference(tree_sha1, tree_type, &size, root); if (!tree) return -1; @@ -210,9 +253,8 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch return 0; } - t.buf = tree; + init_tree_desc(&t, tree, size); retval = find_tree_entry(&t, name, sha1, mode); free(tree); return retval; } -