2 * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 #include "got_compat.h"
18 #include <sys/types.h>
20 #include <sys/queue.h>
23 #include <sys/resource.h>
24 #include <sys/socket.h>
36 #include "got_error.h"
37 #include "got_object.h"
40 #include "got_lib_hash.h"
41 #include "got_lib_delta.h"
42 #include "got_lib_delta_cache.h"
43 #include "got_lib_inflate.h"
44 #include "got_lib_object.h"
45 #include "got_lib_object_qid.h"
46 #include "got_lib_object_parse.h"
47 #include "got_lib_privsep.h"
48 #include "got_lib_pack.h"
51 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
55 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
58 static const struct got_error
*
59 verify_fanout_table(uint32_t *fanout_table
)
63 for (i
= 0; i
< 0xff - 1; i
++) {
64 if (be32toh(fanout_table
[i
]) > be32toh(fanout_table
[i
+ 1]))
65 return got_error(GOT_ERR_BAD_PACKIDX
);
71 const struct got_error
*
72 got_packidx_init_hdr(struct got_packidx
*p
, int verify
, off_t packfile_size
)
74 const struct got_error
*err
= NULL
;
75 struct got_packidx_v2_hdr
*h
;
77 uint8_t hash
[GOT_HASH_DIGEST_MAXLEN
];
78 size_t nobj
, len_fanout
, len_ids
, offset
, remain
, digest_string_len
;
82 got_hash_init(&ctx
, p
->algo
);
83 digest_string_len
= got_hash_digest_length(p
->algo
);
89 if (remain
< sizeof(*h
->magic
)) {
90 err
= got_error(GOT_ERR_BAD_PACKIDX
);
94 h
->magic
= (uint32_t *)(p
->map
+ offset
);
96 h
->magic
= malloc(sizeof(*h
->magic
));
97 if (h
->magic
== NULL
) {
98 err
= got_error_from_errno("malloc");
101 n
= read(p
->fd
, h
->magic
, sizeof(*h
->magic
));
103 err
= got_error_from_errno("read");
105 } else if (n
!= sizeof(*h
->magic
)) {
106 err
= got_error(GOT_ERR_BAD_PACKIDX
);
110 if (*h
->magic
!= htobe32(GOT_PACKIDX_V2_MAGIC
)) {
111 err
= got_error(GOT_ERR_BAD_PACKIDX
);
114 offset
+= sizeof(*h
->magic
);
115 remain
-= sizeof(*h
->magic
);
118 got_hash_update(&ctx
, h
->magic
, sizeof(*h
->magic
));
120 if (remain
< sizeof(*h
->version
)) {
121 err
= got_error(GOT_ERR_BAD_PACKIDX
);
125 h
->version
= (uint32_t *)(p
->map
+ offset
);
127 h
->version
= malloc(sizeof(*h
->version
));
128 if (h
->version
== NULL
) {
129 err
= got_error_from_errno("malloc");
132 n
= read(p
->fd
, h
->version
, sizeof(*h
->version
));
134 err
= got_error_from_errno("read");
136 } else if (n
!= sizeof(*h
->version
)) {
137 err
= got_error(GOT_ERR_BAD_PACKIDX
);
141 if (*h
->version
!= htobe32(GOT_PACKIDX_VERSION
)) {
142 err
= got_error(GOT_ERR_BAD_PACKIDX
);
145 offset
+= sizeof(*h
->version
);
146 remain
-= sizeof(*h
->version
);
149 got_hash_update(&ctx
, h
->version
, sizeof(*h
->version
));
152 sizeof(*h
->fanout_table
) * GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS
;
153 if (remain
< len_fanout
) {
154 err
= got_error(GOT_ERR_BAD_PACKIDX
);
158 h
->fanout_table
= (uint32_t *)(p
->map
+ offset
);
160 h
->fanout_table
= malloc(len_fanout
);
161 if (h
->fanout_table
== NULL
) {
162 err
= got_error_from_errno("malloc");
165 n
= read(p
->fd
, h
->fanout_table
, len_fanout
);
167 err
= got_error_from_errno("read");
169 } else if (n
!= len_fanout
) {
170 err
= got_error(GOT_ERR_BAD_PACKIDX
);
174 err
= verify_fanout_table(h
->fanout_table
);
178 got_hash_update(&ctx
, h
->fanout_table
, len_fanout
);
179 offset
+= len_fanout
;
180 remain
-= len_fanout
;
182 nobj
= be32toh(h
->fanout_table
[0xff]);
183 len_ids
= nobj
* got_hash_digest_length(p
->algo
);
184 if (len_ids
<= nobj
|| len_ids
> remain
) {
185 err
= got_error(GOT_ERR_BAD_PACKIDX
);
189 h
->sorted_ids
= p
->map
+ offset
;
191 h
->sorted_ids
= malloc(len_ids
);
192 if (h
->sorted_ids
== NULL
) {
193 err
= got_error(GOT_ERR_BAD_PACKIDX
);
196 n
= read(p
->fd
, h
->sorted_ids
, len_ids
);
198 err
= got_error_from_errno("read");
199 else if (n
!= len_ids
) {
200 err
= got_error(GOT_ERR_BAD_PACKIDX
);
205 got_hash_update(&ctx
, h
->sorted_ids
, len_ids
);
209 if (remain
< nobj
* sizeof(*h
->crc32
)) {
210 err
= got_error(GOT_ERR_BAD_PACKIDX
);
214 h
->crc32
= (uint32_t *)((uint8_t*)(p
->map
+ offset
));
216 h
->crc32
= malloc(nobj
* sizeof(*h
->crc32
));
217 if (h
->crc32
== NULL
) {
218 err
= got_error_from_errno("malloc");
221 n
= read(p
->fd
, h
->crc32
, nobj
* sizeof(*h
->crc32
));
223 err
= got_error_from_errno("read");
224 else if (n
!= nobj
* sizeof(*h
->crc32
)) {
225 err
= got_error(GOT_ERR_BAD_PACKIDX
);
230 got_hash_update(&ctx
, h
->crc32
, nobj
* sizeof(*h
->crc32
));
231 remain
-= nobj
* sizeof(*h
->crc32
);
232 offset
+= nobj
* sizeof(*h
->crc32
);
234 if (remain
< nobj
* sizeof(*h
->offsets
)) {
235 err
= got_error(GOT_ERR_BAD_PACKIDX
);
239 h
->offsets
= (uint32_t *)((uint8_t*)(p
->map
+ offset
));
241 h
->offsets
= malloc(nobj
* sizeof(*h
->offsets
));
242 if (h
->offsets
== NULL
) {
243 err
= got_error_from_errno("malloc");
246 n
= read(p
->fd
, h
->offsets
, nobj
* sizeof(*h
->offsets
));
248 err
= got_error_from_errno("read");
249 else if (n
!= nobj
* sizeof(*h
->offsets
)) {
250 err
= got_error(GOT_ERR_BAD_PACKIDX
);
255 got_hash_update(&ctx
, h
->offsets
, nobj
* sizeof(*h
->offsets
));
256 remain
-= nobj
* sizeof(*h
->offsets
);
257 offset
+= nobj
* sizeof(*h
->offsets
);
259 /* Large file offsets are contained only in files > 2GB. */
260 if (verify
|| packfile_size
> 0x7fffffff) {
261 for (i
= 0; i
< nobj
; i
++) {
262 uint32_t o
= h
->offsets
[i
];
263 if (o
& htobe32(GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
))
267 if (p
->nlargeobj
== 0)
269 else if (packfile_size
<= 0x7fffffff) {
270 err
= got_error(GOT_ERR_BAD_PACKIDX
);
274 if (remain
< p
->nlargeobj
* sizeof(*h
->large_offsets
)) {
275 err
= got_error(GOT_ERR_BAD_PACKIDX
);
279 h
->large_offsets
= (uint64_t *)((uint8_t*)(p
->map
+ offset
));
281 h
->large_offsets
= malloc(p
->nlargeobj
*
282 sizeof(*h
->large_offsets
));
283 if (h
->large_offsets
== NULL
) {
284 err
= got_error_from_errno("malloc");
287 n
= read(p
->fd
, h
->large_offsets
,
288 p
->nlargeobj
* sizeof(*h
->large_offsets
));
290 err
= got_error_from_errno("read");
291 else if (n
!= p
->nlargeobj
* sizeof(*h
->large_offsets
)) {
292 err
= got_error(GOT_ERR_BAD_PACKIDX
);
297 got_hash_update(&ctx
, h
->large_offsets
,
298 p
->nlargeobj
* sizeof(*h
->large_offsets
));
299 remain
-= p
->nlargeobj
* sizeof(*h
->large_offsets
);
300 offset
+= p
->nlargeobj
* sizeof(*h
->large_offsets
);
303 if (remain
< digest_string_len
* 2) {
304 err
= got_error(GOT_ERR_BAD_PACKIDX
);
308 memcpy(h
->trailer
.packfile_hash
, p
->map
+ offset
,
310 memcpy(h
->trailer
.packidx_hash
,
311 p
->map
+ offset
+ digest_string_len
, digest_string_len
);
313 n
= read(p
->fd
, h
->trailer
.packfile_hash
, digest_string_len
);
315 err
= got_error_from_errno("read");
316 else if (n
!= digest_string_len
) {
317 err
= got_error(GOT_ERR_BAD_PACKIDX
);
320 n
= read(p
->fd
, h
->trailer
.packidx_hash
, digest_string_len
);
322 err
= got_error_from_errno("read");
323 else if (n
!= digest_string_len
) {
324 err
= got_error(GOT_ERR_BAD_PACKIDX
);
329 got_hash_update(&ctx
, h
->trailer
.packfile_hash
,
331 got_hash_final(&ctx
, hash
);
332 if (got_hash_cmp(ctx
.algo
, hash
, h
->trailer
.packidx_hash
) != 0)
333 err
= got_error(GOT_ERR_PACKIDX_CSUM
);
339 const struct got_error
*
340 got_packidx_open(struct got_packidx
**packidx
,
341 int dir_fd
, const char *relpath
, int verify
,
342 enum got_hash_algorithm algo
)
344 const struct got_error
*err
= NULL
;
345 struct got_packidx
*p
= NULL
;
347 struct stat idx_sb
, pack_sb
;
351 err
= got_packidx_get_packfile_path(&pack_relpath
, relpath
);
356 * Ensure that a corresponding pack file exists.
357 * Some Git repositories have this problem. Git seems to ignore
358 * the existence of lonely pack index files but we do not.
360 if (fstatat(dir_fd
, pack_relpath
, &pack_sb
, 0) == -1) {
362 err
= got_error_path(relpath
, GOT_ERR_LONELY_PACKIDX
);
364 err
= got_error_from_errno2("fstatat", pack_relpath
);
368 p
= calloc(1, sizeof(*p
));
370 err
= got_error_from_errno("calloc");
376 p
->fd
= openat(dir_fd
, relpath
, O_RDONLY
| O_NOFOLLOW
| O_CLOEXEC
);
378 err
= got_error_from_errno2("openat", relpath
);
382 if (fstat(p
->fd
, &idx_sb
) != 0) {
383 err
= got_error_from_errno2("fstat", relpath
);
386 p
->len
= idx_sb
.st_size
;
387 if (p
->len
< sizeof(p
->hdr
)) {
388 err
= got_error(GOT_ERR_BAD_PACKIDX
);
392 p
->path_packidx
= strdup(relpath
);
393 if (p
->path_packidx
== NULL
) {
394 err
= got_error_from_errno("strdup");
398 #ifndef GOT_PACK_NO_MMAP
399 if (p
->len
> 0 && p
->len
<= SIZE_MAX
) {
400 p
->map
= mmap(NULL
, p
->len
, PROT_READ
, MAP_PRIVATE
, p
->fd
, 0);
401 if (p
->map
== MAP_FAILED
) {
402 if (errno
!= ENOMEM
) {
403 err
= got_error_from_errno("mmap");
406 p
->map
= NULL
; /* fall back to read(2) */
411 err
= got_packidx_init_hdr(p
, verify
, pack_sb
.st_size
);
415 got_packidx_close(p
);
422 const struct got_error
*
423 got_packidx_close(struct got_packidx
*packidx
)
425 const struct got_error
*err
= NULL
;
427 free(packidx
->path_packidx
);
429 if (munmap(packidx
->map
, packidx
->len
) == -1)
430 err
= got_error_from_errno("munmap");
432 free(packidx
->hdr
.magic
);
433 free(packidx
->hdr
.version
);
434 free(packidx
->hdr
.fanout_table
);
435 free(packidx
->hdr
.sorted_ids
);
436 free(packidx
->hdr
.crc32
);
437 free(packidx
->hdr
.offsets
);
438 free(packidx
->hdr
.large_offsets
);
440 if (close(packidx
->fd
) == -1 && err
== NULL
)
441 err
= got_error_from_errno("close");
442 free(packidx
->sorted_offsets
);
443 free(packidx
->sorted_large_offsets
);
449 const struct got_error
*
450 got_packidx_get_packfile_path(char **path_packfile
, const char *path_packidx
)
454 /* Packfile path contains ".pack" instead of ".idx", so add one byte. */
455 size
= strlen(path_packidx
) + 2;
456 if (size
< GOT_PACKFILE_NAMELEN
+ 1)
457 return got_error_path(path_packidx
, GOT_ERR_BAD_PATH
);
459 *path_packfile
= malloc(size
);
460 if (*path_packfile
== NULL
)
461 return got_error_from_errno("malloc");
463 /* Copy up to and excluding ".idx". */
464 if (strlcpy(*path_packfile
, path_packidx
,
465 size
- strlen(GOT_PACKIDX_SUFFIX
) - 1) >= size
)
466 return got_error(GOT_ERR_NO_SPACE
);
468 if (strlcat(*path_packfile
, GOT_PACKFILE_SUFFIX
, size
) >= size
)
469 return got_error(GOT_ERR_NO_SPACE
);
475 got_packidx_get_object_offset(struct got_packidx
*packidx
, int idx
)
477 uint32_t offset
= be32toh(packidx
->hdr
.offsets
[idx
]);
478 if (offset
& GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
) {
480 idx
= offset
& GOT_PACKIDX_OFFSET_VAL_MASK
;
481 if (idx
< 0 || idx
>= packidx
->nlargeobj
||
482 packidx
->hdr
.large_offsets
== NULL
)
484 loffset
= be64toh(packidx
->hdr
.large_offsets
[idx
]);
485 return (loffset
> INT64_MAX
? -1 : (off_t
)loffset
);
487 return (off_t
)(offset
& GOT_PACKIDX_OFFSET_VAL_MASK
);
491 got_packidx_get_object_idx(struct got_packidx
*packidx
,
492 struct got_object_id
*id
)
494 u_int8_t id0
= id
->hash
[0];
495 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
496 int left
= 0, right
= totobj
- 1;
497 size_t digest_len
= got_hash_digest_length(packidx
->algo
);
500 left
= be32toh(packidx
->hdr
.fanout_table
[id0
- 1]);
502 while (left
<= right
) {
506 i
= ((left
+ right
) / 2);
507 oid
= packidx
->hdr
.sorted_ids
+ i
* digest_len
;
508 cmp
= memcmp(id
->hash
, oid
, digest_len
);
521 offset_cmp(const void *pa
, const void *pb
)
523 const struct got_pack_offset_index
*a
, *b
;
525 a
= (const struct got_pack_offset_index
*)pa
;
526 b
= (const struct got_pack_offset_index
*)pb
;
528 if (a
->offset
< b
->offset
)
530 else if (a
->offset
> b
->offset
)
537 large_offset_cmp(const void *pa
, const void *pb
)
539 const struct got_pack_large_offset_index
*a
, *b
;
541 a
= (const struct got_pack_large_offset_index
*)pa
;
542 b
= (const struct got_pack_large_offset_index
*)pb
;
544 if (a
->offset
< b
->offset
)
546 else if (a
->offset
> b
->offset
)
552 static const struct got_error
*
553 build_offset_index(struct got_packidx
*p
)
555 uint32_t nobj
= be32toh(p
->hdr
.fanout_table
[0xff]);
556 unsigned int i
, j
, k
;
558 p
->sorted_offsets
= calloc(nobj
- p
->nlargeobj
,
559 sizeof(p
->sorted_offsets
[0]));
560 if (p
->sorted_offsets
== NULL
)
561 return got_error_from_errno("calloc");
563 if (p
->nlargeobj
> 0) {
564 p
->sorted_large_offsets
= calloc(p
->nlargeobj
,
565 sizeof(p
->sorted_large_offsets
[0]));
566 if (p
->sorted_large_offsets
== NULL
)
567 return got_error_from_errno("calloc");
572 for (i
= 0; i
< nobj
; i
++) {
573 uint32_t offset
= be32toh(p
->hdr
.offsets
[i
]);
574 if (offset
& GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
) {
577 idx
= offset
& GOT_PACKIDX_OFFSET_VAL_MASK
;
578 if (idx
>= p
->nlargeobj
||
580 p
->hdr
.large_offsets
== NULL
)
581 return got_error(GOT_ERR_BAD_PACKIDX
);
582 loffset
= be64toh(p
->hdr
.large_offsets
[idx
]);
583 p
->sorted_large_offsets
[j
].offset
= loffset
;
584 p
->sorted_large_offsets
[j
].idx
= i
;
587 p
->sorted_offsets
[k
].offset
= offset
;
588 p
->sorted_offsets
[k
].idx
= i
;
592 if (j
!= p
->nlargeobj
|| k
!= nobj
- p
->nlargeobj
)
593 return got_error(GOT_ERR_BAD_PACKIDX
);
595 qsort(p
->sorted_offsets
, nobj
- p
->nlargeobj
,
596 sizeof(p
->sorted_offsets
[0]), offset_cmp
);
598 if (p
->sorted_large_offsets
)
599 qsort(p
->sorted_large_offsets
, p
->nlargeobj
,
600 sizeof(p
->sorted_large_offsets
[0]), large_offset_cmp
);
605 const struct got_error
*
606 got_packidx_get_offset_idx(int *idx
, struct got_packidx
*packidx
, off_t offset
)
608 const struct got_error
*err
;
609 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
614 if (packidx
->sorted_offsets
== NULL
) {
615 err
= build_offset_index(packidx
);
620 if (offset
>= 0x7fffffff) {
622 left
= 0, right
= packidx
->nlargeobj
- 1;
623 while (left
<= right
) {
624 i
= ((left
+ right
) / 2);
625 lo
= packidx
->sorted_large_offsets
[i
].offset
;
627 *idx
= packidx
->sorted_large_offsets
[i
].idx
;
629 } else if (offset
> lo
)
631 else if (offset
< lo
)
636 left
= 0, right
= totobj
- packidx
->nlargeobj
- 1;
637 while (left
<= right
) {
638 i
= ((left
+ right
) / 2);
639 o
= packidx
->sorted_offsets
[i
].offset
;
641 *idx
= packidx
->sorted_offsets
[i
].idx
;
643 } else if (offset
> o
)
653 const struct got_error
*
654 got_packidx_get_object_id(struct got_object_id
*id
,
655 struct got_packidx
*packidx
, int idx
)
657 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
659 size_t digest_len
= got_hash_digest_length(packidx
->algo
);
661 if (idx
< 0 || idx
>= totobj
)
662 return got_error(GOT_ERR_NO_OBJ
);
664 oid
= packidx
->hdr
.sorted_ids
+ idx
* digest_len
;
665 memcpy(id
->hash
, oid
, digest_len
);
666 id
->algo
= packidx
->algo
;
670 const struct got_error
*
671 got_packidx_match_id_str_prefix(struct got_object_id_queue
*matched_ids
,
672 struct got_packidx
*packidx
, const char *id_str_prefix
)
674 const struct got_error
*err
= NULL
;
676 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
678 size_t prefix_len
= strlen(id_str_prefix
);
681 size_t digest_len
= got_hash_digest_length(packidx
->algo
);
684 return got_error_path(id_str_prefix
, GOT_ERR_BAD_OBJ_ID_STR
);
686 hex
[0] = id_str_prefix
[0];
687 hex
[1] = id_str_prefix
[1];
689 if (!got_parse_xdigit(&id0
, hex
))
690 return got_error_path(id_str_prefix
, GOT_ERR_BAD_OBJ_ID_STR
);
693 i
= be32toh(packidx
->hdr
.fanout_table
[id0
- 1]);
694 oid
= packidx
->hdr
.sorted_ids
+ i
* digest_len
;
695 while (i
< totobj
&& oid
[0] == id0
) {
696 char id_str
[GOT_HASH_DIGEST_STRING_MAXLEN
];
697 struct got_object_qid
*qid
;
700 if (!got_hash_digest_to_str(oid
, id_str
, sizeof(id_str
),
702 return got_error(GOT_ERR_NO_SPACE
);
704 cmp
= strncmp(id_str
, id_str_prefix
, prefix_len
);
706 oid
= packidx
->hdr
.sorted_ids
+ (++i
) * digest_len
;
711 err
= got_object_qid_alloc_partial(&qid
);
714 memcpy(qid
->id
.hash
, oid
, digest_len
);
715 qid
->id
.algo
= packidx
->algo
;
716 STAILQ_INSERT_TAIL(matched_ids
, qid
, entry
);
718 oid
= packidx
->hdr
.sorted_ids
+ (++i
) * digest_len
;
725 set_max_datasize(void)
729 if (getrlimit(RLIMIT_DATA
, &rl
) != 0)
732 rl
.rlim_cur
= rl
.rlim_max
;
733 setrlimit(RLIMIT_DATA
, &rl
);
736 const struct got_error
*
737 got_pack_start_privsep_child(struct got_pack
*pack
, struct got_packidx
*packidx
)
739 const struct got_error
*err
= NULL
;
742 struct imsgbuf
*ibuf
;
744 ibuf
= calloc(1, sizeof(*ibuf
));
746 return got_error_from_errno("calloc");
748 pack
->privsep_child
= calloc(1, sizeof(*pack
->privsep_child
));
749 if (pack
->privsep_child
== NULL
) {
750 err
= got_error_from_errno("calloc");
754 pack
->child_has_tempfiles
= 0;
755 pack
->child_has_delta_outfd
= 0;
757 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
758 err
= got_error_from_errno("socketpair");
764 err
= got_error_from_errno("fork");
768 } else if (pid
== 0) {
770 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_PACK
,
771 pack
->path_packfile
);
775 if (close(imsg_fds
[1]) == -1) {
776 err
= got_error_from_errno("close");
780 pack
->privsep_child
->imsg_fd
= imsg_fds
[0];
781 pack
->privsep_child
->pid
= pid
;
782 imsg_init(ibuf
, imsg_fds
[0]);
783 pack
->privsep_child
->ibuf
= ibuf
;
785 err
= got_privsep_init_pack_child(ibuf
, pack
, packidx
);
787 const struct got_error
*child_err
;
788 err
= got_privsep_send_stop(pack
->privsep_child
->imsg_fd
);
789 child_err
= got_privsep_wait_for_child(
790 pack
->privsep_child
->pid
);
791 if (child_err
&& err
== NULL
)
797 free(pack
->privsep_child
);
798 pack
->privsep_child
= NULL
;
803 static const struct got_error
*
804 pack_stop_privsep_child(struct got_pack
*pack
)
806 const struct got_error
*err
= NULL
, *close_err
= NULL
;
808 if (pack
->privsep_child
== NULL
)
811 err
= got_privsep_send_stop(pack
->privsep_child
->imsg_fd
);
814 if (close(pack
->privsep_child
->imsg_fd
) == -1)
815 close_err
= got_error_from_errno("close");
816 err
= got_privsep_wait_for_child(pack
->privsep_child
->pid
);
817 if (close_err
&& err
== NULL
)
819 imsg_clear(pack
->privsep_child
->ibuf
);
820 free(pack
->privsep_child
->ibuf
);
821 free(pack
->privsep_child
);
822 pack
->privsep_child
= NULL
;
826 const struct got_error
*
827 got_pack_close(struct got_pack
*pack
)
829 const struct got_error
*err
= NULL
;
831 err
= pack_stop_privsep_child(pack
);
832 if (pack
->map
&& munmap(pack
->map
, pack
->filesize
) == -1 && !err
)
833 err
= got_error_from_errno("munmap");
834 if (pack
->fd
!= -1 && close(pack
->fd
) == -1 && err
== NULL
)
835 err
= got_error_from_errno("close");
837 free(pack
->path_packfile
);
838 pack
->path_packfile
= NULL
;
840 if (pack
->delta_cache
) {
841 got_delta_cache_free(pack
->delta_cache
);
842 pack
->delta_cache
= NULL
;
846 * Leave accumfd and basefd alone. They are managed by the
847 * repository layer and can be reused.
853 const struct got_error
*
854 got_pack_parse_object_type_and_size(uint8_t *type
, uint64_t *size
, size_t *len
,
855 struct got_pack
*pack
, off_t offset
)
865 if (offset
>= pack
->filesize
)
866 return got_error(GOT_ERR_PACK_OFFSET
);
869 if (offset
> SIZE_MAX
) {
870 return got_error_fmt(GOT_ERR_PACK_OFFSET
,
871 "offset %lld overflows size_t",
875 mapoff
= (size_t)offset
;
877 if (lseek(pack
->fd
, offset
, SEEK_SET
) == -1)
878 return got_error_from_errno("lseek");
882 /* We do not support size values which don't fit in 64 bit. */
884 return got_error_fmt(GOT_ERR_OBJ_TOO_LARGE
,
885 "packfile offset %lld", (long long)offset
);
888 if (mapoff
+ sizeof(sizeN
) >= pack
->filesize
)
889 return got_error(GOT_ERR_BAD_PACKFILE
);
890 sizeN
= *(pack
->map
+ mapoff
);
891 mapoff
+= sizeof(sizeN
);
893 ssize_t n
= read(pack
->fd
, &sizeN
, sizeof(sizeN
));
895 return got_error_from_errno("read");
896 if (n
!= sizeof(sizeN
))
897 return got_error(GOT_ERR_BAD_PACKFILE
);
899 *len
+= sizeof(sizeN
);
902 t
= (sizeN
& GOT_PACK_OBJ_SIZE0_TYPE_MASK
) >>
903 GOT_PACK_OBJ_SIZE0_TYPE_MASK_SHIFT
;
904 s
= (sizeN
& GOT_PACK_OBJ_SIZE0_VAL_MASK
);
906 size_t shift
= 4 + 7 * (i
- 1);
907 s
|= ((sizeN
& GOT_PACK_OBJ_SIZE_VAL_MASK
) << shift
);
910 } while (sizeN
& GOT_PACK_OBJ_SIZE_MORE
);
917 static const struct got_error
*
918 open_plain_object(struct got_object
**obj
, struct got_object_id
*id
,
919 uint8_t type
, off_t offset
, size_t size
, int idx
)
921 *obj
= calloc(1, sizeof(**obj
));
923 return got_error_from_errno("calloc");
926 (*obj
)->flags
= GOT_OBJ_FLAG_PACKED
;
927 (*obj
)->pack_idx
= idx
;
930 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
931 (*obj
)->pack_offset
= offset
;
936 static const struct got_error
*
937 parse_negative_offset(int64_t *offset
, size_t *len
, struct got_pack
*pack
,
948 /* We do not support offset values which don't fit in 64 bit. */
950 return got_error(GOT_ERR_NO_SPACE
);
955 if (delta_offset
> SIZE_MAX
- *len
) {
956 return got_error_fmt(GOT_ERR_PACK_OFFSET
,
957 "mapoff %lld would overflow size_t",
958 (long long)delta_offset
+ *len
);
961 mapoff
= (size_t)delta_offset
+ *len
;
962 if (mapoff
+ sizeof(offN
) >= pack
->filesize
)
963 return got_error(GOT_ERR_PACK_OFFSET
);
964 offN
= *(pack
->map
+ mapoff
);
967 n
= read(pack
->fd
, &offN
, sizeof(offN
));
969 return got_error_from_errno("read");
970 if (n
!= sizeof(offN
))
971 return got_error(GOT_ERR_BAD_PACKFILE
);
973 *len
+= sizeof(offN
);
976 o
= (offN
& GOT_PACK_OBJ_DELTA_OFF_VAL_MASK
);
980 o
+= (offN
& GOT_PACK_OBJ_DELTA_OFF_VAL_MASK
);
983 } while (offN
& GOT_PACK_OBJ_DELTA_OFF_MORE
);
989 const struct got_error
*
990 got_pack_parse_offset_delta(off_t
*base_offset
, size_t *len
,
991 struct got_pack
*pack
, off_t offset
, size_t tslen
)
993 const struct got_error
*err
;
999 err
= parse_negative_offset(&negoffset
, &negofflen
, pack
,
1004 /* Compute the base object's offset (must be in the same pack file). */
1005 *base_offset
= (offset
- negoffset
);
1006 if (*base_offset
<= 0)
1007 return got_error(GOT_ERR_BAD_PACKFILE
);
1013 static const struct got_error
*
1014 read_delta_data(uint8_t **delta_buf
, size_t *delta_len
,
1015 size_t *delta_compressed_len
, size_t delta_data_offset
,
1016 struct got_pack
*pack
)
1018 const struct got_error
*err
= NULL
;
1019 size_t consumed
= 0;
1022 if (delta_data_offset
>= pack
->filesize
)
1023 return got_error(GOT_ERR_PACK_OFFSET
);
1024 err
= got_inflate_to_mem_mmap(delta_buf
, delta_len
,
1025 &consumed
, NULL
, pack
->map
, delta_data_offset
,
1026 pack
->filesize
- delta_data_offset
);
1030 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
) == -1)
1031 return got_error_from_errno("lseek");
1032 err
= got_inflate_to_mem_fd(delta_buf
, delta_len
,
1033 &consumed
, NULL
, 0, pack
->fd
);
1038 if (delta_compressed_len
)
1039 *delta_compressed_len
= consumed
;
1044 static const struct got_error
*
1045 add_delta(struct got_delta_chain
*deltas
, off_t delta_offset
, size_t tslen
,
1046 int delta_type
, size_t delta_size
, off_t delta_data_offset
)
1048 struct got_delta
*delta
;
1050 delta
= got_delta_open(delta_offset
, tslen
, delta_type
, delta_size
,
1053 return got_error_from_errno("got_delta_open");
1054 /* delta is freed in got_object_close() */
1056 STAILQ_INSERT_HEAD(&deltas
->entries
, delta
, entry
);
1060 static const struct got_error
*
1061 resolve_offset_delta(struct got_delta_chain
*deltas
,
1062 struct got_packidx
*packidx
, struct got_pack
*pack
, off_t delta_offset
,
1063 size_t tslen
, int delta_type
, size_t delta_size
, unsigned int recursion
)
1065 const struct got_error
*err
;
1070 off_t delta_data_offset
;
1073 err
= got_pack_parse_offset_delta(&base_offset
, &consumed
, pack
,
1074 delta_offset
, tslen
);
1078 delta_data_offset
= delta_offset
+ tslen
+ consumed
;
1079 if (delta_data_offset
>= pack
->filesize
)
1080 return got_error(GOT_ERR_PACK_OFFSET
);
1082 if (pack
->map
== NULL
) {
1083 delta_data_offset
= lseek(pack
->fd
, 0, SEEK_CUR
);
1084 if (delta_data_offset
== -1)
1085 return got_error_from_errno("lseek");
1088 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
, delta_size
,
1093 /* An offset delta must be in the same packfile. */
1094 if (base_offset
>= pack
->filesize
)
1095 return got_error(GOT_ERR_PACK_OFFSET
);
1097 err
= got_pack_parse_object_type_and_size(&base_type
, &base_size
,
1098 &base_tslen
, pack
, base_offset
);
1102 return got_pack_resolve_delta_chain(deltas
, packidx
, pack
, base_offset
,
1103 base_tslen
, base_type
, base_size
, recursion
- 1);
1106 const struct got_error
*
1107 got_pack_parse_ref_delta(struct got_object_id
*id
,
1108 struct got_pack
*pack
, off_t delta_offset
, int tslen
)
1110 size_t digest_len
= got_hash_digest_length(pack
->algo
);
1112 memset(id
, 0, sizeof(*id
));
1113 id
->algo
= pack
->algo
;
1118 if (delta_offset
> SIZE_MAX
- tslen
) {
1119 return got_error_fmt(GOT_ERR_PACK_OFFSET
,
1120 "mapoff %lld would overflow size_t",
1121 (long long)delta_offset
+ tslen
);
1124 mapoff
= delta_offset
+ tslen
;
1125 if (mapoff
+ sizeof(*id
) >= pack
->filesize
)
1126 return got_error(GOT_ERR_PACK_OFFSET
);
1127 memcpy(id
->hash
, pack
->map
+ mapoff
, digest_len
);
1130 n
= read(pack
->fd
, id
->hash
, digest_len
);
1132 return got_error_from_errno("read");
1133 if (n
!= digest_len
)
1134 return got_error(GOT_ERR_BAD_PACKFILE
);
1140 static const struct got_error
*
1141 resolve_ref_delta(struct got_delta_chain
*deltas
, struct got_packidx
*packidx
,
1142 struct got_pack
*pack
, off_t delta_offset
, size_t tslen
, int delta_type
,
1143 size_t delta_size
, unsigned int recursion
)
1145 const struct got_error
*err
;
1146 struct got_object_id id
;
1152 off_t delta_data_offset
;
1154 if (delta_offset
+ tslen
>= pack
->filesize
)
1155 return got_error(GOT_ERR_PACK_OFFSET
);
1157 err
= got_pack_parse_ref_delta(&id
, pack
, delta_offset
, tslen
);
1161 delta_data_offset
= delta_offset
+ tslen
+
1162 got_hash_digest_length(packidx
->algo
);
1164 delta_data_offset
= lseek(pack
->fd
, 0, SEEK_CUR
);
1165 if (delta_data_offset
== -1)
1166 return got_error_from_errno("lseek");
1169 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
, delta_size
,
1174 /* Delta base must be in the same pack file. */
1175 idx
= got_packidx_get_object_idx(packidx
, &id
);
1177 return got_error(GOT_ERR_NO_OBJ
);
1179 base_offset
= got_packidx_get_object_offset(packidx
, idx
);
1180 if (base_offset
== -1)
1181 return got_error(GOT_ERR_BAD_PACKIDX
);
1183 if (base_offset
>= pack
->filesize
)
1184 return got_error(GOT_ERR_PACK_OFFSET
);
1186 err
= got_pack_parse_object_type_and_size(&base_type
, &base_size
,
1187 &base_tslen
, pack
, base_offset
);
1191 return got_pack_resolve_delta_chain(deltas
, packidx
, pack
, base_offset
,
1192 base_tslen
, base_type
, base_size
, recursion
- 1);
1195 const struct got_error
*
1196 got_pack_resolve_delta_chain(struct got_delta_chain
*deltas
,
1197 struct got_packidx
*packidx
, struct got_pack
*pack
, off_t delta_offset
,
1198 size_t tslen
, int delta_type
, size_t delta_size
, unsigned int recursion
)
1200 const struct got_error
*err
= NULL
;
1202 if (--recursion
== 0)
1203 return got_error(GOT_ERR_RECURSION
);
1205 switch (delta_type
) {
1206 case GOT_OBJ_TYPE_COMMIT
:
1207 case GOT_OBJ_TYPE_TREE
:
1208 case GOT_OBJ_TYPE_BLOB
:
1209 case GOT_OBJ_TYPE_TAG
:
1210 /* Plain types are the final delta base. Recursion ends. */
1211 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
,
1214 case GOT_OBJ_TYPE_OFFSET_DELTA
:
1215 err
= resolve_offset_delta(deltas
, packidx
, pack
,
1216 delta_offset
, tslen
, delta_type
, delta_size
, recursion
- 1);
1218 case GOT_OBJ_TYPE_REF_DELTA
:
1219 err
= resolve_ref_delta(deltas
, packidx
, pack
,
1220 delta_offset
, tslen
, delta_type
, delta_size
, recursion
- 1);
1223 return got_error(GOT_ERR_OBJ_TYPE
);
1229 static const struct got_error
*
1230 open_delta_object(struct got_object
**obj
, struct got_packidx
*packidx
,
1231 struct got_pack
*pack
, struct got_object_id
*id
, off_t offset
,
1232 size_t tslen
, int delta_type
, size_t delta_size
, int idx
)
1234 const struct got_error
*err
= NULL
;
1237 *obj
= calloc(1, sizeof(**obj
));
1239 return got_error_from_errno("calloc");
1243 (*obj
)->size
= 0; /* Not known because deltas aren't applied yet. */
1244 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
1245 (*obj
)->pack_offset
= offset
+ tslen
;
1247 STAILQ_INIT(&(*obj
)->deltas
.entries
);
1248 (*obj
)->flags
|= GOT_OBJ_FLAG_DELTIFIED
;
1249 (*obj
)->flags
|= GOT_OBJ_FLAG_PACKED
;
1250 (*obj
)->pack_idx
= idx
;
1252 err
= got_pack_resolve_delta_chain(&(*obj
)->deltas
, packidx
, pack
,
1253 offset
, tslen
, delta_type
, delta_size
,
1254 GOT_DELTA_CHAIN_RECURSION_MAX
);
1258 err
= got_delta_chain_get_base_type(&resolved_type
, &(*obj
)->deltas
);
1261 (*obj
)->type
= resolved_type
;
1264 got_object_close(*obj
);
1270 const struct got_error
*
1271 got_packfile_open_object(struct got_object
**obj
, struct got_pack
*pack
,
1272 struct got_packidx
*packidx
, int idx
, struct got_object_id
*id
)
1274 const struct got_error
*err
= NULL
;
1282 offset
= got_packidx_get_object_offset(packidx
, idx
);
1284 return got_error(GOT_ERR_BAD_PACKIDX
);
1286 err
= got_pack_parse_object_type_and_size(&type
, &size
, &tslen
,
1292 case GOT_OBJ_TYPE_COMMIT
:
1293 case GOT_OBJ_TYPE_TREE
:
1294 case GOT_OBJ_TYPE_BLOB
:
1295 case GOT_OBJ_TYPE_TAG
:
1296 err
= open_plain_object(obj
, id
, type
, offset
+ tslen
,
1299 case GOT_OBJ_TYPE_OFFSET_DELTA
:
1300 case GOT_OBJ_TYPE_REF_DELTA
:
1301 err
= open_delta_object(obj
, packidx
, pack
, id
, offset
,
1302 tslen
, type
, size
, idx
);
1305 err
= got_error(GOT_ERR_OBJ_TYPE
);
1312 const struct got_error
*
1313 got_pack_get_delta_chain_max_size(uint64_t *max_size
,
1314 struct got_delta_chain
*deltas
, struct got_pack
*pack
)
1316 struct got_delta
*delta
;
1317 uint64_t base_size
= 0, result_size
= 0;
1320 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1321 /* Plain object types are the delta base. */
1322 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1323 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1324 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1325 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1326 const struct got_error
*err
;
1327 uint8_t *delta_buf
= NULL
;
1331 if (pack
->delta_cache
) {
1332 got_delta_cache_get(&delta_buf
, &delta_len
,
1333 NULL
, NULL
, pack
->delta_cache
,
1334 delta
->data_offset
);
1336 if (delta_buf
== NULL
) {
1338 err
= read_delta_data(&delta_buf
, &delta_len
,
1339 NULL
, delta
->data_offset
, pack
);
1343 if (pack
->delta_cache
&& !cached
) {
1344 err
= got_delta_cache_add(pack
->delta_cache
,
1345 delta
->data_offset
, delta_buf
, delta_len
);
1348 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1353 err
= got_delta_get_sizes(&base_size
, &result_size
,
1354 delta_buf
, delta_len
);
1360 base_size
= delta
->size
;
1361 if (base_size
> *max_size
)
1362 *max_size
= base_size
;
1363 if (result_size
> *max_size
)
1364 *max_size
= result_size
;
1370 const struct got_error
*
1371 got_pack_get_max_delta_object_size(uint64_t *size
, struct got_object
*obj
,
1372 struct got_pack
*pack
)
1374 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0)
1375 return got_error(GOT_ERR_OBJ_TYPE
);
1377 return got_pack_get_delta_chain_max_size(size
, &obj
->deltas
, pack
);
1380 const struct got_error
*
1381 got_pack_dump_delta_chain_to_file(size_t *result_size
,
1382 struct got_delta_chain
*deltas
, struct got_pack
*pack
, FILE *outfile
,
1383 FILE *base_file
, FILE *accum_file
)
1385 const struct got_error
*err
= NULL
;
1386 struct got_delta
*delta
;
1387 uint8_t *base_buf
= NULL
, *accum_buf
= NULL
;
1388 size_t base_bufsz
= 0, accum_bufsz
= 0, accum_size
= 0;
1389 /* We process small enough files entirely in memory for speed. */
1390 const size_t max_bufsize
= GOT_DELTA_RESULT_SIZE_CACHED_MAX
;
1391 uint64_t max_size
= 0;
1396 if (STAILQ_EMPTY(&deltas
->entries
))
1397 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1399 if (pack
->delta_cache
) {
1400 uint8_t *delta_buf
= NULL
, *fulltext
= NULL
;
1401 size_t delta_len
, fulltext_len
;
1403 delta
= STAILQ_LAST(&deltas
->entries
, got_delta
, entry
);
1404 got_delta_cache_get(&delta_buf
, &delta_len
,
1405 &fulltext
, &fulltext_len
,
1406 pack
->delta_cache
, delta
->data_offset
);
1410 w
= fwrite(fulltext
, 1, fulltext_len
, outfile
);
1411 if (w
!= fulltext_len
)
1412 return got_ferror(outfile
, GOT_ERR_IO
);
1413 if (fflush(outfile
) != 0)
1414 return got_error_from_errno("fflush");
1415 *result_size
= fulltext_len
;
1420 if (fseeko(base_file
, 0L, SEEK_SET
) == -1)
1421 return got_error_from_errno("fseeko");
1422 if (fseeko(accum_file
, 0L, SEEK_SET
) == -1)
1423 return got_error_from_errno("fseeko");
1425 /* Deltas are ordered in ascending order. */
1426 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1427 uint8_t *delta_buf
= NULL
, *fulltext
= NULL
;
1428 size_t delta_len
, fulltext_len
;
1429 uint64_t base_size
, result_size
= 0;
1433 off_t delta_data_offset
;
1435 /* Plain object types are the delta base. */
1436 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1437 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1438 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1439 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1440 err
= got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1444 delta_data_offset
= delta
->offset
+ delta
->tslen
;
1445 if (delta_data_offset
>= pack
->filesize
) {
1446 err
= got_error(GOT_ERR_PACK_OFFSET
);
1449 if (pack
->map
== NULL
) {
1450 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
)
1452 err
= got_error_from_errno("lseek");
1456 if (delta
->size
> max_size
)
1457 max_size
= delta
->size
;
1458 if (max_size
> max_bufsize
) {
1460 if (delta_data_offset
> SIZE_MAX
) {
1461 return got_error_fmt(
1463 "delta offset %lld "
1469 mapoff
= delta_data_offset
;
1470 err
= got_inflate_to_file_mmap(
1471 &base_bufsz
, NULL
, NULL
, pack
->map
,
1472 mapoff
, pack
->filesize
- mapoff
,
1475 err
= got_inflate_to_file_fd(
1476 &base_bufsz
, NULL
, NULL
, pack
->fd
,
1479 accum_buf
= malloc(max_size
);
1480 if (accum_buf
== NULL
) {
1481 err
= got_error_from_errno("malloc");
1484 accum_bufsz
= max_size
;
1486 if (delta_data_offset
> SIZE_MAX
) {
1487 err
= got_error_fmt(
1489 "delta offset %lld "
1496 mapoff
= delta_data_offset
;
1497 err
= got_inflate_to_mem_mmap(&base_buf
,
1498 &base_bufsz
, NULL
, NULL
,
1500 pack
->filesize
- mapoff
);
1502 err
= got_inflate_to_mem_fd(&base_buf
,
1503 &base_bufsz
, NULL
, NULL
, max_size
,
1509 if (base_buf
== NULL
)
1511 else if (pack
->delta_cache
&& fulltext
== NULL
) {
1512 err
= got_delta_cache_add(pack
->delta_cache
,
1513 delta_data_offset
, NULL
, 0);
1515 if (err
->code
!= GOT_ERR_NO_SPACE
)
1519 err
= got_delta_cache_add_fulltext(
1522 base_buf
, base_bufsz
);
1524 err
->code
!= GOT_ERR_NO_SPACE
)
1532 if (pack
->delta_cache
) {
1533 got_delta_cache_get(&delta_buf
, &delta_len
,
1534 &fulltext
, &fulltext_len
,
1535 pack
->delta_cache
, delta
->data_offset
);
1537 if (delta_buf
== NULL
) {
1539 err
= read_delta_data(&delta_buf
, &delta_len
, NULL
,
1540 delta
->data_offset
, pack
);
1544 if (pack
->delta_cache
&& !cached
) {
1545 err
= got_delta_cache_add(pack
->delta_cache
,
1546 delta
->data_offset
, delta_buf
, delta_len
);
1549 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1555 err
= got_delta_get_sizes(&base_size
, &result_size
,
1556 delta_buf
, delta_len
);
1562 if (base_size
> max_size
)
1563 max_size
= base_size
;
1564 if (result_size
> max_size
)
1565 max_size
= result_size
;
1566 if (fulltext_len
> max_size
)
1567 max_size
= fulltext_len
;
1569 if (base_buf
&& max_size
> max_bufsize
) {
1570 /* Switch from buffers to temporary files. */
1571 size_t w
= fwrite(base_buf
, 1, base_bufsz
,
1573 if (w
!= base_bufsz
) {
1574 err
= got_ferror(outfile
, GOT_ERR_IO
);
1585 if (base_buf
&& max_size
> base_bufsz
) {
1586 uint8_t *p
= realloc(base_buf
, max_size
);
1588 err
= got_error_from_errno("realloc");
1594 base_bufsz
= max_size
;
1597 if (accum_buf
&& max_size
> accum_bufsz
) {
1598 uint8_t *p
= realloc(accum_buf
, max_size
);
1600 err
= got_error_from_errno("realloc");
1606 accum_bufsz
= max_size
;
1611 memcpy(accum_buf
, fulltext
, fulltext_len
);
1612 accum_size
= fulltext_len
;
1615 err
= got_delta_apply_in_mem(base_buf
,
1616 base_bufsz
, delta_buf
, delta_len
,
1617 accum_buf
, &accum_size
, max_size
);
1624 if (fulltext
== NULL
) {
1625 err
= got_delta_cache_add_fulltext(
1626 pack
->delta_cache
, delta
->data_offset
,
1627 accum_buf
, accum_size
);
1629 if (err
->code
!= GOT_ERR_NO_SPACE
)
1635 err
= got_delta_apply(base_file
, delta_buf
,
1637 /* Final delta application writes to output file. */
1638 ++n
< deltas
->nentries
? accum_file
: outfile
,
1646 if (n
< deltas
->nentries
) {
1647 /* Accumulated delta becomes the new base. */
1649 uint8_t *tmp
= accum_buf
;
1650 size_t tmp_size
= accum_bufsz
;
1651 accum_buf
= base_buf
;
1652 accum_bufsz
= base_bufsz
;
1654 base_bufsz
= tmp_size
;
1656 FILE *tmp
= accum_file
;
1657 accum_file
= base_file
;
1672 size_t len
= fwrite(accum_buf
, 1, accum_size
, outfile
);
1674 if (len
!= accum_size
)
1675 err
= got_ferror(outfile
, GOT_ERR_IO
);
1679 *result_size
= accum_size
;
1683 const struct got_error
*
1684 got_pack_dump_delta_chain_to_mem(uint8_t **outbuf
, size_t *outlen
,
1685 struct got_delta_chain
*deltas
, struct got_pack
*pack
)
1687 const struct got_error
*err
= NULL
;
1688 struct got_delta
*delta
;
1689 uint8_t *base_buf
= NULL
, *accum_buf
= NULL
;
1690 size_t base_bufsz
= 0, accum_bufsz
= 0, accum_size
= 0;
1691 uint64_t max_size
= 0;
1697 if (STAILQ_EMPTY(&deltas
->entries
))
1698 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1700 if (pack
->delta_cache
) {
1701 uint8_t *delta_buf
= NULL
, *fulltext
= NULL
;
1702 size_t delta_len
, fulltext_len
;
1704 delta
= STAILQ_LAST(&deltas
->entries
, got_delta
, entry
);
1705 got_delta_cache_get(&delta_buf
, &delta_len
,
1706 &fulltext
, &fulltext_len
,
1707 pack
->delta_cache
, delta
->data_offset
);
1709 *outbuf
= malloc(fulltext_len
);
1710 if (*outbuf
== NULL
)
1711 return got_error_from_errno("malloc");
1712 memcpy(*outbuf
, fulltext
, fulltext_len
);
1713 *outlen
= fulltext_len
;
1718 /* Deltas are ordered in ascending order. */
1719 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1720 uint8_t *delta_buf
= NULL
, *fulltext
= NULL
;
1721 size_t delta_len
, fulltext_len
= 0;
1722 uint64_t base_size
, result_size
= 0;
1725 off_t delta_data_offset
;
1727 /* Plain object types are the delta base. */
1728 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1729 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1730 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1731 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1732 err
= got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1736 delta_data_offset
= delta
->offset
+ delta
->tslen
;
1737 if (delta_data_offset
>= pack
->filesize
) {
1738 err
= got_error(GOT_ERR_PACK_OFFSET
);
1742 if (pack
->delta_cache
) {
1743 got_delta_cache_get(&delta_buf
, &delta_len
,
1744 &fulltext
, &fulltext_len
,
1745 pack
->delta_cache
, delta_data_offset
);
1748 if (delta
->size
> max_size
)
1749 max_size
= delta
->size
;
1750 if (delta
->size
> fulltext_len
)
1751 max_size
= fulltext_len
;
1754 base_buf
= malloc(fulltext_len
);
1755 if (base_buf
== NULL
) {
1756 err
= got_error_from_errno("malloc");
1759 memcpy(base_buf
, fulltext
, fulltext_len
);
1760 base_bufsz
= fulltext_len
;
1761 } else if (pack
->map
) {
1764 if (delta_data_offset
> SIZE_MAX
) {
1765 return got_error_fmt(GOT_ERR_RANGE
,
1766 "delta %lld offset would "
1768 (long long)delta_data_offset
);
1771 mapoff
= delta_data_offset
;
1772 err
= got_inflate_to_mem_mmap(&base_buf
,
1773 &base_bufsz
, NULL
, NULL
, pack
->map
,
1774 mapoff
, pack
->filesize
- mapoff
);
1776 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
)
1778 err
= got_error_from_errno("lseek");
1781 err
= got_inflate_to_mem_fd(&base_buf
,
1782 &base_bufsz
, NULL
, NULL
, max_size
,
1789 if (pack
->delta_cache
&& fulltext
== NULL
) {
1790 err
= got_delta_cache_add(pack
->delta_cache
,
1791 delta_data_offset
, NULL
, 0);
1793 if (err
->code
!= GOT_ERR_NO_SPACE
)
1797 err
= got_delta_cache_add_fulltext(
1800 base_buf
, base_bufsz
);
1802 err
->code
!= GOT_ERR_NO_SPACE
)
1810 if (pack
->delta_cache
) {
1811 got_delta_cache_get(&delta_buf
, &delta_len
,
1812 &fulltext
, &fulltext_len
,
1813 pack
->delta_cache
, delta
->data_offset
);
1815 if (delta_buf
== NULL
) {
1817 err
= read_delta_data(&delta_buf
, &delta_len
, NULL
,
1818 delta
->data_offset
, pack
);
1822 if (pack
->delta_cache
&& !cached
) {
1823 err
= got_delta_cache_add(pack
->delta_cache
,
1824 delta
->data_offset
, delta_buf
, delta_len
);
1827 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1833 err
= got_delta_get_sizes(&base_size
, &result_size
,
1834 delta_buf
, delta_len
);
1840 if (base_size
> max_size
)
1841 max_size
= base_size
;
1842 if (result_size
> max_size
)
1843 max_size
= result_size
;
1844 if (fulltext_len
> max_size
)
1845 max_size
= fulltext_len
;
1847 if (max_size
> base_bufsz
) {
1848 uint8_t *p
= realloc(base_buf
, max_size
);
1850 err
= got_error_from_errno("realloc");
1856 base_bufsz
= max_size
;
1859 if (max_size
> accum_bufsz
) {
1860 uint8_t *p
= realloc(accum_buf
, max_size
);
1862 err
= got_error_from_errno("realloc");
1868 accum_bufsz
= max_size
;
1872 memcpy(accum_buf
, fulltext
, fulltext_len
);
1873 accum_size
= fulltext_len
;
1876 err
= got_delta_apply_in_mem(base_buf
, base_bufsz
,
1877 delta_buf
, delta_len
, accum_buf
,
1878 &accum_size
, max_size
);
1886 if (fulltext
== NULL
) {
1887 err
= got_delta_cache_add_fulltext(pack
->delta_cache
,
1888 delta
->data_offset
, accum_buf
, accum_size
);
1890 if (err
->code
!= GOT_ERR_NO_SPACE
)
1896 if (n
< deltas
->nentries
) {
1897 /* Accumulated delta becomes the new base. */
1898 uint8_t *tmp
= accum_buf
;
1899 size_t tmp_size
= accum_bufsz
;
1900 accum_buf
= base_buf
;
1901 accum_bufsz
= base_bufsz
;
1903 base_bufsz
= tmp_size
;
1914 *outbuf
= accum_buf
;
1915 *outlen
= accum_size
;
1920 const struct got_error
*
1921 got_packfile_extract_object(struct got_pack
*pack
, struct got_object
*obj
,
1922 FILE *outfile
, FILE *base_file
, FILE *accum_file
)
1924 const struct got_error
*err
= NULL
;
1926 if ((obj
->flags
& GOT_OBJ_FLAG_PACKED
) == 0)
1927 return got_error(GOT_ERR_OBJ_NOT_PACKED
);
1929 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0) {
1930 if (obj
->pack_offset
>= pack
->filesize
)
1931 return got_error(GOT_ERR_PACK_OFFSET
);
1936 if (obj
->pack_offset
> SIZE_MAX
) {
1937 return got_error_fmt(GOT_ERR_RANGE
,
1938 "pack offset %lld would overflow size_t",
1939 (long long)obj
->pack_offset
);
1942 mapoff
= obj
->pack_offset
;
1943 err
= got_inflate_to_file_mmap(&obj
->size
, NULL
, NULL
,
1944 pack
->map
, mapoff
, pack
->filesize
- mapoff
,
1947 if (lseek(pack
->fd
, obj
->pack_offset
, SEEK_SET
) == -1)
1948 return got_error_from_errno("lseek");
1949 err
= got_inflate_to_file_fd(&obj
->size
, NULL
, NULL
,
1953 err
= got_pack_dump_delta_chain_to_file(&obj
->size
,
1954 &obj
->deltas
, pack
, outfile
, base_file
, accum_file
);
1959 const struct got_error
*
1960 got_packfile_extract_object_to_mem(uint8_t **buf
, size_t *len
,
1961 struct got_object
*obj
, struct got_pack
*pack
)
1963 const struct got_error
*err
= NULL
;
1965 if ((obj
->flags
& GOT_OBJ_FLAG_PACKED
) == 0)
1966 return got_error(GOT_ERR_OBJ_NOT_PACKED
);
1968 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0) {
1969 if (obj
->pack_offset
>= pack
->filesize
)
1970 return got_error(GOT_ERR_PACK_OFFSET
);
1974 if (obj
->pack_offset
> SIZE_MAX
) {
1975 return got_error_fmt(GOT_ERR_RANGE
,
1976 "pack offset %lld would overflow size_t",
1977 (long long)obj
->pack_offset
);
1980 mapoff
= obj
->pack_offset
;
1981 err
= got_inflate_to_mem_mmap(buf
, len
, NULL
, NULL
,
1982 pack
->map
, mapoff
, pack
->filesize
- mapoff
);
1984 if (lseek(pack
->fd
, obj
->pack_offset
, SEEK_SET
) == -1)
1985 return got_error_from_errno("lseek");
1986 err
= got_inflate_to_mem_fd(buf
, len
, NULL
, NULL
,
1987 obj
->size
, pack
->fd
);
1990 err
= got_pack_dump_delta_chain_to_mem(buf
, len
, &obj
->deltas
,
1996 static const struct got_error
*
1997 read_raw_delta_data(uint8_t **delta_buf
, size_t *delta_len
,
1998 size_t *delta_len_compressed
, uint64_t *base_size
, uint64_t *result_size
,
1999 off_t delta_data_offset
, struct got_pack
*pack
, struct got_packidx
*packidx
)
2001 const struct got_error
*err
= NULL
;
2003 /* Validate decompression and obtain the decompressed size. */
2004 err
= read_delta_data(delta_buf
, delta_len
, delta_len_compressed
,
2005 delta_data_offset
, pack
);
2009 /* Read delta base/result sizes from head of delta stream. */
2010 err
= got_delta_get_sizes(base_size
, result_size
,
2011 *delta_buf
, *delta_len
);
2015 /* Discard decompressed delta and read it again in compressed form. */
2017 *delta_buf
= malloc(*delta_len_compressed
);
2018 if (*delta_buf
== NULL
) {
2019 err
= got_error_from_errno("malloc");
2023 if (delta_data_offset
>= pack
->filesize
) {
2024 err
= got_error(GOT_ERR_PACK_OFFSET
);
2027 memcpy(*delta_buf
, pack
->map
+ delta_data_offset
,
2028 *delta_len_compressed
);
2031 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
) == -1) {
2032 err
= got_error_from_errno("lseek");
2035 n
= read(pack
->fd
, *delta_buf
, *delta_len_compressed
);
2037 err
= got_error_from_errno("read");
2039 } else if (n
!= *delta_len_compressed
) {
2040 err
= got_error(GOT_ERR_IO
);
2049 *delta_len_compressed
= 0;
2056 const struct got_error
*
2057 got_packfile_extract_raw_delta(uint8_t **delta_buf
, size_t *delta_size
,
2058 size_t *delta_compressed_size
, off_t
*delta_offset
,
2059 off_t
*delta_data_offset
, off_t
*base_offset
,
2060 struct got_object_id
*base_id
, uint64_t *base_size
, uint64_t *result_size
,
2061 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
)
2063 const struct got_error
*err
= NULL
;
2067 size_t tslen
, delta_hdrlen
;
2071 *delta_compressed_size
= 0;
2073 *delta_data_offset
= 0;
2078 offset
= got_packidx_get_object_offset(packidx
, idx
);
2080 return got_error(GOT_ERR_BAD_PACKIDX
);
2082 if (offset
>= pack
->filesize
)
2083 return got_error(GOT_ERR_PACK_OFFSET
);
2085 err
= got_pack_parse_object_type_and_size(&type
, &size
, &tslen
,
2090 if (tslen
+ size
< tslen
|| offset
+ size
< size
||
2091 tslen
+ offset
< tslen
)
2092 return got_error(GOT_ERR_PACK_OFFSET
);
2095 case GOT_OBJ_TYPE_OFFSET_DELTA
:
2096 err
= got_pack_parse_offset_delta(base_offset
, &delta_hdrlen
,
2097 pack
, offset
, tslen
);
2101 case GOT_OBJ_TYPE_REF_DELTA
:
2102 err
= got_pack_parse_ref_delta(base_id
, pack
, offset
, tslen
);
2105 delta_hdrlen
= got_hash_digest_length(pack
->algo
);
2108 return got_error_fmt(GOT_ERR_OBJ_TYPE
,
2109 "non-delta object type %d found at offset %lld",
2110 type
, (long long)offset
);
2113 if (tslen
+ delta_hdrlen
< delta_hdrlen
||
2114 offset
+ delta_hdrlen
< delta_hdrlen
)
2115 return got_error(GOT_ERR_BAD_DELTA
);
2117 *delta_data_offset
= offset
+ tslen
+ delta_hdrlen
;
2118 err
= read_raw_delta_data(delta_buf
, delta_size
, delta_compressed_size
,
2119 base_size
, result_size
, *delta_data_offset
, pack
, packidx
);
2123 if (*delta_size
!= size
) {
2124 err
= got_error(GOT_ERR_BAD_DELTA
);
2128 *delta_offset
= offset
;
2134 *delta_compressed_size
= 0;