diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 716f792514..6876f3d793 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -39,7 +39,7 @@ static struct tree_entry_list df_conflict_list = { typedef int (*merge_fn_t)(struct cache_entry **src); -static int entcmp(char *name1, int dir1, char *name2, int dir2) +static int entcmp(const char *name1, int dir1, const char *name2, int dir2) { int len1 = strlen(name1); int len2 = strlen(name2); @@ -67,7 +67,7 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len, int src_size = len + 1; do { int i; - char *first; + const char *first; int firstdir = 0; int pathlen; unsigned ce_size; diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 5277d3cf12..72c1549c70 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -136,10 +136,11 @@ static struct object_list **process_tree(struct tree *tree, p = process_tree(entry->item.tree, p, &me, entry->name); else p = process_blob(entry->item.blob, p, &me, entry->name); - free(entry->name); free(entry); entry = next; } + free(tree->buffer); + tree->buffer = NULL; return p; } diff --git a/fsck-objects.c b/fsck-objects.c index 1922b6d84c..5e65df436b 100644 --- a/fsck-objects.c +++ b/fsck-objects.c @@ -198,17 +198,16 @@ static int fsck_tree(struct tree *item) default: break; } - free(last->name); free(last); } last = entry; } - if (last) { - free(last->name); + if (last) free(last); - } item->entries = NULL; + free(item->buffer); + item->buffer = NULL; retval = 0; if (has_full_path) { diff --git a/object.c b/object.c index 4d46e0d5e4..1a7823c234 100644 --- a/object.c +++ b/object.c @@ -200,8 +200,11 @@ struct object *parse_object(const unsigned char *sha1) obj = &blob->object; } else if (!strcmp(type, tree_type)) { struct tree *tree = lookup_tree(sha1); - parse_tree_buffer(tree, buffer, size); obj = &tree->object; + if (!tree->object.parsed) { + parse_tree_buffer(tree, buffer, size); + buffer = NULL; + } } else if (!strcmp(type, commit_type)) { struct commit *commit = lookup_commit(sha1); parse_commit_buffer(commit, buffer, size); diff --git a/tree.c b/tree.c index d599fb5e1a..1e76d9cc11 100644 --- a/tree.c +++ b/tree.c @@ -3,6 +3,7 @@ #include "blob.h" #include "commit.h" #include "tag.h" +#include "tree-walk.h" #include const char *tree_type = "tree"; @@ -145,46 +146,45 @@ struct tree *lookup_tree(const unsigned char *sha1) int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size) { - void *bufptr = buffer; + struct tree_desc desc; struct tree_entry_list **list_p; int n_refs = 0; if (item->object.parsed) return 0; item->object.parsed = 1; + item->buffer = buffer; + item->size = size; + + desc.buf = buffer; + desc.size = size; + list_p = &item->entries; - while (size) { - struct object *obj; + while (desc.size) { + unsigned mode; + const char *path; + const unsigned char *sha1; struct tree_entry_list *entry; - int len = 1+strlen(bufptr); - unsigned char *file_sha1 = bufptr + len; - char *path = strchr(bufptr, ' '); - unsigned int mode; - if (size < len + 20 || !path || - sscanf(bufptr, "%o", &mode) != 1) - return -1; + + sha1 = tree_entry_extract(&desc, &path, &mode); entry = xmalloc(sizeof(struct tree_entry_list)); - entry->name = strdup(path + 1); + entry->name = path; + entry->mode = mode; entry->directory = S_ISDIR(mode) != 0; entry->executable = (mode & S_IXUSR) != 0; entry->symlink = S_ISLNK(mode) != 0; - entry->zeropad = *(char *)bufptr == '0'; - entry->mode = mode; + entry->zeropad = *(const char *)(desc.buf) == '0'; entry->next = NULL; - bufptr += len + 20; - size -= len + 20; + update_tree_entry(&desc); if (entry->directory) { - entry->item.tree = lookup_tree(file_sha1); - obj = &entry->item.tree->object; + entry->item.tree = lookup_tree(sha1); } else { - entry->item.blob = lookup_blob(file_sha1); - obj = &entry->item.blob->object; + entry->item.blob = lookup_blob(sha1); } - if (obj) - n_refs++; + n_refs++; *list_p = entry; list_p = &entry->next; } @@ -206,7 +206,6 @@ int parse_tree(struct tree *item) char type[20]; void *buffer; unsigned long size; - int ret; if (item->object.parsed) return 0; @@ -219,9 +218,7 @@ int parse_tree(struct tree *item) return error("Object %s not a tree", sha1_to_hex(item->object.sha1)); } - ret = parse_tree_buffer(item, buffer, size); - free(buffer); - return ret; + return parse_tree_buffer(item, buffer, size); } struct tree *parse_tree_indirect(const unsigned char *sha1) diff --git a/tree.h b/tree.h index 330ab64bbd..066ac5d5bf 100644 --- a/tree.h +++ b/tree.h @@ -12,7 +12,7 @@ struct tree_entry_list { unsigned symlink : 1; unsigned zeropad : 1; unsigned int mode; - char *name; + const char *name; union { struct object *any; struct tree *tree; @@ -22,6 +22,8 @@ struct tree_entry_list { struct tree { struct object object; + void *buffer; + unsigned long size; struct tree_entry_list *entries; };