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