{"thread":{"id":"4356","subject":"tree_entry(): new tree-walking helper function","startedAt":"2006-05-30T16:45:45Z","lastAt":"2006-05-30T16:45:45Z","messageCount":1,"participants":["Linus Torvalds"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"20977","messageId":"Pine.LNX.4.64.0605300931170.5623@g5.osdl.org","threadId":"4356","inReplyTo":null,"subject":"tree_entry(): new tree-walking helper function","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-30T16:45:45Z","receivedAt":"2006-05-30T16:45:45Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThis adds a \"tree_entry()\" function that combines the common operation of \ndoing a \"tree_entry_extract()\" + \"update_tree_entry()\".\n\nIt also has a simplified calling convention, designed for simple loops \nthat traverse over a whole tree: the arguments are pointers to the tree \ndescriptor and a name_entry structure to fill in, and it returns a boolean \n\"true\" if there was an entry left to be gotten in the tree.\n\nThis allows tree traversal with\n\n\tstruct tree_desc desc;\n\tstruct name_entry entry;\n\n\tdesc.buf = tree->buffer;\n\tdesc.size = tree->size;\n\twhile (tree_entry(&desc, &entry) {\n\t\t... use \"entry.{path, sha1, mode, pathlen}\" ...\n\t}\n\nwhich is not only shorter than writing it out in full, it's hopefully less \nerror prone too.\n\n[ It's actually a tad faster too - we don't need to recalculate the entry \n  pathlength in both extract and update, but need to do it only once.  \n  Also, some callers can avoid doing a \"strlen()\" on the result, since \n  it's returned as part of the name_entry structure.\n\n  However, by now we're talking just 1% speedup on \"git-rev-list --objects \n  --all\", and we're definitely at the point where tree walking is no \n  longer the issue any more. ]\n\nNOTE! Not everybody wants to use this new helper function, since some of \nthe tree walkers very much on purpose do the descriptor update separately \nfrom the entry extraction. So the \"extract + update\" sequence still \nremains as the core sequence, this is just a simplified interface.\n\nWe should probably add a silly two-line inline helper function for \ninitializing the descriptor from the \"struct tree\" too, just to cut down \non the noise from that common \"desc\" initializer.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n\nThis is another of my \"I'm not going to push this patch very aggressively\" \nseries. I think it's a cleanup, and it removes more lines than it adds and \nseems to make things more readable, but is it worth it? You decide.\n\n builtin-grep.c      |   26 ++++++++++----------------\n builtin-read-tree.c |   36 +++++++++++++-----------------------\n builtin-rev-list.c  |   16 +++++-----------\n builtin-tar-tree.c  |   21 ++++++++-------------\n fetch.c             |   16 +++++-----------\n http-push.c         |   16 +++++-----------\n pack-objects.c      |   27 +++++++++++----------------\n revision.c          |   16 +++++-----------\n tree-walk.c         |   33 +++++++++++++++++++++++++++++++--\n tree-walk.h         |    5 ++++-\n tree.c              |   41 +++++++++++++++--------------------------\n 11 files changed, 112 insertions(+), 141 deletions(-)\n\ndiff --git a/builtin-grep.c b/builtin-grep.c\nindex 53de8a8..acc4eea 100644\n--- a/builtin-grep.c\n+++ b/builtin-grep.c\n@@ -578,11 +578,9 @@ static int grep_tree(struct grep_opt *op\n \t\t     struct tree_desc *tree,\n \t\t     const char *tree_name, const char *base)\n {\n-\tunsigned mode;\n \tint len;\n \tint hit = 0;\n-\tconst char *path;\n-\tconst unsigned char *sha1;\n+\tstruct name_entry entry;\n \tchar *down;\n \tchar *path_buf = xmalloc(PATH_MAX + strlen(tree_name) + 100);\n \n@@ -597,36 +595,32 @@ static int grep_tree(struct grep_opt *op\n \t}\n \tlen = strlen(path_buf);\n \n-\twhile (tree->size) {\n-\t\tint pathlen;\n-\t\tsha1 = tree_entry_extract(tree, &path, &mode);\n-\t\tpathlen = strlen(path);\n-\t\tstrcpy(path_buf + len, path);\n+\twhile (tree_entry(tree, &entry)) {\n+\t\tstrcpy(path_buf + len, entry.path);\n \n-\t\tif (S_ISDIR(mode))\n+\t\tif (S_ISDIR(entry.mode))\n \t\t\t/* Match \"abc/\" against pathspec to\n \t\t\t * decide if we want to descend into \"abc\"\n \t\t\t * directory.\n \t\t\t */\n-\t\t\tstrcpy(path_buf + len + pathlen, \"/\");\n+\t\t\tstrcpy(path_buf + len + entry.pathlen, \"/\");\n \n \t\tif (!pathspec_matches(paths, down))\n \t\t\t;\n-\t\telse if (S_ISREG(mode))\n-\t\t\thit |= grep_sha1(opt, sha1, path_buf);\n-\t\telse if (S_ISDIR(mode)) {\n+\t\telse if (S_ISREG(entry.mode))\n+\t\t\thit |= grep_sha1(opt, entry.sha1, path_buf);\n+\t\telse if (S_ISDIR(entry.mode)) {\n \t\t\tchar type[20];\n \t\t\tstruct tree_desc sub;\n \t\t\tvoid *data;\n-\t\t\tdata = read_sha1_file(sha1, type, &sub.size);\n+\t\t\tdata = read_sha1_file(entry.sha1, type, &sub.size);\n \t\t\tif (!data)\n \t\t\t\tdie(\"unable to read tree (%s)\",\n-\t\t\t\t    sha1_to_hex(sha1));\n+\t\t\t\t    sha1_to_hex(entry.sha1));\n \t\t\tsub.buf = data;\n \t\t\thit |= grep_tree(opt, paths, &sub, tree_name, down);\n \t\t\tfree(data);\n \t\t}\n-\t\tupdate_tree_entry(tree);\n \t}\n \treturn hit;\n }\ndiff --git a/builtin-read-tree.c b/builtin-read-tree.c\nindex d70411f..0c6ba3d 100644\n--- a/builtin-read-tree.c\n+++ b/builtin-read-tree.c\n@@ -54,28 +54,23 @@ typedef int (*merge_fn_t)(struct cache_e\n static struct tree_entry_list *create_tree_entry_list(struct tree *tree)\n {\n \tstruct tree_desc desc;\n+\tstruct name_entry one;\n \tstruct tree_entry_list *ret = NULL;\n \tstruct tree_entry_list **list_p = &ret;\n \n \tdesc.buf = tree->buffer;\n \tdesc.size = tree->size;\n \n-\twhile (desc.size) {\n-\t\tunsigned mode;\n-\t\tconst char *path;\n-\t\tconst unsigned char *sha1;\n+\twhile (tree_entry(&desc, &one)) {\n \t\tstruct tree_entry_list *entry;\n \n-\t\tsha1 = tree_entry_extract(&desc, &path, &mode);\n-\t\tupdate_tree_entry(&desc);\n-\n \t\tentry = xmalloc(sizeof(struct tree_entry_list));\n-\t\tentry->name = path;\n-\t\tentry->sha1 = sha1;\n-\t\tentry->mode = mode;\n-\t\tentry->directory = S_ISDIR(mode) != 0;\n-\t\tentry->executable = (mode & S_IXUSR) != 0;\n-\t\tentry->symlink = S_ISLNK(mode) != 0;\n+\t\tentry->name = one.path;\n+\t\tentry->sha1 = one.sha1;\n+\t\tentry->mode = one.mode;\n+\t\tentry->directory = S_ISDIR(one.mode) != 0;\n+\t\tentry->executable = (one.mode & S_IXUSR) != 0;\n+\t\tentry->symlink = S_ISLNK(one.mode) != 0;\n \t\tentry->next = NULL;\n \n \t\t*list_p = entry;\n@@ -846,27 +841,22 @@ static int read_cache_unmerged(void)\n static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)\n {\n \tstruct tree_desc desc;\n+\tstruct name_entry entry;\n \tint cnt;\n \n \tmemcpy(it->sha1, tree->object.sha1, 20);\n \tdesc.buf = tree->buffer;\n \tdesc.size = tree->size;\n \tcnt = 0;\n-\twhile (desc.size) {\n-\t\tunsigned mode;\n-\t\tconst char *name;\n-\t\tconst unsigned char *sha1;\n-\n-\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n-\t\tupdate_tree_entry(&desc);\n-\t\tif (!S_ISDIR(mode))\n+\twhile (tree_entry(&desc, &entry)) {\n+\t\tif (!S_ISDIR(entry.mode))\n \t\t\tcnt++;\n \t\telse {\n \t\t\tstruct cache_tree_sub *sub;\n-\t\t\tstruct tree *subtree = lookup_tree(sha1);\n+\t\t\tstruct tree *subtree = lookup_tree(entry.sha1);\n \t\t\tif (!subtree->object.parsed)\n \t\t\t\tparse_tree(subtree);\n-\t\t\tsub = cache_tree_sub(it, name);\n+\t\t\tsub = cache_tree_sub(it, entry.path);\n \t\t\tsub->cache_tree = cache_tree();\n \t\t\tprime_cache_tree_rec(sub->cache_tree, subtree);\n \t\t\tcnt += sub->cache_tree->entry_count;\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex 6e2b898..17c04b9 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -114,6 +114,7 @@ static struct object_list **process_tree\n {\n \tstruct object *obj = &tree->object;\n \tstruct tree_desc desc;\n+\tstruct name_entry entry;\n \tstruct name_path me;\n \n \tif (!revs.tree_objects)\n@@ -132,18 +133,11 @@ static struct object_list **process_tree\n \tdesc.buf = tree->buffer;\n \tdesc.size = tree->size;\n \n-\twhile (desc.size) {\n-\t\tunsigned mode;\n-\t\tconst char *name;\n-\t\tconst unsigned char *sha1;\n-\n-\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n-\t\tupdate_tree_entry(&desc);\n-\n-\t\tif (S_ISDIR(mode))\n-\t\t\tp = process_tree(lookup_tree(sha1), p, &me, name);\n+\twhile (tree_entry(&desc, &entry)) {\n+\t\tif (S_ISDIR(entry.mode))\n+\t\t\tp = process_tree(lookup_tree(entry.sha1), p, &me, name);\n \t\telse\n-\t\t\tp = process_blob(lookup_blob(sha1), p, &me, name);\n+\t\t\tp = process_blob(lookup_blob(entry.sha1), p, &me, name);\n \t}\n \tfree(tree->buffer);\n \ttree->buffer = NULL;\ndiff --git a/builtin-tar-tree.c b/builtin-tar-tree.c\nindex 2d5e06f..5f740cf 100644\n--- a/builtin-tar-tree.c\n+++ b/builtin-tar-tree.c\n@@ -271,30 +271,25 @@ static void write_global_extended_header\n static void traverse_tree(struct tree_desc *tree, struct strbuf *path)\n {\n \tint pathlen = path->len;\n+\tstruct name_entry entry;\n \n-\twhile (tree->size) {\n-\t\tconst char *name;\n-\t\tconst unsigned char *sha1;\n-\t\tunsigned mode;\n+\twhile (tree_entry(tree, &entry)) {\n \t\tvoid *eltbuf;\n \t\tchar elttype[20];\n \t\tunsigned long eltsize;\n \n-\t\tsha1 = tree_entry_extract(tree, &name, &mode);\n-\t\tupdate_tree_entry(tree);\n-\n-\t\teltbuf = read_sha1_file(sha1, elttype, &eltsize);\n+\t\teltbuf = read_sha1_file(entry.sha1, elttype, &eltsize);\n \t\tif (!eltbuf)\n-\t\t\tdie(\"cannot read %s\", sha1_to_hex(sha1));\n+\t\t\tdie(\"cannot read %s\", sha1_to_hex(entry.sha1));\n \n \t\tpath->len = pathlen;\n-\t\tstrbuf_append_string(path, name);\n-\t\tif (S_ISDIR(mode))\n+\t\tstrbuf_append_string(path, entry.path);\n+\t\tif (S_ISDIR(entry.mode))\n \t\t\tstrbuf_append_string(path, \"/\");\n \n-\t\twrite_entry(sha1, path, mode, eltbuf, eltsize);\n+\t\twrite_entry(entry.sha1, path, entry.mode, eltbuf, eltsize);\n \n-\t\tif (S_ISDIR(mode)) {\n+\t\tif (S_ISDIR(entry.mode)) {\n \t\t\tstruct tree_desc subtree;\n \t\t\tsubtree.buf = eltbuf;\n \t\t\tsubtree.size = eltsize;\ndiff --git a/fetch.c b/fetch.c\nindex b03c201..e9347ba 100644\n--- a/fetch.c\n+++ b/fetch.c\n@@ -39,25 +39,19 @@ static int process(struct object *obj);\n static int process_tree(struct tree *tree)\n {\n \tstruct tree_desc desc;\n+\tstruct name_entry entry;\n \n \tif (parse_tree(tree))\n \t\treturn -1;\n \n \tdesc.buf = tree->buffer;\n \tdesc.size = tree->size;\n-\twhile (desc.size) {\n-\t\tunsigned mode;\n-\t\tconst char *name;\n-\t\tconst unsigned char *sha1;\n-\n-\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n-\t\tupdate_tree_entry(&desc);\n-\n-\t\tif (S_ISDIR(mode)) {\n-\t\t\tstruct tree *tree = lookup_tree(sha1);\n+\twhile (tree_entry(&desc, &entry)) {\n+\t\tif (S_ISDIR(entry.mode)) {\n+\t\t\tstruct tree *tree = lookup_tree(entry.sha1);\n \t\t\tprocess_tree(tree);\n \t\t} else {\n-\t\t\tstruct blob *blob = lookup_blob(sha1);\n+\t\t\tstruct blob *blob = lookup_blob(entry.sha1);\n \t\t\tprocess(&blob->object);\n \t\t}\n \t}\ndiff --git a/http-push.c b/http-push.c\nindex 72ad89c..b1c018a 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1715,6 +1715,7 @@ static struct object_list **process_tree\n {\n \tstruct object *obj = &tree->object;\n \tstruct tree_desc desc;\n+\tstruct name_entry entry;\n \tstruct name_path me;\n \n \tobj->flags |= LOCAL;\n@@ -1734,18 +1735,11 @@ static struct object_list **process_tree\n \tdesc.buf = tree->buffer;\n \tdesc.size = tree->size;\n \n-\twhile (desc.size) {\n-\t\tunsigned mode;\n-\t\tconst char *name;\n-\t\tconst unsigned char *sha1;\n-\n-\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n-\t\tupdate_tree_entry(&desc);\n-\n-\t\tif (S_ISDIR(mode))\n-\t\t\tp = process_tree(lookup_tree(sha1), p, &me, name);\n+\twhile (tree_entry(&desc, &entry)) {\n+\t\tif (S_ISDIR(entry.mode))\n+\t\t\tp = process_tree(lookup_tree(entry.sha1), p, &me, name);\n \t\telse\n-\t\t\tp = process_blob(lookup_blob(sha1), p, &me, name);\n+\t\t\tp = process_blob(lookup_blob(entry.sha1), p, &me, name);\n \t}\n \tfree(tree->buffer);\n \ttree->buffer = NULL;\ndiff --git a/pack-objects.c b/pack-objects.c\nindex 77284cf..3590cd5 100644\n--- a/pack-objects.c\n+++ b/pack-objects.c\n@@ -690,25 +690,20 @@ static void add_pbase_object(struct tree\n \t\t\t     const char *name,\n \t\t\t     int cmplen)\n {\n-\twhile (tree->size) {\n-\t\tconst unsigned char *sha1;\n-\t\tconst char *entry_name;\n-\t\tint entry_len;\n-\t\tunsigned mode;\n+\tstruct name_entry entry;\n+\n+\twhile (tree_entry(tree,&entry)) {\n \t\tunsigned long size;\n \t\tchar type[20];\n \n-\t\tsha1 = tree_entry_extract(tree, &entry_name, &mode);\n-\t\tupdate_tree_entry(tree);\n-\t\tentry_len = strlen(entry_name);\n-\t\tif (entry_len != cmplen ||\n-\t\t    memcmp(entry_name, name, cmplen) ||\n-\t\t    !has_sha1_file(sha1) ||\n-\t\t    sha1_object_info(sha1, type, &size))\n+\t\tif (entry.pathlen != cmplen ||\n+\t\t    memcmp(entry.path, name, cmplen) ||\n+\t\t    !has_sha1_file(entry.sha1) ||\n+\t\t    sha1_object_info(entry.sha1, type, &size))\n \t\t\tcontinue;\n \t\tif (name[cmplen] != '/') {\n \t\t\tunsigned hash = name_hash(up, name);\n-\t\t\tadd_object_entry(sha1, hash, 1);\n+\t\t\tadd_object_entry(entry.sha1, hash, 1);\n \t\t\treturn;\n \t\t}\n \t\tif (!strcmp(type, tree_type)) {\n@@ -718,15 +713,15 @@ static void add_pbase_object(struct tree\n \t\t\tconst char *down = name+cmplen+1;\n \t\t\tint downlen = name_cmp_len(down);\n \n-\t\t\ttree = pbase_tree_get(sha1);\n+\t\t\ttree = pbase_tree_get(entry.sha1);\n \t\t\tif (!tree)\n \t\t\t\treturn;\n \t\t\tsub.buf = tree->tree_data;\n \t\t\tsub.size = tree->tree_size;\n \n \t\t\tme.up = up;\n-\t\t\tme.elem = entry_name;\n-\t\t\tme.len = entry_len;\n+\t\t\tme.elem = entry.path;\n+\t\t\tme.len = entry.pathlen;\n \t\t\tadd_pbase_object(&sub, &me, down, downlen);\n \t\t\tpbase_tree_put(tree);\n \t\t}\ndiff --git a/revision.c b/revision.c\nindex 8e93e40..6a6952c 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -54,6 +54,7 @@ static void mark_blob_uninteresting(stru\n void mark_tree_uninteresting(struct tree *tree)\n {\n \tstruct tree_desc desc;\n+\tstruct name_entry entry;\n \tstruct object *obj = &tree->object;\n \n \tif (obj->flags & UNINTERESTING)\n@@ -66,18 +67,11 @@ void mark_tree_uninteresting(struct tree\n \n \tdesc.buf = tree->buffer;\n \tdesc.size = tree->size;\n-\twhile (desc.size) {\n-\t\tunsigned mode;\n-\t\tconst char *name;\n-\t\tconst unsigned char *sha1;\n-\n-\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n-\t\tupdate_tree_entry(&desc);\n-\n-\t\tif (S_ISDIR(mode))\n-\t\t\tmark_tree_uninteresting(lookup_tree(sha1));\n+\twhile (tree_entry(&desc, &entry)) {\n+\t\tif (S_ISDIR(entry.mode))\n+\t\t\tmark_tree_uninteresting(lookup_tree(entry.sha1));\n \t\telse\n-\t\t\tmark_blob_uninteresting(lookup_blob(sha1));\n+\t\t\tmark_blob_uninteresting(lookup_blob(entry.sha1));\n \t}\n \n \t/*\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 3922058..297c697 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -37,7 +37,7 @@ static void entry_extract(struct tree_de\n \n void update_tree_entry(struct tree_desc *desc)\n {\n-\tvoid *buf = desc->buf;\n+\tconst void *buf = desc->buf;\n \tunsigned long size = desc->size;\n \tint len = strlen(buf) + 1 + 20;\n \n@@ -63,7 +63,7 @@ static const char *get_mode(const char *\n \n const unsigned char *tree_entry_extract(struct tree_desc *desc, const char **pathp, unsigned int *modep)\n {\n-\tvoid *tree = desc->buf;\n+\tconst void *tree = desc->buf;\n \tunsigned long size = desc->size;\n \tint len = strlen(tree)+1;\n \tconst unsigned char *sha1 = tree + len;\n@@ -78,6 +78,35 @@ const unsigned char *tree_entry_extract(\n \treturn sha1;\n }\n \n+int tree_entry(struct tree_desc *desc, struct name_entry *entry)\n+{\n+\tconst void *tree = desc->buf, *path;\n+\tunsigned long len, size = desc->size;\n+\n+\tif (!size)\n+\t\treturn 0;\n+\n+\tpath = get_mode(tree, &entry->mode);\n+\tif (!path)\n+\t\tdie(\"corrupt tree file\");\n+\n+\tentry->path = path;\n+\tlen = strlen(path);\n+\tentry->pathlen = len;\n+\n+\tpath += len + 1;\n+\tentry->sha1 = path;\n+\n+\tpath += 20;\n+\tlen = path - tree;\n+\tif (len > size)\n+\t\tdie(\"corrupt tree file\");\n+\n+\tdesc->buf = path;\n+\tdesc->size = size - len;\n+\treturn 1;\n+}\n+\n void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback)\n {\n \tstruct name_entry *entry = xmalloc(n*sizeof(*entry));\ndiff --git a/tree-walk.h b/tree-walk.h\nindex 47438fe..e57befa 100644\n--- a/tree-walk.h\n+++ b/tree-walk.h\n@@ -2,7 +2,7 @@ #ifndef TREE_WALK_H\n #define TREE_WALK_H\n \n struct tree_desc {\n-\tvoid *buf;\n+\tconst void *buf;\n \tunsigned long size;\n };\n \n@@ -16,6 +16,9 @@ struct name_entry {\n void update_tree_entry(struct tree_desc *);\n const unsigned char *tree_entry_extract(struct tree_desc *, const char **, unsigned int *);\n \n+/* Helper function that does both of the above and returns true for success */\n+int tree_entry(struct tree_desc *, struct name_entry *);\n+\n void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1);\n \n typedef void (*traverse_callback_t)(int n, unsigned long mask, struct name_entry *entry, const char *base);\ndiff --git a/tree.c b/tree.c\nindex fb18724..9bbe2da 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -79,6 +79,7 @@ int read_tree_recursive(struct tree *tre\n \t\t\tread_tree_fn_t fn)\n {\n \tstruct tree_desc desc;\n+\tstruct name_entry entry;\n \n \tif (parse_tree(tree))\n \t\treturn -1;\n@@ -86,18 +87,11 @@ int read_tree_recursive(struct tree *tre\n \tdesc.buf = tree->buffer;\n \tdesc.size = tree->size;\n \n-\twhile (desc.size) {\n-\t\tunsigned mode;\n-\t\tconst char *name;\n-\t\tconst unsigned char *sha1;\n-\n-\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n-\t\tupdate_tree_entry(&desc);\n-\n-\t\tif (!match_tree_entry(base, baselen, name, mode, match))\n+\twhile (tree_entry(&desc, &entry)) {\n+\t\tif (!match_tree_entry(base, baselen, entry.path, entry.mode, match))\n \t\t\tcontinue;\n \n-\t\tswitch (fn(sha1, base, baselen, name, mode, stage)) {\n+\t\tswitch (fn(entry.sha1, base, baselen, entry.path, entry.mode, stage)) {\n \t\tcase 0:\n \t\t\tcontinue;\n \t\tcase READ_TREE_RECURSIVE:\n@@ -105,18 +99,17 @@ int read_tree_recursive(struct tree *tre\n \t\tdefault:\n \t\t\treturn -1;\n \t\t}\n-\t\tif (S_ISDIR(mode)) {\n+\t\tif (S_ISDIR(entry.mode)) {\n \t\t\tint retval;\n-\t\t\tint pathlen = strlen(name);\n \t\t\tchar *newbase;\n \n-\t\t\tnewbase = xmalloc(baselen + 1 + pathlen);\n+\t\t\tnewbase = xmalloc(baselen + 1 + entry.pathlen);\n \t\t\tmemcpy(newbase, base, baselen);\n-\t\t\tmemcpy(newbase + baselen, name, pathlen);\n-\t\t\tnewbase[baselen + pathlen] = '/';\n-\t\t\tretval = read_tree_recursive(lookup_tree(sha1),\n+\t\t\tmemcpy(newbase + baselen, entry.path, entry.pathlen);\n+\t\t\tnewbase[baselen + entry.pathlen] = '/';\n+\t\t\tretval = read_tree_recursive(lookup_tree(entry.sha1),\n \t\t\t\t\t\t     newbase,\n-\t\t\t\t\t\t     baselen + pathlen + 1,\n+\t\t\t\t\t\t     baselen + entry.pathlen + 1,\n \t\t\t\t\t\t     stage, match, fn);\n \t\t\tfree(newbase);\n \t\t\tif (retval)\n@@ -156,6 +149,7 @@ static int track_tree_refs(struct tree *\n \tint n_refs = 0, i;\n \tstruct object_refs *refs;\n \tstruct tree_desc desc;\n+\tstruct name_entry entry;\n \n \t/* Count how many entries there are.. */\n \tdesc.buf = item->buffer;\n@@ -170,18 +164,13 @@ static int track_tree_refs(struct tree *\n \trefs = alloc_object_refs(n_refs);\n \tdesc.buf = item->buffer;\n \tdesc.size = item->size;\n-\twhile (desc.size) {\n-\t\tunsigned mode;\n-\t\tconst char *name;\n-\t\tconst unsigned char *sha1;\n+\twhile (tree_entry(&desc, &entry)) {\n \t\tstruct object *obj;\n \n-\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n-\t\tupdate_tree_entry(&desc);\n-\t\tif (S_ISDIR(mode))\n-\t\t\tobj = &lookup_tree(sha1)->object;\n+\t\tif (S_ISDIR(entry.mode))\n+\t\t\tobj = &lookup_tree(entry.sha1)->object;\n \t\telse\n-\t\t\tobj = &lookup_blob(sha1)->object;\n+\t\t\tobj = &lookup_blob(entry.sha1)->object;\n \t\trefs->ref[i++] = obj;\n \t}\n \tset_object_refs(&item->object, refs);\n"}]}