18
#define MIDX_HASH_LEN 20
19
#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + MIDX_HASH_LEN)
20
21
-#define MIDX_MAX_CHUNKS 3
21
+#define MIDX_MAX_CHUNKS 5
22
#define MIDX_CHUNK_ALIGNMENT 4
23
#define MIDX_CHUNKID_PACKNAMES 0x504e414d /* "PNAM" */
24
#define MIDX_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
25
#define MIDX_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
26
+#define MIDX_CHUNKID_OBJECTOFFSETS 0x4f4f4646 /* "OOFF" */
27
+#define MIDX_CHUNKID_LARGEOFFSETS 0x4c4f4646 /* "LOFF" */
28
#define MIDX_CHUNKLOOKUP_WIDTH (sizeof(uint32_t) + sizeof(uint64_t))
29
#define MIDX_CHUNK_FANOUT_SIZE (sizeof(uint32_t) * 256)
30
+#define MIDX_CHUNK_OFFSET_WIDTH (2 * sizeof(uint32_t))
31
+#define MIDX_CHUNK_LARGE_OFFSET_WIDTH (sizeof(uint64_t))
32
+#define MIDX_LARGE_OFFSET_NEEDED 0x80000000
33
34
static char *get_midx_filename(const char *object_dir)
35
{
117
m->chunk_oid_lookup = m->data + chunk_offset;
118
break;
119
120
+ case MIDX_CHUNKID_OBJECTOFFSETS:
121
+ m->chunk_object_offsets = m->data + chunk_offset;
122
+ break;
123
+
124
+ case MIDX_CHUNKID_LARGEOFFSETS:
125
+ m->chunk_large_offsets = m->data + chunk_offset;
126
+ break;
127
+
128
case 0:
129
die(_("terminating multi-pack-index chunk id appears earlier than expected"));
130
break;
144
die(_("multi-pack-index missing required OID fanout chunk"));
145
if (!m->chunk_oid_lookup)
146
die(_("multi-pack-index missing required OID lookup chunk"));
147
+ if (!m->chunk_object_offsets)
148
+ die(_("multi-pack-index missing required object offsets chunk"));
149
150
m->num_objects = ntohl(m->chunk_oid_fanout[255]);
151
469
return written;
470
}
471
472
+static size_t write_midx_object_offsets(struct hashfile *f, int large_offset_needed,
473
+ struct pack_midx_entry *objects, uint32_t nr_objects)
474
+{
475
+ struct pack_midx_entry *list = objects;
476
+ uint32_t i, nr_large_offset = 0;
477
+ size_t written = 0;
478
+
479
+ for (i = 0; i < nr_objects; i++) {
480
+ struct pack_midx_entry *obj = list++;
481
+
482
+ hashwrite_be32(f, obj->pack_int_id);
483
+
484
+ if (large_offset_needed && obj->offset >> 31)
485
+ hashwrite_be32(f, MIDX_LARGE_OFFSET_NEEDED | nr_large_offset++);
486
+ else if (!large_offset_needed && obj->offset >> 32)
487
+ BUG("object %s requires a large offset (%"PRIx64") but the MIDX is not writing large offsets!",
488
+ oid_to_hex(&obj->oid),
489
+ obj->offset);
490
+ else
491
+ hashwrite_be32(f, (uint32_t)obj->offset);
492
+
493
+ written += MIDX_CHUNK_OFFSET_WIDTH;
494
+ }
495
+
496
+ return written;
497
+}
498
+
499
+static size_t write_midx_large_offsets(struct hashfile *f, uint32_t nr_large_offset,
500
+ struct pack_midx_entry *objects, uint32_t nr_objects)
501
+{
502
+ struct pack_midx_entry *list = objects;
503
+ size_t written = 0;
504
+
505
+ while (nr_large_offset) {
506
+ struct pack_midx_entry *obj = list++;
507
+ uint64_t offset = obj->offset;
508
+
509
+ if (!(offset >> 31))
510
+ continue;
511
+
512
+ hashwrite_be32(f, offset >> 32);
513
+ hashwrite_be32(f, offset & 0xffffffffUL);
514
+ written += 2 * sizeof(uint32_t);
515
+
516
+ nr_large_offset--;
517
+ }
518
+
519
+ return written;
520
+}
521
+
522
int write_midx_file(const char *object_dir)
523
{
524
unsigned char cur_chunk, num_chunks = 0;
531
uint64_t written = 0;
532
uint32_t chunk_ids[MIDX_MAX_CHUNKS + 1];
533
uint64_t chunk_offsets[MIDX_MAX_CHUNKS + 1];
469
- uint32_t nr_entries;
534
+ uint32_t nr_entries, num_large_offsets = 0;
535
struct pack_midx_entry *entries = NULL;
536
+ int large_offsets_needed = 0;
537
538
midx_name = get_midx_filename(object_dir);
539
if (safe_create_leading_directories(midx_name)) {
560
sort_packs_by_name(packs.names, packs.nr, pack_perm);
561
562
entries = get_sorted_entries(packs.list, pack_perm, packs.nr, &nr_entries);
563
+ for (i = 0; i < nr_entries; i++) {
564
+ if (entries[i].offset > 0x7fffffff)
565
+ num_large_offsets++;
566
+ if (entries[i].offset > 0xffffffff)
567
+ large_offsets_needed = 1;
568
+ }
569
570
hold_lock_file_for_update(&lk, midx_name, LOCK_DIE_ON_ERROR);
571
f = hashfd(lk.tempfile->fd, lk.tempfile->filename.buf);
572
FREE_AND_NULL(midx_name);
573
574
cur_chunk = 0;
503
- num_chunks = 3;
575
+ num_chunks = large_offsets_needed ? 5 : 4;
576
577
written = write_midx_header(f, num_chunks, packs.nr);
578
588
chunk_offsets[cur_chunk] = chunk_offsets[cur_chunk - 1] + MIDX_CHUNK_FANOUT_SIZE;
589
590
cur_chunk++;
519
- chunk_ids[cur_chunk] = 0;
591
+ chunk_ids[cur_chunk] = MIDX_CHUNKID_OBJECTOFFSETS;
592
chunk_offsets[cur_chunk] = chunk_offsets[cur_chunk - 1] + nr_entries * MIDX_HASH_LEN;
593
594
+ cur_chunk++;
595
+ chunk_offsets[cur_chunk] = chunk_offsets[cur_chunk - 1] + nr_entries * MIDX_CHUNK_OFFSET_WIDTH;
596
+ if (large_offsets_needed) {
597
+ chunk_ids[cur_chunk] = MIDX_CHUNKID_LARGEOFFSETS;
598
+
599
+ cur_chunk++;
600
+ chunk_offsets[cur_chunk] = chunk_offsets[cur_chunk - 1] +
601
+ num_large_offsets * MIDX_CHUNK_LARGE_OFFSET_WIDTH;
602
+ }
603
+
604
+ chunk_ids[cur_chunk] = 0;
605
+
606
for (i = 0; i <= num_chunks; i++) {
607
if (i && chunk_offsets[i] < chunk_offsets[i - 1])
608
BUG("incorrect chunk offsets: %"PRIu64" before %"PRIu64,
640
written += write_midx_oid_lookup(f, MIDX_HASH_LEN, entries, nr_entries);
641
break;
642
643
+ case MIDX_CHUNKID_OBJECTOFFSETS:
644
+ written += write_midx_object_offsets(f, large_offsets_needed, entries, nr_entries);
645
+ break;
646
+
647
+ case MIDX_CHUNKID_LARGEOFFSETS:
648
+ written += write_midx_large_offsets(f, num_large_offsets, entries, nr_entries);
649
+ break;
650
+
651
default:
652
BUG("trying to write unknown chunk id %"PRIx32,
653
chunk_ids[i]);