Skip to content

Commit be484d3

Browse files
committed
midx: support sha256
1 parent 8772740 commit be484d3

File tree

5 files changed

+96
-36
lines changed

5 files changed

+96
-36
lines changed

include/git2/sys/midx.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ GIT_BEGIN_DECL
2929
*/
3030
GIT_EXTERN(int) git_midx_writer_new(
3131
git_midx_writer **out,
32-
const char *pack_dir);
32+
const char *pack_dir
33+
#ifdef GIT_EXPERIMENTAL_SHA256
34+
, git_oid_t oid_type
35+
#endif
36+
);
3337

3438
/**
3539
* Free the multi-pack-index writer and its resources.

src/libgit2/midx.c

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,20 @@ static int midx_parse_oid_lookup(
115115
struct git_midx_chunk *chunk_oid_lookup)
116116
{
117117
uint32_t i;
118-
unsigned char *oid, *prev_oid, zero_oid[GIT_OID_SHA1_SIZE] = {0};
118+
unsigned char *oid, *prev_oid, zero_oid[GIT_OID_MAX_SIZE] = {0};
119+
size_t oid_size = git_oid_size(idx->oid_type);
119120

120121
if (chunk_oid_lookup->offset == 0)
121122
return midx_error("missing OID Lookup chunk");
122123
if (chunk_oid_lookup->length == 0)
123124
return midx_error("empty OID Lookup chunk");
124-
if (chunk_oid_lookup->length != idx->num_objects * GIT_OID_SHA1_SIZE)
125+
if (chunk_oid_lookup->length != idx->num_objects * oid_size)
125126
return midx_error("OID Lookup chunk has wrong length");
126127

127128
idx->oid_lookup = oid = (unsigned char *)(data + chunk_oid_lookup->offset);
128129
prev_oid = zero_oid;
129-
for (i = 0; i < idx->num_objects; ++i, oid += GIT_OID_SHA1_SIZE) {
130-
if (git_oid_raw_cmp(prev_oid, oid, GIT_OID_SHA1_SIZE) >= 0)
130+
for (i = 0; i < idx->num_objects; ++i, oid += oid_size) {
131+
if (git_oid_raw_cmp(prev_oid, oid, oid_size) >= 0)
131132
return midx_error("OID Lookup index is non-monotonic");
132133
prev_oid = oid;
133134
}
@@ -178,7 +179,7 @@ int git_midx_parse(
178179
struct git_midx_chunk *last_chunk;
179180
uint32_t i;
180181
off64_t last_chunk_offset, chunk_offset, trailer_offset;
181-
size_t checksum_size;
182+
size_t checksum_size, oid_size;
182183
int error;
183184
struct git_midx_chunk chunk_packfile_names = {0},
184185
chunk_oid_fanout = {0},
@@ -188,7 +189,9 @@ int git_midx_parse(
188189

189190
GIT_ASSERT_ARG(idx);
190191

191-
if (size < sizeof(struct git_midx_header) + GIT_OID_SHA1_SIZE)
192+
oid_size = git_oid_size(idx->oid_type);
193+
194+
if (size < sizeof(struct git_midx_header) + oid_size)
192195
return midx_error("multi-pack index is too short");
193196

194197
hdr = ((struct git_midx_header *)data);
@@ -209,7 +212,7 @@ int git_midx_parse(
209212
sizeof(struct git_midx_header) +
210213
(1 + hdr->chunks) * 12;
211214

212-
checksum_size = GIT_HASH_SHA1_SIZE;
215+
checksum_size = oid_size;
213216
trailer_offset = size - checksum_size;
214217

215218
if (trailer_offset < last_chunk_offset)
@@ -287,15 +290,18 @@ int git_midx_parse(
287290
}
288291

289292
int git_midx_open(
290-
git_midx_file **idx_out,
291-
const char *path)
293+
git_midx_file **idx_out,
294+
const char *path,
295+
git_oid_t oid_type)
292296
{
293297
git_midx_file *idx;
294298
git_file fd = -1;
295299
size_t idx_size;
296300
struct stat st;
297301
int error;
298302

303+
GIT_ASSERT_ARG(idx_out && path && oid_type);
304+
299305
/* TODO: properly open the file without access time using O_NOATIME */
300306
fd = git_futils_open_ro(path);
301307
if (fd < 0)
@@ -317,6 +323,8 @@ int git_midx_open(
317323
idx = git__calloc(1, sizeof(git_midx_file));
318324
GIT_ERROR_CHECK_ALLOC(idx);
319325

326+
idx->oid_type = oid_type;
327+
320328
error = git_str_sets(&idx->filename, path);
321329
if (error < 0)
322330
return error;
@@ -344,7 +352,7 @@ bool git_midx_needs_refresh(
344352
git_file fd = -1;
345353
struct stat st;
346354
ssize_t bytes_read;
347-
unsigned char checksum[GIT_HASH_SHA1_SIZE];
355+
unsigned char checksum[GIT_HASH_MAX_SIZE];
348356
size_t checksum_size;
349357

350358
/* TODO: properly open the file without access time using O_NOATIME */
@@ -364,8 +372,8 @@ bool git_midx_needs_refresh(
364372
return true;
365373
}
366374

367-
checksum_size = GIT_HASH_SHA1_SIZE;
368-
bytes_read = p_pread(fd, checksum, checksum_size, st.st_size - GIT_OID_SHA1_SIZE);
375+
checksum_size = git_oid_size(idx->oid_type);
376+
bytes_read = p_pread(fd, checksum, checksum_size, st.st_size - checksum_size);
369377
p_close(fd);
370378

371379
if (bytes_read != (ssize_t)checksum_size)
@@ -381,38 +389,41 @@ int git_midx_entry_find(
381389
size_t len)
382390
{
383391
int pos, found = 0;
384-
size_t pack_index;
392+
size_t pack_index, oid_size, oid_hexsize;
385393
uint32_t hi, lo;
386394
unsigned char *current = NULL;
387395
const unsigned char *object_offset;
388396
off64_t offset;
389397

390398
GIT_ASSERT_ARG(idx);
391399

400+
oid_size = git_oid_size(idx->oid_type);
401+
oid_hexsize = git_oid_hexsize(idx->oid_type);
402+
392403
hi = ntohl(idx->oid_fanout[(int)short_oid->id[0]]);
393404
lo = ((short_oid->id[0] == 0x0) ? 0 : ntohl(idx->oid_fanout[(int)short_oid->id[0] - 1]));
394405

395-
pos = git_pack__lookup_id(idx->oid_lookup, GIT_OID_SHA1_SIZE, lo, hi, short_oid->id, GIT_OID_SHA1);
406+
pos = git_pack__lookup_id(idx->oid_lookup, oid_size, lo, hi, short_oid->id, idx->oid_type);
396407

397408
if (pos >= 0) {
398409
/* An object matching exactly the oid was found */
399410
found = 1;
400-
current = idx->oid_lookup + (pos * GIT_OID_SHA1_SIZE);
411+
current = idx->oid_lookup + (pos * oid_size);
401412
} else {
402413
/* No object was found */
403414
/* pos refers to the object with the "closest" oid to short_oid */
404415
pos = -1 - pos;
405416
if (pos < (int)idx->num_objects) {
406-
current = idx->oid_lookup + (pos * GIT_OID_SHA1_SIZE);
417+
current = idx->oid_lookup + (pos * oid_size);
407418

408419
if (!git_oid_raw_ncmp(short_oid->id, current, len))
409420
found = 1;
410421
}
411422
}
412423

413-
if (found && len != GIT_OID_SHA1_HEXSIZE && pos + 1 < (int)idx->num_objects) {
424+
if (found && len != oid_hexsize && pos + 1 < (int)idx->num_objects) {
414425
/* Check for ambiguousity */
415-
const unsigned char *next = current + GIT_OID_SHA1_SIZE;
426+
const unsigned char *next = current + oid_size;
416427

417428
if (!git_oid_raw_ncmp(short_oid->id, next, len))
418429
found = 2;
@@ -443,7 +454,7 @@ int git_midx_entry_find(
443454
return midx_error("invalid index into the packfile names table");
444455
e->pack_index = pack_index;
445456
e->offset = offset;
446-
git_oid__fromraw(&e->sha1, current, GIT_OID_SHA1);
457+
git_oid__fromraw(&e->sha1, current, idx->oid_type);
447458
return 0;
448459
}
449460

@@ -453,13 +464,15 @@ int git_midx_foreach_entry(
453464
void *data)
454465
{
455466
git_oid oid;
456-
size_t i;
467+
size_t oid_size, i;
457468
int error;
458469

459470
GIT_ASSERT_ARG(idx);
460471

472+
oid_size = git_oid_size(idx->oid_type);
473+
461474
for (i = 0; i < idx->num_objects; ++i) {
462-
if ((error = git_oid__fromraw(&oid, &idx->oid_lookup[i * GIT_OID_SHA1_SIZE], GIT_OID_SHA1)) < 0)
475+
if ((error = git_oid__fromraw(&oid, &idx->oid_lookup[i * oid_size], idx->oid_type)) < 0)
463476
return error;
464477

465478
if ((error = cb(&oid, data)) != 0)
@@ -501,9 +514,21 @@ static int packfile__cmp(const void *a_, const void *b_)
501514

502515
int git_midx_writer_new(
503516
git_midx_writer **out,
504-
const char *pack_dir)
517+
const char *pack_dir
518+
#ifdef GIT_EXPERIMENTAL_SHA256
519+
, git_oid_t oid_type
520+
#endif
521+
)
505522
{
506-
git_midx_writer *w = git__calloc(1, sizeof(git_midx_writer));
523+
git_midx_writer *w;
524+
525+
#ifndef GIT_EXPERIMENTAL_SHA256
526+
git_oid_t oid_type = GIT_OID_SHA1;
527+
#endif
528+
529+
GIT_ASSERT_ARG(out && pack_dir && oid_type);
530+
531+
w = git__calloc(1, sizeof(git_midx_writer));
507532
GIT_ERROR_CHECK_ALLOC(w);
508533

509534
if (git_str_sets(&w->pack_dir, pack_dir) < 0) {
@@ -518,6 +543,8 @@ int git_midx_writer_new(
518543
return -1;
519544
}
520545

546+
w->oid_type = oid_type;
547+
521548
*out = w;
522549
return 0;
523550
}
@@ -662,12 +689,13 @@ static int midx_write(
662689
oid_lookup = GIT_STR_INIT,
663690
object_offsets = GIT_STR_INIT,
664691
object_large_offsets = GIT_STR_INIT;
665-
unsigned char checksum[GIT_HASH_SHA1_SIZE];
666-
size_t checksum_size;
692+
unsigned char checksum[GIT_HASH_MAX_SIZE];
693+
size_t checksum_size, oid_size;
667694
git_midx_entry *entry;
668695
object_entry_array_t object_entries_array = GIT_ARRAY_INIT;
669696
git_vector object_entries = GIT_VECTOR_INIT;
670697
git_hash_ctx ctx;
698+
git_hash_algorithm_t checksum_type;
671699
struct midx_write_hash_context hash_cb_data = {0};
672700

673701
hdr.signature = htonl(MIDX_SIGNATURE);
@@ -679,10 +707,14 @@ static int midx_write(
679707
hash_cb_data.cb_data = cb_data;
680708
hash_cb_data.ctx = &ctx;
681709

682-
checksum_size = GIT_HASH_SHA1_SIZE;
683-
error = git_hash_ctx_init(&ctx, GIT_HASH_ALGORITHM_SHA1);
684-
if (error < 0)
710+
oid_size = git_oid_size(w->oid_type);
711+
712+
GIT_ASSERT((checksum_type = git_oid_algorithm(w->oid_type)));
713+
checksum_size = git_hash_size(checksum_type);
714+
715+
if ((error = git_hash_ctx_init(&ctx, checksum_type)) < 0)
685716
return error;
717+
686718
cb_data = &hash_cb_data;
687719
write_cb = midx_write_hash;
688720

@@ -749,7 +781,9 @@ static int midx_write(
749781

750782
/* Fill the OID Lookup table. */
751783
git_vector_foreach (&object_entries, i, entry) {
752-
error = git_str_put(&oid_lookup, (char *)&entry->sha1.id, GIT_OID_SHA1_SIZE);
784+
error = git_str_put(&oid_lookup,
785+
(char *)&entry->sha1.id, oid_size);
786+
753787
if (error < 0)
754788
goto cleanup;
755789
}

src/libgit2/midx.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,14 @@ typedef struct git_midx_file {
5151
/* The number of entries in the Object Large Offsets table. Each entry has an 8-byte with an offset */
5252
size_t num_object_large_offsets;
5353

54-
/* The trailer of the file. Contains the SHA1-checksum of the whole file. */
55-
unsigned char checksum[GIT_HASH_SHA1_SIZE];
54+
/*
55+
* The trailer of the file. Contains the checksum of the whole
56+
* file, in the repository's object format hash.
57+
*/
58+
unsigned char checksum[GIT_HASH_MAX_SIZE];
59+
60+
/* The type of object IDs in the midx. */
61+
git_oid_t oid_type;
5662

5763
/* something like ".git/objects/pack/multi-pack-index". */
5864
git_str filename;
@@ -82,11 +88,15 @@ struct git_midx_writer {
8288

8389
/* The list of `git_pack_file`s. */
8490
git_vector packs;
91+
92+
/* The object ID type of the writer. */
93+
git_oid_t oid_type;
8594
};
8695

8796
int git_midx_open(
8897
git_midx_file **idx_out,
89-
const char *path);
98+
const char *path,
99+
git_oid_t oid_type);
90100
bool git_midx_needs_refresh(
91101
const git_midx_file *idx,
92102
const char *path);

src/libgit2/odb_pack.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,9 @@ static int refresh_multi_pack_index(struct pack_backend *backend)
479479
}
480480
}
481481

482-
error = git_midx_open(&backend->midx, git_str_cstr(&midx_path));
482+
error = git_midx_open(&backend->midx, git_str_cstr(&midx_path),
483+
backend->opts.oid_type);
484+
483485
git_str_dispose(&midx_path);
484486
if (error < 0)
485487
return error;
@@ -798,7 +800,12 @@ static int pack_backend__writemidx(git_odb_backend *_backend)
798800

799801
backend = (struct pack_backend *)_backend;
800802

801-
error = git_midx_writer_new(&w, backend->pack_folder);
803+
error = git_midx_writer_new(&w, backend->pack_folder
804+
#ifdef GIT_EXPERIMENTAL_SHA256
805+
, backend->opts.oid_type
806+
#endif
807+
);
808+
802809
if (error < 0)
803810
return error;
804811

tests/libgit2/pack/midx.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ void test_pack_midx__parse(void)
1616

1717
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
1818
cl_git_pass(git_str_joinpath(&midx_path, git_repository_path(repo), "objects/pack/multi-pack-index"));
19-
cl_git_pass(git_midx_open(&idx, git_str_cstr(&midx_path)));
19+
cl_git_pass(git_midx_open(&idx, git_str_cstr(&midx_path), GIT_OID_SHA1));
2020
cl_assert_equal_i(git_midx_needs_refresh(idx, git_str_cstr(&midx_path)), 0);
2121

2222
cl_git_pass(git_oid__fromstr(&id, "5001298e0c09ad9c34e4249bc5801c75e9754fa5", GIT_OID_SHA1));
@@ -57,7 +57,12 @@ void test_pack_midx__writer(void)
5757
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
5858

5959
cl_git_pass(git_str_joinpath(&path, git_repository_path(repo), "objects/pack"));
60+
61+
#ifdef GIT_EXPERIMENTAL_SHA256
62+
cl_git_pass(git_midx_writer_new(&w, git_str_cstr(&path), GIT_OID_SHA1));
63+
#else
6064
cl_git_pass(git_midx_writer_new(&w, git_str_cstr(&path)));
65+
#endif
6166

6267
cl_git_pass(git_midx_writer_add(w, "pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx"));
6368
cl_git_pass(git_midx_writer_add(w, "pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.idx"));

0 commit comments

Comments
 (0)