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>
24 #include <sys/resource.h>
25 #include <sys/socket.h>
37 #include "got_error.h"
38 #include "got_object.h"
41 #include "got_lib_hash.h"
42 #include "got_lib_delta.h"
43 #include "got_lib_delta_cache.h"
44 #include "got_lib_inflate.h"
45 #include "got_lib_object.h"
46 #include "got_lib_object_qid.h"
47 #include "got_lib_object_parse.h"
48 #include "got_lib_privsep.h"
49 #include "got_lib_pack.h"
52 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
56 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
59 static const struct got_error
*
60 verify_fanout_table(uint32_t *fanout_table
)
64 for (i
= 0; i
< 0xff - 1; i
++) {
65 if (be32toh(fanout_table
[i
]) > be32toh(fanout_table
[i
+ 1]))
66 return got_error(GOT_ERR_BAD_PACKIDX
);
72 const struct got_error
*
73 got_packidx_init_hdr(struct got_packidx
*p
, int verify
, off_t packfile_size
)
75 const struct got_error
*err
= NULL
;
76 struct got_packidx_v2_hdr
*h
;
78 uint8_t hash
[GOT_HASH_DIGEST_MAXLEN
];
79 size_t nobj
, len_fanout
, len_ids
, offset
, remain
, digest_string_len
;
83 got_hash_init(&ctx
, p
->algo
);
84 digest_string_len
= got_hash_digest_length(p
->algo
);
90 if (remain
< sizeof(*h
->magic
)) {
91 err
= got_error(GOT_ERR_BAD_PACKIDX
);
95 h
->magic
= (uint32_t *)(p
->map
+ offset
);
97 h
->magic
= malloc(sizeof(*h
->magic
));
98 if (h
->magic
== NULL
) {
99 err
= got_error_from_errno("malloc");
102 n
= read(p
->fd
, h
->magic
, sizeof(*h
->magic
));
104 err
= got_error_from_errno("read");
106 } else if (n
!= sizeof(*h
->magic
)) {
107 err
= got_error(GOT_ERR_BAD_PACKIDX
);
111 if (*h
->magic
!= htobe32(GOT_PACKIDX_V2_MAGIC
)) {
112 err
= got_error(GOT_ERR_BAD_PACKIDX
);
115 offset
+= sizeof(*h
->magic
);
116 remain
-= sizeof(*h
->magic
);
119 got_hash_update(&ctx
, h
->magic
, sizeof(*h
->magic
));
121 if (remain
< sizeof(*h
->version
)) {
122 err
= got_error(GOT_ERR_BAD_PACKIDX
);
126 h
->version
= (uint32_t *)(p
->map
+ offset
);
128 h
->version
= malloc(sizeof(*h
->version
));
129 if (h
->version
== NULL
) {
130 err
= got_error_from_errno("malloc");
133 n
= read(p
->fd
, h
->version
, sizeof(*h
->version
));
135 err
= got_error_from_errno("read");
137 } else if (n
!= sizeof(*h
->version
)) {
138 err
= got_error(GOT_ERR_BAD_PACKIDX
);
142 if (*h
->version
!= htobe32(GOT_PACKIDX_VERSION
)) {
143 err
= got_error(GOT_ERR_BAD_PACKIDX
);
146 offset
+= sizeof(*h
->version
);
147 remain
-= sizeof(*h
->version
);
150 got_hash_update(&ctx
, h
->version
, sizeof(*h
->version
));
153 sizeof(*h
->fanout_table
) * GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS
;
154 if (remain
< len_fanout
) {
155 err
= got_error(GOT_ERR_BAD_PACKIDX
);
159 h
->fanout_table
= (uint32_t *)(p
->map
+ offset
);
161 h
->fanout_table
= malloc(len_fanout
);
162 if (h
->fanout_table
== NULL
) {
163 err
= got_error_from_errno("malloc");
166 n
= read(p
->fd
, h
->fanout_table
, len_fanout
);
168 err
= got_error_from_errno("read");
170 } else if (n
!= len_fanout
) {
171 err
= got_error(GOT_ERR_BAD_PACKIDX
);
175 err
= verify_fanout_table(h
->fanout_table
);
179 got_hash_update(&ctx
, h
->fanout_table
, len_fanout
);
180 offset
+= len_fanout
;
181 remain
-= len_fanout
;
183 nobj
= be32toh(h
->fanout_table
[0xff]);
184 len_ids
= nobj
* got_hash_digest_length(p
->algo
);
185 if (len_ids
<= nobj
|| len_ids
> remain
) {
186 err
= got_error(GOT_ERR_BAD_PACKIDX
);
190 h
->sorted_ids
= p
->map
+ offset
;
192 h
->sorted_ids
= malloc(len_ids
);
193 if (h
->sorted_ids
== NULL
) {
194 err
= got_error(GOT_ERR_BAD_PACKIDX
);
197 n
= read(p
->fd
, h
->sorted_ids
, len_ids
);
199 err
= got_error_from_errno("read");
200 else if (n
!= len_ids
) {
201 err
= got_error(GOT_ERR_BAD_PACKIDX
);
206 got_hash_update(&ctx
, h
->sorted_ids
, len_ids
);
210 if (remain
< nobj
* sizeof(*h
->crc32
)) {
211 err
= got_error(GOT_ERR_BAD_PACKIDX
);
215 h
->crc32
= (uint32_t *)((uint8_t*)(p
->map
+ offset
));
217 h
->crc32
= malloc(nobj
* sizeof(*h
->crc32
));
218 if (h
->crc32
== NULL
) {
219 err
= got_error_from_errno("malloc");
222 n
= read(p
->fd
, h
->crc32
, nobj
* sizeof(*h
->crc32
));
224 err
= got_error_from_errno("read");
225 else if (n
!= nobj
* sizeof(*h
->crc32
)) {
226 err
= got_error(GOT_ERR_BAD_PACKIDX
);
231 got_hash_update(&ctx
, h
->crc32
, nobj
* sizeof(*h
->crc32
));
232 remain
-= nobj
* sizeof(*h
->crc32
);
233 offset
+= nobj
* sizeof(*h
->crc32
);
235 if (remain
< nobj
* sizeof(*h
->offsets
)) {
236 err
= got_error(GOT_ERR_BAD_PACKIDX
);
240 h
->offsets
= (uint32_t *)((uint8_t*)(p
->map
+ offset
));
242 h
->offsets
= malloc(nobj
* sizeof(*h
->offsets
));
243 if (h
->offsets
== NULL
) {
244 err
= got_error_from_errno("malloc");
247 n
= read(p
->fd
, h
->offsets
, nobj
* sizeof(*h
->offsets
));
249 err
= got_error_from_errno("read");
250 else if (n
!= nobj
* sizeof(*h
->offsets
)) {
251 err
= got_error(GOT_ERR_BAD_PACKIDX
);
256 got_hash_update(&ctx
, h
->offsets
, nobj
* sizeof(*h
->offsets
));
257 remain
-= nobj
* sizeof(*h
->offsets
);
258 offset
+= nobj
* sizeof(*h
->offsets
);
260 /* Large file offsets are contained only in files > 2GB. */
261 if (verify
|| packfile_size
> 0x7fffffff) {
262 for (i
= 0; i
< nobj
; i
++) {
263 uint32_t o
= h
->offsets
[i
];
264 if (o
& htobe32(GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
))
268 if (p
->nlargeobj
== 0)
270 else if (packfile_size
<= 0x7fffffff) {
271 err
= got_error(GOT_ERR_BAD_PACKIDX
);
275 if (remain
< p
->nlargeobj
* sizeof(*h
->large_offsets
)) {
276 err
= got_error(GOT_ERR_BAD_PACKIDX
);
280 h
->large_offsets
= (uint64_t *)((uint8_t*)(p
->map
+ offset
));
282 h
->large_offsets
= malloc(p
->nlargeobj
*
283 sizeof(*h
->large_offsets
));
284 if (h
->large_offsets
== NULL
) {
285 err
= got_error_from_errno("malloc");
288 n
= read(p
->fd
, h
->large_offsets
,
289 p
->nlargeobj
* sizeof(*h
->large_offsets
));
291 err
= got_error_from_errno("read");
292 else if (n
!= p
->nlargeobj
* sizeof(*h
->large_offsets
)) {
293 err
= got_error(GOT_ERR_BAD_PACKIDX
);
298 got_hash_update(&ctx
, h
->large_offsets
,
299 p
->nlargeobj
* sizeof(*h
->large_offsets
));
300 remain
-= p
->nlargeobj
* sizeof(*h
->large_offsets
);
301 offset
+= p
->nlargeobj
* sizeof(*h
->large_offsets
);
304 if (remain
< digest_string_len
* 2) {
305 err
= got_error(GOT_ERR_BAD_PACKIDX
);
309 memcpy(h
->trailer
.packfile_hash
, p
->map
+ offset
,
311 memcpy(h
->trailer
.packidx_hash
,
312 p
->map
+ offset
+ digest_string_len
, digest_string_len
);
314 n
= read(p
->fd
, h
->trailer
.packfile_hash
, digest_string_len
);
316 err
= got_error_from_errno("read");
317 else if (n
!= digest_string_len
) {
318 err
= got_error(GOT_ERR_BAD_PACKIDX
);
321 n
= read(p
->fd
, h
->trailer
.packidx_hash
, digest_string_len
);
323 err
= got_error_from_errno("read");
324 else if (n
!= digest_string_len
) {
325 err
= got_error(GOT_ERR_BAD_PACKIDX
);
330 got_hash_update(&ctx
, h
->trailer
.packfile_hash
,
332 got_hash_final(&ctx
, hash
);
333 if (got_hash_cmp(ctx
.algo
, hash
, h
->trailer
.packidx_hash
) != 0)
334 err
= got_error(GOT_ERR_PACKIDX_CSUM
);
340 const struct got_error
*
341 got_packidx_open(struct got_packidx
**packidx
,
342 int dir_fd
, const char *relpath
, int verify
,
343 enum got_hash_algorithm algo
)
345 const struct got_error
*err
= NULL
;
346 struct got_packidx
*p
= NULL
;
348 struct stat idx_sb
, pack_sb
;
352 err
= got_packidx_get_packfile_path(&pack_relpath
, relpath
);
357 * Ensure that a corresponding pack file exists.
358 * Some Git repositories have this problem. Git seems to ignore
359 * the existence of lonely pack index files but we do not.
361 if (fstatat(dir_fd
, pack_relpath
, &pack_sb
, 0) == -1) {
363 err
= got_error_path(relpath
, GOT_ERR_LONELY_PACKIDX
);
365 err
= got_error_from_errno2("fstatat", pack_relpath
);
369 p
= calloc(1, sizeof(*p
));
371 err
= got_error_from_errno("calloc");
377 p
->fd
= openat(dir_fd
, relpath
, O_RDONLY
| O_NOFOLLOW
| O_CLOEXEC
);
379 err
= got_error_from_errno2("openat", relpath
);
383 if (fstat(p
->fd
, &idx_sb
) != 0) {
384 err
= got_error_from_errno2("fstat", relpath
);
387 p
->len
= idx_sb
.st_size
;
388 if (p
->len
< sizeof(p
->hdr
)) {
389 err
= got_error(GOT_ERR_BAD_PACKIDX
);
393 p
->path_packidx
= strdup(relpath
);
394 if (p
->path_packidx
== NULL
) {
395 err
= got_error_from_errno("strdup");
399 #ifndef GOT_PACK_NO_MMAP
400 if (p
->len
> 0 && p
->len
<= SIZE_MAX
) {
401 p
->map
= mmap(NULL
, p
->len
, PROT_READ
, MAP_PRIVATE
, p
->fd
, 0);
402 if (p
->map
== MAP_FAILED
) {
403 if (errno
!= ENOMEM
) {
404 err
= got_error_from_errno("mmap");
407 p
->map
= NULL
; /* fall back to read(2) */
412 err
= got_packidx_init_hdr(p
, verify
, pack_sb
.st_size
);
416 got_packidx_close(p
);
423 const struct got_error
*
424 got_packidx_close(struct got_packidx
*packidx
)
426 const struct got_error
*err
= NULL
;
428 free(packidx
->path_packidx
);
430 if (munmap(packidx
->map
, packidx
->len
) == -1)
431 err
= got_error_from_errno("munmap");
433 free(packidx
->hdr
.magic
);
434 free(packidx
->hdr
.version
);
435 free(packidx
->hdr
.fanout_table
);
436 free(packidx
->hdr
.sorted_ids
);
437 free(packidx
->hdr
.crc32
);
438 free(packidx
->hdr
.offsets
);
439 free(packidx
->hdr
.large_offsets
);
441 if (close(packidx
->fd
) == -1 && err
== NULL
)
442 err
= got_error_from_errno("close");
443 free(packidx
->sorted_offsets
);
444 free(packidx
->sorted_large_offsets
);
450 const struct got_error
*
451 got_packidx_get_packfile_path(char **path_packfile
, const char *path_packidx
)
455 /* Packfile path contains ".pack" instead of ".idx", so add one byte. */
456 size
= strlen(path_packidx
) + 2;
457 if (size
< GOT_PACKFILE_NAMELEN
+ 1)
458 return got_error_path(path_packidx
, GOT_ERR_BAD_PATH
);
460 *path_packfile
= malloc(size
);
461 if (*path_packfile
== NULL
)
462 return got_error_from_errno("malloc");
464 /* Copy up to and excluding ".idx". */
465 if (strlcpy(*path_packfile
, path_packidx
,
466 size
- strlen(GOT_PACKIDX_SUFFIX
) - 1) >= size
)
467 return got_error(GOT_ERR_NO_SPACE
);
469 if (strlcat(*path_packfile
, GOT_PACKFILE_SUFFIX
, size
) >= size
)
470 return got_error(GOT_ERR_NO_SPACE
);
476 got_packidx_get_object_offset(struct got_packidx
*packidx
, int idx
)
478 uint32_t offset
= be32toh(packidx
->hdr
.offsets
[idx
]);
479 if (offset
& GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
) {
481 idx
= offset
& GOT_PACKIDX_OFFSET_VAL_MASK
;
482 if (idx
< 0 || idx
>= packidx
->nlargeobj
||
483 packidx
->hdr
.large_offsets
== NULL
)
485 loffset
= be64toh(packidx
->hdr
.large_offsets
[idx
]);
486 return (loffset
> INT64_MAX
? -1 : (off_t
)loffset
);
488 return (off_t
)(offset
& GOT_PACKIDX_OFFSET_VAL_MASK
);
492 got_packidx_get_object_idx(struct got_packidx
*packidx
,
493 struct got_object_id
*id
)
495 u_int8_t id0
= id
->hash
[0];
496 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
497 int left
= 0, right
= totobj
- 1;
498 size_t digest_len
= got_hash_digest_length(packidx
->algo
);
501 left
= be32toh(packidx
->hdr
.fanout_table
[id0
- 1]);
503 while (left
<= right
) {
507 i
= ((left
+ right
) / 2);
508 oid
= packidx
->hdr
.sorted_ids
+ i
* digest_len
;
509 cmp
= memcmp(id
->hash
, oid
, digest_len
);
522 offset_cmp(const void *pa
, const void *pb
)
524 const struct got_pack_offset_index
*a
, *b
;
526 a
= (const struct got_pack_offset_index
*)pa
;
527 b
= (const struct got_pack_offset_index
*)pb
;
529 if (a
->offset
< b
->offset
)
531 else if (a
->offset
> b
->offset
)
538 large_offset_cmp(const void *pa
, const void *pb
)
540 const struct got_pack_large_offset_index
*a
, *b
;
542 a
= (const struct got_pack_large_offset_index
*)pa
;
543 b
= (const struct got_pack_large_offset_index
*)pb
;
545 if (a
->offset
< b
->offset
)
547 else if (a
->offset
> b
->offset
)
553 static const struct got_error
*
554 build_offset_index(struct got_packidx
*p
)
556 uint32_t nobj
= be32toh(p
->hdr
.fanout_table
[0xff]);
557 unsigned int i
, j
, k
;
559 p
->sorted_offsets
= calloc(nobj
- p
->nlargeobj
,
560 sizeof(p
->sorted_offsets
[0]));
561 if (p
->sorted_offsets
== NULL
)
562 return got_error_from_errno("calloc");
564 if (p
->nlargeobj
> 0) {
565 p
->sorted_large_offsets
= calloc(p
->nlargeobj
,
566 sizeof(p
->sorted_large_offsets
[0]));
567 if (p
->sorted_large_offsets
== NULL
)
568 return got_error_from_errno("calloc");
573 for (i
= 0; i
< nobj
; i
++) {
574 uint32_t offset
= be32toh(p
->hdr
.offsets
[i
]);
575 if (offset
& GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
) {
578 idx
= offset
& GOT_PACKIDX_OFFSET_VAL_MASK
;
579 if (idx
>= p
->nlargeobj
||
581 p
->hdr
.large_offsets
== NULL
)
582 return got_error(GOT_ERR_BAD_PACKIDX
);
583 loffset
= be64toh(p
->hdr
.large_offsets
[idx
]);
584 p
->sorted_large_offsets
[j
].offset
= loffset
;
585 p
->sorted_large_offsets
[j
].idx
= i
;
588 p
->sorted_offsets
[k
].offset
= offset
;
589 p
->sorted_offsets
[k
].idx
= i
;
593 if (j
!= p
->nlargeobj
|| k
!= nobj
- p
->nlargeobj
)
594 return got_error(GOT_ERR_BAD_PACKIDX
);
596 qsort(p
->sorted_offsets
, nobj
- p
->nlargeobj
,
597 sizeof(p
->sorted_offsets
[0]), offset_cmp
);
599 if (p
->sorted_large_offsets
)
600 qsort(p
->sorted_large_offsets
, p
->nlargeobj
,
601 sizeof(p
->sorted_large_offsets
[0]), large_offset_cmp
);
606 const struct got_error
*
607 got_packidx_get_offset_idx(int *idx
, struct got_packidx
*packidx
, off_t offset
)
609 const struct got_error
*err
;
610 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
615 if (packidx
->sorted_offsets
== NULL
) {
616 err
= build_offset_index(packidx
);
621 if (offset
>= 0x7fffffff) {
623 left
= 0, right
= packidx
->nlargeobj
- 1;
624 while (left
<= right
) {
625 i
= ((left
+ right
) / 2);
626 lo
= packidx
->sorted_large_offsets
[i
].offset
;
628 *idx
= packidx
->sorted_large_offsets
[i
].idx
;
630 } else if (offset
> lo
)
632 else if (offset
< lo
)
637 left
= 0, right
= totobj
- packidx
->nlargeobj
- 1;
638 while (left
<= right
) {
639 i
= ((left
+ right
) / 2);
640 o
= packidx
->sorted_offsets
[i
].offset
;
642 *idx
= packidx
->sorted_offsets
[i
].idx
;
644 } else if (offset
> o
)
654 const struct got_error
*
655 got_packidx_get_object_id(struct got_object_id
*id
,
656 struct got_packidx
*packidx
, int idx
)
658 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
660 size_t digest_len
= got_hash_digest_length(packidx
->algo
);
662 if (idx
< 0 || idx
>= totobj
)
663 return got_error(GOT_ERR_NO_OBJ
);
665 oid
= packidx
->hdr
.sorted_ids
+ idx
* digest_len
;
666 memcpy(id
->hash
, oid
, digest_len
);
667 id
->algo
= packidx
->algo
;
671 const struct got_error
*
672 got_packidx_match_id_str_prefix(struct got_object_id_queue
*matched_ids
,
673 struct got_packidx
*packidx
, const char *id_str_prefix
)
675 const struct got_error
*err
= NULL
;
677 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
679 size_t prefix_len
= strlen(id_str_prefix
);
682 size_t digest_len
= got_hash_digest_length(packidx
->algo
);
685 return got_error_path(id_str_prefix
, GOT_ERR_BAD_OBJ_ID_STR
);
687 hex
[0] = id_str_prefix
[0];
688 hex
[1] = id_str_prefix
[1];
690 if (!got_parse_xdigit(&id0
, hex
))
691 return got_error_path(id_str_prefix
, GOT_ERR_BAD_OBJ_ID_STR
);
694 i
= be32toh(packidx
->hdr
.fanout_table
[id0
- 1]);
695 oid
= packidx
->hdr
.sorted_ids
+ i
* digest_len
;
696 while (i
< totobj
&& oid
[0] == id0
) {
697 char id_str
[GOT_HASH_DIGEST_STRING_MAXLEN
];
698 struct got_object_qid
*qid
;
701 if (!got_hash_digest_to_str(oid
, id_str
, sizeof(id_str
),
703 return got_error(GOT_ERR_NO_SPACE
);
705 cmp
= strncmp(id_str
, id_str_prefix
, prefix_len
);
707 oid
= packidx
->hdr
.sorted_ids
+ (++i
) * digest_len
;
712 err
= got_object_qid_alloc_partial(&qid
);
715 memcpy(qid
->id
.hash
, oid
, digest_len
);
716 qid
->id
.algo
= packidx
->algo
;
717 STAILQ_INSERT_TAIL(matched_ids
, qid
, entry
);
719 oid
= packidx
->hdr
.sorted_ids
+ (++i
) * digest_len
;
726 set_max_datasize(void)
730 if (getrlimit(RLIMIT_DATA
, &rl
) != 0)
733 rl
.rlim_cur
= rl
.rlim_max
;
734 setrlimit(RLIMIT_DATA
, &rl
);
737 const struct got_error
*
738 got_pack_start_privsep_child(struct got_pack
*pack
, struct got_packidx
*packidx
)
740 const struct got_error
*err
= NULL
;
743 struct imsgbuf
*ibuf
;
745 ibuf
= calloc(1, sizeof(*ibuf
));
747 return got_error_from_errno("calloc");
749 pack
->privsep_child
= calloc(1, sizeof(*pack
->privsep_child
));
750 if (pack
->privsep_child
== NULL
) {
751 err
= got_error_from_errno("calloc");
755 pack
->child_has_tempfiles
= 0;
756 pack
->child_has_delta_outfd
= 0;
758 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
759 err
= got_error_from_errno("socketpair");
765 err
= got_error_from_errno("fork");
769 } else if (pid
== 0) {
771 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_PACK
,
772 pack
->path_packfile
);
776 if (close(imsg_fds
[1]) == -1) {
777 err
= got_error_from_errno("close");
781 pack
->privsep_child
->imsg_fd
= imsg_fds
[0];
782 pack
->privsep_child
->pid
= pid
;
783 if (imsgbuf_init(ibuf
, imsg_fds
[0]) == -1) {
784 err
= got_error_from_errno("imsgbuf_init");
788 imsgbuf_allow_fdpass(ibuf
);
790 pack
->privsep_child
->ibuf
= ibuf
;
792 err
= got_privsep_init_pack_child(ibuf
, pack
, packidx
);
794 const struct got_error
*child_err
;
795 err
= got_privsep_send_stop(pack
->privsep_child
->imsg_fd
);
796 child_err
= got_privsep_wait_for_child(
797 pack
->privsep_child
->pid
);
798 if (child_err
&& err
== NULL
)
805 free(pack
->privsep_child
);
806 pack
->privsep_child
= NULL
;
811 static const struct got_error
*
812 pack_stop_privsep_child(struct got_pack
*pack
)
814 const struct got_error
*err
= NULL
;
815 const struct got_error
*close_err
= NULL
, *child_err
= NULL
;
817 if (pack
->privsep_child
== NULL
)
820 err
= got_privsep_send_stop(pack
->privsep_child
->imsg_fd
);
821 if (close(pack
->privsep_child
->imsg_fd
) == -1)
822 close_err
= got_error_from_errno("close");
823 if (close_err
&& err
== NULL
)
825 child_err
= got_privsep_wait_for_child(pack
->privsep_child
->pid
);
826 if (child_err
&& err
== NULL
)
828 imsgbuf_clear(pack
->privsep_child
->ibuf
);
829 free(pack
->privsep_child
->ibuf
);
830 free(pack
->privsep_child
);
831 pack
->privsep_child
= NULL
;
835 const struct got_error
*
836 got_pack_close(struct got_pack
*pack
)
838 const struct got_error
*err
= NULL
;
840 err
= pack_stop_privsep_child(pack
);
841 if (pack
->map
&& munmap(pack
->map
, pack
->filesize
) == -1 && !err
)
842 err
= got_error_from_errno("munmap");
843 if (pack
->fd
!= -1 && close(pack
->fd
) == -1 && err
== NULL
)
844 err
= got_error_from_errno("close");
846 free(pack
->path_packfile
);
847 pack
->path_packfile
= NULL
;
849 if (pack
->delta_cache
) {
850 got_delta_cache_free(pack
->delta_cache
);
851 pack
->delta_cache
= NULL
;
855 * Leave accumfd and basefd alone. They are managed by the
856 * repository layer and can be reused.
862 const struct got_error
*
863 got_pack_parse_object_type_and_size(uint8_t *type
, uint64_t *size
, size_t *len
,
864 struct got_pack
*pack
, off_t offset
)
874 if (offset
>= pack
->filesize
)
875 return got_error(GOT_ERR_PACK_OFFSET
);
878 if (offset
> SIZE_MAX
) {
879 return got_error_fmt(GOT_ERR_PACK_OFFSET
,
880 "offset %lld overflows size_t",
884 mapoff
= (size_t)offset
;
886 if (lseek(pack
->fd
, offset
, SEEK_SET
) == -1)
887 return got_error_from_errno("lseek");
891 /* We do not support size values which don't fit in 64 bit. */
893 return got_error_fmt(GOT_ERR_OBJ_TOO_LARGE
,
894 "packfile offset %lld", (long long)offset
);
897 if (mapoff
+ sizeof(sizeN
) >= pack
->filesize
)
898 return got_error(GOT_ERR_BAD_PACKFILE
);
899 sizeN
= *(pack
->map
+ mapoff
);
900 mapoff
+= sizeof(sizeN
);
902 ssize_t n
= read(pack
->fd
, &sizeN
, sizeof(sizeN
));
904 return got_error_from_errno("read");
905 if (n
!= sizeof(sizeN
))
906 return got_error(GOT_ERR_BAD_PACKFILE
);
908 *len
+= sizeof(sizeN
);
911 t
= (sizeN
& GOT_PACK_OBJ_SIZE0_TYPE_MASK
) >>
912 GOT_PACK_OBJ_SIZE0_TYPE_MASK_SHIFT
;
913 s
= (sizeN
& GOT_PACK_OBJ_SIZE0_VAL_MASK
);
915 size_t shift
= 4 + 7 * (i
- 1);
916 s
|= ((sizeN
& GOT_PACK_OBJ_SIZE_VAL_MASK
) << shift
);
919 } while (sizeN
& GOT_PACK_OBJ_SIZE_MORE
);
926 static const struct got_error
*
927 open_plain_object(struct got_object
**obj
, struct got_object_id
*id
,
928 uint8_t type
, off_t offset
, size_t size
, int idx
)
930 *obj
= calloc(1, sizeof(**obj
));
932 return got_error_from_errno("calloc");
935 (*obj
)->flags
= GOT_OBJ_FLAG_PACKED
;
936 (*obj
)->pack_idx
= idx
;
939 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
940 (*obj
)->pack_offset
= offset
;
945 static const struct got_error
*
946 parse_negative_offset(int64_t *offset
, size_t *len
, struct got_pack
*pack
,
957 /* We do not support offset values which don't fit in 64 bit. */
959 return got_error(GOT_ERR_NO_SPACE
);
964 if (delta_offset
> SIZE_MAX
- *len
) {
965 return got_error_fmt(GOT_ERR_PACK_OFFSET
,
966 "mapoff %lld would overflow size_t",
967 (long long)delta_offset
+ *len
);
970 mapoff
= (size_t)delta_offset
+ *len
;
971 if (mapoff
+ sizeof(offN
) >= pack
->filesize
)
972 return got_error(GOT_ERR_PACK_OFFSET
);
973 offN
= *(pack
->map
+ mapoff
);
976 n
= read(pack
->fd
, &offN
, sizeof(offN
));
978 return got_error_from_errno("read");
979 if (n
!= sizeof(offN
))
980 return got_error(GOT_ERR_BAD_PACKFILE
);
982 *len
+= sizeof(offN
);
985 o
= (offN
& GOT_PACK_OBJ_DELTA_OFF_VAL_MASK
);
989 o
+= (offN
& GOT_PACK_OBJ_DELTA_OFF_VAL_MASK
);
992 } while (offN
& GOT_PACK_OBJ_DELTA_OFF_MORE
);
998 const struct got_error
*
999 got_pack_parse_offset_delta(off_t
*base_offset
, size_t *len
,
1000 struct got_pack
*pack
, off_t offset
, size_t tslen
)
1002 const struct got_error
*err
;
1008 err
= parse_negative_offset(&negoffset
, &negofflen
, pack
,
1013 /* Compute the base object's offset (must be in the same pack file). */
1014 *base_offset
= (offset
- negoffset
);
1015 if (*base_offset
<= 0)
1016 return got_error(GOT_ERR_BAD_PACKFILE
);
1022 static const struct got_error
*
1023 read_delta_data(uint8_t **delta_buf
, size_t *delta_len
,
1024 size_t *delta_compressed_len
, size_t delta_data_offset
,
1025 struct got_pack
*pack
)
1027 const struct got_error
*err
= NULL
;
1028 size_t consumed
= 0;
1031 if (delta_data_offset
>= pack
->filesize
)
1032 return got_error(GOT_ERR_PACK_OFFSET
);
1033 err
= got_inflate_to_mem_mmap(delta_buf
, delta_len
,
1034 &consumed
, NULL
, pack
->map
, delta_data_offset
,
1035 pack
->filesize
- delta_data_offset
);
1039 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
) == -1)
1040 return got_error_from_errno("lseek");
1041 err
= got_inflate_to_mem_fd(delta_buf
, delta_len
,
1042 &consumed
, NULL
, 0, pack
->fd
);
1047 if (delta_compressed_len
)
1048 *delta_compressed_len
= consumed
;
1053 static const struct got_error
*
1054 add_delta(struct got_delta_chain
*deltas
, off_t delta_offset
, size_t tslen
,
1055 int delta_type
, size_t delta_size
, off_t delta_data_offset
)
1057 struct got_delta
*delta
;
1059 delta
= got_delta_open(delta_offset
, tslen
, delta_type
, delta_size
,
1062 return got_error_from_errno("got_delta_open");
1063 /* delta is freed in got_object_close() */
1065 STAILQ_INSERT_HEAD(&deltas
->entries
, delta
, entry
);
1069 static const struct got_error
*
1070 resolve_offset_delta(struct got_delta_chain
*deltas
,
1071 struct got_packidx
*packidx
, struct got_pack
*pack
, off_t delta_offset
,
1072 size_t tslen
, int delta_type
, size_t delta_size
, unsigned int recursion
)
1074 const struct got_error
*err
;
1079 off_t delta_data_offset
;
1082 err
= got_pack_parse_offset_delta(&base_offset
, &consumed
, pack
,
1083 delta_offset
, tslen
);
1087 delta_data_offset
= delta_offset
+ tslen
+ consumed
;
1088 if (delta_data_offset
>= pack
->filesize
)
1089 return got_error(GOT_ERR_PACK_OFFSET
);
1091 if (pack
->map
== NULL
) {
1092 delta_data_offset
= lseek(pack
->fd
, 0, SEEK_CUR
);
1093 if (delta_data_offset
== -1)
1094 return got_error_from_errno("lseek");
1097 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
, delta_size
,
1102 /* An offset delta must be in the same packfile. */
1103 if (base_offset
>= pack
->filesize
)
1104 return got_error(GOT_ERR_PACK_OFFSET
);
1106 err
= got_pack_parse_object_type_and_size(&base_type
, &base_size
,
1107 &base_tslen
, pack
, base_offset
);
1111 return got_pack_resolve_delta_chain(deltas
, packidx
, pack
, base_offset
,
1112 base_tslen
, base_type
, base_size
, recursion
- 1);
1115 const struct got_error
*
1116 got_pack_parse_ref_delta(struct got_object_id
*id
,
1117 struct got_pack
*pack
, off_t delta_offset
, int tslen
)
1119 size_t digest_len
= got_hash_digest_length(pack
->algo
);
1121 memset(id
, 0, sizeof(*id
));
1122 id
->algo
= pack
->algo
;
1127 if (delta_offset
> SIZE_MAX
- tslen
) {
1128 return got_error_fmt(GOT_ERR_PACK_OFFSET
,
1129 "mapoff %lld would overflow size_t",
1130 (long long)delta_offset
+ tslen
);
1133 mapoff
= delta_offset
+ tslen
;
1134 if (mapoff
+ sizeof(*id
) >= pack
->filesize
)
1135 return got_error(GOT_ERR_PACK_OFFSET
);
1136 memcpy(id
->hash
, pack
->map
+ mapoff
, digest_len
);
1139 n
= read(pack
->fd
, id
->hash
, digest_len
);
1141 return got_error_from_errno("read");
1142 if (n
!= digest_len
)
1143 return got_error(GOT_ERR_BAD_PACKFILE
);
1149 static const struct got_error
*
1150 resolve_ref_delta(struct got_delta_chain
*deltas
, struct got_packidx
*packidx
,
1151 struct got_pack
*pack
, off_t delta_offset
, size_t tslen
, int delta_type
,
1152 size_t delta_size
, unsigned int recursion
)
1154 const struct got_error
*err
;
1155 struct got_object_id id
;
1161 off_t delta_data_offset
;
1163 if (delta_offset
+ tslen
>= pack
->filesize
)
1164 return got_error(GOT_ERR_PACK_OFFSET
);
1166 err
= got_pack_parse_ref_delta(&id
, pack
, delta_offset
, tslen
);
1170 delta_data_offset
= delta_offset
+ tslen
+
1171 got_hash_digest_length(packidx
->algo
);
1173 delta_data_offset
= lseek(pack
->fd
, 0, SEEK_CUR
);
1174 if (delta_data_offset
== -1)
1175 return got_error_from_errno("lseek");
1178 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
, delta_size
,
1183 /* Delta base must be in the same pack file. */
1184 idx
= got_packidx_get_object_idx(packidx
, &id
);
1186 return got_error(GOT_ERR_NO_OBJ
);
1188 base_offset
= got_packidx_get_object_offset(packidx
, idx
);
1189 if (base_offset
== -1)
1190 return got_error(GOT_ERR_BAD_PACKIDX
);
1192 if (base_offset
>= pack
->filesize
)
1193 return got_error(GOT_ERR_PACK_OFFSET
);
1195 err
= got_pack_parse_object_type_and_size(&base_type
, &base_size
,
1196 &base_tslen
, pack
, base_offset
);
1200 return got_pack_resolve_delta_chain(deltas
, packidx
, pack
, base_offset
,
1201 base_tslen
, base_type
, base_size
, recursion
- 1);
1204 const struct got_error
*
1205 got_pack_resolve_delta_chain(struct got_delta_chain
*deltas
,
1206 struct got_packidx
*packidx
, struct got_pack
*pack
, off_t delta_offset
,
1207 size_t tslen
, int delta_type
, size_t delta_size
, unsigned int recursion
)
1209 const struct got_error
*err
= NULL
;
1211 if (--recursion
== 0)
1212 return got_error(GOT_ERR_RECURSION
);
1214 switch (delta_type
) {
1215 case GOT_OBJ_TYPE_COMMIT
:
1216 case GOT_OBJ_TYPE_TREE
:
1217 case GOT_OBJ_TYPE_BLOB
:
1218 case GOT_OBJ_TYPE_TAG
:
1219 /* Plain types are the final delta base. Recursion ends. */
1220 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
,
1223 case GOT_OBJ_TYPE_OFFSET_DELTA
:
1224 err
= resolve_offset_delta(deltas
, packidx
, pack
,
1225 delta_offset
, tslen
, delta_type
, delta_size
, recursion
- 1);
1227 case GOT_OBJ_TYPE_REF_DELTA
:
1228 err
= resolve_ref_delta(deltas
, packidx
, pack
,
1229 delta_offset
, tslen
, delta_type
, delta_size
, recursion
- 1);
1232 return got_error(GOT_ERR_OBJ_TYPE
);
1238 static const struct got_error
*
1239 open_delta_object(struct got_object
**obj
, struct got_packidx
*packidx
,
1240 struct got_pack
*pack
, struct got_object_id
*id
, off_t offset
,
1241 size_t tslen
, int delta_type
, size_t delta_size
, int idx
)
1243 const struct got_error
*err
= NULL
;
1246 *obj
= calloc(1, sizeof(**obj
));
1248 return got_error_from_errno("calloc");
1252 (*obj
)->size
= 0; /* Not known because deltas aren't applied yet. */
1253 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
1254 (*obj
)->pack_offset
= offset
+ tslen
;
1256 STAILQ_INIT(&(*obj
)->deltas
.entries
);
1257 (*obj
)->flags
|= GOT_OBJ_FLAG_DELTIFIED
;
1258 (*obj
)->flags
|= GOT_OBJ_FLAG_PACKED
;
1259 (*obj
)->pack_idx
= idx
;
1261 err
= got_pack_resolve_delta_chain(&(*obj
)->deltas
, packidx
, pack
,
1262 offset
, tslen
, delta_type
, delta_size
,
1263 GOT_DELTA_CHAIN_RECURSION_MAX
);
1267 err
= got_delta_chain_get_base_type(&resolved_type
, &(*obj
)->deltas
);
1270 (*obj
)->type
= resolved_type
;
1273 got_object_close(*obj
);
1279 const struct got_error
*
1280 got_packfile_open_object(struct got_object
**obj
, struct got_pack
*pack
,
1281 struct got_packidx
*packidx
, int idx
, struct got_object_id
*id
)
1283 const struct got_error
*err
= NULL
;
1291 offset
= got_packidx_get_object_offset(packidx
, idx
);
1293 return got_error(GOT_ERR_BAD_PACKIDX
);
1295 err
= got_pack_parse_object_type_and_size(&type
, &size
, &tslen
,
1301 case GOT_OBJ_TYPE_COMMIT
:
1302 case GOT_OBJ_TYPE_TREE
:
1303 case GOT_OBJ_TYPE_BLOB
:
1304 case GOT_OBJ_TYPE_TAG
:
1305 err
= open_plain_object(obj
, id
, type
, offset
+ tslen
,
1308 case GOT_OBJ_TYPE_OFFSET_DELTA
:
1309 case GOT_OBJ_TYPE_REF_DELTA
:
1310 err
= open_delta_object(obj
, packidx
, pack
, id
, offset
,
1311 tslen
, type
, size
, idx
);
1314 err
= got_error(GOT_ERR_OBJ_TYPE
);
1321 const struct got_error
*
1322 got_pack_get_delta_chain_max_size(uint64_t *max_size
,
1323 struct got_delta_chain
*deltas
, struct got_pack
*pack
)
1325 struct got_delta
*delta
;
1326 uint64_t base_size
= 0, result_size
= 0;
1329 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1330 /* Plain object types are the delta base. */
1331 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1332 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1333 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1334 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1335 const struct got_error
*err
;
1336 uint8_t *delta_buf
= NULL
;
1340 if (pack
->delta_cache
) {
1341 got_delta_cache_get(&delta_buf
, &delta_len
,
1342 NULL
, NULL
, pack
->delta_cache
,
1343 delta
->data_offset
);
1345 if (delta_buf
== NULL
) {
1347 err
= read_delta_data(&delta_buf
, &delta_len
,
1348 NULL
, delta
->data_offset
, pack
);
1352 if (pack
->delta_cache
&& !cached
) {
1353 err
= got_delta_cache_add(pack
->delta_cache
,
1354 delta
->data_offset
, delta_buf
, delta_len
);
1357 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1362 err
= got_delta_get_sizes(&base_size
, &result_size
,
1363 delta_buf
, delta_len
);
1369 base_size
= delta
->size
;
1370 if (base_size
> *max_size
)
1371 *max_size
= base_size
;
1372 if (result_size
> *max_size
)
1373 *max_size
= result_size
;
1379 const struct got_error
*
1380 got_pack_get_max_delta_object_size(uint64_t *size
, struct got_object
*obj
,
1381 struct got_pack
*pack
)
1383 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0)
1384 return got_error(GOT_ERR_OBJ_TYPE
);
1386 return got_pack_get_delta_chain_max_size(size
, &obj
->deltas
, pack
);
1389 const struct got_error
*
1390 got_pack_dump_delta_chain_to_file(size_t *result_size
,
1391 struct got_delta_chain
*deltas
, struct got_pack
*pack
, FILE *outfile
,
1392 FILE *base_file
, FILE *accum_file
)
1394 const struct got_error
*err
= NULL
;
1395 struct got_delta
*delta
;
1396 uint8_t *base_buf
= NULL
, *accum_buf
= NULL
;
1397 size_t base_bufsz
= 0, accum_bufsz
= 0, accum_size
= 0;
1398 /* We process small enough files entirely in memory for speed. */
1399 const size_t max_bufsize
= GOT_DELTA_RESULT_SIZE_CACHED_MAX
;
1400 uint64_t max_size
= 0;
1405 if (STAILQ_EMPTY(&deltas
->entries
))
1406 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1408 if (pack
->delta_cache
) {
1409 uint8_t *delta_buf
= NULL
, *fulltext
= NULL
;
1410 size_t delta_len
, fulltext_len
;
1412 delta
= STAILQ_LAST(&deltas
->entries
, got_delta
, entry
);
1413 got_delta_cache_get(&delta_buf
, &delta_len
,
1414 &fulltext
, &fulltext_len
,
1415 pack
->delta_cache
, delta
->data_offset
);
1419 w
= fwrite(fulltext
, 1, fulltext_len
, outfile
);
1420 if (w
!= fulltext_len
)
1421 return got_ferror(outfile
, GOT_ERR_IO
);
1422 if (fflush(outfile
) != 0)
1423 return got_error_from_errno("fflush");
1424 *result_size
= fulltext_len
;
1429 if (fseeko(base_file
, 0L, SEEK_SET
) == -1)
1430 return got_error_from_errno("fseeko");
1431 if (fseeko(accum_file
, 0L, SEEK_SET
) == -1)
1432 return got_error_from_errno("fseeko");
1434 /* Deltas are ordered in ascending order. */
1435 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1436 uint8_t *delta_buf
= NULL
, *fulltext
= NULL
;
1437 size_t delta_len
, fulltext_len
;
1438 uint64_t base_size
, result_size
= 0;
1442 off_t delta_data_offset
;
1444 /* Plain object types are the delta base. */
1445 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1446 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1447 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1448 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1449 err
= got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1453 delta_data_offset
= delta
->offset
+ delta
->tslen
;
1454 if (delta_data_offset
>= pack
->filesize
) {
1455 err
= got_error(GOT_ERR_PACK_OFFSET
);
1458 if (pack
->map
== NULL
) {
1459 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
)
1461 err
= got_error_from_errno("lseek");
1465 if (delta
->size
> max_size
)
1466 max_size
= delta
->size
;
1467 if (max_size
> max_bufsize
) {
1469 if (delta_data_offset
> SIZE_MAX
) {
1470 return got_error_fmt(
1472 "delta offset %lld "
1478 mapoff
= delta_data_offset
;
1479 err
= got_inflate_to_file_mmap(
1480 &base_bufsz
, NULL
, NULL
, pack
->map
,
1481 mapoff
, pack
->filesize
- mapoff
,
1484 err
= got_inflate_to_file_fd(
1485 &base_bufsz
, NULL
, NULL
, pack
->fd
,
1488 accum_buf
= malloc(max_size
);
1489 if (accum_buf
== NULL
) {
1490 err
= got_error_from_errno("malloc");
1493 accum_bufsz
= max_size
;
1495 if (delta_data_offset
> SIZE_MAX
) {
1496 err
= got_error_fmt(
1498 "delta offset %lld "
1505 mapoff
= delta_data_offset
;
1506 err
= got_inflate_to_mem_mmap(&base_buf
,
1507 &base_bufsz
, NULL
, NULL
,
1509 pack
->filesize
- mapoff
);
1511 err
= got_inflate_to_mem_fd(&base_buf
,
1512 &base_bufsz
, NULL
, NULL
, max_size
,
1518 if (base_buf
== NULL
)
1520 else if (pack
->delta_cache
&& fulltext
== NULL
) {
1521 err
= got_delta_cache_add(pack
->delta_cache
,
1522 delta_data_offset
, NULL
, 0);
1524 if (err
->code
!= GOT_ERR_NO_SPACE
)
1528 err
= got_delta_cache_add_fulltext(
1531 base_buf
, base_bufsz
);
1533 err
->code
!= GOT_ERR_NO_SPACE
)
1541 if (pack
->delta_cache
) {
1542 got_delta_cache_get(&delta_buf
, &delta_len
,
1543 &fulltext
, &fulltext_len
,
1544 pack
->delta_cache
, delta
->data_offset
);
1546 if (delta_buf
== NULL
) {
1548 err
= read_delta_data(&delta_buf
, &delta_len
, NULL
,
1549 delta
->data_offset
, pack
);
1553 if (pack
->delta_cache
&& !cached
) {
1554 err
= got_delta_cache_add(pack
->delta_cache
,
1555 delta
->data_offset
, delta_buf
, delta_len
);
1558 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1564 err
= got_delta_get_sizes(&base_size
, &result_size
,
1565 delta_buf
, delta_len
);
1571 if (base_size
> max_size
)
1572 max_size
= base_size
;
1573 if (result_size
> max_size
)
1574 max_size
= result_size
;
1575 if (fulltext_len
> max_size
)
1576 max_size
= fulltext_len
;
1578 if (base_buf
&& max_size
> max_bufsize
) {
1579 /* Switch from buffers to temporary files. */
1580 size_t w
= fwrite(base_buf
, 1, base_bufsz
,
1582 if (w
!= base_bufsz
) {
1583 err
= got_ferror(outfile
, GOT_ERR_IO
);
1594 if (base_buf
&& max_size
> base_bufsz
) {
1595 uint8_t *p
= realloc(base_buf
, max_size
);
1597 err
= got_error_from_errno("realloc");
1603 base_bufsz
= max_size
;
1606 if (accum_buf
&& max_size
> accum_bufsz
) {
1607 uint8_t *p
= realloc(accum_buf
, max_size
);
1609 err
= got_error_from_errno("realloc");
1615 accum_bufsz
= max_size
;
1620 memcpy(accum_buf
, fulltext
, fulltext_len
);
1621 accum_size
= fulltext_len
;
1624 err
= got_delta_apply_in_mem(base_buf
,
1625 base_bufsz
, delta_buf
, delta_len
,
1626 accum_buf
, &accum_size
, max_size
);
1633 if (fulltext
== NULL
) {
1634 err
= got_delta_cache_add_fulltext(
1635 pack
->delta_cache
, delta
->data_offset
,
1636 accum_buf
, accum_size
);
1638 if (err
->code
!= GOT_ERR_NO_SPACE
)
1644 err
= got_delta_apply(base_file
, delta_buf
,
1646 /* Final delta application writes to output file. */
1647 ++n
< deltas
->nentries
? accum_file
: outfile
,
1655 if (n
< deltas
->nentries
) {
1656 /* Accumulated delta becomes the new base. */
1658 uint8_t *tmp
= accum_buf
;
1659 size_t tmp_size
= accum_bufsz
;
1660 accum_buf
= base_buf
;
1661 accum_bufsz
= base_bufsz
;
1663 base_bufsz
= tmp_size
;
1665 FILE *tmp
= accum_file
;
1666 accum_file
= base_file
;
1681 size_t len
= fwrite(accum_buf
, 1, accum_size
, outfile
);
1683 if (len
!= accum_size
)
1684 err
= got_ferror(outfile
, GOT_ERR_IO
);
1688 *result_size
= accum_size
;
1692 const struct got_error
*
1693 got_pack_dump_delta_chain_to_mem(uint8_t **outbuf
, size_t *outlen
,
1694 struct got_delta_chain
*deltas
, struct got_pack
*pack
)
1696 const struct got_error
*err
= NULL
;
1697 struct got_delta
*delta
;
1698 uint8_t *base_buf
= NULL
, *accum_buf
= NULL
;
1699 size_t base_bufsz
= 0, accum_bufsz
= 0, accum_size
= 0;
1700 uint64_t max_size
= 0;
1706 if (STAILQ_EMPTY(&deltas
->entries
))
1707 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1709 if (pack
->delta_cache
) {
1710 uint8_t *delta_buf
= NULL
, *fulltext
= NULL
;
1711 size_t delta_len
, fulltext_len
;
1713 delta
= STAILQ_LAST(&deltas
->entries
, got_delta
, entry
);
1714 got_delta_cache_get(&delta_buf
, &delta_len
,
1715 &fulltext
, &fulltext_len
,
1716 pack
->delta_cache
, delta
->data_offset
);
1718 *outbuf
= malloc(fulltext_len
);
1719 if (*outbuf
== NULL
)
1720 return got_error_from_errno("malloc");
1721 memcpy(*outbuf
, fulltext
, fulltext_len
);
1722 *outlen
= fulltext_len
;
1727 /* Deltas are ordered in ascending order. */
1728 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1729 uint8_t *delta_buf
= NULL
, *fulltext
= NULL
;
1730 size_t delta_len
, fulltext_len
= 0;
1731 uint64_t base_size
, result_size
= 0;
1734 off_t delta_data_offset
;
1736 /* Plain object types are the delta base. */
1737 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1738 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1739 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1740 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1741 err
= got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1745 delta_data_offset
= delta
->offset
+ delta
->tslen
;
1746 if (delta_data_offset
>= pack
->filesize
) {
1747 err
= got_error(GOT_ERR_PACK_OFFSET
);
1751 if (pack
->delta_cache
) {
1752 got_delta_cache_get(&delta_buf
, &delta_len
,
1753 &fulltext
, &fulltext_len
,
1754 pack
->delta_cache
, delta_data_offset
);
1757 if (delta
->size
> max_size
)
1758 max_size
= delta
->size
;
1759 if (delta
->size
> fulltext_len
)
1760 max_size
= fulltext_len
;
1763 base_buf
= malloc(fulltext_len
);
1764 if (base_buf
== NULL
) {
1765 err
= got_error_from_errno("malloc");
1768 memcpy(base_buf
, fulltext
, fulltext_len
);
1769 base_bufsz
= fulltext_len
;
1770 } else if (pack
->map
) {
1773 if (delta_data_offset
> SIZE_MAX
) {
1774 return got_error_fmt(GOT_ERR_RANGE
,
1775 "delta %lld offset would "
1777 (long long)delta_data_offset
);
1780 mapoff
= delta_data_offset
;
1781 err
= got_inflate_to_mem_mmap(&base_buf
,
1782 &base_bufsz
, NULL
, NULL
, pack
->map
,
1783 mapoff
, pack
->filesize
- mapoff
);
1785 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
)
1787 err
= got_error_from_errno("lseek");
1790 err
= got_inflate_to_mem_fd(&base_buf
,
1791 &base_bufsz
, NULL
, NULL
, max_size
,
1798 if (pack
->delta_cache
&& fulltext
== NULL
) {
1799 err
= got_delta_cache_add(pack
->delta_cache
,
1800 delta_data_offset
, NULL
, 0);
1802 if (err
->code
!= GOT_ERR_NO_SPACE
)
1806 err
= got_delta_cache_add_fulltext(
1809 base_buf
, base_bufsz
);
1811 err
->code
!= GOT_ERR_NO_SPACE
)
1819 if (pack
->delta_cache
) {
1820 got_delta_cache_get(&delta_buf
, &delta_len
,
1821 &fulltext
, &fulltext_len
,
1822 pack
->delta_cache
, delta
->data_offset
);
1824 if (delta_buf
== NULL
) {
1826 err
= read_delta_data(&delta_buf
, &delta_len
, NULL
,
1827 delta
->data_offset
, pack
);
1831 if (pack
->delta_cache
&& !cached
) {
1832 err
= got_delta_cache_add(pack
->delta_cache
,
1833 delta
->data_offset
, delta_buf
, delta_len
);
1836 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1842 err
= got_delta_get_sizes(&base_size
, &result_size
,
1843 delta_buf
, delta_len
);
1849 if (base_size
> max_size
)
1850 max_size
= base_size
;
1851 if (result_size
> max_size
)
1852 max_size
= result_size
;
1853 if (fulltext_len
> max_size
)
1854 max_size
= fulltext_len
;
1856 if (max_size
> base_bufsz
) {
1857 uint8_t *p
= realloc(base_buf
, max_size
);
1859 err
= got_error_from_errno("realloc");
1865 base_bufsz
= max_size
;
1868 if (max_size
> accum_bufsz
) {
1869 uint8_t *p
= realloc(accum_buf
, max_size
);
1871 err
= got_error_from_errno("realloc");
1877 accum_bufsz
= max_size
;
1881 memcpy(accum_buf
, fulltext
, fulltext_len
);
1882 accum_size
= fulltext_len
;
1885 err
= got_delta_apply_in_mem(base_buf
, base_bufsz
,
1886 delta_buf
, delta_len
, accum_buf
,
1887 &accum_size
, max_size
);
1895 if (fulltext
== NULL
) {
1896 err
= got_delta_cache_add_fulltext(pack
->delta_cache
,
1897 delta
->data_offset
, accum_buf
, accum_size
);
1899 if (err
->code
!= GOT_ERR_NO_SPACE
)
1905 if (n
< deltas
->nentries
) {
1906 /* Accumulated delta becomes the new base. */
1907 uint8_t *tmp
= accum_buf
;
1908 size_t tmp_size
= accum_bufsz
;
1909 accum_buf
= base_buf
;
1910 accum_bufsz
= base_bufsz
;
1912 base_bufsz
= tmp_size
;
1923 *outbuf
= accum_buf
;
1924 *outlen
= accum_size
;
1929 const struct got_error
*
1930 got_packfile_extract_object(struct got_pack
*pack
, struct got_object
*obj
,
1931 FILE *outfile
, FILE *base_file
, FILE *accum_file
)
1933 const struct got_error
*err
= NULL
;
1935 if ((obj
->flags
& GOT_OBJ_FLAG_PACKED
) == 0)
1936 return got_error(GOT_ERR_OBJ_NOT_PACKED
);
1938 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0) {
1939 if (obj
->pack_offset
>= pack
->filesize
)
1940 return got_error(GOT_ERR_PACK_OFFSET
);
1945 if (obj
->pack_offset
> SIZE_MAX
) {
1946 return got_error_fmt(GOT_ERR_RANGE
,
1947 "pack offset %lld would overflow size_t",
1948 (long long)obj
->pack_offset
);
1951 mapoff
= obj
->pack_offset
;
1952 err
= got_inflate_to_file_mmap(&obj
->size
, NULL
, NULL
,
1953 pack
->map
, mapoff
, pack
->filesize
- mapoff
,
1956 if (lseek(pack
->fd
, obj
->pack_offset
, SEEK_SET
) == -1)
1957 return got_error_from_errno("lseek");
1958 err
= got_inflate_to_file_fd(&obj
->size
, NULL
, NULL
,
1962 err
= got_pack_dump_delta_chain_to_file(&obj
->size
,
1963 &obj
->deltas
, pack
, outfile
, base_file
, accum_file
);
1968 const struct got_error
*
1969 got_packfile_extract_object_to_mem(uint8_t **buf
, size_t *len
,
1970 struct got_object
*obj
, struct got_pack
*pack
)
1972 const struct got_error
*err
= NULL
;
1974 if ((obj
->flags
& GOT_OBJ_FLAG_PACKED
) == 0)
1975 return got_error(GOT_ERR_OBJ_NOT_PACKED
);
1977 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0) {
1978 if (obj
->pack_offset
>= pack
->filesize
)
1979 return got_error(GOT_ERR_PACK_OFFSET
);
1983 if (obj
->pack_offset
> SIZE_MAX
) {
1984 return got_error_fmt(GOT_ERR_RANGE
,
1985 "pack offset %lld would overflow size_t",
1986 (long long)obj
->pack_offset
);
1989 mapoff
= obj
->pack_offset
;
1990 err
= got_inflate_to_mem_mmap(buf
, len
, NULL
, NULL
,
1991 pack
->map
, mapoff
, pack
->filesize
- mapoff
);
1993 if (lseek(pack
->fd
, obj
->pack_offset
, SEEK_SET
) == -1)
1994 return got_error_from_errno("lseek");
1995 err
= got_inflate_to_mem_fd(buf
, len
, NULL
, NULL
,
1996 obj
->size
, pack
->fd
);
1999 err
= got_pack_dump_delta_chain_to_mem(buf
, len
, &obj
->deltas
,
2005 static const struct got_error
*
2006 read_raw_delta_data(uint8_t **delta_buf
, size_t *delta_len
,
2007 size_t *delta_len_compressed
, uint64_t *base_size
, uint64_t *result_size
,
2008 off_t delta_data_offset
, struct got_pack
*pack
, struct got_packidx
*packidx
)
2010 const struct got_error
*err
= NULL
;
2012 /* Validate decompression and obtain the decompressed size. */
2013 err
= read_delta_data(delta_buf
, delta_len
, delta_len_compressed
,
2014 delta_data_offset
, pack
);
2018 /* Read delta base/result sizes from head of delta stream. */
2019 err
= got_delta_get_sizes(base_size
, result_size
,
2020 *delta_buf
, *delta_len
);
2024 /* Discard decompressed delta and read it again in compressed form. */
2026 *delta_buf
= malloc(*delta_len_compressed
);
2027 if (*delta_buf
== NULL
) {
2028 err
= got_error_from_errno("malloc");
2032 if (delta_data_offset
>= pack
->filesize
) {
2033 err
= got_error(GOT_ERR_PACK_OFFSET
);
2036 memcpy(*delta_buf
, pack
->map
+ delta_data_offset
,
2037 *delta_len_compressed
);
2040 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
) == -1) {
2041 err
= got_error_from_errno("lseek");
2044 n
= read(pack
->fd
, *delta_buf
, *delta_len_compressed
);
2046 err
= got_error_from_errno("read");
2048 } else if (n
!= *delta_len_compressed
) {
2049 err
= got_error(GOT_ERR_IO
);
2058 *delta_len_compressed
= 0;
2065 const struct got_error
*
2066 got_packfile_extract_raw_delta(uint8_t **delta_buf
, size_t *delta_size
,
2067 size_t *delta_compressed_size
, off_t
*delta_offset
,
2068 off_t
*delta_data_offset
, off_t
*base_offset
,
2069 struct got_object_id
*base_id
, uint64_t *base_size
, uint64_t *result_size
,
2070 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
)
2072 const struct got_error
*err
= NULL
;
2076 size_t tslen
, delta_hdrlen
;
2080 *delta_compressed_size
= 0;
2082 *delta_data_offset
= 0;
2087 offset
= got_packidx_get_object_offset(packidx
, idx
);
2089 return got_error(GOT_ERR_BAD_PACKIDX
);
2091 if (offset
>= pack
->filesize
)
2092 return got_error(GOT_ERR_PACK_OFFSET
);
2094 err
= got_pack_parse_object_type_and_size(&type
, &size
, &tslen
,
2099 if (tslen
+ size
< tslen
|| offset
+ size
< size
||
2100 tslen
+ offset
< tslen
)
2101 return got_error(GOT_ERR_PACK_OFFSET
);
2104 case GOT_OBJ_TYPE_OFFSET_DELTA
:
2105 err
= got_pack_parse_offset_delta(base_offset
, &delta_hdrlen
,
2106 pack
, offset
, tslen
);
2110 case GOT_OBJ_TYPE_REF_DELTA
:
2111 err
= got_pack_parse_ref_delta(base_id
, pack
, offset
, tslen
);
2114 delta_hdrlen
= got_hash_digest_length(pack
->algo
);
2117 return got_error_fmt(GOT_ERR_OBJ_TYPE
,
2118 "non-delta object type %d found at offset %lld",
2119 type
, (long long)offset
);
2122 if (tslen
+ delta_hdrlen
< delta_hdrlen
||
2123 offset
+ delta_hdrlen
< delta_hdrlen
)
2124 return got_error(GOT_ERR_BAD_DELTA
);
2126 *delta_data_offset
= offset
+ tslen
+ delta_hdrlen
;
2127 err
= read_raw_delta_data(delta_buf
, delta_size
, delta_compressed_size
,
2128 base_size
, result_size
, *delta_data_offset
, pack
, packidx
);
2132 if (*delta_size
!= size
) {
2133 err
= got_error(GOT_ERR_BAD_DELTA
);
2137 *delta_offset
= offset
;
2143 *delta_compressed_size
= 0;