X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=tree-walk.c;h=297c6972b9256578f9cd7a92404dda55c8e34a2e;hb=fb6a9f93d39e4e5fdb83673a927f71a34e9fb7c0;hp=bf8bfdfdf8564d10b0ca5450dc62612e0ae4525d;hpb=3ffe0c245f290d55b32bed8b4ae04d00983df690;p=git.git diff --git a/tree-walk.c b/tree-walk.c index bf8bfdfd..297c6972 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -37,7 +37,7 @@ static void entry_extract(struct tree_desc *t, struct name_entry *a) void update_tree_entry(struct tree_desc *desc) { - void *buf = desc->buf; + const void *buf = desc->buf; unsigned long size = desc->size; int len = strlen(buf) + 1 + 20; @@ -47,22 +47,66 @@ void update_tree_entry(struct tree_desc *desc) desc->size = size - len; } +static const char *get_mode(const char *str, unsigned int *modep) +{ + unsigned char c; + unsigned int mode = 0; + + while ((c = *str++) != ' ') { + if (c < '0' || c > '7') + return NULL; + mode = (mode << 3) + (c - '0'); + } + *modep = mode; + return str; +} + const unsigned char *tree_entry_extract(struct tree_desc *desc, const char **pathp, unsigned int *modep) { - void *tree = desc->buf; + const void *tree = desc->buf; unsigned long size = desc->size; int len = strlen(tree)+1; const unsigned char *sha1 = tree + len; - const char *path = strchr(tree, ' '); + const char *path; unsigned int mode; - if (!path || size < len + 20 || sscanf(tree, "%o", &mode) != 1) + path = get_mode(tree, &mode); + if (!path || size < len + 20) die("corrupt tree file"); - *pathp = path+1; + *pathp = path; *modep = canon_mode(mode); return sha1; } +int tree_entry(struct tree_desc *desc, struct name_entry *entry) +{ + const void *tree = desc->buf, *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; + + path += len + 1; + entry->sha1 = path; + + path += 20; + len = path - tree; + if (len > size) + die("corrupt tree file"); + + desc->buf = path; + desc->size = size - len; + return 1; +} + void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback) { struct name_entry *entry = xmalloc(n*sizeof(*entry)); @@ -115,3 +159,53 @@ void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callb free(entry); } +static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char *result, unsigned *mode) +{ + int namelen = strlen(name); + while (t->size) { + const char *entry; + const unsigned char *sha1; + int entrylen, cmp; + + sha1 = tree_entry_extract(t, &entry, mode); + update_tree_entry(t); + entrylen = strlen(entry); + if (entrylen > namelen) + continue; + cmp = memcmp(name, entry, entrylen); + if (cmp > 0) + continue; + if (cmp < 0) + break; + if (entrylen == namelen) { + memcpy(result, sha1, 20); + return 0; + } + if (name[entrylen] != '/') + continue; + if (!S_ISDIR(*mode)) + break; + if (++entrylen == namelen) { + memcpy(result, sha1, 20); + return 0; + } + return get_tree_entry(sha1, name + entrylen, result, mode); + } + return -1; +} + +int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned char *sha1, unsigned *mode) +{ + int retval; + void *tree; + struct tree_desc t; + + tree = read_object_with_reference(tree_sha1, tree_type, &t.size, NULL); + if (!tree) + return -1; + t.buf = tree; + retval = find_tree_entry(&t, name, sha1, mode); + free(tree); + return retval; +} +