2 * Copyright (c) 2019 Ori Bernstein <ori@openbsd.org>
3 * Copyright (c) 2020 Stefan Sperling <stsp@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
41 #include "got_error.h"
42 #include "got_object.h"
44 #include "got_compat.h"
46 #include "got_lib_sha1.h"
47 #include "got_lib_delta.h"
48 #include "got_lib_inflate.h"
49 #include "got_lib_object.h"
50 #include "got_lib_object_parse.h"
51 #include "got_lib_object_idset.h"
52 #include "got_lib_privsep.h"
53 #include "got_lib_pack.h"
54 #include "got_lib_delta_cache.h"
57 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
60 struct got_indexed_object
{
61 struct got_object_id id
;
64 * Has this object been fully resolved?
65 * If so, we know its ID, otherwise we don't and 'id' is invalid.
69 /* Offset of type+size field for this object in pack file. */
72 /* Type+size values parsed from pack file. */
76 /* Length of on-disk type+size data. */
79 /* Length of object data following type+size. */
87 struct got_object_id ref_id
;
90 /* For offset deltas. */
92 size_t base_offsetlen
;
98 putbe32(char *b
, uint32_t n
)
106 static const struct got_error
*
107 get_obj_type_label(const char **label
, int obj_type
)
109 const struct got_error
*err
= NULL
;
112 case GOT_OBJ_TYPE_BLOB
:
113 *label
= GOT_OBJ_LABEL_BLOB
;
115 case GOT_OBJ_TYPE_TREE
:
116 *label
= GOT_OBJ_LABEL_TREE
;
118 case GOT_OBJ_TYPE_COMMIT
:
119 *label
= GOT_OBJ_LABEL_COMMIT
;
121 case GOT_OBJ_TYPE_TAG
:
122 *label
= GOT_OBJ_LABEL_TAG
;
126 err
= got_error(GOT_ERR_OBJ_TYPE
);
133 static const struct got_error
*
134 read_checksum(uint32_t *crc
, SHA1_CTX
*sha1_ctx
, int fd
, size_t len
)
140 for (n
= len
; n
> 0; n
-= r
){
141 r
= read(fd
, buf
, n
> sizeof(buf
) ? sizeof(buf
) : n
);
143 return got_error_from_errno("read");
147 *crc
= crc32(*crc
, buf
, r
);
149 SHA1Update(sha1_ctx
, buf
, r
);
155 static const struct got_error
*
156 read_file_sha1(SHA1_CTX
*ctx
, FILE *f
, size_t len
)
161 for (n
= len
; n
> 0; n
-= r
) {
162 r
= fread(buf
, 1, n
> sizeof(buf
) ? sizeof(buf
) : n
, f
);
166 return got_ferror(f
, GOT_ERR_IO
);
168 SHA1Update(ctx
, buf
, r
);
174 static const struct got_error
*
175 read_packed_object(struct got_pack
*pack
, struct got_indexed_object
*obj
,
176 FILE *tmpfile
, SHA1_CTX
*pack_sha1_ctx
)
178 const struct got_error
*err
= NULL
;
180 uint8_t *data
= NULL
;
185 const char *obj_label
;
186 size_t mapoff
= obj
->off
;
187 struct got_inflate_checksum csum
;
189 memset(&csum
, 0, sizeof(csum
));
190 csum
.input_sha1
= pack_sha1_ctx
;
191 csum
.input_crc
= &obj
->crc
;
193 err
= got_pack_parse_object_type_and_size(&obj
->type
, &obj
->size
,
194 &obj
->tslen
, pack
, obj
->off
);
199 obj
->crc
= crc32(obj
->crc
, pack
->map
+ mapoff
, obj
->tslen
);
200 SHA1Update(pack_sha1_ctx
, pack
->map
+ mapoff
, obj
->tslen
);
201 mapoff
+= obj
->tslen
;
203 /* XXX Seek back and get the CRC of on-disk type+size bytes. */
204 if (lseek(pack
->fd
, obj
->off
, SEEK_SET
) == -1)
205 return got_error_from_errno("lseek");
206 err
= read_checksum(&obj
->crc
, pack_sha1_ctx
,
207 pack
->fd
, obj
->tslen
);
213 case GOT_OBJ_TYPE_BLOB
:
214 case GOT_OBJ_TYPE_COMMIT
:
215 case GOT_OBJ_TYPE_TREE
:
216 case GOT_OBJ_TYPE_TAG
:
217 if (obj
->size
> GOT_DELTA_RESULT_SIZE_CACHED_MAX
) {
218 if (fseek(tmpfile
, 0L, SEEK_SET
) == -1) {
219 err
= got_error_from_errno("fseek");
223 err
= got_inflate_to_file_mmap(&datalen
,
224 &obj
->len
, &csum
, pack
->map
, mapoff
,
225 pack
->filesize
- mapoff
, tmpfile
);
227 err
= got_inflate_to_file_fd(&datalen
,
228 &obj
->len
, &csum
, pack
->fd
, tmpfile
);
232 err
= got_inflate_to_mem_mmap(&data
, &datalen
,
233 &obj
->len
, &csum
, pack
->map
, mapoff
,
234 pack
->filesize
- mapoff
);
236 err
= got_inflate_to_mem_fd(&data
, &datalen
,
237 &obj
->len
, &csum
, obj
->size
, pack
->fd
);
243 err
= get_obj_type_label(&obj_label
, obj
->type
);
248 if (asprintf(&header
, "%s %lld", obj_label
,
249 (long long)obj
->size
) == -1) {
250 err
= got_error_from_errno("asprintf");
254 headerlen
= strlen(header
) + 1;
255 SHA1Update(&ctx
, header
, headerlen
);
256 if (obj
->size
> GOT_DELTA_RESULT_SIZE_CACHED_MAX
) {
257 err
= read_file_sha1(&ctx
, tmpfile
, datalen
);
261 SHA1Update(&ctx
, data
, datalen
);
262 SHA1Final(obj
->id
.sha1
, &ctx
);
266 case GOT_OBJ_TYPE_REF_DELTA
:
267 memset(obj
->id
.sha1
, 0xff, SHA1_DIGEST_LENGTH
);
269 if (mapoff
+ SHA1_DIGEST_LENGTH
>= pack
->filesize
) {
270 err
= got_error(GOT_ERR_BAD_PACKFILE
);
273 memcpy(obj
->delta
.ref
.ref_id
.sha1
, pack
->map
+ mapoff
,
275 obj
->crc
= crc32(obj
->crc
, pack
->map
+ mapoff
,
277 SHA1Update(pack_sha1_ctx
, pack
->map
+ mapoff
,
279 mapoff
+= SHA1_DIGEST_LENGTH
;
280 err
= got_inflate_to_mem_mmap(NULL
, &datalen
,
281 &obj
->len
, &csum
, pack
->map
, mapoff
,
282 pack
->filesize
- mapoff
);
286 n
= read(pack
->fd
, obj
->delta
.ref
.ref_id
.sha1
,
289 err
= got_error_from_errno("read");
292 if (n
< sizeof(obj
->id
)) {
293 err
= got_error(GOT_ERR_BAD_PACKFILE
);
296 obj
->crc
= crc32(obj
->crc
, obj
->delta
.ref
.ref_id
.sha1
,
298 SHA1Update(pack_sha1_ctx
, obj
->delta
.ref
.ref_id
.sha1
,
300 err
= got_inflate_to_mem_fd(NULL
, &datalen
, &obj
->len
,
301 &csum
, obj
->size
, pack
->fd
);
305 obj
->len
+= SHA1_DIGEST_LENGTH
;
307 case GOT_OBJ_TYPE_OFFSET_DELTA
:
308 memset(obj
->id
.sha1
, 0xff, SHA1_DIGEST_LENGTH
);
309 err
= got_pack_parse_offset_delta(&obj
->delta
.ofs
.base_offset
,
310 &obj
->delta
.ofs
.base_offsetlen
, pack
, obj
->off
,
316 obj
->crc
= crc32(obj
->crc
, pack
->map
+ mapoff
,
317 obj
->delta
.ofs
.base_offsetlen
);
318 SHA1Update(pack_sha1_ctx
, pack
->map
+ mapoff
,
319 obj
->delta
.ofs
.base_offsetlen
);
320 mapoff
+= obj
->delta
.ofs
.base_offsetlen
;
321 err
= got_inflate_to_mem_mmap(NULL
, &datalen
,
322 &obj
->len
, &csum
, pack
->map
, mapoff
,
323 pack
->filesize
- mapoff
);
328 * XXX Seek back and get CRC and SHA1 of on-disk
331 if (lseek(pack
->fd
, obj
->off
+ obj
->tslen
, SEEK_SET
)
333 err
= got_error_from_errno("lseek");
336 err
= read_checksum(&obj
->crc
, pack_sha1_ctx
,
337 pack
->fd
, obj
->delta
.ofs
.base_offsetlen
);
341 err
= got_inflate_to_mem_fd(NULL
, &datalen
, &obj
->len
,
342 &csum
, obj
->size
, pack
->fd
);
346 obj
->len
+= obj
->delta
.ofs
.base_offsetlen
;
349 err
= got_error(GOT_ERR_OBJ_TYPE
);
356 static const struct got_error
*
357 hwrite(int fd
, void *buf
, int len
, SHA1_CTX
*ctx
)
361 SHA1Update(ctx
, buf
, len
);
363 w
= write(fd
, buf
, len
);
365 return got_error_from_errno("write");
367 return got_error(GOT_ERR_IO
);
372 static const struct got_error
*
373 resolve_deltified_object(struct got_pack
*pack
, struct got_packidx
*packidx
,
374 struct got_indexed_object
*obj
, FILE *tmpfile
, FILE *delta_base_file
,
375 FILE *delta_accum_file
)
377 const struct got_error
*err
= NULL
;
378 struct got_delta_chain deltas
;
379 struct got_delta
*delta
;
387 const char *obj_label
;
390 STAILQ_INIT(&deltas
.entries
);
392 err
= got_pack_resolve_delta_chain(&deltas
, packidx
, pack
,
393 obj
->off
, obj
->tslen
, obj
->type
, obj
->size
,
394 GOT_DELTA_CHAIN_RECURSION_MAX
);
398 err
= got_pack_get_delta_chain_max_size(&max_size
, &deltas
, pack
);
401 if (max_size
> GOT_DELTA_RESULT_SIZE_CACHED_MAX
) {
403 rewind(delta_base_file
);
404 rewind(delta_accum_file
);
405 err
= got_pack_dump_delta_chain_to_file(&len
, &deltas
,
406 pack
, tmpfile
, delta_base_file
, delta_accum_file
);
410 err
= got_pack_dump_delta_chain_to_mem(&buf
, &len
,
416 err
= got_delta_chain_get_base_type(&base_obj_type
, &deltas
);
419 err
= get_obj_type_label(&obj_label
, base_obj_type
);
422 if (asprintf(&header
, "%s %zd", obj_label
, len
) == -1) {
423 err
= got_error_from_errno("asprintf");
426 headerlen
= strlen(header
) + 1;
428 SHA1Update(&ctx
, header
, headerlen
);
429 if (max_size
> GOT_DELTA_RESULT_SIZE_CACHED_MAX
) {
430 err
= read_file_sha1(&ctx
, tmpfile
, len
);
434 SHA1Update(&ctx
, buf
, len
);
435 SHA1Final(obj
->id
.sha1
, &ctx
);
439 while (!STAILQ_EMPTY(&deltas
.entries
)) {
440 delta
= STAILQ_FIRST(&deltas
.entries
);
441 STAILQ_REMOVE_HEAD(&deltas
.entries
, entry
);
447 /* Determine the slot in the pack index a given object ID should use. */
449 find_object_idx(struct got_packidx
*packidx
, uint8_t *sha1
)
451 u_int8_t id0
= sha1
[0];
452 uint32_t nindexed
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
453 int left
= 0, right
= nindexed
- 1;
457 left
= be32toh(packidx
->hdr
.fanout_table
[id0
- 1]);
459 while (left
<= right
) {
460 struct got_packidx_object_id
*oid
;
462 i
= ((left
+ right
) / 2);
463 oid
= &packidx
->hdr
.sorted_ids
[i
];
465 cmp
= memcmp(sha1
, oid
->sha1
, SHA1_DIGEST_LENGTH
);
467 return -1; /* object already indexed */
479 print_packidx(struct got_packidx
*packidx
)
481 uint32_t nindexed
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
484 fprintf(stderr
, "object IDs:\n");
485 for (i
= 0; i
< nindexed
; i
++) {
486 char hex
[SHA1_DIGEST_STRING_LENGTH
];
487 got_sha1_digest_to_str(packidx
->hdr
.sorted_ids
[i
].sha1
,
489 fprintf(stderr
, "%s\n", hex
);
491 fprintf(stderr
, "\n");
493 fprintf(stderr
, "object offsets:\n");
494 for (i
= 0; i
< nindexed
; i
++) {
495 uint32_t offset
= be32toh(packidx
->hdr
.offsets
[i
]);
496 if (offset
& GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
) {
497 int j
= offset
& GOT_PACKIDX_OFFSET_VAL_MASK
;
498 fprintf(stderr
, "%u -> %llu\n", offset
,
499 be64toh(packidx
->hdr
.large_offsets
[j
]));
501 fprintf(stderr
, "%u\n", offset
);
503 fprintf(stderr
, "\n");
505 fprintf(stderr
, "fanout table:");
506 for (i
= 0; i
<= 0xff; i
++)
507 fprintf(stderr
, " %u", be32toh(packidx
->hdr
.fanout_table
[i
]));
508 fprintf(stderr
, "\n");
513 add_indexed_object(struct got_packidx
*packidx
, uint32_t idx
,
514 struct got_indexed_object
*obj
)
518 memcpy(packidx
->hdr
.sorted_ids
[idx
].sha1
, obj
->id
.sha1
,
520 packidx
->hdr
.crc32
[idx
] = htobe32(obj
->crc
);
521 if (obj
->off
< GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
)
522 packidx
->hdr
.offsets
[idx
] = htobe32(obj
->off
);
524 packidx
->hdr
.offsets
[idx
] = htobe32(packidx
->nlargeobj
|
525 GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
);
526 packidx
->hdr
.large_offsets
[packidx
->nlargeobj
] =
528 packidx
->nlargeobj
++;
531 for (i
= obj
->id
.sha1
[0]; i
<= 0xff; i
++) {
532 uint32_t n
= be32toh(packidx
->hdr
.fanout_table
[i
]);
533 packidx
->hdr
.fanout_table
[i
] = htobe32(n
+ 1);
538 indexed_obj_cmp(const void *pa
, const void *pb
)
540 struct got_indexed_object
*a
, *b
;
542 a
= (struct got_indexed_object
*)pa
;
543 b
= (struct got_indexed_object
*)pb
;
544 return got_object_id_cmp(&a
->id
, &b
->id
);
548 make_packidx(struct got_packidx
*packidx
, int nobj
,
549 struct got_indexed_object
*objects
)
551 struct got_indexed_object
*obj
;
555 qsort(objects
, nobj
, sizeof(struct got_indexed_object
),
558 memset(packidx
->hdr
.fanout_table
, 0,
559 GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS
* sizeof(uint32_t));
560 packidx
->nlargeobj
= 0;
562 for (i
= 0; i
< nobj
; i
++) {
565 add_indexed_object(packidx
, idx
++, obj
);
570 update_packidx(struct got_packidx
*packidx
, int nobj
,
571 struct got_indexed_object
*obj
)
574 uint32_t nindexed
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
576 idx
= find_object_idx(packidx
, obj
->id
.sha1
);
578 char hex
[SHA1_DIGEST_STRING_LENGTH
];
579 got_sha1_digest_to_str(obj
->id
.sha1
, hex
, sizeof(hex
));
580 return; /* object already indexed */
583 memmove(&packidx
->hdr
.sorted_ids
[idx
+ 1],
584 &packidx
->hdr
.sorted_ids
[idx
],
585 sizeof(struct got_packidx_object_id
) * (nindexed
- idx
));
586 memmove(&packidx
->hdr
.offsets
[idx
+ 1], &packidx
->hdr
.offsets
[idx
],
587 sizeof(uint32_t) * (nindexed
- idx
));
589 add_indexed_object(packidx
, idx
, obj
);
592 static const struct got_error
*
593 send_index_pack_progress(struct imsgbuf
*ibuf
, int nobj_total
,
594 int nobj_indexed
, int nobj_loose
, int nobj_resolved
)
596 struct got_imsg_index_pack_progress iprogress
;
598 iprogress
.nobj_total
= nobj_total
;
599 iprogress
.nobj_indexed
= nobj_indexed
;
600 iprogress
.nobj_loose
= nobj_loose
;
601 iprogress
.nobj_resolved
= nobj_resolved
;
603 if (imsg_compose(ibuf
, GOT_IMSG_IDXPACK_PROGRESS
, 0, 0, -1,
604 &iprogress
, sizeof(iprogress
)) == -1)
605 return got_error_from_errno("imsg_compose IDXPACK_PROGRESS");
607 return got_privsep_flush_imsg(ibuf
);
610 static const struct got_error
*
611 send_index_pack_done(struct imsgbuf
*ibuf
)
613 if (imsg_compose(ibuf
, GOT_IMSG_IDXPACK_DONE
, 0, 0, -1, NULL
, 0) == -1)
614 return got_error_from_errno("imsg_compose FETCH");
615 return got_privsep_flush_imsg(ibuf
);
619 static const struct got_error
*
620 index_pack(struct got_pack
*pack
, int idxfd
, FILE *tmpfile
,
621 FILE *delta_base_file
, FILE *delta_accum_file
, uint8_t *pack_sha1_expected
,
622 struct imsgbuf
*ibuf
)
624 const struct got_error
*err
;
625 struct got_packfile_hdr hdr
;
626 struct got_packidx packidx
;
628 char pack_sha1
[SHA1_DIGEST_LENGTH
];
629 int nobj
, nvalid
, nloose
, nresolved
= 0, i
;
630 struct got_indexed_object
*objects
= NULL
, *obj
;
632 uint8_t packidx_hash
[SHA1_DIGEST_LENGTH
];
634 int pass
, have_ref_deltas
= 0, first_delta_idx
= -1;
636 int p_indexed
= 0, last_p_indexed
= -1;
637 int p_resolved
= 0, last_p_resolved
= -1;
639 /* Require that pack file header and SHA1 trailer are present. */
640 if (pack
->filesize
< sizeof(hdr
) + SHA1_DIGEST_LENGTH
)
641 return got_error_msg(GOT_ERR_BAD_PACKFILE
,
645 memcpy(&hdr
, pack
->map
, sizeof(hdr
));
646 mapoff
+= sizeof(hdr
);
648 r
= read(pack
->fd
, &hdr
, sizeof(hdr
));
650 return got_error_from_errno("read");
652 return got_error_msg(GOT_ERR_BAD_PACKFILE
,
656 if (hdr
.signature
!= htobe32(GOT_PACKFILE_SIGNATURE
))
657 return got_error_msg(GOT_ERR_BAD_PACKFILE
,
658 "bad packfile signature");
659 if (hdr
.version
!= htobe32(GOT_PACKFILE_VERSION
))
660 return got_error_msg(GOT_ERR_BAD_PACKFILE
,
661 "bad packfile version");
662 nobj
= be32toh(hdr
.nobjects
);
664 return got_error_msg(GOT_ERR_BAD_PACKFILE
,
665 "bad packfile with zero objects");
667 /* We compute the SHA1 of pack file contents and verify later on. */
669 SHA1Update(&ctx
, (void *)&hdr
, sizeof(hdr
));
672 * Create an in-memory pack index which will grow as objects
673 * IDs in the pack file are discovered. Only fields used to
674 * read deltified objects will be needed by the pack.c library
675 * code, so setting up just a pack index header is sufficient.
677 memset(&packidx
, 0, sizeof(packidx
));
678 packidx
.hdr
.magic
= malloc(sizeof(uint32_t));
679 if (packidx
.hdr
.magic
== NULL
)
680 return got_error_from_errno("calloc");
681 *packidx
.hdr
.magic
= htobe32(GOT_PACKIDX_V2_MAGIC
);
682 packidx
.hdr
.version
= malloc(sizeof(uint32_t));
683 if (packidx
.hdr
.version
== NULL
) {
684 err
= got_error_from_errno("malloc");
687 *packidx
.hdr
.version
= htobe32(GOT_PACKIDX_VERSION
);
688 packidx
.hdr
.fanout_table
= calloc(GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS
,
690 if (packidx
.hdr
.fanout_table
== NULL
) {
691 err
= got_error_from_errno("calloc");
694 packidx
.hdr
.sorted_ids
= calloc(nobj
,
695 sizeof(struct got_packidx_object_id
));
696 if (packidx
.hdr
.sorted_ids
== NULL
) {
697 err
= got_error_from_errno("calloc");
700 packidx
.hdr
.crc32
= calloc(nobj
, sizeof(uint32_t));
701 if (packidx
.hdr
.crc32
== NULL
) {
702 err
= got_error_from_errno("calloc");
705 packidx
.hdr
.offsets
= calloc(nobj
, sizeof(uint32_t));
706 if (packidx
.hdr
.offsets
== NULL
) {
707 err
= got_error_from_errno("calloc");
710 /* Large offsets table is empty for pack files < 2 GB. */
711 if (pack
->filesize
>= GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
) {
712 packidx
.hdr
.large_offsets
= calloc(nobj
, sizeof(uint64_t));
713 if (packidx
.hdr
.large_offsets
== NULL
) {
714 err
= got_error_from_errno("calloc");
721 objects
= calloc(nobj
, sizeof(struct got_indexed_object
));
723 return got_error_from_errno("calloc");
726 * First pass: locate all objects and identify un-deltified objects.
728 * When this pass has completed we will know offset, type, size, and
729 * CRC information for all objects in this pack file. We won't know
730 * any of the actual object IDs of deltified objects yet since we
731 * will not yet attempt to combine deltas.
734 for (i
= 0; i
< nobj
; i
++) {
735 /* Don't send too many progress privsep messages. */
736 p_indexed
= ((i
+ 1) * 100) / nobj
;
737 if (p_indexed
!= last_p_indexed
) {
738 err
= send_index_pack_progress(ibuf
, nobj
, i
+ 1,
742 last_p_indexed
= p_indexed
;
746 obj
->crc
= crc32(0L, NULL
, 0);
748 /* Store offset to type+size information for this object. */
752 obj
->off
= lseek(pack
->fd
, 0, SEEK_CUR
);
753 if (obj
->off
== -1) {
754 err
= got_error_from_errno("lseek");
759 err
= read_packed_object(pack
, obj
, tmpfile
, &ctx
);
764 mapoff
+= obj
->tslen
+ obj
->len
;
766 if (lseek(pack
->fd
, obj
->off
+ obj
->tslen
+ obj
->len
,
768 err
= got_error_from_errno("lseek");
773 if (obj
->type
== GOT_OBJ_TYPE_BLOB
||
774 obj
->type
== GOT_OBJ_TYPE_TREE
||
775 obj
->type
== GOT_OBJ_TYPE_COMMIT
||
776 obj
->type
== GOT_OBJ_TYPE_TAG
) {
780 if (first_delta_idx
== -1)
782 if (obj
->type
== GOT_OBJ_TYPE_REF_DELTA
)
789 * Having done a full pass over the pack file and can now
790 * verify its checksum.
792 SHA1Final(pack_sha1
, &ctx
);
793 if (memcmp(pack_sha1_expected
, pack_sha1
, SHA1_DIGEST_LENGTH
) != 0) {
794 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
,
795 "pack file checksum mismatch");
799 /* Verify the SHA1 checksum stored at the end of the pack file. */
801 memcpy(pack_sha1_expected
, pack
->map
+
802 pack
->filesize
- SHA1_DIGEST_LENGTH
,
806 if (lseek(pack
->fd
, -SHA1_DIGEST_LENGTH
, SEEK_END
) == -1) {
807 err
= got_error_from_errno("lseek");
810 n
= read(pack
->fd
, pack_sha1_expected
, SHA1_DIGEST_LENGTH
);
812 err
= got_error_from_errno("read");
815 if (n
!= SHA1_DIGEST_LENGTH
) {
816 err
= got_error(GOT_ERR_IO
);
820 if (memcmp(pack_sha1
, pack_sha1_expected
, SHA1_DIGEST_LENGTH
) != 0) {
821 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
,
822 "bad checksum in pack file trailer");
826 if (first_delta_idx
== -1)
829 /* In order to resolve ref deltas we need an in-progress pack index. */
831 make_packidx(&packidx
, nobj
, objects
);
834 * Second pass: We can now resolve deltas to compute the IDs of
835 * objects which appear in deltified form. Because deltas can be
836 * chained this pass may require a couple of iterations until all
837 * IDs of deltified objects have been discovered.
840 while (nvalid
!= nobj
) {
843 * This loop will only run once unless the pack file
844 * contains ref deltas which refer to objects located
845 * later in the pack file, which is unusual.
846 * Offset deltas can always be resolved in one pass
847 * unless the packfile is corrupt.
849 for (i
= first_delta_idx
; i
< nobj
; i
++) {
851 if (obj
->type
!= GOT_OBJ_TYPE_REF_DELTA
&&
852 obj
->type
!= GOT_OBJ_TYPE_OFFSET_DELTA
)
858 if (pack
->map
== NULL
&& lseek(pack
->fd
,
859 obj
->off
+ obj
->tslen
, SEEK_SET
) == -1) {
860 err
= got_error_from_errno("lseek");
864 err
= resolve_deltified_object(pack
, &packidx
, obj
,
865 tmpfile
, delta_base_file
, delta_accum_file
);
867 if (err
->code
!= GOT_ERR_NO_OBJ
)
870 * We cannot resolve this object yet because
871 * a delta base is unknown. Try again later.
879 update_packidx(&packidx
, nobj
, obj
);
880 /* Don't send too many progress privsep messages. */
881 p_resolved
= ((nresolved
+ n
) * 100) / nobj
;
882 if (p_resolved
!= last_p_resolved
) {
883 err
= send_index_pack_progress(ibuf
, nobj
,
884 nobj
, nloose
, nresolved
+ n
);
887 last_p_resolved
= p_resolved
;
891 if (pass
++ > 3 && n
== 0) {
893 snprintf(msg
, sizeof(msg
), "could not resolve "
894 "any of deltas; packfile could be corrupt");
895 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
, msg
);
903 if (nloose
+ nresolved
!= nobj
) {
905 snprintf(msg
, sizeof(msg
), "discovered only %d of %d objects",
906 nloose
+ nresolved
, nobj
);
907 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
, msg
);
911 err
= send_index_pack_progress(ibuf
, nobj
, nobj
, nloose
, nresolved
);
915 make_packidx(&packidx
, nobj
, objects
);
921 putbe32(buf
, GOT_PACKIDX_V2_MAGIC
);
922 putbe32(buf
+ 4, GOT_PACKIDX_VERSION
);
923 err
= hwrite(idxfd
, buf
, 8, &ctx
);
926 err
= hwrite(idxfd
, packidx
.hdr
.fanout_table
,
927 GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS
* sizeof(uint32_t), &ctx
);
930 err
= hwrite(idxfd
, packidx
.hdr
.sorted_ids
,
931 nobj
* SHA1_DIGEST_LENGTH
, &ctx
);
934 err
= hwrite(idxfd
, packidx
.hdr
.crc32
, nobj
* sizeof(uint32_t), &ctx
);
937 err
= hwrite(idxfd
, packidx
.hdr
.offsets
, nobj
* sizeof(uint32_t),
941 if (packidx
.nlargeobj
> 0) {
942 err
= hwrite(idxfd
, packidx
.hdr
.large_offsets
,
943 packidx
.nlargeobj
* sizeof(uint64_t), &ctx
);
947 err
= hwrite(idxfd
, pack_sha1
, SHA1_DIGEST_LENGTH
, &ctx
);
951 SHA1Final(packidx_hash
, &ctx
);
952 w
= write(idxfd
, packidx_hash
, sizeof(packidx_hash
));
954 err
= got_error_from_errno("write");
957 if (w
!= sizeof(packidx_hash
)) {
958 err
= got_error(GOT_ERR_IO
);
963 free(packidx
.hdr
.magic
);
964 free(packidx
.hdr
.version
);
965 free(packidx
.hdr
.fanout_table
);
966 free(packidx
.hdr
.sorted_ids
);
967 free(packidx
.hdr
.offsets
);
968 free(packidx
.hdr
.large_offsets
);
973 main(int argc
, char **argv
)
975 const struct got_error
*err
= NULL
, *close_err
;
979 int idxfd
= -1, tmpfd
= -1;
981 struct got_pack pack
;
982 uint8_t pack_hash
[SHA1_DIGEST_LENGTH
];
990 for (i
= 0; i
< nitems(tmpfiles
); i
++)
993 memset(&pack
, 0, sizeof(pack
));
995 pack
.delta_cache
= got_delta_cache_alloc(500,
996 GOT_DELTA_RESULT_SIZE_CACHED_MAX
);
997 if (pack
.delta_cache
== NULL
) {
998 err
= got_error_from_errno("got_delta_cache_alloc");
1002 imsg_init(&ibuf
, GOT_IMSG_FD_CHILD
);
1004 /* revoke access to most system calls */
1005 if (pledge("stdio recvfd", NULL
) == -1) {
1006 err
= got_error_from_errno("pledge");
1007 got_privsep_send_error(&ibuf
, err
);
1011 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
1014 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
1016 if (imsg
.hdr
.type
!= GOT_IMSG_IDXPACK_REQUEST
) {
1017 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1020 if (imsg
.hdr
.len
- IMSG_HEADER_SIZE
!= sizeof(pack_hash
)) {
1021 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1024 memcpy(pack_hash
, imsg
.data
, sizeof(pack_hash
));
1027 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
1030 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
1032 if (imsg
.hdr
.type
!= GOT_IMSG_IDXPACK_OUTFD
) {
1033 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1036 if (imsg
.hdr
.len
- IMSG_HEADER_SIZE
!= 0) {
1037 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1042 for (i
= 0; i
< nitems(tmpfiles
); i
++) {
1043 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
1046 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
1048 if (imsg
.hdr
.type
!= GOT_IMSG_TMPFD
) {
1049 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1052 if (imsg
.hdr
.len
- IMSG_HEADER_SIZE
!= 0) {
1053 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1057 tmpfiles
[i
] = fdopen(tmpfd
, "w+");
1058 if (tmpfiles
[i
] == NULL
) {
1059 err
= got_error_from_errno("fdopen");
1065 if (lseek(pack
.fd
, 0, SEEK_END
) == -1) {
1066 err
= got_error_from_errno("lseek");
1069 packfile_size
= lseek(pack
.fd
, 0, SEEK_CUR
);
1070 if (packfile_size
== -1) {
1071 err
= got_error_from_errno("lseek");
1074 pack
.filesize
= packfile_size
; /* XXX off_t vs size_t */
1076 if (lseek(pack
.fd
, 0, SEEK_SET
) == -1) {
1077 err
= got_error_from_errno("lseek");
1081 #ifndef GOT_PACK_NO_MMAP
1082 pack
.map
= mmap(NULL
, pack
.filesize
, PROT_READ
, MAP_PRIVATE
,
1084 if (pack
.map
== MAP_FAILED
)
1085 pack
.map
= NULL
; /* fall back to read(2) */
1087 err
= index_pack(&pack
, idxfd
, tmpfiles
[0], tmpfiles
[1], tmpfiles
[2],
1090 close_err
= got_pack_close(&pack
);
1091 if (close_err
&& err
== NULL
)
1093 if (idxfd
!= -1 && close(idxfd
) == -1 && err
== NULL
)
1094 err
= got_error_from_errno("close");
1095 if (tmpfd
!= -1 && close(tmpfd
) == -1 && err
== NULL
)
1096 err
= got_error_from_errno("close");
1097 for (i
= 0; i
< nitems(tmpfiles
); i
++) {
1098 if (tmpfiles
[i
] != NULL
&& fclose(tmpfiles
[i
]) == EOF
&&
1100 err
= got_error_from_errno("close");
1104 err
= send_index_pack_done(&ibuf
);
1106 got_privsep_send_error(&ibuf
, err
);
1107 fprintf(stderr
, "%s: %s\n", getprogname(), err
->msg
);
1108 got_privsep_send_error(&ibuf
, err
);