diff options
-rw-r--r-- | include/git2/sys/midx.h | 6 | ||||
-rw-r--r-- | src/libgit2/midx.c | 92 | ||||
-rw-r--r-- | src/libgit2/midx.h | 16 | ||||
-rw-r--r-- | src/libgit2/odb_pack.c | 11 | ||||
-rw-r--r-- | tests/libgit2/pack/midx.c | 7 |
5 files changed, 96 insertions, 36 deletions
diff --git a/include/git2/sys/midx.h b/include/git2/sys/midx.h index e3d749829..3a87484d2 100644 --- a/include/git2/sys/midx.h +++ b/include/git2/sys/midx.h @@ -29,7 +29,11 @@ GIT_BEGIN_DECL */ GIT_EXTERN(int) git_midx_writer_new( git_midx_writer **out, - const char *pack_dir); + const char *pack_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ); /** * Free the multi-pack-index writer and its resources. diff --git a/src/libgit2/midx.c b/src/libgit2/midx.c index b09055237..f6071f0bb 100644 --- a/src/libgit2/midx.c +++ b/src/libgit2/midx.c @@ -115,19 +115,20 @@ static int midx_parse_oid_lookup( struct git_midx_chunk *chunk_oid_lookup) { uint32_t i; - unsigned char *oid, *prev_oid, zero_oid[GIT_OID_SHA1_SIZE] = {0}; + unsigned char *oid, *prev_oid, zero_oid[GIT_OID_MAX_SIZE] = {0}; + size_t oid_size = git_oid_size(idx->oid_type); if (chunk_oid_lookup->offset == 0) return midx_error("missing OID Lookup chunk"); if (chunk_oid_lookup->length == 0) return midx_error("empty OID Lookup chunk"); - if (chunk_oid_lookup->length != idx->num_objects * GIT_OID_SHA1_SIZE) + if (chunk_oid_lookup->length != idx->num_objects * oid_size) return midx_error("OID Lookup chunk has wrong length"); idx->oid_lookup = oid = (unsigned char *)(data + chunk_oid_lookup->offset); prev_oid = zero_oid; - for (i = 0; i < idx->num_objects; ++i, oid += GIT_OID_SHA1_SIZE) { - if (git_oid_raw_cmp(prev_oid, oid, GIT_OID_SHA1_SIZE) >= 0) + for (i = 0; i < idx->num_objects; ++i, oid += oid_size) { + if (git_oid_raw_cmp(prev_oid, oid, oid_size) >= 0) return midx_error("OID Lookup index is non-monotonic"); prev_oid = oid; } @@ -178,7 +179,7 @@ int git_midx_parse( struct git_midx_chunk *last_chunk; uint32_t i; off64_t last_chunk_offset, chunk_offset, trailer_offset; - size_t checksum_size; + size_t checksum_size, oid_size; int error; struct git_midx_chunk chunk_packfile_names = {0}, chunk_oid_fanout = {0}, @@ -188,7 +189,9 @@ int git_midx_parse( GIT_ASSERT_ARG(idx); - if (size < sizeof(struct git_midx_header) + GIT_OID_SHA1_SIZE) + oid_size = git_oid_size(idx->oid_type); + + if (size < sizeof(struct git_midx_header) + oid_size) return midx_error("multi-pack index is too short"); hdr = ((struct git_midx_header *)data); @@ -209,7 +212,7 @@ int git_midx_parse( sizeof(struct git_midx_header) + (1 + hdr->chunks) * 12; - checksum_size = GIT_HASH_SHA1_SIZE; + checksum_size = oid_size; trailer_offset = size - checksum_size; if (trailer_offset < last_chunk_offset) @@ -287,8 +290,9 @@ int git_midx_parse( } int git_midx_open( - git_midx_file **idx_out, - const char *path) + git_midx_file **idx_out, + const char *path, + git_oid_t oid_type) { git_midx_file *idx; git_file fd = -1; @@ -296,6 +300,8 @@ int git_midx_open( struct stat st; int error; + GIT_ASSERT_ARG(idx_out && path && oid_type); + /* TODO: properly open the file without access time using O_NOATIME */ fd = git_futils_open_ro(path); if (fd < 0) @@ -317,6 +323,8 @@ int git_midx_open( idx = git__calloc(1, sizeof(git_midx_file)); GIT_ERROR_CHECK_ALLOC(idx); + idx->oid_type = oid_type; + error = git_str_sets(&idx->filename, path); if (error < 0) return error; @@ -344,7 +352,7 @@ bool git_midx_needs_refresh( git_file fd = -1; struct stat st; ssize_t bytes_read; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + unsigned char checksum[GIT_HASH_MAX_SIZE]; size_t checksum_size; /* TODO: properly open the file without access time using O_NOATIME */ @@ -364,8 +372,8 @@ bool git_midx_needs_refresh( return true; } - checksum_size = GIT_HASH_SHA1_SIZE; - bytes_read = p_pread(fd, checksum, checksum_size, st.st_size - GIT_OID_SHA1_SIZE); + checksum_size = git_oid_size(idx->oid_type); + bytes_read = p_pread(fd, checksum, checksum_size, st.st_size - checksum_size); p_close(fd); if (bytes_read != (ssize_t)checksum_size) @@ -381,7 +389,7 @@ int git_midx_entry_find( size_t len) { int pos, found = 0; - size_t pack_index; + size_t pack_index, oid_size, oid_hexsize; uint32_t hi, lo; unsigned char *current = NULL; const unsigned char *object_offset; @@ -389,30 +397,33 @@ int git_midx_entry_find( GIT_ASSERT_ARG(idx); + oid_size = git_oid_size(idx->oid_type); + oid_hexsize = git_oid_hexsize(idx->oid_type); + hi = ntohl(idx->oid_fanout[(int)short_oid->id[0]]); lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(idx->oid_fanout[(int)short_oid->id[0] - 1])); - pos = git_pack__lookup_id(idx->oid_lookup, GIT_OID_SHA1_SIZE, lo, hi, short_oid->id, GIT_OID_SHA1); + pos = git_pack__lookup_id(idx->oid_lookup, oid_size, lo, hi, short_oid->id, idx->oid_type); if (pos >= 0) { /* An object matching exactly the oid was found */ found = 1; - current = idx->oid_lookup + (pos * GIT_OID_SHA1_SIZE); + current = idx->oid_lookup + (pos * oid_size); } else { /* No object was found */ /* pos refers to the object with the "closest" oid to short_oid */ pos = -1 - pos; if (pos < (int)idx->num_objects) { - current = idx->oid_lookup + (pos * GIT_OID_SHA1_SIZE); + current = idx->oid_lookup + (pos * oid_size); if (!git_oid_raw_ncmp(short_oid->id, current, len)) found = 1; } } - if (found && len != GIT_OID_SHA1_HEXSIZE && pos + 1 < (int)idx->num_objects) { + if (found && len != oid_hexsize && pos + 1 < (int)idx->num_objects) { /* Check for ambiguousity */ - const unsigned char *next = current + GIT_OID_SHA1_SIZE; + const unsigned char *next = current + oid_size; if (!git_oid_raw_ncmp(short_oid->id, next, len)) found = 2; @@ -443,7 +454,7 @@ int git_midx_entry_find( return midx_error("invalid index into the packfile names table"); e->pack_index = pack_index; e->offset = offset; - git_oid__fromraw(&e->sha1, current, GIT_OID_SHA1); + git_oid__fromraw(&e->sha1, current, idx->oid_type); return 0; } @@ -453,13 +464,15 @@ int git_midx_foreach_entry( void *data) { git_oid oid; - size_t i; + size_t oid_size, i; int error; GIT_ASSERT_ARG(idx); + oid_size = git_oid_size(idx->oid_type); + for (i = 0; i < idx->num_objects; ++i) { - if ((error = git_oid__fromraw(&oid, &idx->oid_lookup[i * GIT_OID_SHA1_SIZE], GIT_OID_SHA1)) < 0) + if ((error = git_oid__fromraw(&oid, &idx->oid_lookup[i * oid_size], idx->oid_type)) < 0) return error; if ((error = cb(&oid, data)) != 0) @@ -501,9 +514,21 @@ static int packfile__cmp(const void *a_, const void *b_) int git_midx_writer_new( git_midx_writer **out, - const char *pack_dir) + const char *pack_dir +#ifdef GIT_EXPERIMENTAL_SHA256 + , git_oid_t oid_type +#endif + ) { - git_midx_writer *w = git__calloc(1, sizeof(git_midx_writer)); + git_midx_writer *w; + +#ifndef GIT_EXPERIMENTAL_SHA256 + git_oid_t oid_type = GIT_OID_SHA1; +#endif + + GIT_ASSERT_ARG(out && pack_dir && oid_type); + + w = git__calloc(1, sizeof(git_midx_writer)); GIT_ERROR_CHECK_ALLOC(w); if (git_str_sets(&w->pack_dir, pack_dir) < 0) { @@ -518,6 +543,8 @@ int git_midx_writer_new( return -1; } + w->oid_type = oid_type; + *out = w; return 0; } @@ -662,12 +689,13 @@ static int midx_write( oid_lookup = GIT_STR_INIT, object_offsets = GIT_STR_INIT, object_large_offsets = GIT_STR_INIT; - unsigned char checksum[GIT_HASH_SHA1_SIZE]; - size_t checksum_size; + unsigned char checksum[GIT_HASH_MAX_SIZE]; + size_t checksum_size, oid_size; git_midx_entry *entry; object_entry_array_t object_entries_array = GIT_ARRAY_INIT; git_vector object_entries = GIT_VECTOR_INIT; git_hash_ctx ctx; + git_hash_algorithm_t checksum_type; struct midx_write_hash_context hash_cb_data = {0}; hdr.signature = htonl(MIDX_SIGNATURE); @@ -679,10 +707,14 @@ static int midx_write( hash_cb_data.cb_data = cb_data; hash_cb_data.ctx = &ctx; - checksum_size = GIT_HASH_SHA1_SIZE; - error = git_hash_ctx_init(&ctx, GIT_HASH_ALGORITHM_SHA1); - if (error < 0) + oid_size = git_oid_size(w->oid_type); + + GIT_ASSERT((checksum_type = git_oid_algorithm(w->oid_type))); + checksum_size = git_hash_size(checksum_type); + + if ((error = git_hash_ctx_init(&ctx, checksum_type)) < 0) return error; + cb_data = &hash_cb_data; write_cb = midx_write_hash; @@ -749,7 +781,9 @@ static int midx_write( /* Fill the OID Lookup table. */ git_vector_foreach (&object_entries, i, entry) { - error = git_str_put(&oid_lookup, (char *)&entry->sha1.id, GIT_OID_SHA1_SIZE); + error = git_str_put(&oid_lookup, + (char *)&entry->sha1.id, oid_size); + if (error < 0) goto cleanup; } diff --git a/src/libgit2/midx.h b/src/libgit2/midx.h index bcb0d9a0a..5107f69cb 100644 --- a/src/libgit2/midx.h +++ b/src/libgit2/midx.h @@ -51,8 +51,14 @@ typedef struct git_midx_file { /* The number of entries in the Object Large Offsets table. Each entry has an 8-byte with an offset */ size_t num_object_large_offsets; - /* The trailer of the file. Contains the SHA1-checksum of the whole file. */ - unsigned char checksum[GIT_HASH_SHA1_SIZE]; + /* + * The trailer of the file. Contains the checksum of the whole + * file, in the repository's object format hash. + */ + unsigned char checksum[GIT_HASH_MAX_SIZE]; + + /* The type of object IDs in the midx. */ + git_oid_t oid_type; /* something like ".git/objects/pack/multi-pack-index". */ git_str filename; @@ -82,11 +88,15 @@ struct git_midx_writer { /* The list of `git_pack_file`s. */ git_vector packs; + + /* The object ID type of the writer. */ + git_oid_t oid_type; }; int git_midx_open( git_midx_file **idx_out, - const char *path); + const char *path, + git_oid_t oid_type); bool git_midx_needs_refresh( const git_midx_file *idx, const char *path); diff --git a/src/libgit2/odb_pack.c b/src/libgit2/odb_pack.c index c6151f4e7..fc533ae83 100644 --- a/src/libgit2/odb_pack.c +++ b/src/libgit2/odb_pack.c @@ -479,7 +479,9 @@ static int refresh_multi_pack_index(struct pack_backend *backend) } } - error = git_midx_open(&backend->midx, git_str_cstr(&midx_path)); + error = git_midx_open(&backend->midx, git_str_cstr(&midx_path), + backend->opts.oid_type); + git_str_dispose(&midx_path); if (error < 0) return error; @@ -798,7 +800,12 @@ static int pack_backend__writemidx(git_odb_backend *_backend) backend = (struct pack_backend *)_backend; - error = git_midx_writer_new(&w, backend->pack_folder); + error = git_midx_writer_new(&w, backend->pack_folder +#ifdef GIT_EXPERIMENTAL_SHA256 + , backend->opts.oid_type +#endif + ); + if (error < 0) return error; diff --git a/tests/libgit2/pack/midx.c b/tests/libgit2/pack/midx.c index f7d680165..4c4dfc511 100644 --- a/tests/libgit2/pack/midx.c +++ b/tests/libgit2/pack/midx.c @@ -16,7 +16,7 @@ void test_pack_midx__parse(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_str_joinpath(&midx_path, git_repository_path(repo), "objects/pack/multi-pack-index")); - cl_git_pass(git_midx_open(&idx, git_str_cstr(&midx_path))); + cl_git_pass(git_midx_open(&idx, git_str_cstr(&midx_path), GIT_OID_SHA1)); cl_assert_equal_i(git_midx_needs_refresh(idx, git_str_cstr(&midx_path)), 0); cl_git_pass(git_oid__fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5", GIT_OID_SHA1)); @@ -57,7 +57,12 @@ void test_pack_midx__writer(void) cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_str_joinpath(&path, git_repository_path(repo), "objects/pack")); + +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_midx_writer_new(&w, git_str_cstr(&path), GIT_OID_SHA1)); +#else cl_git_pass(git_midx_writer_new(&w, git_str_cstr(&path))); +#endif cl_git_pass(git_midx_writer_add(w, "pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx")); cl_git_pass(git_midx_writer_add(w, "pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.idx")); |