Merge branch 'bc/tree-walk-oid'

The code to walk tree objects has been taught that we may be
working with object names that are not computed with SHA-1.

* bc/tree-walk-oid:
  cache: make oidcpy always copy GIT_MAX_RAWSZ bytes
  tree-walk: store object_id in a separate member
  match-trees: use hashcpy to splice trees
  match-trees: compute buffer offset correctly when splicing
  tree-walk: copy object ID before use
This commit is contained in:
Junio C Hamano 2019-01-29 12:47:56 -08:00
Родитель a6e3839976 974e4a85e3
Коммит 371820d5f1
21 изменённых файлов: 84 добавлений и 98 удалений

Просмотреть файл

@ -570,7 +570,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
strbuf_add(base, entry.path, te_len);
if (S_ISREG(entry.mode)) {
hit |= grep_oid(opt, entry.oid, base->buf, tn_len,
hit |= grep_oid(opt, &entry.oid, base->buf, tn_len,
check_attr ? base->buf + tn_len : NULL);
} else if (S_ISDIR(entry.mode)) {
enum object_type type;
@ -578,10 +578,10 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
void *data;
unsigned long size;
data = lock_and_read_oid_file(entry.oid, &type, &size);
data = lock_and_read_oid_file(&entry.oid, &type, &size);
if (!data)
die(_("unable to read tree (%s)"),
oid_to_hex(entry.oid));
oid_to_hex(&entry.oid));
strbuf_addch(base, '/');
init_tree_desc(&sub, data, size);
@ -589,7 +589,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
check_attr, repo);
free(data);
} else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
hit |= grep_submodule(opt, repo, pathspec, entry.oid,
hit |= grep_submodule(opt, repo, pathspec, &entry.oid,
base->buf, base->buf + tn_len);
}

Просмотреть файл

@ -154,15 +154,15 @@ static void show_result(void)
/* An empty entry never compares same, not even to another empty entry */
static int same_entry(struct name_entry *a, struct name_entry *b)
{
return a->oid &&
b->oid &&
oideq(a->oid, b->oid) &&
return !is_null_oid(&a->oid) &&
!is_null_oid(&b->oid) &&
oideq(&a->oid, &b->oid) &&
a->mode == b->mode;
}
static int both_empty(struct name_entry *a, struct name_entry *b)
{
return !(a->oid || b->oid);
return is_null_oid(&a->oid) && is_null_oid(&b->oid);
}
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
static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
{
char *path = xmallocz(traverse_path_len(info, n));
char *path = xmallocz(traverse_path_len(info, n) + the_hash_algo->rawsz);
return make_traverse_path(path, info, n);
}
@ -192,8 +192,8 @@ static void resolve(const struct traverse_info *info, struct name_entry *ours, s
return;
path = traverse_path(info, result);
orig = create_entry(2, ours->mode, ours->oid, path);
final = create_entry(0, result->mode, result->oid, path);
orig = create_entry(2, ours->mode, &ours->oid, path);
final = create_entry(0, result->mode, &result->oid, path);
final->link = orig;
@ -217,7 +217,7 @@ static void unresolved_directory(const struct traverse_info *info,
newbase = traverse_path(info, p);
#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? (e)->oid : NULL)
#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? &(e)->oid : NULL)
buf0 = fill_tree_descriptor(t + 0, ENTRY_OID(n + 0));
buf1 = fill_tree_descriptor(t + 1, ENTRY_OID(n + 1));
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
path = entry->path;
else
path = traverse_path(info, n);
link = create_entry(stage, n->mode, n->oid, path);
link = create_entry(stage, n->mode, &n->oid, path);
link->link = entry;
return link;
}
@ -318,7 +318,7 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
}
if (same_entry(entry+0, entry+1)) {
if (entry[2].oid && !S_ISDIR(entry[2].mode)) {
if (!is_null_oid(&entry[2].oid) && !S_ISDIR(entry[2].mode)) {
/* We did not touch, they modified -- take theirs */
resolve(info, entry+1, entry+2);
return mask;

Просмотреть файл

@ -1334,7 +1334,7 @@ static void add_pbase_object(struct tree_desc *tree,
if (cmp < 0)
return;
if (name[cmplen] != '/') {
add_object_entry(entry.oid,
add_object_entry(&entry.oid,
object_type(entry.mode),
fullname, 1);
return;
@ -1345,7 +1345,7 @@ static void add_pbase_object(struct tree_desc *tree,
const char *down = name+cmplen+1;
int downlen = name_cmp_len(down);
tree = pbase_tree_get(entry.oid);
tree = pbase_tree_get(&entry.oid);
if (!tree)
return;
init_tree_desc(&sub, tree->tree_data, tree->tree_size);

Просмотреть файл

@ -94,8 +94,8 @@ static int tree_is_complete(const struct object_id *oid)
init_tree_desc(&desc, tree->buffer, tree->size);
complete = 1;
while (tree_entry(&desc, &entry)) {
if (!has_sha1_file(entry.oid->hash) ||
(S_ISDIR(entry.mode) && !tree_is_complete(entry.oid))) {
if (!has_sha1_file(entry.oid.hash) ||
(S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
tree->object.flags |= INCOMPLETE;
complete = 0;
}

Просмотреть файл

@ -675,7 +675,7 @@ static void prime_cache_tree_rec(struct repository *r,
cnt++;
else {
struct cache_tree_sub *sub;
struct tree *subtree = lookup_tree(r, entry.oid);
struct tree *subtree = lookup_tree(r, &entry.oid);
if (!subtree->object.parsed)
parse_tree(subtree);
sub = cache_tree_sub(it, entry.path);
@ -724,7 +724,7 @@ int cache_tree_matches_traversal(struct cache_tree *root,
it = find_cache_tree_from_traversal(root, info);
it = cache_tree_find(it, ent->path);
if (it && it->entry_count > 0 && oideq(ent->oid, &it->oid))
if (it && it->entry_count > 0 && oideq(&ent->oid, &it->oid))
return it->entry_count;
return 0;
}

Просмотреть файл

@ -1084,7 +1084,7 @@ static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
static inline void oidcpy(struct object_id *dst, const struct object_id *src)
{
hashcpy(dst->hash, src->hash);
memcpy(dst->hash, src->hash, GIT_MAX_RAWSZ);
}
static inline struct object_id *oiddup(const struct object_id *src)

Просмотреть файл

@ -86,36 +86,6 @@ struct object_id OID;
- hashcmp(OID.hash, OIDPTR->hash)
+ oidcmp(&OID, OIDPTR)
@@
struct object_id OID1, OID2;
@@
- hashcpy(OID1.hash, OID2.hash)
+ oidcpy(&OID1, &OID2)
@@
identifier f != oidcpy;
struct object_id *OIDPTR1;
struct object_id *OIDPTR2;
@@
f(...) {<...
- hashcpy(OIDPTR1->hash, OIDPTR2->hash)
+ oidcpy(OIDPTR1, OIDPTR2)
...>}
@@
struct object_id *OIDPTR;
struct object_id OID;
@@
- hashcpy(OIDPTR->hash, OID.hash)
+ oidcpy(OIDPTR, &OID)
@@
struct object_id *OIDPTR;
struct object_id OID;
@@
- hashcpy(OID.hash, OIDPTR->hash)
+ oidcpy(&OID, OIDPTR)
@@
struct object_id *OIDPTR1;
struct object_id *OIDPTR2;

Просмотреть файл

@ -296,7 +296,7 @@ void resolve_tree_islands(struct repository *r,
if (S_ISGITLINK(entry.mode))
continue;
obj = lookup_object(r, entry.oid->hash);
obj = lookup_object(r, entry.oid.hash);
if (!obj)
continue;

4
fsck.c
Просмотреть файл

@ -410,14 +410,14 @@ static int fsck_walk_tree(struct tree *tree, void *data, struct fsck_options *op
continue;
if (S_ISDIR(entry.mode)) {
obj = (struct object *)lookup_tree(the_repository, entry.oid);
obj = (struct object *)lookup_tree(the_repository, &entry.oid);
if (name && obj)
put_object_name(options, obj, "%s%s/", name,
entry.path);
result = options->walk(obj, OBJ_TREE, data, options);
}
else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) {
obj = (struct object *)lookup_blob(the_repository, entry.oid);
obj = (struct object *)lookup_blob(the_repository, &entry.oid);
if (name && obj)
put_object_name(options, obj, "%s%s", name,
entry.path);

Просмотреть файл

@ -1311,11 +1311,11 @@ static struct object_list **process_tree(struct tree *tree,
while (tree_entry(&desc, &entry))
switch (object_type(entry.mode)) {
case OBJ_TREE:
p = process_tree(lookup_tree(the_repository, entry.oid),
p = process_tree(lookup_tree(the_repository, &entry.oid),
p);
break;
case OBJ_BLOB:
p = process_blob(lookup_blob(the_repository, entry.oid),
p = process_blob(lookup_blob(the_repository, &entry.oid),
p);
break;
default:

Просмотреть файл

@ -124,15 +124,15 @@ static void process_tree_contents(struct traversal_context *ctx,
}
if (S_ISDIR(entry.mode)) {
struct tree *t = lookup_tree(ctx->revs->repo, entry.oid);
struct tree *t = lookup_tree(ctx->revs->repo, &entry.oid);
t->object.flags |= NOT_USER_GIVEN;
process_tree(ctx, t, base, entry.path);
}
else if (S_ISGITLINK(entry.mode))
process_gitlink(ctx, entry.oid->hash,
process_gitlink(ctx, entry.oid.hash,
base, entry.path);
else {
struct blob *b = lookup_blob(ctx->revs->repo, entry.oid);
struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
b->object.flags |= NOT_USER_GIVEN;
process_blob(ctx, b, base, entry.path);
}

Просмотреть файл

@ -106,7 +106,7 @@ static int score_trees(const struct object_id *hash1, const struct object_id *ha
update_tree_entry(&two);
} else {
/* path appears in both */
if (!oideq(one.entry.oid, two.entry.oid)) {
if (!oideq(&one.entry.oid, &two.entry.oid)) {
/* they are different */
score += score_differs(one.entry.mode,
two.entry.mode,
@ -179,7 +179,7 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
char *buf;
unsigned long sz;
struct tree_desc desc;
struct object_id *rewrite_here;
unsigned char *rewrite_here;
const struct object_id *rewrite_with;
struct object_id subtree;
enum object_type type;
@ -199,15 +199,26 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
while (desc.size) {
const char *name;
unsigned mode;
const struct object_id *oid;
oid = tree_entry_extract(&desc, &name, &mode);
tree_entry_extract(&desc, &name, &mode);
if (strlen(name) == toplen &&
!memcmp(name, prefix, toplen)) {
if (!S_ISDIR(mode))
die("entry %s in tree %s is not a tree", name,
oid_to_hex(oid1));
rewrite_here = (struct object_id *)oid;
/*
* We cast here for two reasons:
*
* - to flip the "char *" (for the path) to "unsigned
* char *" (for the hash stored after it)
*
* - to discard the "const"; this is OK because we
* know it points into our non-const "buf"
*/
rewrite_here = (unsigned char *)(desc.entry.path +
strlen(desc.entry.path) +
1);
break;
}
update_tree_entry(&desc);
@ -216,14 +227,16 @@ static int splice_tree(const struct object_id *oid1, const char *prefix,
die("entry %.*s not found in tree %s", toplen, prefix,
oid_to_hex(oid1));
if (*subpath) {
status = splice_tree(rewrite_here, subpath, oid2, &subtree);
struct object_id tree_oid;
hashcpy(tree_oid.hash, rewrite_here);
status = splice_tree(&tree_oid, subpath, oid2, &subtree);
if (status)
return status;
rewrite_with = &subtree;
} else {
rewrite_with = oid2;
}
oidcpy(rewrite_here, rewrite_with);
hashcpy(rewrite_here, rewrite_with->hash);
status = write_object_file(buf, sz, tree_type, result);
free(buf);
return status;

Просмотреть файл

@ -450,7 +450,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
l = xcalloc(1, sizeof(*l));
oidcpy(&l->key_oid, &object_oid);
oidcpy(&l->val_oid, entry.oid);
oidcpy(&l->val_oid, &entry.oid);
if (note_tree_insert(t, node, n, l, type,
combine_notes_concatenate))
die("Failed to load %s %s into notes tree "
@ -481,7 +481,7 @@ handle_non_note:
}
strbuf_addstr(&non_note_path, entry.path);
add_non_note(t, strbuf_detach(&non_note_path, NULL),
entry.mode, entry.oid->hash);
entry.mode, entry.oid.hash);
}
}
free(buf);

Просмотреть файл

@ -2097,7 +2097,7 @@ static int add_promisor_object(const struct object_id *oid,
*/
return 0;
while (tree_entry_gently(&desc, &entry))
oidset_insert(set, entry.oid);
oidset_insert(set, &entry.oid);
} else if (obj->type == OBJ_COMMIT) {
struct commit *commit = (struct commit *) obj;
struct commit_list *parents = commit->parents;

Просмотреть файл

@ -67,10 +67,10 @@ static void mark_tree_contents_uninteresting(struct repository *r,
while (tree_entry(&desc, &entry)) {
switch (object_type(entry.mode)) {
case OBJ_TREE:
mark_tree_uninteresting(r, lookup_tree(r, entry.oid));
mark_tree_uninteresting(r, lookup_tree(r, &entry.oid));
break;
case OBJ_BLOB:
mark_blob_uninteresting(lookup_blob(r, entry.oid));
mark_blob_uninteresting(lookup_blob(r, &entry.oid));
break;
default:
/* Subproject commit - not in this repository */

Просмотреть файл

@ -239,7 +239,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
DIFF_STATUS_ADDED;
if (tpi_valid) {
oid_i = tp[i].entry.oid;
oid_i = &tp[i].entry.oid;
mode_i = tp[i].entry.mode;
}
else {
@ -280,7 +280,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
/* same rule as in emitthis */
int tpi_valid = tp && !(tp[i].entry.mode & S_IFXMIN_NEQ);
parents_oid[i] = tpi_valid ? tp[i].entry.oid : NULL;
parents_oid[i] = tpi_valid ? &tp[i].entry.oid : NULL;
}
strbuf_add(base, path, pathlen);
@ -492,7 +492,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
continue;
/* diff(t,pi) != ø */
if (!oideq(t.entry.oid, tp[i].entry.oid) ||
if (!oideq(&t.entry.oid, &tp[i].entry.oid) ||
(t.entry.mode != tp[i].entry.mode))
continue;

Просмотреть файл

@ -48,7 +48,8 @@ static int decode_tree_entry(struct tree_desc *desc, const char *buf, unsigned l
/* Initialize the descriptor entry */
desc->entry.path = path;
desc->entry.mode = canon_mode(mode);
desc->entry.oid = (const struct object_id *)(path + len);
desc->entry.pathlen = len - 1;
hashcpy(desc->entry.oid.hash, (const unsigned char *)path + len);
return 0;
}
@ -107,7 +108,7 @@ static void entry_extract(struct tree_desc *t, struct name_entry *a)
static int update_tree_entry_internal(struct tree_desc *desc, struct strbuf *err)
{
const void *buf = desc->buffer;
const unsigned char *end = desc->entry.oid->hash + the_hash_algo->rawsz;
const unsigned char *end = (const unsigned char *)desc->entry.path + desc->entry.pathlen + 1 + the_hash_algo->rawsz;
unsigned long size = desc->size;
unsigned long len = end - (const unsigned char *)buf;
@ -175,9 +176,11 @@ void setup_traverse_info(struct traverse_info *info, const char *base)
pathlen--;
info->pathlen = pathlen ? pathlen + 1 : 0;
info->name.path = base;
info->name.oid = (void *)(base + pathlen + 1);
if (pathlen)
info->name.pathlen = pathlen;
if (pathlen) {
hashcpy(info->name.oid.hash, (const unsigned char *)base + pathlen + 1);
info->prev = &dummy;
}
}
char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
@ -502,10 +505,10 @@ static int find_tree_entry(struct tree_desc *t, const char *name, struct object_
int namelen = strlen(name);
while (t->size) {
const char *entry;
const struct object_id *oid;
struct object_id oid;
int entrylen, cmp;
oid = tree_entry_extract(t, &entry, mode);
oidcpy(&oid, tree_entry_extract(t, &entry, mode));
entrylen = tree_entry_len(&t->entry);
update_tree_entry(t);
if (entrylen > namelen)
@ -516,7 +519,7 @@ static int find_tree_entry(struct tree_desc *t, const char *name, struct object_
if (cmp < 0)
break;
if (entrylen == namelen) {
oidcpy(result, oid);
oidcpy(result, &oid);
return 0;
}
if (name[entrylen] != '/')
@ -524,10 +527,10 @@ static int find_tree_entry(struct tree_desc *t, const char *name, struct object_
if (!S_ISDIR(*mode))
break;
if (++entrylen == namelen) {
oidcpy(result, oid);
oidcpy(result, &oid);
return 0;
}
return get_tree_entry(oid, name + entrylen, result, mode);
return get_tree_entry(&oid, name + entrylen, result, mode);
}
return -1;
}

Просмотреть файл

@ -1,12 +1,12 @@
#ifndef TREE_WALK_H
#define TREE_WALK_H
struct index_state;
struct strbuf;
#include "cache.h"
struct name_entry {
const struct object_id *oid;
struct object_id oid;
const char *path;
int pathlen;
unsigned int mode;
};
@ -20,12 +20,12 @@ static inline const struct object_id *tree_entry_extract(struct tree_desc *desc,
{
*pathp = desc->entry.path;
*modep = desc->entry.mode;
return desc->entry.oid;
return &desc->entry.oid;
}
static inline int tree_entry_len(const struct name_entry *ne)
{
return (const char *)ne->oid - ne->path - 1;
return ne->pathlen;
}
/*

10
tree.c
Просмотреть файл

@ -86,7 +86,7 @@ static int read_tree_1(struct repository *r,
continue;
}
switch (fn(entry.oid, base,
switch (fn(&entry.oid, base,
entry.path, entry.mode, stage, context)) {
case 0:
continue;
@ -97,19 +97,19 @@ static int read_tree_1(struct repository *r,
}
if (S_ISDIR(entry.mode))
oidcpy(&oid, entry.oid);
oidcpy(&oid, &entry.oid);
else if (S_ISGITLINK(entry.mode)) {
struct commit *commit;
commit = lookup_commit(r, entry.oid);
commit = lookup_commit(r, &entry.oid);
if (!commit)
die("Commit %s in submodule path %s%s not found",
oid_to_hex(entry.oid),
oid_to_hex(&entry.oid),
base->buf, entry.path);
if (parse_commit(commit))
die("Invalid commit %s in submodule path %s%s",
oid_to_hex(entry.oid),
oid_to_hex(&entry.oid),
base->buf, entry.path);
oidcpy(&oid, get_commit_tree_oid(commit));

Просмотреть файл

@ -679,7 +679,7 @@ static int switch_cache_bottom(struct traverse_info *info)
static inline int are_same_oid(struct name_entry *name_j, struct name_entry *name_k)
{
return name_j->oid && name_k->oid && oideq(name_j->oid, name_k->oid);
return !is_null_oid(&name_j->oid) && !is_null_oid(&name_k->oid) && oideq(&name_j->oid, &name_k->oid);
}
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,
else {
const struct object_id *oid = NULL;
if (dirmask & 1)
oid = names[i].oid;
oid = &names[i].oid;
buf[nr_buf++] = fill_tree_descriptor(t + i, oid);
}
}
@ -981,7 +981,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
ce->ce_mode = create_ce_mode(n->mode);
ce->ce_flags = create_ce_flags(stage);
ce->ce_namelen = len;
oidcpy(&ce->oid, n->oid);
oidcpy(&ce->oid, &n->oid);
make_traverse_path(ce->name, info, n);
return ce;

Просмотреть файл

@ -50,13 +50,13 @@ static int process_tree(struct walker *walker, struct tree *tree)
continue;
if (S_ISDIR(entry.mode)) {
struct tree *tree = lookup_tree(the_repository,
entry.oid);
&entry.oid);
if (tree)
obj = &tree->object;
}
else {
struct blob *blob = lookup_blob(the_repository,
entry.oid);
&entry.oid);
if (blob)
obj = &blob->object;
}