tree-walk: store object_id in a separate member

When parsing a tree, we read the object ID directly out of the tree buffer. This is normally fine, but such an object ID cannot be used with oidcpy, which copies GIT_MAX_RAWSZ bytes, because if we are using SHA-1, there may not be that many bytes to copy. Instead, store the object ID in a separate struct member. Since we can no longer efficiently compute the path length, store that information as well in struct name_entry. Ensure we only copy the object ID into the new buffer if the path length is nonzero, as some callers will pass us an empty path with no object ID following it, and we will not want to read past the end of the buffer. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

brian m. carlson committed Jan 15, 2019 at 00:39 UTC ea82b2a0857e3e0449bdce4e3987dee6adbc51ae
19 files changed +60 -54
builtin/grep.c
+4 -4
@@ -566,7 +566,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
566 strbuf_add(base, entry.path, te_len);
567
568 if (S_ISREG(entry.mode)) {
569 - hit |= grep_oid(opt, entry.oid, base->buf, tn_len,
569 + hit |= grep_oid(opt, &entry.oid, base->buf, tn_len,
570 check_attr ? base->buf + tn_len : NULL);
571 } else if (S_ISDIR(entry.mode)) {
572 enum object_type type;
@@ -574,10 +574,10 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
574 void *data;
575 unsigned long size;
576
577 - data = lock_and_read_oid_file(entry.oid, &type, &size);
577 + data = lock_and_read_oid_file(&entry.oid, &type, &size);
578 if (!data)
579 die(_("unable to read tree (%s)"),
580 - oid_to_hex(entry.oid));
580 + oid_to_hex(&entry.oid));
581
582 strbuf_addch(base, '/');
583 init_tree_desc(&sub, data, size);
@@ -585,7 +585,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
585 check_attr, repo);
586 free(data);
587 } else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
588 - hit |= grep_submodule(opt, repo, pathspec, entry.oid,
588 + hit |= grep_submodule(opt, repo, pathspec, &entry.oid,
589 base->buf, base->buf + tn_len);
590 }
591
builtin/merge-tree.c
+10 -10
@@ -154,15 +154,15 @@ static void show_result(void)
154 /* An empty entry never compares same, not even to another empty entry */
155 static int same_entry(struct name_entry *a, struct name_entry *b)
156 {
157 - return a->oid &&
158 - b->oid &&
159 - oideq(a->oid, b->oid) &&
157 + return !is_null_oid(&a->oid) &&
158 + !is_null_oid(&b->oid) &&
159 + oideq(&a->oid, &b->oid) &&
160 a->mode == b->mode;
161 }
162
163 static int both_empty(struct name_entry *a, struct name_entry *b)
164 {
165 - return !(a->oid || b->oid);
165 + return is_null_oid(&a->oid) && is_null_oid(&b->oid);
166 }
167
168 static struct merge_list *create_entry(unsigned stage, unsigned mode, const struct object_id *oid, const char *path)
@@ -178,7 +178,7 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const stru
178
179 static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
180 {
181 - char *path = xmallocz(traverse_path_len(info, n));
181 + char *path = xmallocz(traverse_path_len(info, n) + the_hash_algo->rawsz);
182 return make_traverse_path(path, info, n);
183 }
184
@@ -192,8 +192,8 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s
192 return;
193
194 path = traverse_path(info, result);
195 - orig = create_entry(2, ours->mode, ours->oid, path);
196 - final = create_entry(0, result->mode, result->oid, path);
195 + orig = create_entry(2, ours->mode, &ours->oid, path);
196 + final = create_entry(0, result->mode, &result->oid, path);
197
198 final->link = orig;
199
@@ -217,7 +217,7 @@ static void unresolved_directory(const struct traverse_info *info,
217
218 newbase = traverse_path(info, p);
219
220 -#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? (e)->oid : NULL)
220 +#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? &(e)->oid : NULL)
221 buf0 = fill_tree_descriptor(t + 0, ENTRY_OID(n + 0));
222 buf1 = fill_tree_descriptor(t + 1, ENTRY_OID(n + 1));
223 buf2 = fill_tree_descriptor(t + 2, ENTRY_OID(n + 2));
@@ -243,7 +243,7 @@ static struct merge_list *link_entry(unsigned stage, const struct traverse_info
243 path = entry->path;
244 else
245 path = traverse_path(info, n);
246 - link = create_entry(stage, n->mode, n->oid, path);
246 + link = create_entry(stage, n->mode, &n->oid, path);
247 link->link = entry;
248 return link;
249 }
@@ -318,7 +318,7 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
318 }
319
320 if (same_entry(entry+0, entry+1)) {
321 - if (entry[2].oid && !S_ISDIR(entry[2].mode)) {
321 + if (!is_null_oid(&entry[2].oid) && !S_ISDIR(entry[2].mode)) {
322 /* We did not touch, they modified -- take theirs */
323 resolve(info, entry+1, entry+2);
324 return mask;
builtin/pack-objects.c
+2 -2
@@ -1334,7 +1334,7 @@ static void add_pbase_object(struct tree_desc *tree,
1334 if (cmp < 0)
1335 return;
1336 if (name[cmplen] != '/') {
1337 - add_object_entry(entry.oid,
1337 + add_object_entry(&entry.oid,
1338 object_type(entry.mode),
1339 fullname, 1);
1340 return;
@@ -1345,7 +1345,7 @@ static void add_pbase_object(struct tree_desc *tree,
1345 const char *down = name+cmplen+1;
1346 int downlen = name_cmp_len(down);
1347
1348 - tree = pbase_tree_get(entry.oid);
1348 + tree = pbase_tree_get(&entry.oid);
1349 if (!tree)
1350 return;
1351 init_tree_desc(&sub, tree->tree_data, tree->tree_size);
builtin/reflog.c
+2 -2
@@ -94,8 +94,8 @@ static int tree_is_complete(const struct object_id *oid)
94 init_tree_desc(&desc, tree->buffer, tree->size);
95 complete = 1;
96 while (tree_entry(&desc, &entry)) {
97 - if (!has_sha1_file(entry.oid->hash) ||
98 - (S_ISDIR(entry.mode) && !tree_is_complete(entry.oid))) {
97 + if (!has_sha1_file(entry.oid.hash) ||
98 + (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
99 tree->object.flags |= INCOMPLETE;
100 complete = 0;
101 }
cache-tree.c
+2 -2
@@ -675,7 +675,7 @@ static void prime_cache_tree_rec(struct repository *r,
675 cnt++;
676 else {
677 struct cache_tree_sub *sub;
678 - struct tree *subtree = lookup_tree(r, entry.oid);
678 + struct tree *subtree = lookup_tree(r, &entry.oid);
679 if (!subtree->object.parsed)
680 parse_tree(subtree);
681 sub = cache_tree_sub(it, entry.path);
@@ -724,7 +724,7 @@ int cache_tree_matches_traversal(struct cache_tree *root,
724
725 it = find_cache_tree_from_traversal(root, info);
726 it = cache_tree_find(it, ent->path);
727 - if (it && it->entry_count > 0 && oideq(ent->oid, &it->oid))
727 + if (it && it->entry_count > 0 && oideq(&ent->oid, &it->oid))
728 return it->entry_count;
729 return 0;
730 }
delta-islands.c
+1 -1
@@ -296,7 +296,7 @@ void resolve_tree_islands(struct repository *r,
296 if (S_ISGITLINK(entry.mode))
297 continue;
298
299 - obj = lookup_object(r, entry.oid->hash);
299 + obj = lookup_object(r, entry.oid.hash);
300 if (!obj)
301 continue;
302
fsck.c
+2 -2
@@ -410,14 +410,14 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
410 continue;
411
412 if (S_ISDIR(entry.mode)) {
413 - obj = (struct object *)lookup_tree(the_repository, entry.oid);
413 + obj = (struct object *)lookup_tree(the_repository, &entry.oid);
414 if (name && obj)
415 put_object_name(options, obj, "%s%s/", name,
416 entry.path);
417 result = options->walk(obj, OBJ_TREE, data, options);
418 }
419 else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
420 - obj = (struct object *)lookup_blob(the_repository, entry.oid);
420 + obj = (struct object *)lookup_blob(the_repository, &entry.oid);
421 if (name && obj)
422 put_object_name(options, obj, "%s%s", name,
423 entry.path);
http-push.c
+2 -2
@@ -1311,11 +1311,11 @@ static struct object_list **process_tree(struct tree *tree,
1311 while (tree_entry(&desc, &entry))
1312 switch (object_type(entry.mode)) {
1313 case OBJ_TREE:
1314 - p = process_tree(lookup_tree(the_repository, entry.oid),
1314 + p = process_tree(lookup_tree(the_repository, &entry.oid),
1315 p);
1316 break;
1317 case OBJ_BLOB:
1318 - p = process_blob(lookup_blob(the_repository, entry.oid),
1318 + p = process_blob(lookup_blob(the_repository, &entry.oid),
1319 p);
1320 break;
1321 default:
list-objects.c
+3 -3
@@ -123,15 +123,15 @@ static void process_tree_contents(struct traversal_context *ctx,
123 }
124
125 if (S_ISDIR(entry.mode)) {
126 - struct tree *t = lookup_tree(ctx->revs->repo, entry.oid);
126 + struct tree *t = lookup_tree(ctx->revs->repo, &entry.oid);
127 t->object.flags |= NOT_USER_GIVEN;
128 process_tree(ctx, t, base, entry.path);
129 }
130 else if (S_ISGITLINK(entry.mode))
131 - process_gitlink(ctx, entry.oid->hash,
131 + process_gitlink(ctx, entry.oid.hash,
132 base, entry.path);
133 else {
134 - struct blob *b = lookup_blob(ctx->revs->repo, entry.oid);
134 + struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
135 b->object.flags |= NOT_USER_GIVEN;
136 process_blob(ctx, b, base, entry.path);
137 }
match-trees.c
+1 -1
@@ -106,7 +106,7 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
106 update_tree_entry(&two);
107 } else {
108 /* path appears in both */
109 - if (!oideq(one.entry.oid, two.entry.oid)) {
109 + if (!oideq(&one.entry.oid, &two.entry.oid)) {
110 /* they are different */
111 score += score_differs(one.entry.mode,
112 two.entry.mode,
notes.c
+2 -2
@@ -450,7 +450,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
450
451 l = xcalloc(1, sizeof(*l));
452 oidcpy(&l->key_oid, &object_oid);
453 - oidcpy(&l->val_oid, entry.oid);
453 + oidcpy(&l->val_oid, &entry.oid);
454 if (note_tree_insert(t, node, n, l, type,
455 combine_notes_concatenate))
456 die("Failed to load %s %s into notes tree "
@@ -481,7 +481,7 @@ handle_non_note:
481 }
482 strbuf_addstr(&non_note_path, entry.path);
483 add_non_note(t, strbuf_detach(&non_note_path, NULL),
484 - entry.mode, entry.oid->hash);
484 + entry.mode, entry.oid.hash);
485 }
486 }
487 free(buf);
packfile.c
+1 -1
@@ -2100,7 +2100,7 @@ static int add_promisor_object(const struct object_id *oid,
2100 */
2101 return 0;
2102 while (tree_entry_gently(&desc, &entry))
2103 - oidset_insert(set, entry.oid);
2103 + oidset_insert(set, &entry.oid);
2104 } else if (obj->type == OBJ_COMMIT) {
2105 struct commit *commit = (struct commit *) obj;
2106 struct commit_list *parents = commit->parents;
revision.c
+2 -2
@@ -67,10 +67,10 @@ static void mark_tree_contents_uninteresting(struct repository *r,
67 while (tree_entry(&desc, &entry)) {
68 switch (object_type(entry.mode)) {
69 case OBJ_TREE:
70 - mark_tree_uninteresting(r, lookup_tree(r, entry.oid));
70 + mark_tree_uninteresting(r, lookup_tree(r, &entry.oid));
71 break;
72 case OBJ_BLOB:
73 - mark_blob_uninteresting(lookup_blob(r, entry.oid));
73 + mark_blob_uninteresting(lookup_blob(r, &entry.oid));
74 break;
75 default:
76 /* Subproject commit - not in this repository */
tree-diff.c
+3 -3
@@ -239,7 +239,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
239 DIFF_STATUS_ADDED;
240
241 if (tpi_valid) {
242 - oid_i = tp[i].entry.oid;
242 + oid_i = &tp[i].entry.oid;
243 mode_i = tp[i].entry.mode;
244 }
245 else {
@@ -280,7 +280,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
280 /* same rule as in emitthis */
281 int tpi_valid = tp && !(tp[i].entry.mode & S_IFXMIN_NEQ);
282
283 - parents_oid[i] = tpi_valid ? tp[i].entry.oid : NULL;
283 + parents_oid[i] = tpi_valid ? &tp[i].entry.oid : NULL;
284 }
285
286 strbuf_add(base, path, pathlen);
@@ -491,7 +491,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
491 continue;
492
493 /* diff(t,pi) != ø */
494 - if (!oideq(t.entry.oid, tp[i].entry.oid) ||
494 + if (!oideq(&t.entry.oid, &tp[i].entry.oid) ||
495 (t.entry.mode != tp[i].entry.mode))
496 continue;
497
tree-walk.c
+7 -4
@@ -48,7 +48,8 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
48 /* Initialize the descriptor entry */
49 desc->entry.path = path;
50 desc->entry.mode = canon_mode(mode);
51 - desc->entry.oid = (const struct object_id *)(path + len);
51 + desc->entry.pathlen = len - 1;
52 + hashcpy(desc->entry.oid.hash, (const unsigned char *)path + len);
53
54 return 0;
55 }
@@ -107,7 +108,7 @@ static void entry_extract(struct tree_desc *t, struct name_entry *a)
108 static int update_tree_entry_internal(struct tree_desc *desc, struct strbuf *err)
109 {
110 const void *buf = desc->buffer;
110 - const unsigned char *end = desc->entry.oid->hash + the_hash_algo->rawsz;
111 + const unsigned char *end = (const unsigned char *)desc->entry.path + desc->entry.pathlen + 1 + the_hash_algo->rawsz;
112 unsigned long size = desc->size;
113 unsigned long len = end - (const unsigned char *)buf;
114
@@ -175,9 +176,11 @@ void setup_traverse_info(struct traverse_info *info, const char *base)
176 pathlen--;
177 info->pathlen = pathlen ? pathlen + 1 : 0;
178 info->name.path = base;
178 - info->name.oid = (void *)(base + pathlen + 1);
179 - if (pathlen)
179 + info->name.pathlen = pathlen;
180 + if (pathlen) {
181 + hashcpy(info->name.oid.hash, (const unsigned char *)base + pathlen + 1);
182 info->prev = &dummy;
183 + }
184 }
185
186 char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
tree-walk.h
+6 -3
@@ -1,11 +1,14 @@
1 #ifndef TREE_WALK_H
2 #define TREE_WALK_H
3
4 +#include "cache.h"
5 +
6 struct strbuf;
7
8 struct name_entry {
7 - const struct object_id *oid;
9 + struct object_id oid;
10 const char *path;
11 + int pathlen;
12 unsigned int mode;
13 };
14
@@ -19,12 +22,12 @@ static inline const struct object_id *tree_entry_extract(struct tree_desc *desc,
22 {
23 *pathp = desc->entry.path;
24 *modep = desc->entry.mode;
22 - return desc->entry.oid;
25 + return &desc->entry.oid;
26 }
27
28 static inline int tree_entry_len(const struct name_entry *ne)
29 {
27 - return (const char *)ne->oid - ne->path - 1;
30 + return ne->pathlen;
31 }
32
33 /*
tree.c
+5 -5
@@ -84,7 +84,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
84 continue;
85 }
86
87 - switch (fn(entry.oid, base,
87 + switch (fn(&entry.oid, base,
88 entry.path, entry.mode, stage, context)) {
89 case 0:
90 continue;
@@ -95,19 +95,19 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
95 }
96
97 if (S_ISDIR(entry.mode))
98 - oidcpy(&oid, entry.oid);
98 + oidcpy(&oid, &entry.oid);
99 else if (S_ISGITLINK(entry.mode)) {
100 struct commit *commit;
101
102 - commit = lookup_commit(the_repository, entry.oid);
102 + commit = lookup_commit(the_repository, &entry.oid);
103 if (!commit)
104 die("Commit %s in submodule path %s%s not found",
105 - oid_to_hex(entry.oid),
105 + oid_to_hex(&entry.oid),
106 base->buf, entry.path);
107
108 if (parse_commit(commit))
109 die("Invalid commit %s in submodule path %s%s",
110 - oid_to_hex(entry.oid),
110 + oid_to_hex(&entry.oid),
111 base->buf, entry.path);
112
113 oidcpy(&oid, get_commit_tree_oid(commit));
unpack-trees.c
+3 -3
@@ -679,7 +679,7 @@ static int switch_cache_bottom(struct traverse_info *info)
679
680 static inline int are_same_oid(struct name_entry *name_j, struct name_entry *name_k)
681 {
682 - return name_j->oid && name_k->oid && oideq(name_j->oid, name_k->oid);
682 + return !is_null_oid(&name_j->oid) && !is_null_oid(&name_k->oid) && oideq(&name_j->oid, &name_k->oid);
683 }
684
685 static int all_trees_same_as_cache_tree(int n, unsigned long dirmask,
@@ -857,7 +857,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
857 else {
858 const struct object_id *oid = NULL;
859 if (dirmask & 1)
860 - oid = names[i].oid;
860 + oid = &names[i].oid;
861 buf[nr_buf++] = fill_tree_descriptor(t + i, oid);
862 }
863 }
@@ -981,7 +981,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
981 ce->ce_mode = create_ce_mode(n->mode);
982 ce->ce_flags = create_ce_flags(stage);
983 ce->ce_namelen = len;
984 - oidcpy(&ce->oid, n->oid);
984 + oidcpy(&ce->oid, &n->oid);
985 make_traverse_path(ce->name, info, n);
986
987 return ce;
walker.c
+2 -2
@@ -50,13 +50,13 @@ static int process_tree(struct walker *walker, struct tree *tree)
50 continue;
51 if (S_ISDIR(entry.mode)) {
52 struct tree *tree = lookup_tree(the_repository,
53 - entry.oid);
53 + &entry.oid);
54 if (tree)
55 obj = &tree->object;
56 }
57 else {
58 struct blob *blob = lookup_blob(the_repository,
59 - entry.oid);
59 + &entry.oid);
60 if (blob)
61 obj = &blob->object;
62 }