diff --git a/src/pack.c b/src/pack.c index e1fa085fd..9346aced6 100644 --- a/src/pack.c +++ b/src/pack.c @@ -54,6 +54,10 @@ static int packfile_error(const char *message) static void pack_index_free(struct git_pack_file *p) { + if (p->oids) { + git__free(p->oids); + p->oids = NULL; + } if (p->index_map.data) { git_futils_mmap_free(&p->index_map); p->index_map.data = NULL; @@ -686,13 +690,16 @@ static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_ } } +static int git__memcmp4(const void *a, const void *b) { + return memcmp(a, b, 4); +} + int git_pack_foreach_entry( struct git_pack_file *p, int (*cb)(git_oid *oid, void *data), void *data) { const unsigned char *index = p->index_map.data, *current; - unsigned stride; uint32_t i; if (index == NULL) { @@ -712,21 +719,38 @@ int git_pack_foreach_entry( index += 4 * 256; - if (p->index_version > 1) { - stride = 20; - } else { - stride = 24; - index += 4; + if (p->oids == NULL) { + git_vector offsets, oids; + int error; + + if ((error = git_vector_init(&oids, p->num_objects, NULL))) + return error; + + if ((error = git_vector_init(&offsets, p->num_objects, git__memcmp4))) + return error; + + if (p->index_version > 1) { + const unsigned char *off = index + 24 * p->num_objects; + for (i = 0; i < p->num_objects; i++) + git_vector_insert(&offsets, (void*)&off[4 * i]); + git_vector_sort(&offsets); + git_vector_foreach(&offsets, i, current) + git_vector_insert(&oids, (void*)&index[5 * (current - off)]); + } else { + for (i = 0; i < p->num_objects; i++) + git_vector_insert(&offsets, (void*)&index[24 * i]); + git_vector_sort(&offsets); + git_vector_foreach(&offsets, i, current) + git_vector_insert(&oids, (void*)¤t[4]); + } + git_vector_free(&offsets); + p->oids = (git_oid **)oids.contents; } - current = index; - for (i = 0; i < p->num_objects; i++) { - if (cb((git_oid *)current, data)) + for (i = 0; i < p->num_objects; i++) + if (cb(p->oids[i], data)) return GIT_EUSER; - current += stride; - } - return 0; } diff --git a/src/pack.h b/src/pack.h index 178545675..af87b7cd5 100644 --- a/src/pack.h +++ b/src/pack.h @@ -64,6 +64,7 @@ struct git_pack_file { unsigned pack_local:1, pack_keep:1, has_cache:1; git_oid sha1; git_vector cache; + git_oid **oids; /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[GIT_FLEX_ARRAY]; /* more */