Raw
1 #define DISABLE_SIGN_COMPARE_WARNINGS
2
3 #include "git-compat-util.h"
4 #include "config.h"
5 #include "dir.h"
6 #include "hex.h"
7 #include "packfile.h"
8 #include "hash-lookup.h"
9 #include "midx.h"
10 #include "progress.h"
11 #include "trace2.h"
12 #include "chunk-format.h"
13 #include "pack-bitmap.h"
14 #include "pack-revindex.h"
15 #include "strvec.h"
16
17 #define MIDX_PACK_ERROR ((void *)(intptr_t)-1)
18
19 int midx_checksum_valid(struct multi_pack_index *m);
20 void clear_midx_files_ext(struct odb_source *source, const char *ext,
21 const char *keep_hash);
22 void clear_incremental_midx_files_ext(struct odb_source *source, const char *ext,
23 const struct strvec *keep_hashes);
24 int cmp_idx_or_pack_name(const char *idx_or_pack_name,
25 const char *idx_name);
26
27 const char *midx_get_checksum_hex(const struct multi_pack_index *m)
28 {
29 return hash_to_hex_algop(midx_get_checksum_hash(m),
30 m->source->odb->repo->hash_algo);
31 }
32
33 const unsigned char *midx_get_checksum_hash(const struct multi_pack_index *m)
34 {
35 return m->data + m->data_len - m->source->odb->repo->hash_algo->rawsz;
36 }
37
38 void get_midx_filename(struct odb_source *source, struct strbuf *out)
39 {
40 get_midx_filename_ext(source, out, NULL, NULL);
41 }
42
43 void get_midx_filename_ext(struct odb_source *source, struct strbuf *out,
44 const unsigned char *hash, const char *ext)
45 {
46 strbuf_addf(out, "%s/pack/multi-pack-index", source->path);
47 if (ext)
48 strbuf_addf(out, "-%s.%s", hash_to_hex_algop(hash, source->odb->repo->hash_algo), ext);
49 }
50
51 static int midx_read_oid_fanout(const unsigned char *chunk_start,
52 size_t chunk_size, void *data)
53 {
54 int i;
55 struct multi_pack_index *m = data;
56 m->chunk_oid_fanout = (uint32_t *)chunk_start;
57
58 if (chunk_size != 4 * 256) {
59 error(_("multi-pack-index OID fanout is of the wrong size"));
60 return 1;
61 }
62 for (i = 0; i < 255; i++) {
63 uint32_t oid_fanout1 = ntohl(m->chunk_oid_fanout[i]);
64 uint32_t oid_fanout2 = ntohl(m->chunk_oid_fanout[i+1]);
65
66 if (oid_fanout1 > oid_fanout2) {
67 error(_("oid fanout out of order: fanout[%d] = %"PRIx32" > %"PRIx32" = fanout[%d]"),
68 i, oid_fanout1, oid_fanout2, i + 1);
69 return 1;
70 }
71 }
72 m->num_objects = ntohl(m->chunk_oid_fanout[255]);
73 return 0;
74 }
75
76 static int midx_read_oid_lookup(const unsigned char *chunk_start,
77 size_t chunk_size, void *data)
78 {
79 struct multi_pack_index *m = data;
80 m->chunk_oid_lookup = chunk_start;
81
82 if (chunk_size != st_mult(m->hash_len, m->num_objects)) {
83 error(_("multi-pack-index OID lookup chunk is the wrong size"));
84 return 1;
85 }
86 return 0;
87 }
88
89 static int midx_read_object_offsets(const unsigned char *chunk_start,
90 size_t chunk_size, void *data)
91 {
92 struct multi_pack_index *m = data;
93 m->chunk_object_offsets = chunk_start;
94
95 if (chunk_size != st_mult(m->num_objects, MIDX_CHUNK_OFFSET_WIDTH)) {
96 error(_("multi-pack-index object offset chunk is the wrong size"));
97 return 1;
98 }
99 return 0;
100 }
101
102 struct multi_pack_index *get_multi_pack_index(struct odb_source *source)
103 {
104 struct odb_source_files *files = odb_source_files_downcast(source);
105 packfile_store_prepare(files->packed);
106 return files->packed->midx;
107 }
108
109 static struct multi_pack_index *load_multi_pack_index_one(struct odb_source *source,
110 const char *midx_name)
111 {
112 struct repository *r = source->odb->repo;
113 struct multi_pack_index *m = NULL;
114 int fd;
115 struct stat st;
116 size_t midx_size;
117 void *midx_map = NULL;
118 uint32_t hash_version;
119 uint32_t i;
120 const char *cur_pack_name;
121 struct chunkfile *cf = NULL;
122
123 fd = git_open(midx_name);
124
125 if (fd < 0)
126 goto cleanup_fail;
127 if (fstat(fd, &st)) {
128 error_errno(_("failed to read %s"), midx_name);
129 goto cleanup_fail;
130 }
131
132 midx_size = xsize_t(st.st_size);
133
134 if (midx_size < (MIDX_HEADER_SIZE + r->hash_algo->rawsz)) {
135 error(_("multi-pack-index file %s is too small"), midx_name);
136 goto cleanup_fail;
137 }
138
139 midx_map = xmmap(NULL, midx_size, PROT_READ, MAP_PRIVATE, fd, 0);
140 close(fd);
141
142 CALLOC_ARRAY(m, 1);
143 m->data = midx_map;
144 m->data_len = midx_size;
145 m->source = source;
146
147 m->signature = get_be32(m->data);
148 if (m->signature != MIDX_SIGNATURE)
149 die(_("multi-pack-index signature 0x%08x does not match signature 0x%08x"),
150 m->signature, MIDX_SIGNATURE);
151
152 m->version = m->data[MIDX_BYTE_FILE_VERSION];
153 if (m->version != MIDX_VERSION_V1 && m->version != MIDX_VERSION_V2)
154 die(_("multi-pack-index version %d not recognized"),
155 m->version);
156
157 hash_version = m->data[MIDX_BYTE_HASH_VERSION];
158 if (hash_version != oid_version(r->hash_algo)) {
159 error(_("multi-pack-index hash version %u does not match version %u"),
160 hash_version, oid_version(r->hash_algo));
161 goto cleanup_fail;
162 }
163 m->hash_len = r->hash_algo->rawsz;
164
165 m->num_chunks = m->data[MIDX_BYTE_NUM_CHUNKS];
166
167 m->num_packs = get_be32(m->data + MIDX_BYTE_NUM_PACKS);
168
169 m->preferred_pack_idx = -1;
170
171 cf = init_chunkfile(NULL);
172
173 if (read_table_of_contents(cf, m->data, midx_size,
174 MIDX_HEADER_SIZE, m->num_chunks,
175 MIDX_CHUNK_ALIGNMENT))
176 goto cleanup_fail;
177
178 if (pair_chunk(cf, MIDX_CHUNKID_PACKNAMES, &m->chunk_pack_names, &m->chunk_pack_names_len))
179 die(_("multi-pack-index required pack-name chunk missing or corrupted"));
180 if (read_chunk(cf, MIDX_CHUNKID_OIDFANOUT, midx_read_oid_fanout, m))
181 die(_("multi-pack-index required OID fanout chunk missing or corrupted"));
182 if (read_chunk(cf, MIDX_CHUNKID_OIDLOOKUP, midx_read_oid_lookup, m))
183 die(_("multi-pack-index required OID lookup chunk missing or corrupted"));
184 if (read_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS, midx_read_object_offsets, m))
185 die(_("multi-pack-index required object offsets chunk missing or corrupted"));
186
187 pair_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS, &m->chunk_large_offsets,
188 &m->chunk_large_offsets_len);
189 if (git_env_bool("GIT_TEST_MIDX_READ_BTMP", 1))
190 pair_chunk(cf, MIDX_CHUNKID_BITMAPPEDPACKS,
191 (const unsigned char **)&m->chunk_bitmapped_packs,
192 &m->chunk_bitmapped_packs_len);
193
194 if (git_env_bool("GIT_TEST_MIDX_READ_RIDX", 1))
195 pair_chunk(cf, MIDX_CHUNKID_REVINDEX, &m->chunk_revindex,
196 &m->chunk_revindex_len);
197
198 CALLOC_ARRAY(m->pack_names, m->num_packs);
199 CALLOC_ARRAY(m->packs, m->num_packs);
200
201 cur_pack_name = (const char *)m->chunk_pack_names;
202 for (i = 0; i < m->num_packs; i++) {
203 const char *end;
204 size_t avail = m->chunk_pack_names_len -
205 (cur_pack_name - (const char *)m->chunk_pack_names);
206
207 m->pack_names[i] = cur_pack_name;
208
209 end = memchr(cur_pack_name, '\0', avail);
210 if (!end)
211 die(_("multi-pack-index pack-name chunk is too short"));
212 cur_pack_name = end + 1;
213
214 if (m->version == MIDX_VERSION_V1 &&
215 i && strcmp(m->pack_names[i], m->pack_names[i - 1]) <= 0)
216 die(_("multi-pack-index pack names out of order: '%s' before '%s'"),
217 m->pack_names[i - 1],
218 m->pack_names[i]);
219 }
220
221 trace2_data_intmax("midx", r, "load/num_packs", m->num_packs);
222 trace2_data_intmax("midx", r, "load/num_objects", m->num_objects);
223
224 free_chunkfile(cf);
225 return m;
226
227 cleanup_fail:
228 free(m);
229 free_chunkfile(cf);
230 if (midx_map)
231 munmap(midx_map, midx_size);
232 if (0 <= fd)
233 close(fd);
234 return NULL;
235 }
236
237 void get_midx_chain_dirname(struct odb_source *source, struct strbuf *buf)
238 {
239 strbuf_addf(buf, "%s/pack/multi-pack-index.d", source->path);
240 }
241
242 void get_midx_chain_filename(struct odb_source *source, struct strbuf *buf)
243 {
244 get_midx_chain_dirname(source, buf);
245 strbuf_addstr(buf, "/multi-pack-index-chain");
246 }
247
248 void get_split_midx_filename_ext(struct odb_source *source, struct strbuf *buf,
249 const unsigned char *hash, const char *ext)
250 {
251 get_midx_chain_dirname(source, buf);
252 strbuf_addf(buf, "/multi-pack-index-%s.%s",
253 hash_to_hex_algop(hash, source->odb->repo->hash_algo), ext);
254 }
255
256 static int open_multi_pack_index_chain(const struct git_hash_algo *hash_algo,
257 const char *chain_file, int *fd,
258 struct stat *st)
259 {
260 *fd = git_open(chain_file);
261 if (*fd < 0)
262 return 0;
263 if (fstat(*fd, st)) {
264 close(*fd);
265 return 0;
266 }
267 if (st->st_size < hash_algo->hexsz) {
268 close(*fd);
269 if (!st->st_size) {
270 /* treat empty files the same as missing */
271 errno = ENOENT;
272 } else {
273 warning(_("multi-pack-index chain file too small"));
274 errno = EINVAL;
275 }
276 return 0;
277 }
278 return 1;
279 }
280
281 static int add_midx_to_chain(struct multi_pack_index *midx,
282 struct multi_pack_index *midx_chain)
283 {
284 if (midx_chain) {
285 if (unsigned_add_overflows(midx_chain->num_packs,
286 midx_chain->num_packs_in_base)) {
287 warning(_("pack count in base MIDX too high: %"PRIuMAX),
288 (uintmax_t)midx_chain->num_packs_in_base);
289 return 0;
290 }
291 if (unsigned_add_overflows(midx_chain->num_objects,
292 midx_chain->num_objects_in_base)) {
293 warning(_("object count in base MIDX too high: %"PRIuMAX),
294 (uintmax_t)midx_chain->num_objects_in_base);
295 return 0;
296 }
297 midx->num_packs_in_base = midx_chain->num_packs +
298 midx_chain->num_packs_in_base;
299 midx->num_objects_in_base = midx_chain->num_objects +
300 midx_chain->num_objects_in_base;
301 }
302
303 midx->base_midx = midx_chain;
304 midx->has_chain = 1;
305
306 return 1;
307 }
308
309 static struct multi_pack_index *load_midx_chain_fd_st(struct odb_source *source,
310 int fd, struct stat *st,
311 int *incomplete_chain)
312 {
313 const struct git_hash_algo *hash_algo = source->odb->repo->hash_algo;
314 struct multi_pack_index *midx_chain = NULL;
315 struct strbuf buf = STRBUF_INIT;
316 int valid = 1;
317 uint32_t i, count;
318 FILE *fp = xfdopen(fd, "r");
319
320 count = st->st_size / (hash_algo->hexsz + 1);
321
322 for (i = 0; i < count; i++) {
323 struct multi_pack_index *m;
324 struct object_id layer;
325
326 if (strbuf_getline_lf(&buf, fp) == EOF)
327 break;
328
329 if (get_oid_hex_algop(buf.buf, &layer, hash_algo)) {
330 warning(_("invalid multi-pack-index chain: line '%s' "
331 "not a hash"),
332 buf.buf);
333 valid = 0;
334 break;
335 }
336
337 valid = 0;
338
339 strbuf_reset(&buf);
340 get_split_midx_filename_ext(source, &buf,
341 layer.hash, MIDX_EXT_MIDX);
342 m = load_multi_pack_index_one(source, buf.buf);
343
344 if (m) {
345 if (add_midx_to_chain(m, midx_chain)) {
346 midx_chain = m;
347 valid = 1;
348 } else {
349 close_midx(m);
350 }
351 }
352 if (!valid) {
353 warning(_("unable to find all multi-pack index files"));
354 break;
355 }
356 }
357
358 fclose(fp);
359 strbuf_release(&buf);
360
361 *incomplete_chain = !valid;
362 return midx_chain;
363 }
364
365 static struct multi_pack_index *load_multi_pack_index_chain(struct odb_source *source)
366 {
367 struct strbuf chain_file = STRBUF_INIT;
368 struct stat st;
369 int fd;
370 struct multi_pack_index *m = NULL;
371
372 get_midx_chain_filename(source, &chain_file);
373 if (open_multi_pack_index_chain(source->odb->repo->hash_algo, chain_file.buf, &fd, &st)) {
374 int incomplete;
375 /* ownership of fd is taken over by load function */
376 m = load_midx_chain_fd_st(source, fd, &st, &incomplete);
377 }
378
379 strbuf_release(&chain_file);
380 return m;
381 }
382
383 struct multi_pack_index *load_multi_pack_index(struct odb_source *source)
384 {
385 struct strbuf midx_name = STRBUF_INIT;
386 struct multi_pack_index *m;
387
388 get_midx_filename(source, &midx_name);
389
390 m = load_multi_pack_index_one(source, midx_name.buf);
391 if (!m)
392 m = load_multi_pack_index_chain(source);
393
394 strbuf_release(&midx_name);
395
396 return m;
397 }
398
399 void close_midx(struct multi_pack_index *m)
400 {
401 uint32_t i;
402
403 if (!m)
404 return;
405
406 close_midx(m->base_midx);
407
408 munmap((unsigned char *)m->data, m->data_len);
409
410 for (i = 0; i < m->num_packs; i++) {
411 if (m->packs[i] && m->packs[i] != MIDX_PACK_ERROR)
412 m->packs[i]->multi_pack_index = 0;
413 }
414 FREE_AND_NULL(m->packs);
415 FREE_AND_NULL(m->pack_names);
416 FREE_AND_NULL(m->pack_names_sorted);
417 free(m);
418 }
419
420 static uint32_t midx_for_object(struct multi_pack_index **_m, uint32_t pos)
421 {
422 struct multi_pack_index *m = *_m;
423 while (m && pos < m->num_objects_in_base)
424 m = m->base_midx;
425
426 if (!m)
427 BUG("NULL multi-pack-index for object position: %"PRIu32, pos);
428
429 if (pos >= m->num_objects + m->num_objects_in_base)
430 die(_("invalid MIDX object position, MIDX is likely corrupt"));
431
432 *_m = m;
433
434 return pos - m->num_objects_in_base;
435 }
436
437 static uint32_t midx_for_pack(struct multi_pack_index **_m,
438 uint32_t pack_int_id)
439 {
440 struct multi_pack_index *m = *_m;
441 while (m && pack_int_id < m->num_packs_in_base)
442 m = m->base_midx;
443
444 if (!m)
445 BUG("NULL multi-pack-index for pack ID: %"PRIu32, pack_int_id);
446
447 if (pack_int_id >= m->num_packs + m->num_packs_in_base)
448 die(_("bad pack-int-id: %u (%u total packs)"),
449 pack_int_id, m->num_packs + m->num_packs_in_base);
450
451 *_m = m;
452
453 return pack_int_id - m->num_packs_in_base;
454 }
455
456 int prepare_midx_pack(struct multi_pack_index *m,
457 uint32_t pack_int_id)
458 {
459 struct odb_source_files *files = odb_source_files_downcast(m->source);
460 struct strbuf pack_name = STRBUF_INIT;
461 struct packed_git *p;
462
463 pack_int_id = midx_for_pack(&m, pack_int_id);
464
465 if (m->packs[pack_int_id] == MIDX_PACK_ERROR)
466 return 1;
467 if (m->packs[pack_int_id])
468 return 0;
469
470 strbuf_addf(&pack_name, "%s/pack/%s", files->base.path,
471 m->pack_names[pack_int_id]);
472 p = packfile_store_load_pack(files->packed,
473 pack_name.buf, files->base.local);
474 strbuf_release(&pack_name);
475
476 if (!p) {
477 m->packs[pack_int_id] = MIDX_PACK_ERROR;
478 return 1;
479 }
480
481 p->multi_pack_index = 1;
482 m->packs[pack_int_id] = p;
483
484 return 0;
485 }
486
487 struct packed_git *nth_midxed_pack(struct multi_pack_index *m,
488 uint32_t pack_int_id)
489 {
490 uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id);
491 if (m->packs[local_pack_int_id] == MIDX_PACK_ERROR)
492 return NULL;
493 return m->packs[local_pack_int_id];
494 }
495
496 #define MIDX_CHUNK_BITMAPPED_PACKS_WIDTH (2 * sizeof(uint32_t))
497
498 int nth_bitmapped_pack(struct multi_pack_index *m,
499 struct bitmapped_pack *bp, uint32_t pack_int_id)
500 {
501 uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id);
502
503 if (!m->chunk_bitmapped_packs)
504 return error(_("MIDX does not contain the BTMP chunk"));
505
506 if (prepare_midx_pack(m, pack_int_id))
507 return error(_("could not load bitmapped pack %"PRIu32), pack_int_id);
508
509 bp->p = m->packs[local_pack_int_id];
510 bp->bitmap_pos = get_be32((char *)m->chunk_bitmapped_packs +
511 MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * local_pack_int_id);
512 bp->bitmap_nr = get_be32((char *)m->chunk_bitmapped_packs +
513 MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * local_pack_int_id +
514 sizeof(uint32_t));
515 bp->pack_int_id = pack_int_id;
516 bp->from_midx = m;
517
518 return 0;
519 }
520
521 int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m,
522 uint32_t *result)
523 {
524 int ret = bsearch_hash(oid->hash, m->chunk_oid_fanout,
525 m->chunk_oid_lookup,
526 m->source->odb->repo->hash_algo->rawsz,
527 result);
528 if (result)
529 *result += m->num_objects_in_base;
530 return ret;
531 }
532
533 int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m,
534 uint32_t *result)
535 {
536 for (; m; m = m->base_midx)
537 if (bsearch_one_midx(oid, m, result))
538 return 1;
539 return 0;
540 }
541
542 int midx_has_oid(struct multi_pack_index *m, const struct object_id *oid)
543 {
544 return bsearch_midx(oid, m, NULL);
545 }
546
547 struct object_id *nth_midxed_object_oid(struct object_id *oid,
548 struct multi_pack_index *m,
549 uint32_t n)
550 {
551 if (n >= m->num_objects + m->num_objects_in_base)
552 return NULL;
553
554 n = midx_for_object(&m, n);
555
556 oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n),
557 m->source->odb->repo->hash_algo);
558 return oid;
559 }
560
561 off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
562 {
563 const unsigned char *offset_data;
564 uint32_t offset32;
565
566 pos = midx_for_object(&m, pos);
567
568 offset_data = m->chunk_object_offsets + (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH;
569 offset32 = get_be32(offset_data + sizeof(uint32_t));
570
571 if (m->chunk_large_offsets && offset32 & MIDX_LARGE_OFFSET_NEEDED) {
572 if (sizeof(off_t) < sizeof(uint64_t))
573 die(_("multi-pack-index stores a 64-bit offset, but off_t is too small"));
574
575 offset32 ^= MIDX_LARGE_OFFSET_NEEDED;
576 if (offset32 >= m->chunk_large_offsets_len / sizeof(uint64_t))
577 die(_("multi-pack-index large offset out of bounds"));
578 return get_be64(m->chunk_large_offsets + sizeof(uint64_t) * offset32);
579 }
580
581 return offset32;
582 }
583
584 uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos)
585 {
586 pos = midx_for_object(&m, pos);
587
588 return m->num_packs_in_base + get_be32(m->chunk_object_offsets +
589 (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
590 }
591
592 int fill_midx_entry(struct multi_pack_index *m,
593 const struct object_id *oid,
594 struct pack_entry *e)
595 {
596 uint32_t pos;
597 uint32_t pack_int_id;
598 struct packed_git *p;
599
600 if (!bsearch_midx(oid, m, &pos))
601 return 0;
602
603 midx_for_object(&m, pos);
604 pack_int_id = nth_midxed_pack_int_id(m, pos);
605
606 if (prepare_midx_pack(m, pack_int_id))
607 return 0;
608 p = m->packs[pack_int_id - m->num_packs_in_base];
609
610 /*
611 * We are about to tell the caller where they can locate the
612 * requested object. We better make sure the packfile is
613 * still here and can be accessed before supplying that
614 * answer, as it may have been deleted since the MIDX was
615 * loaded!
616 */
617 if (!is_pack_valid(p))
618 return 0;
619
620 if (oidset_size(&p->bad_objects) &&
621 oidset_contains(&p->bad_objects, oid))
622 return 0;
623
624 e->offset = nth_midxed_offset(m, pos);
625 e->p = p;
626
627 return 1;
628 }
629
630 /* Match "foo.idx" against either "foo.pack" _or_ "foo.idx". */
631 int cmp_idx_or_pack_name(const char *idx_or_pack_name,
632 const char *idx_name)
633 {
634 /* Skip past any initial matching prefix. */
635 while (*idx_name && *idx_name == *idx_or_pack_name) {
636 idx_name++;
637 idx_or_pack_name++;
638 }
639
640 /*
641 * If we didn't match completely, we may have matched "pack-1234." and
642 * be left with "idx" and "pack" respectively, which is also OK. We do
643 * not have to check for "idx" and "idx", because that would have been
644 * a complete match (and in that case these strcmps will be false, but
645 * we'll correctly return 0 from the final strcmp() below.
646 *
647 * Technically this matches "fooidx" and "foopack", but we'd never have
648 * such names in the first place.
649 */
650 if (!strcmp(idx_name, "idx") && !strcmp(idx_or_pack_name, "pack"))
651 return 0;
652
653 /*
654 * This not only checks for a complete match, but also orders based on
655 * the first non-identical character, which means our ordering will
656 * match a raw strcmp(). That makes it OK to use this to binary search
657 * a naively-sorted list.
658 */
659 return strcmp(idx_or_pack_name, idx_name);
660 }
661
662
663 static int midx_pack_names_cmp(const void *a, const void *b, void *m_)
664 {
665 struct multi_pack_index *m = m_;
666 return strcmp(m->pack_names[*(const size_t *)a],
667 m->pack_names[*(const size_t *)b]);
668 }
669
670 int midx_layer_contains_pack(struct multi_pack_index *m,
671 const char *idx_or_pack_name)
672 {
673 uint32_t first = 0, last = m->num_packs;
674
675 if (m->version == MIDX_VERSION_V2 && !m->pack_names_sorted) {
676 uint32_t i;
677
678 ALLOC_ARRAY(m->pack_names_sorted, m->num_packs);
679
680 for (i = 0; i < m->num_packs; i++)
681 m->pack_names_sorted[i] = i;
682
683 QSORT_S(m->pack_names_sorted, m->num_packs, midx_pack_names_cmp,
684 m);
685 }
686
687 while (first < last) {
688 uint32_t mid = first + (last - first) / 2;
689 const char *current;
690 int cmp;
691
692 if (m->pack_names_sorted)
693 current = m->pack_names[m->pack_names_sorted[mid]];
694 else
695 current = m->pack_names[mid];
696 cmp = cmp_idx_or_pack_name(idx_or_pack_name, current);
697 if (!cmp)
698 return 1;
699 if (cmp > 0) {
700 first = mid + 1;
701 continue;
702 }
703 last = mid;
704 }
705
706 return 0;
707 }
708
709 int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name)
710 {
711 for (; m; m = m->base_midx)
712 if (midx_layer_contains_pack(m, idx_or_pack_name))
713 return 1;
714 return 0;
715 }
716
717 int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id)
718 {
719 if (m->preferred_pack_idx == -1) {
720 uint32_t midx_pos;
721 if (load_midx_revindex(m)) {
722 m->preferred_pack_idx = -2;
723 return -1;
724 }
725
726 midx_pos = pack_pos_to_midx(m, m->num_objects_in_base);
727
728 m->preferred_pack_idx = nth_midxed_pack_int_id(m, midx_pos);
729
730 } else if (m->preferred_pack_idx == -2)
731 return -1; /* no revindex */
732
733 *pack_int_id = m->preferred_pack_idx;
734 return 0;
735 }
736
737 int prepare_multi_pack_index_one(struct odb_source *source)
738 {
739 struct odb_source_files *files = odb_source_files_downcast(source);
740 struct repository *r = source->odb->repo;
741
742 prepare_repo_settings(r);
743 if (!r->settings.core_multi_pack_index)
744 return 0;
745
746 if (files->packed->midx)
747 return 1;
748
749 files->packed->midx = load_multi_pack_index(source);
750
751 return !!files->packed->midx;
752 }
753
754 int midx_checksum_valid(struct multi_pack_index *m)
755 {
756 return hashfile_checksum_valid(m->source->odb->repo->hash_algo,
757 m->data, m->data_len);
758 }
759
760 struct clear_midx_data {
761 struct strset keep;
762 const char *ext;
763 };
764
765 static void clear_midx_file_ext(const char *full_path, size_t full_path_len UNUSED,
766 const char *file_name, void *_data)
767 {
768 struct clear_midx_data *data = _data;
769
770 if (!(starts_with(file_name, "multi-pack-index-") &&
771 ends_with(file_name, data->ext)))
772 return;
773 if (strset_contains(&data->keep, file_name))
774 return;
775 if (unlink(full_path))
776 die_errno(_("failed to remove %s"), full_path);
777 }
778
779 void clear_midx_files_ext(struct odb_source *source, const char *ext,
780 const char *keep_hash)
781 {
782 struct clear_midx_data data = {
783 .keep = STRSET_INIT,
784 .ext = ext,
785 };
786
787 if (keep_hash) {
788 struct strbuf buf = STRBUF_INIT;
789 strbuf_addf(&buf, "multi-pack-index-%s.%s", keep_hash, ext);
790
791 strset_add(&data.keep, buf.buf);
792
793 strbuf_release(&buf);
794 }
795
796 for_each_file_in_pack_dir(source->path, clear_midx_file_ext, &data);
797
798 strset_clear(&data.keep);
799 }
800
801 void clear_incremental_midx_files_ext(struct odb_source *source, const char *ext,
802 const struct strvec *keep_hashes)
803 {
804 struct clear_midx_data data = {
805 .keep = STRSET_INIT,
806 .ext = ext,
807 };
808 struct strbuf buf = STRBUF_INIT;
809
810 if (keep_hashes) {
811 for (size_t i = 0; i < keep_hashes->nr; i++) {
812 strbuf_reset(&buf);
813 strbuf_addf(&buf, "multi-pack-index-%s.%s",
814 keep_hashes->v[i], ext);
815
816 strset_add(&data.keep, buf.buf);
817 }
818 }
819
820 for_each_file_in_pack_subdir(source->path, "multi-pack-index.d",
821 clear_midx_file_ext, &data);
822
823 strbuf_release(&buf);
824 strset_clear(&data.keep);
825 }
826
827 void clear_midx_file(struct repository *r)
828 {
829 struct strbuf midx = STRBUF_INIT;
830
831 get_midx_filename(r->objects->sources, &midx);
832
833 if (r->objects) {
834 struct odb_source *source;
835
836 for (source = r->objects->sources; source; source = source->next) {
837 struct odb_source_files *files = odb_source_files_downcast(source);
838 if (files->packed->midx)
839 close_midx(files->packed->midx);
840 files->packed->midx = NULL;
841 }
842 }
843
844 if (remove_path(midx.buf))
845 die(_("failed to clear multi-pack-index at %s"), midx.buf);
846
847 clear_midx_files_ext(r->objects->sources, MIDX_EXT_BITMAP, NULL);
848 clear_midx_files_ext(r->objects->sources, MIDX_EXT_REV, NULL);
849
850 strbuf_release(&midx);
851 }
852
853 void clear_incremental_midx_files(struct repository *r,
854 const struct strvec *keep_hashes)
855 {
856 struct odb_source *source = r->objects->sources;
857 struct strbuf chain = STRBUF_INIT;
858
859 get_midx_chain_filename(source, &chain);
860
861 for (; source; source = source->next) {
862 struct odb_source_files *files = odb_source_files_downcast(source);
863 if (files->packed->midx)
864 close_midx(files->packed->midx);
865 files->packed->midx = NULL;
866 }
867
868 if (!keep_hashes && remove_path(chain.buf))
869 die(_("failed to clear multi-pack-index chain at %s"),
870 chain.buf);
871
872 clear_incremental_midx_files_ext(r->objects->sources, MIDX_EXT_BITMAP,
873 keep_hashes);
874 clear_incremental_midx_files_ext(r->objects->sources, MIDX_EXT_REV,
875 keep_hashes);
876 clear_incremental_midx_files_ext(r->objects->sources, MIDX_EXT_MIDX,
877 keep_hashes);
878
879 strbuf_release(&chain);
880 }
881
882 static int verify_midx_error;
883
884 __attribute__((format (printf, 1, 2)))
885 static void midx_report(const char *fmt, ...)
886 {
887 va_list ap;
888 verify_midx_error = 1;
889 va_start(ap, fmt);
890 vfprintf(stderr, fmt, ap);
891 fprintf(stderr, "\n");
892 va_end(ap);
893 }
894
895 struct pair_pos_vs_id
896 {
897 uint32_t pos;
898 uint32_t pack_int_id;
899 };
900
901 static int compare_pair_pos_vs_id(const void *_a, const void *_b)
902 {
903 struct pair_pos_vs_id *a = (struct pair_pos_vs_id *)_a;
904 struct pair_pos_vs_id *b = (struct pair_pos_vs_id *)_b;
905
906 return b->pack_int_id - a->pack_int_id;
907 }
908
909 /*
910 * Limit calls to display_progress() for performance reasons.
911 * The interval here was arbitrarily chosen.
912 */
913 #define SPARSE_PROGRESS_INTERVAL (1 << 12)
914 #define midx_display_sparse_progress(progress, n) \
915 do { \
916 uint64_t _n = (n); \
917 if ((_n & (SPARSE_PROGRESS_INTERVAL - 1)) == 0) \
918 display_progress(progress, _n); \
919 } while (0)
920
921 int verify_midx_file(struct odb_source *source, unsigned flags)
922 {
923 struct repository *r = source->odb->repo;
924 struct pair_pos_vs_id *pairs = NULL;
925 uint32_t i;
926 struct progress *progress = NULL;
927 struct multi_pack_index *m = load_multi_pack_index(source);
928 struct multi_pack_index *curr;
929 verify_midx_error = 0;
930
931 if (!m) {
932 int result = 0;
933 struct stat sb;
934 struct strbuf filename = STRBUF_INIT;
935
936 get_midx_filename(source, &filename);
937
938 if (!stat(filename.buf, &sb)) {
939 error(_("multi-pack-index file exists, but failed to parse"));
940 result = 1;
941 }
942 strbuf_release(&filename);
943 return result;
944 }
945
946 if (!midx_checksum_valid(m))
947 midx_report(_("incorrect checksum"));
948
949 if (flags & MIDX_PROGRESS)
950 progress = start_delayed_progress(r,
951 _("Looking for referenced packfiles"),
952 m->num_packs + m->num_packs_in_base);
953 for (i = 0; i < m->num_packs + m->num_packs_in_base; i++) {
954 if (prepare_midx_pack(m, i))
955 midx_report("failed to load pack in position %d", i);
956
957 display_progress(progress, i + 1);
958 }
959 stop_progress(&progress);
960
961 if (m->num_objects == 0) {
962 midx_report(_("the midx contains no oid"));
963 /*
964 * Remaining tests assume that we have objects, so we can
965 * return here.
966 */
967 goto cleanup;
968 }
969
970 if (flags & MIDX_PROGRESS)
971 progress = start_sparse_progress(r,
972 _("Verifying OID order in multi-pack-index"),
973 m->num_objects - 1);
974
975 for (curr = m; curr; curr = curr->base_midx) {
976 for (i = 0; i < m->num_objects - 1; i++) {
977 struct object_id oid1, oid2;
978
979 nth_midxed_object_oid(&oid1, m, m->num_objects_in_base + i);
980 nth_midxed_object_oid(&oid2, m, m->num_objects_in_base + i + 1);
981
982 if (oidcmp(&oid1, &oid2) >= 0)
983 midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"),
984 i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1);
985
986 midx_display_sparse_progress(progress, i + 1);
987 }
988 }
989 stop_progress(&progress);
990
991 /*
992 * Create an array mapping each object to its packfile id. Sort it
993 * to group the objects by packfile. Use this permutation to visit
994 * each of the objects and only require 1 packfile to be open at a
995 * time.
996 */
997 ALLOC_ARRAY(pairs, m->num_objects + m->num_objects_in_base);
998 for (i = 0; i < m->num_objects + m->num_objects_in_base; i++) {
999 pairs[i].pos = i;
1000 pairs[i].pack_int_id = nth_midxed_pack_int_id(m, i);
1001 }
1002
1003 if (flags & MIDX_PROGRESS)
1004 progress = start_sparse_progress(r,
1005 _("Sorting objects by packfile"),
1006 m->num_objects);
1007 display_progress(progress, 0); /* TODO: Measure QSORT() progress */
1008 QSORT(pairs, m->num_objects, compare_pair_pos_vs_id);
1009 stop_progress(&progress);
1010
1011 if (flags & MIDX_PROGRESS)
1012 progress = start_sparse_progress(r,
1013 _("Verifying object offsets"),
1014 m->num_objects);
1015 for (i = 0; i < m->num_objects + m->num_objects_in_base; i++) {
1016 struct object_id oid;
1017 struct pack_entry e;
1018 off_t m_offset, p_offset;
1019
1020 if (i > 0 && pairs[i-1].pack_int_id != pairs[i].pack_int_id &&
1021 nth_midxed_pack(m, pairs[i-1].pack_int_id)) {
1022 uint32_t pack_int_id = pairs[i-1].pack_int_id;
1023 struct packed_git *p = nth_midxed_pack(m, pack_int_id);
1024
1025 close_pack_fd(p);
1026 close_pack_index(p);
1027 }
1028
1029 nth_midxed_object_oid(&oid, m, pairs[i].pos);
1030
1031 if (!fill_midx_entry(m, &oid, &e)) {
1032 midx_report(_("failed to load pack entry for oid[%d] = %s"),
1033 pairs[i].pos, oid_to_hex(&oid));
1034 continue;
1035 }
1036
1037 if (open_pack_index(e.p)) {
1038 midx_report(_("failed to load pack-index for packfile %s"),
1039 e.p->pack_name);
1040 break;
1041 }
1042
1043 m_offset = e.offset;
1044 p_offset = find_pack_entry_one(&oid, e.p);
1045
1046 if (m_offset != p_offset)
1047 midx_report(_("incorrect object offset for oid[%d] = %s: %"PRIx64" != %"PRIx64),
1048 pairs[i].pos, oid_to_hex(&oid), m_offset, p_offset);
1049
1050 midx_display_sparse_progress(progress, i + 1);
1051 }
1052 stop_progress(&progress);
1053
1054 cleanup:
1055 free(pairs);
1056 close_midx(m);
1057
1058 return verify_midx_error;
1059 }