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.
17 #include <sys/types.h>
19 #include <sys/queue.h>
22 #include <sys/resource.h>
23 #include <sys/socket.h>
35 #include "got_error.h"
36 #include "got_object.h"
39 #include "got_lib_hash.h"
40 #include "got_lib_delta.h"
41 #include "got_lib_delta_cache.h"
42 #include "got_lib_inflate.h"
43 #include "got_lib_object.h"
44 #include "got_lib_object_parse.h"
45 #include "got_lib_privsep.h"
46 #include "got_lib_pack.h"
49 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
53 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
56 static const struct got_error
*
57 verify_fanout_table(uint32_t *fanout_table
)
61 for (i
= 0; i
< 0xff - 1; i
++) {
62 if (be32toh(fanout_table
[i
]) > be32toh(fanout_table
[i
+ 1]))
63 return got_error(GOT_ERR_BAD_PACKIDX
);
69 const struct got_error
*
70 got_packidx_init_hdr(struct got_packidx
*p
, int verify
, off_t packfile_size
)
72 const struct got_error
*err
= NULL
;
73 enum got_hash_algorithm algo
= GOT_HASH_SHA1
;
74 struct got_packidx_v2_hdr
*h
;
76 uint8_t hash
[GOT_HASH_DIGEST_MAXLEN
];
77 size_t nobj
, len_fanout
, len_ids
, offset
, remain
;
81 got_hash_init(&ctx
, algo
);
87 if (remain
< sizeof(*h
->magic
)) {
88 err
= got_error(GOT_ERR_BAD_PACKIDX
);
92 h
->magic
= (uint32_t *)(p
->map
+ offset
);
94 h
->magic
= malloc(sizeof(*h
->magic
));
95 if (h
->magic
== NULL
) {
96 err
= got_error_from_errno("malloc");
99 n
= read(p
->fd
, h
->magic
, sizeof(*h
->magic
));
101 err
= got_error_from_errno("read");
103 } else if (n
!= sizeof(*h
->magic
)) {
104 err
= got_error(GOT_ERR_BAD_PACKIDX
);
108 if (*h
->magic
!= htobe32(GOT_PACKIDX_V2_MAGIC
)) {
109 err
= got_error(GOT_ERR_BAD_PACKIDX
);
112 offset
+= sizeof(*h
->magic
);
113 remain
-= sizeof(*h
->magic
);
116 got_hash_update(&ctx
, h
->magic
, sizeof(*h
->magic
));
118 if (remain
< sizeof(*h
->version
)) {
119 err
= got_error(GOT_ERR_BAD_PACKIDX
);
123 h
->version
= (uint32_t *)(p
->map
+ offset
);
125 h
->version
= malloc(sizeof(*h
->version
));
126 if (h
->version
== NULL
) {
127 err
= got_error_from_errno("malloc");
130 n
= read(p
->fd
, h
->version
, sizeof(*h
->version
));
132 err
= got_error_from_errno("read");
134 } else if (n
!= sizeof(*h
->version
)) {
135 err
= got_error(GOT_ERR_BAD_PACKIDX
);
139 if (*h
->version
!= htobe32(GOT_PACKIDX_VERSION
)) {
140 err
= got_error(GOT_ERR_BAD_PACKIDX
);
143 offset
+= sizeof(*h
->version
);
144 remain
-= sizeof(*h
->version
);
147 got_hash_update(&ctx
, h
->version
, sizeof(*h
->version
));
150 sizeof(*h
->fanout_table
) * GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS
;
151 if (remain
< len_fanout
) {
152 err
= got_error(GOT_ERR_BAD_PACKIDX
);
156 h
->fanout_table
= (uint32_t *)(p
->map
+ offset
);
158 h
->fanout_table
= malloc(len_fanout
);
159 if (h
->fanout_table
== NULL
) {
160 err
= got_error_from_errno("malloc");
163 n
= read(p
->fd
, h
->fanout_table
, len_fanout
);
165 err
= got_error_from_errno("read");
167 } else if (n
!= len_fanout
) {
168 err
= got_error(GOT_ERR_BAD_PACKIDX
);
172 err
= verify_fanout_table(h
->fanout_table
);
176 got_hash_update(&ctx
, h
->fanout_table
, len_fanout
);
177 offset
+= len_fanout
;
178 remain
-= len_fanout
;
180 nobj
= be32toh(h
->fanout_table
[0xff]);
181 len_ids
= nobj
* sizeof(*h
->sorted_ids
);
182 if (len_ids
<= nobj
|| len_ids
> remain
) {
183 err
= got_error(GOT_ERR_BAD_PACKIDX
);
188 (struct got_packidx_object_id
*)((uint8_t*)(p
->map
+ offset
));
190 h
->sorted_ids
= malloc(len_ids
);
191 if (h
->sorted_ids
== NULL
) {
192 err
= got_error(GOT_ERR_BAD_PACKIDX
);
195 n
= read(p
->fd
, h
->sorted_ids
, len_ids
);
197 err
= got_error_from_errno("read");
198 else if (n
!= len_ids
) {
199 err
= got_error(GOT_ERR_BAD_PACKIDX
);
204 got_hash_update(&ctx
, h
->sorted_ids
, len_ids
);
208 if (remain
< nobj
* sizeof(*h
->crc32
)) {
209 err
= got_error(GOT_ERR_BAD_PACKIDX
);
213 h
->crc32
= (uint32_t *)((uint8_t*)(p
->map
+ offset
));
215 h
->crc32
= malloc(nobj
* sizeof(*h
->crc32
));
216 if (h
->crc32
== NULL
) {
217 err
= got_error_from_errno("malloc");
220 n
= read(p
->fd
, h
->crc32
, nobj
* sizeof(*h
->crc32
));
222 err
= got_error_from_errno("read");
223 else if (n
!= nobj
* sizeof(*h
->crc32
)) {
224 err
= got_error(GOT_ERR_BAD_PACKIDX
);
229 got_hash_update(&ctx
, h
->crc32
, nobj
* sizeof(*h
->crc32
));
230 remain
-= nobj
* sizeof(*h
->crc32
);
231 offset
+= nobj
* sizeof(*h
->crc32
);
233 if (remain
< nobj
* sizeof(*h
->offsets
)) {
234 err
= got_error(GOT_ERR_BAD_PACKIDX
);
238 h
->offsets
= (uint32_t *)((uint8_t*)(p
->map
+ offset
));
240 h
->offsets
= malloc(nobj
* sizeof(*h
->offsets
));
241 if (h
->offsets
== NULL
) {
242 err
= got_error_from_errno("malloc");
245 n
= read(p
->fd
, h
->offsets
, nobj
* sizeof(*h
->offsets
));
247 err
= got_error_from_errno("read");
248 else if (n
!= nobj
* sizeof(*h
->offsets
)) {
249 err
= got_error(GOT_ERR_BAD_PACKIDX
);
254 got_hash_update(&ctx
, h
->offsets
, nobj
* sizeof(*h
->offsets
));
255 remain
-= nobj
* sizeof(*h
->offsets
);
256 offset
+= nobj
* sizeof(*h
->offsets
);
258 /* Large file offsets are contained only in files > 2GB. */
259 if (verify
|| packfile_size
> 0x7fffffff) {
260 for (i
= 0; i
< nobj
; i
++) {
261 uint32_t o
= h
->offsets
[i
];
262 if (o
& htobe32(GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
))
266 if (p
->nlargeobj
== 0)
268 else if (packfile_size
<= 0x7fffffff) {
269 err
= got_error(GOT_ERR_BAD_PACKIDX
);
273 if (remain
< p
->nlargeobj
* sizeof(*h
->large_offsets
)) {
274 err
= got_error(GOT_ERR_BAD_PACKIDX
);
278 h
->large_offsets
= (uint64_t *)((uint8_t*)(p
->map
+ offset
));
280 h
->large_offsets
= malloc(p
->nlargeobj
*
281 sizeof(*h
->large_offsets
));
282 if (h
->large_offsets
== NULL
) {
283 err
= got_error_from_errno("malloc");
286 n
= read(p
->fd
, h
->large_offsets
,
287 p
->nlargeobj
* sizeof(*h
->large_offsets
));
289 err
= got_error_from_errno("read");
290 else if (n
!= p
->nlargeobj
* sizeof(*h
->large_offsets
)) {
291 err
= got_error(GOT_ERR_BAD_PACKIDX
);
296 got_hash_update(&ctx
, h
->large_offsets
,
297 p
->nlargeobj
* sizeof(*h
->large_offsets
));
298 remain
-= p
->nlargeobj
* sizeof(*h
->large_offsets
);
299 offset
+= p
->nlargeobj
* sizeof(*h
->large_offsets
);
302 if (remain
< sizeof(*h
->trailer
)) {
303 err
= got_error(GOT_ERR_BAD_PACKIDX
);
308 (struct got_packidx_trailer
*)((uint8_t*)(p
->map
+ offset
));
310 h
->trailer
= malloc(sizeof(*h
->trailer
));
311 if (h
->trailer
== NULL
) {
312 err
= got_error_from_errno("malloc");
315 n
= read(p
->fd
, h
->trailer
, sizeof(*h
->trailer
));
317 err
= got_error_from_errno("read");
318 else if (n
!= sizeof(*h
->trailer
)) {
319 err
= got_error(GOT_ERR_BAD_PACKIDX
);
324 got_hash_update(&ctx
, h
->trailer
->packfile_sha1
,
326 got_hash_final(&ctx
, hash
);
327 if (got_hash_cmp(ctx
.algo
, hash
, h
->trailer
->packidx_sha1
)
329 err
= got_error(GOT_ERR_PACKIDX_CSUM
);
335 const struct got_error
*
336 got_packidx_open(struct got_packidx
**packidx
,
337 int dir_fd
, const char *relpath
, int verify
)
339 const struct got_error
*err
= NULL
;
340 struct got_packidx
*p
= NULL
;
342 struct stat idx_sb
, pack_sb
;
346 err
= got_packidx_get_packfile_path(&pack_relpath
, relpath
);
351 * Ensure that a corresponding pack file exists.
352 * Some Git repositories have this problem. Git seems to ignore
353 * the existence of lonely pack index files but we do not.
355 if (fstatat(dir_fd
, pack_relpath
, &pack_sb
, 0) == -1) {
356 if (errno
== ENOENT
) {
357 err
= got_error_fmt(GOT_ERR_LONELY_PACKIDX
,
360 err
= got_error_from_errno2("fstatat", pack_relpath
);
364 p
= calloc(1, sizeof(*p
));
366 err
= got_error_from_errno("calloc");
370 p
->fd
= openat(dir_fd
, relpath
, O_RDONLY
| O_NOFOLLOW
| O_CLOEXEC
);
372 err
= got_error_from_errno2("openat", relpath
);
376 if (fstat(p
->fd
, &idx_sb
) != 0) {
377 err
= got_error_from_errno2("fstat", relpath
);
380 p
->len
= idx_sb
.st_size
;
381 if (p
->len
< sizeof(p
->hdr
)) {
382 err
= got_error(GOT_ERR_BAD_PACKIDX
);
386 p
->path_packidx
= strdup(relpath
);
387 if (p
->path_packidx
== NULL
) {
388 err
= got_error_from_errno("strdup");
392 #ifndef GOT_PACK_NO_MMAP
393 if (p
->len
> 0 && p
->len
<= SIZE_MAX
) {
394 p
->map
= mmap(NULL
, p
->len
, PROT_READ
, MAP_PRIVATE
, p
->fd
, 0);
395 if (p
->map
== MAP_FAILED
) {
396 if (errno
!= ENOMEM
) {
397 err
= got_error_from_errno("mmap");
400 p
->map
= NULL
; /* fall back to read(2) */
405 err
= got_packidx_init_hdr(p
, verify
, pack_sb
.st_size
);
409 got_packidx_close(p
);
416 const struct got_error
*
417 got_packidx_close(struct got_packidx
*packidx
)
419 const struct got_error
*err
= NULL
;
421 free(packidx
->path_packidx
);
423 if (munmap(packidx
->map
, packidx
->len
) == -1)
424 err
= got_error_from_errno("munmap");
426 free(packidx
->hdr
.magic
);
427 free(packidx
->hdr
.version
);
428 free(packidx
->hdr
.fanout_table
);
429 free(packidx
->hdr
.sorted_ids
);
430 free(packidx
->hdr
.crc32
);
431 free(packidx
->hdr
.offsets
);
432 free(packidx
->hdr
.large_offsets
);
433 free(packidx
->hdr
.trailer
);
435 if (close(packidx
->fd
) == -1 && err
== NULL
)
436 err
= got_error_from_errno("close");
437 free(packidx
->sorted_offsets
);
438 free(packidx
->sorted_large_offsets
);
444 const struct got_error
*
445 got_packidx_get_packfile_path(char **path_packfile
, const char *path_packidx
)
449 /* Packfile path contains ".pack" instead of ".idx", so add one byte. */
450 size
= strlen(path_packidx
) + 2;
451 if (size
< GOT_PACKFILE_NAMELEN
+ 1)
452 return got_error_path(path_packidx
, GOT_ERR_BAD_PATH
);
454 *path_packfile
= malloc(size
);
455 if (*path_packfile
== NULL
)
456 return got_error_from_errno("malloc");
458 /* Copy up to and excluding ".idx". */
459 if (strlcpy(*path_packfile
, path_packidx
,
460 size
- strlen(GOT_PACKIDX_SUFFIX
) - 1) >= size
)
461 return got_error(GOT_ERR_NO_SPACE
);
463 if (strlcat(*path_packfile
, GOT_PACKFILE_SUFFIX
, size
) >= size
)
464 return got_error(GOT_ERR_NO_SPACE
);
470 got_packidx_get_object_offset(struct got_packidx
*packidx
, int idx
)
472 uint32_t offset
= be32toh(packidx
->hdr
.offsets
[idx
]);
473 if (offset
& GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
) {
475 idx
= offset
& GOT_PACKIDX_OFFSET_VAL_MASK
;
476 if (idx
< 0 || idx
>= packidx
->nlargeobj
||
477 packidx
->hdr
.large_offsets
== NULL
)
479 loffset
= be64toh(packidx
->hdr
.large_offsets
[idx
]);
480 return (loffset
> INT64_MAX
? -1 : (off_t
)loffset
);
482 return (off_t
)(offset
& GOT_PACKIDX_OFFSET_VAL_MASK
);
486 got_packidx_get_object_idx(struct got_packidx
*packidx
,
487 struct got_object_id
*id
)
489 u_int8_t id0
= id
->sha1
[0];
490 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
491 int left
= 0, right
= totobj
- 1;
494 left
= be32toh(packidx
->hdr
.fanout_table
[id0
- 1]);
496 while (left
<= right
) {
497 struct got_packidx_object_id
*oid
;
500 i
= ((left
+ right
) / 2);
501 oid
= &packidx
->hdr
.sorted_ids
[i
];
502 cmp
= memcmp(id
->sha1
, oid
->sha1
, SHA1_DIGEST_LENGTH
);
515 offset_cmp(const void *pa
, const void *pb
)
517 const struct got_pack_offset_index
*a
, *b
;
519 a
= (const struct got_pack_offset_index
*)pa
;
520 b
= (const struct got_pack_offset_index
*)pb
;
522 if (a
->offset
< b
->offset
)
524 else if (a
->offset
> b
->offset
)
531 large_offset_cmp(const void *pa
, const void *pb
)
533 const struct got_pack_large_offset_index
*a
, *b
;
535 a
= (const struct got_pack_large_offset_index
*)pa
;
536 b
= (const struct got_pack_large_offset_index
*)pb
;
538 if (a
->offset
< b
->offset
)
540 else if (a
->offset
> b
->offset
)
546 static const struct got_error
*
547 build_offset_index(struct got_packidx
*p
)
549 uint32_t nobj
= be32toh(p
->hdr
.fanout_table
[0xff]);
550 unsigned int i
, j
, k
;
552 p
->sorted_offsets
= calloc(nobj
- p
->nlargeobj
,
553 sizeof(p
->sorted_offsets
[0]));
554 if (p
->sorted_offsets
== NULL
)
555 return got_error_from_errno("calloc");
557 if (p
->nlargeobj
> 0) {
558 p
->sorted_large_offsets
= calloc(p
->nlargeobj
,
559 sizeof(p
->sorted_large_offsets
[0]));
560 if (p
->sorted_large_offsets
== NULL
)
561 return got_error_from_errno("calloc");
566 for (i
= 0; i
< nobj
; i
++) {
567 uint32_t offset
= be32toh(p
->hdr
.offsets
[i
]);
568 if (offset
& GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
) {
571 idx
= offset
& GOT_PACKIDX_OFFSET_VAL_MASK
;
572 if (idx
>= p
->nlargeobj
||
574 p
->hdr
.large_offsets
== NULL
)
575 return got_error(GOT_ERR_BAD_PACKIDX
);
576 loffset
= be64toh(p
->hdr
.large_offsets
[idx
]);
577 p
->sorted_large_offsets
[j
].offset
= loffset
;
578 p
->sorted_large_offsets
[j
].idx
= i
;
581 p
->sorted_offsets
[k
].offset
= offset
;
582 p
->sorted_offsets
[k
].idx
= i
;
586 if (j
!= p
->nlargeobj
|| k
!= nobj
- p
->nlargeobj
)
587 return got_error(GOT_ERR_BAD_PACKIDX
);
589 qsort(p
->sorted_offsets
, nobj
- p
->nlargeobj
,
590 sizeof(p
->sorted_offsets
[0]), offset_cmp
);
592 if (p
->sorted_large_offsets
)
593 qsort(p
->sorted_large_offsets
, p
->nlargeobj
,
594 sizeof(p
->sorted_large_offsets
[0]), large_offset_cmp
);
599 const struct got_error
*
600 got_packidx_get_offset_idx(int *idx
, struct got_packidx
*packidx
, off_t offset
)
602 const struct got_error
*err
;
603 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
608 if (packidx
->sorted_offsets
== NULL
) {
609 err
= build_offset_index(packidx
);
614 if (offset
>= 0x7fffffff) {
616 left
= 0, right
= packidx
->nlargeobj
- 1;
617 while (left
<= right
) {
618 i
= ((left
+ right
) / 2);
619 lo
= packidx
->sorted_large_offsets
[i
].offset
;
621 *idx
= packidx
->sorted_large_offsets
[i
].idx
;
623 } else if (offset
> lo
)
625 else if (offset
< lo
)
630 left
= 0, right
= totobj
- packidx
->nlargeobj
- 1;
631 while (left
<= right
) {
632 i
= ((left
+ right
) / 2);
633 o
= packidx
->sorted_offsets
[i
].offset
;
635 *idx
= packidx
->sorted_offsets
[i
].idx
;
637 } else if (offset
> o
)
647 const struct got_error
*
648 got_packidx_get_object_id(struct got_object_id
*id
,
649 struct got_packidx
*packidx
, int idx
)
651 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
652 struct got_packidx_object_id
*oid
;
654 if (idx
< 0 || idx
>= totobj
)
655 return got_error(GOT_ERR_NO_OBJ
);
657 oid
= &packidx
->hdr
.sorted_ids
[idx
];
658 memcpy(id
->sha1
, oid
->sha1
, SHA1_DIGEST_LENGTH
);
662 const struct got_error
*
663 got_packidx_match_id_str_prefix(struct got_object_id_queue
*matched_ids
,
664 struct got_packidx
*packidx
, const char *id_str_prefix
)
666 const struct got_error
*err
= NULL
;
668 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
670 size_t prefix_len
= strlen(id_str_prefix
);
671 struct got_packidx_object_id
*oid
;
674 STAILQ_INIT(matched_ids
);
677 return got_error_path(id_str_prefix
, GOT_ERR_BAD_OBJ_ID_STR
);
679 hex
[0] = id_str_prefix
[0];
680 hex
[1] = id_str_prefix
[1];
682 if (!got_parse_xdigit(&id0
, hex
))
683 return got_error_path(id_str_prefix
, GOT_ERR_BAD_OBJ_ID_STR
);
686 i
= be32toh(packidx
->hdr
.fanout_table
[id0
- 1]);
687 oid
= &packidx
->hdr
.sorted_ids
[i
];
688 while (i
< totobj
&& oid
->sha1
[0] == id0
) {
689 char id_str
[SHA1_DIGEST_STRING_LENGTH
];
690 struct got_object_qid
*qid
;
693 if (!got_sha1_digest_to_str(oid
->sha1
, id_str
, sizeof(id_str
)))
694 return got_error(GOT_ERR_NO_SPACE
);
696 cmp
= strncmp(id_str
, id_str_prefix
, prefix_len
);
698 oid
= &packidx
->hdr
.sorted_ids
[++i
];
703 err
= got_object_qid_alloc_partial(&qid
);
706 memcpy(qid
->id
.sha1
, oid
->sha1
, SHA1_DIGEST_LENGTH
);
707 STAILQ_INSERT_TAIL(matched_ids
, qid
, entry
);
709 oid
= &packidx
->hdr
.sorted_ids
[++i
];
713 got_object_id_queue_free(matched_ids
);
718 set_max_datasize(void)
722 if (getrlimit(RLIMIT_DATA
, &rl
) != 0)
725 rl
.rlim_cur
= rl
.rlim_max
;
726 setrlimit(RLIMIT_DATA
, &rl
);
729 const struct got_error
*
730 got_pack_start_privsep_child(struct got_pack
*pack
, struct got_packidx
*packidx
)
732 const struct got_error
*err
= NULL
;
735 struct imsgbuf
*ibuf
;
737 ibuf
= calloc(1, sizeof(*ibuf
));
739 return got_error_from_errno("calloc");
741 pack
->privsep_child
= calloc(1, sizeof(*pack
->privsep_child
));
742 if (pack
->privsep_child
== NULL
) {
743 err
= got_error_from_errno("calloc");
747 pack
->child_has_tempfiles
= 0;
748 pack
->child_has_delta_outfd
= 0;
750 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
751 err
= got_error_from_errno("socketpair");
757 err
= got_error_from_errno("fork");
759 } else if (pid
== 0) {
761 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_PACK
,
762 pack
->path_packfile
);
766 if (close(imsg_fds
[1]) == -1)
767 return got_error_from_errno("close");
768 pack
->privsep_child
->imsg_fd
= imsg_fds
[0];
769 pack
->privsep_child
->pid
= pid
;
770 imsg_init(ibuf
, imsg_fds
[0]);
771 pack
->privsep_child
->ibuf
= ibuf
;
773 err
= got_privsep_init_pack_child(ibuf
, pack
, packidx
);
775 const struct got_error
*child_err
;
776 err
= got_privsep_send_stop(pack
->privsep_child
->imsg_fd
);
777 child_err
= got_privsep_wait_for_child(
778 pack
->privsep_child
->pid
);
779 if (child_err
&& err
== NULL
)
785 free(pack
->privsep_child
);
786 pack
->privsep_child
= NULL
;
791 static const struct got_error
*
792 pack_stop_privsep_child(struct got_pack
*pack
)
794 const struct got_error
*err
= NULL
, *close_err
= NULL
;
796 if (pack
->privsep_child
== NULL
)
799 err
= got_privsep_send_stop(pack
->privsep_child
->imsg_fd
);
802 if (close(pack
->privsep_child
->imsg_fd
) == -1)
803 close_err
= got_error_from_errno("close");
804 err
= got_privsep_wait_for_child(pack
->privsep_child
->pid
);
805 if (close_err
&& err
== NULL
)
807 imsg_clear(pack
->privsep_child
->ibuf
);
808 free(pack
->privsep_child
->ibuf
);
809 free(pack
->privsep_child
);
810 pack
->privsep_child
= NULL
;
814 const struct got_error
*
815 got_pack_close(struct got_pack
*pack
)
817 const struct got_error
*err
= NULL
;
819 err
= pack_stop_privsep_child(pack
);
820 if (pack
->map
&& munmap(pack
->map
, pack
->filesize
) == -1 && !err
)
821 err
= got_error_from_errno("munmap");
822 if (pack
->fd
!= -1 && close(pack
->fd
) == -1 && err
== NULL
)
823 err
= got_error_from_errno("close");
825 free(pack
->path_packfile
);
826 pack
->path_packfile
= NULL
;
828 if (pack
->delta_cache
) {
829 got_delta_cache_free(pack
->delta_cache
);
830 pack
->delta_cache
= NULL
;
834 * Leave accumfd and basefd alone. They are managed by the
835 * repository layer and can be reused.
841 const struct got_error
*
842 got_pack_parse_object_type_and_size(uint8_t *type
, uint64_t *size
, size_t *len
,
843 struct got_pack
*pack
, off_t offset
)
853 if (offset
>= pack
->filesize
)
854 return got_error(GOT_ERR_PACK_OFFSET
);
857 if (offset
> SIZE_MAX
) {
858 return got_error_fmt(GOT_ERR_PACK_OFFSET
,
859 "offset %lld overflows size_t",
863 mapoff
= (size_t)offset
;
865 if (lseek(pack
->fd
, offset
, SEEK_SET
) == -1)
866 return got_error_from_errno("lseek");
870 /* We do not support size values which don't fit in 64 bit. */
872 return got_error_fmt(GOT_ERR_OBJ_TOO_LARGE
,
873 "packfile offset %lld", (long long)offset
);
876 if (mapoff
+ sizeof(sizeN
) >= pack
->filesize
)
877 return got_error(GOT_ERR_BAD_PACKFILE
);
878 sizeN
= *(pack
->map
+ mapoff
);
879 mapoff
+= sizeof(sizeN
);
881 ssize_t n
= read(pack
->fd
, &sizeN
, sizeof(sizeN
));
883 return got_error_from_errno("read");
884 if (n
!= sizeof(sizeN
))
885 return got_error(GOT_ERR_BAD_PACKFILE
);
887 *len
+= sizeof(sizeN
);
890 t
= (sizeN
& GOT_PACK_OBJ_SIZE0_TYPE_MASK
) >>
891 GOT_PACK_OBJ_SIZE0_TYPE_MASK_SHIFT
;
892 s
= (sizeN
& GOT_PACK_OBJ_SIZE0_VAL_MASK
);
894 size_t shift
= 4 + 7 * (i
- 1);
895 s
|= ((sizeN
& GOT_PACK_OBJ_SIZE_VAL_MASK
) << shift
);
898 } while (sizeN
& GOT_PACK_OBJ_SIZE_MORE
);
905 static const struct got_error
*
906 open_plain_object(struct got_object
**obj
, struct got_object_id
*id
,
907 uint8_t type
, off_t offset
, size_t size
, int idx
)
909 *obj
= calloc(1, sizeof(**obj
));
911 return got_error_from_errno("calloc");
914 (*obj
)->flags
= GOT_OBJ_FLAG_PACKED
;
915 (*obj
)->pack_idx
= idx
;
918 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
919 (*obj
)->pack_offset
= offset
;
924 static const struct got_error
*
925 parse_negative_offset(int64_t *offset
, size_t *len
, struct got_pack
*pack
,
936 /* We do not support offset values which don't fit in 64 bit. */
938 return got_error(GOT_ERR_NO_SPACE
);
943 if (delta_offset
+ *len
> SIZE_MAX
) {
944 return got_error_fmt(GOT_ERR_PACK_OFFSET
,
945 "mapoff %lld would overflow size_t",
946 (long long)delta_offset
+ *len
);
949 mapoff
= (size_t)delta_offset
+ *len
;
950 if (mapoff
+ sizeof(offN
) >= pack
->filesize
)
951 return got_error(GOT_ERR_PACK_OFFSET
);
952 offN
= *(pack
->map
+ mapoff
);
955 n
= read(pack
->fd
, &offN
, sizeof(offN
));
957 return got_error_from_errno("read");
958 if (n
!= sizeof(offN
))
959 return got_error(GOT_ERR_BAD_PACKFILE
);
961 *len
+= sizeof(offN
);
964 o
= (offN
& GOT_PACK_OBJ_DELTA_OFF_VAL_MASK
);
968 o
+= (offN
& GOT_PACK_OBJ_DELTA_OFF_VAL_MASK
);
971 } while (offN
& GOT_PACK_OBJ_DELTA_OFF_MORE
);
977 const struct got_error
*
978 got_pack_parse_offset_delta(off_t
*base_offset
, size_t *len
,
979 struct got_pack
*pack
, off_t offset
, size_t tslen
)
981 const struct got_error
*err
;
987 err
= parse_negative_offset(&negoffset
, &negofflen
, pack
,
992 /* Compute the base object's offset (must be in the same pack file). */
993 *base_offset
= (offset
- negoffset
);
994 if (*base_offset
<= 0)
995 return got_error(GOT_ERR_BAD_PACKFILE
);
1001 static const struct got_error
*
1002 read_delta_data(uint8_t **delta_buf
, size_t *delta_len
,
1003 size_t *delta_compressed_len
, size_t delta_data_offset
,
1004 struct got_pack
*pack
)
1006 const struct got_error
*err
= NULL
;
1007 size_t consumed
= 0;
1010 if (delta_data_offset
>= pack
->filesize
)
1011 return got_error(GOT_ERR_PACK_OFFSET
);
1012 err
= got_inflate_to_mem_mmap(delta_buf
, delta_len
,
1013 &consumed
, NULL
, pack
->map
, delta_data_offset
,
1014 pack
->filesize
- delta_data_offset
);
1018 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
) == -1)
1019 return got_error_from_errno("lseek");
1020 err
= got_inflate_to_mem_fd(delta_buf
, delta_len
,
1021 &consumed
, NULL
, 0, pack
->fd
);
1026 if (delta_compressed_len
)
1027 *delta_compressed_len
= consumed
;
1032 static const struct got_error
*
1033 add_delta(struct got_delta_chain
*deltas
, off_t delta_offset
, size_t tslen
,
1034 int delta_type
, size_t delta_size
, off_t delta_data_offset
)
1036 struct got_delta
*delta
;
1038 delta
= got_delta_open(delta_offset
, tslen
, delta_type
, delta_size
,
1041 return got_error_from_errno("got_delta_open");
1042 /* delta is freed in got_object_close() */
1044 STAILQ_INSERT_HEAD(&deltas
->entries
, delta
, entry
);
1048 static const struct got_error
*
1049 resolve_offset_delta(struct got_delta_chain
*deltas
,
1050 struct got_packidx
*packidx
, struct got_pack
*pack
, off_t delta_offset
,
1051 size_t tslen
, int delta_type
, size_t delta_size
, unsigned int recursion
)
1053 const struct got_error
*err
;
1058 off_t delta_data_offset
;
1061 err
= got_pack_parse_offset_delta(&base_offset
, &consumed
, pack
,
1062 delta_offset
, tslen
);
1066 delta_data_offset
= delta_offset
+ tslen
+ consumed
;
1067 if (delta_data_offset
>= pack
->filesize
)
1068 return got_error(GOT_ERR_PACK_OFFSET
);
1070 if (pack
->map
== NULL
) {
1071 delta_data_offset
= lseek(pack
->fd
, 0, SEEK_CUR
);
1072 if (delta_data_offset
== -1)
1073 return got_error_from_errno("lseek");
1076 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
, delta_size
,
1081 /* An offset delta must be in the same packfile. */
1082 if (base_offset
>= pack
->filesize
)
1083 return got_error(GOT_ERR_PACK_OFFSET
);
1085 err
= got_pack_parse_object_type_and_size(&base_type
, &base_size
,
1086 &base_tslen
, pack
, base_offset
);
1090 return got_pack_resolve_delta_chain(deltas
, packidx
, pack
, base_offset
,
1091 base_tslen
, base_type
, base_size
, recursion
- 1);
1094 const struct got_error
*
1095 got_pack_parse_ref_delta(struct got_object_id
*id
,
1096 struct got_pack
*pack
, off_t delta_offset
, int tslen
)
1101 if (delta_offset
+ tslen
> SIZE_MAX
) {
1102 return got_error_fmt(GOT_ERR_PACK_OFFSET
,
1103 "mapoff %lld would overflow size_t",
1104 (long long)delta_offset
+ tslen
);
1107 mapoff
= delta_offset
+ tslen
;
1108 if (mapoff
+ sizeof(*id
) >= pack
->filesize
)
1109 return got_error(GOT_ERR_PACK_OFFSET
);
1110 memcpy(id
, pack
->map
+ mapoff
, sizeof(*id
));
1113 n
= read(pack
->fd
, id
, sizeof(*id
));
1115 return got_error_from_errno("read");
1116 if (n
!= sizeof(*id
))
1117 return got_error(GOT_ERR_BAD_PACKFILE
);
1123 static const struct got_error
*
1124 resolve_ref_delta(struct got_delta_chain
*deltas
, struct got_packidx
*packidx
,
1125 struct got_pack
*pack
, off_t delta_offset
, size_t tslen
, int delta_type
,
1126 size_t delta_size
, unsigned int recursion
)
1128 const struct got_error
*err
;
1129 struct got_object_id id
;
1135 off_t delta_data_offset
;
1137 if (delta_offset
+ tslen
>= pack
->filesize
)
1138 return got_error(GOT_ERR_PACK_OFFSET
);
1140 err
= got_pack_parse_ref_delta(&id
, pack
, delta_offset
, tslen
);
1144 delta_data_offset
= delta_offset
+ tslen
+ SHA1_DIGEST_LENGTH
;
1146 delta_data_offset
= lseek(pack
->fd
, 0, SEEK_CUR
);
1147 if (delta_data_offset
== -1)
1148 return got_error_from_errno("lseek");
1151 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
, delta_size
,
1156 /* Delta base must be in the same pack file. */
1157 idx
= got_packidx_get_object_idx(packidx
, &id
);
1159 return got_error(GOT_ERR_NO_OBJ
);
1161 base_offset
= got_packidx_get_object_offset(packidx
, idx
);
1162 if (base_offset
== -1)
1163 return got_error(GOT_ERR_BAD_PACKIDX
);
1165 if (base_offset
>= pack
->filesize
)
1166 return got_error(GOT_ERR_PACK_OFFSET
);
1168 err
= got_pack_parse_object_type_and_size(&base_type
, &base_size
,
1169 &base_tslen
, pack
, base_offset
);
1173 return got_pack_resolve_delta_chain(deltas
, packidx
, pack
, base_offset
,
1174 base_tslen
, base_type
, base_size
, recursion
- 1);
1177 const struct got_error
*
1178 got_pack_resolve_delta_chain(struct got_delta_chain
*deltas
,
1179 struct got_packidx
*packidx
, struct got_pack
*pack
, off_t delta_offset
,
1180 size_t tslen
, int delta_type
, size_t delta_size
, unsigned int recursion
)
1182 const struct got_error
*err
= NULL
;
1184 if (--recursion
== 0)
1185 return got_error(GOT_ERR_RECURSION
);
1187 switch (delta_type
) {
1188 case GOT_OBJ_TYPE_COMMIT
:
1189 case GOT_OBJ_TYPE_TREE
:
1190 case GOT_OBJ_TYPE_BLOB
:
1191 case GOT_OBJ_TYPE_TAG
:
1192 /* Plain types are the final delta base. Recursion ends. */
1193 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
,
1196 case GOT_OBJ_TYPE_OFFSET_DELTA
:
1197 err
= resolve_offset_delta(deltas
, packidx
, pack
,
1198 delta_offset
, tslen
, delta_type
, delta_size
, recursion
- 1);
1200 case GOT_OBJ_TYPE_REF_DELTA
:
1201 err
= resolve_ref_delta(deltas
, packidx
, pack
,
1202 delta_offset
, tslen
, delta_type
, delta_size
, recursion
- 1);
1205 return got_error(GOT_ERR_OBJ_TYPE
);
1211 static const struct got_error
*
1212 open_delta_object(struct got_object
**obj
, struct got_packidx
*packidx
,
1213 struct got_pack
*pack
, struct got_object_id
*id
, off_t offset
,
1214 size_t tslen
, int delta_type
, size_t delta_size
, int idx
)
1216 const struct got_error
*err
= NULL
;
1219 *obj
= calloc(1, sizeof(**obj
));
1221 return got_error_from_errno("calloc");
1225 (*obj
)->size
= 0; /* Not known because deltas aren't applied yet. */
1226 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
1227 (*obj
)->pack_offset
= offset
+ tslen
;
1229 STAILQ_INIT(&(*obj
)->deltas
.entries
);
1230 (*obj
)->flags
|= GOT_OBJ_FLAG_DELTIFIED
;
1231 (*obj
)->flags
|= GOT_OBJ_FLAG_PACKED
;
1232 (*obj
)->pack_idx
= idx
;
1234 err
= got_pack_resolve_delta_chain(&(*obj
)->deltas
, packidx
, pack
,
1235 offset
, tslen
, delta_type
, delta_size
,
1236 GOT_DELTA_CHAIN_RECURSION_MAX
);
1240 err
= got_delta_chain_get_base_type(&resolved_type
, &(*obj
)->deltas
);
1243 (*obj
)->type
= resolved_type
;
1246 got_object_close(*obj
);
1252 const struct got_error
*
1253 got_packfile_open_object(struct got_object
**obj
, struct got_pack
*pack
,
1254 struct got_packidx
*packidx
, int idx
, struct got_object_id
*id
)
1256 const struct got_error
*err
= NULL
;
1264 offset
= got_packidx_get_object_offset(packidx
, idx
);
1266 return got_error(GOT_ERR_BAD_PACKIDX
);
1268 err
= got_pack_parse_object_type_and_size(&type
, &size
, &tslen
,
1274 case GOT_OBJ_TYPE_COMMIT
:
1275 case GOT_OBJ_TYPE_TREE
:
1276 case GOT_OBJ_TYPE_BLOB
:
1277 case GOT_OBJ_TYPE_TAG
:
1278 err
= open_plain_object(obj
, id
, type
, offset
+ tslen
,
1281 case GOT_OBJ_TYPE_OFFSET_DELTA
:
1282 case GOT_OBJ_TYPE_REF_DELTA
:
1283 err
= open_delta_object(obj
, packidx
, pack
, id
, offset
,
1284 tslen
, type
, size
, idx
);
1287 err
= got_error(GOT_ERR_OBJ_TYPE
);
1294 const struct got_error
*
1295 got_pack_get_delta_chain_max_size(uint64_t *max_size
,
1296 struct got_delta_chain
*deltas
, struct got_pack
*pack
)
1298 struct got_delta
*delta
;
1299 uint64_t base_size
= 0, result_size
= 0;
1302 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1303 /* Plain object types are the delta base. */
1304 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1305 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1306 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1307 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1308 const struct got_error
*err
;
1309 uint8_t *delta_buf
= NULL
;
1313 if (pack
->delta_cache
) {
1314 got_delta_cache_get(&delta_buf
, &delta_len
,
1315 pack
->delta_cache
, delta
->data_offset
);
1317 if (delta_buf
== NULL
) {
1319 err
= read_delta_data(&delta_buf
, &delta_len
,
1320 NULL
, delta
->data_offset
, pack
);
1324 if (pack
->delta_cache
&& !cached
) {
1325 err
= got_delta_cache_add(pack
->delta_cache
,
1326 delta
->data_offset
, delta_buf
, delta_len
);
1329 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1334 err
= got_delta_get_sizes(&base_size
, &result_size
,
1335 delta_buf
, delta_len
);
1341 base_size
= delta
->size
;
1342 if (base_size
> *max_size
)
1343 *max_size
= base_size
;
1344 if (result_size
> *max_size
)
1345 *max_size
= result_size
;
1351 const struct got_error
*
1352 got_pack_get_max_delta_object_size(uint64_t *size
, struct got_object
*obj
,
1353 struct got_pack
*pack
)
1355 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0)
1356 return got_error(GOT_ERR_OBJ_TYPE
);
1358 return got_pack_get_delta_chain_max_size(size
, &obj
->deltas
, pack
);
1361 const struct got_error
*
1362 got_pack_dump_delta_chain_to_file(size_t *result_size
,
1363 struct got_delta_chain
*deltas
, struct got_pack
*pack
, FILE *outfile
,
1364 FILE *base_file
, FILE *accum_file
)
1366 const struct got_error
*err
= NULL
;
1367 struct got_delta
*delta
;
1368 uint8_t *base_buf
= NULL
, *accum_buf
= NULL
;
1369 size_t base_bufsz
= 0, accum_bufsz
= 0, accum_size
= 0, delta_len
;
1370 /* We process small enough files entirely in memory for speed. */
1371 const size_t max_bufsize
= GOT_DELTA_RESULT_SIZE_CACHED_MAX
;
1372 uint64_t max_size
= 0;
1377 if (STAILQ_EMPTY(&deltas
->entries
))
1378 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1380 if (fseeko(base_file
, 0L, SEEK_SET
) == -1)
1381 return got_error_from_errno("fseeko");
1382 if (fseeko(accum_file
, 0L, SEEK_SET
) == -1)
1383 return got_error_from_errno("fseeko");
1385 /* Deltas are ordered in ascending order. */
1386 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1387 uint8_t *delta_buf
= NULL
;
1388 uint64_t base_size
, result_size
= 0;
1392 off_t delta_data_offset
;
1394 /* Plain object types are the delta base. */
1395 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1396 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1397 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1398 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1399 err
= got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1403 delta_data_offset
= delta
->offset
+ delta
->tslen
;
1404 if (delta_data_offset
>= pack
->filesize
) {
1405 err
= got_error(GOT_ERR_PACK_OFFSET
);
1408 if (pack
->map
== NULL
) {
1409 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
)
1411 err
= got_error_from_errno("lseek");
1415 if (delta
->size
> max_size
)
1416 max_size
= delta
->size
;
1417 if (max_size
> max_bufsize
) {
1419 if (delta_data_offset
> SIZE_MAX
) {
1420 return got_error_fmt(
1422 "delta offset %lld "
1428 mapoff
= delta_data_offset
;
1429 err
= got_inflate_to_file_mmap(
1430 &base_bufsz
, NULL
, NULL
, pack
->map
,
1431 mapoff
, pack
->filesize
- mapoff
,
1434 err
= got_inflate_to_file_fd(
1435 &base_bufsz
, NULL
, NULL
, pack
->fd
,
1438 accum_buf
= malloc(max_size
);
1439 if (accum_buf
== NULL
) {
1440 err
= got_error_from_errno("malloc");
1443 accum_bufsz
= max_size
;
1445 if (delta_data_offset
> SIZE_MAX
) {
1446 return got_error_fmt(
1448 "delta offset %lld "
1454 mapoff
= delta_data_offset
;
1455 err
= got_inflate_to_mem_mmap(&base_buf
,
1456 &base_bufsz
, NULL
, NULL
,
1458 pack
->filesize
- mapoff
);
1460 err
= got_inflate_to_mem_fd(&base_buf
,
1461 &base_bufsz
, NULL
, NULL
, max_size
,
1467 if (base_buf
== NULL
)
1472 if (pack
->delta_cache
) {
1473 got_delta_cache_get(&delta_buf
, &delta_len
,
1474 pack
->delta_cache
, delta
->data_offset
);
1476 if (delta_buf
== NULL
) {
1478 err
= read_delta_data(&delta_buf
, &delta_len
, NULL
,
1479 delta
->data_offset
, pack
);
1483 if (pack
->delta_cache
&& !cached
) {
1484 err
= got_delta_cache_add(pack
->delta_cache
,
1485 delta
->data_offset
, delta_buf
, delta_len
);
1488 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1494 err
= got_delta_get_sizes(&base_size
, &result_size
,
1495 delta_buf
, delta_len
);
1501 if (base_size
> max_size
)
1502 max_size
= base_size
;
1503 if (result_size
> max_size
)
1504 max_size
= result_size
;
1506 if (base_buf
&& max_size
> max_bufsize
) {
1507 /* Switch from buffers to temporary files. */
1508 size_t w
= fwrite(base_buf
, 1, base_bufsz
,
1510 if (w
!= base_bufsz
) {
1511 err
= got_ferror(outfile
, GOT_ERR_IO
);
1522 if (base_buf
&& max_size
> base_bufsz
) {
1523 uint8_t *p
= realloc(base_buf
, max_size
);
1525 err
= got_error_from_errno("realloc");
1531 base_bufsz
= max_size
;
1534 if (accum_buf
&& max_size
> accum_bufsz
) {
1535 uint8_t *p
= realloc(accum_buf
, max_size
);
1537 err
= got_error_from_errno("realloc");
1543 accum_bufsz
= max_size
;
1547 err
= got_delta_apply_in_mem(base_buf
, base_bufsz
,
1548 delta_buf
, delta_len
, accum_buf
,
1549 &accum_size
, max_size
);
1552 err
= got_delta_apply(base_file
, delta_buf
,
1554 /* Final delta application writes to output file. */
1555 ++n
< deltas
->nentries
? accum_file
: outfile
,
1563 if (n
< deltas
->nentries
) {
1564 /* Accumulated delta becomes the new base. */
1566 uint8_t *tmp
= accum_buf
;
1567 size_t tmp_size
= accum_bufsz
;
1568 accum_buf
= base_buf
;
1569 accum_bufsz
= base_bufsz
;
1571 base_bufsz
= tmp_size
;
1573 FILE *tmp
= accum_file
;
1574 accum_file
= base_file
;
1585 size_t len
= fwrite(accum_buf
, 1, accum_size
, outfile
);
1587 if (len
!= accum_size
)
1588 err
= got_ferror(outfile
, GOT_ERR_IO
);
1592 *result_size
= accum_size
;
1596 const struct got_error
*
1597 got_pack_dump_delta_chain_to_mem(uint8_t **outbuf
, size_t *outlen
,
1598 struct got_delta_chain
*deltas
, struct got_pack
*pack
)
1600 const struct got_error
*err
= NULL
;
1601 struct got_delta
*delta
;
1602 uint8_t *base_buf
= NULL
, *accum_buf
= NULL
;
1603 size_t base_bufsz
= 0, accum_bufsz
= 0, accum_size
= 0, delta_len
;
1604 uint64_t max_size
= 0;
1610 if (STAILQ_EMPTY(&deltas
->entries
))
1611 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1613 /* Deltas are ordered in ascending order. */
1614 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1615 uint8_t *delta_buf
= NULL
;
1616 uint64_t base_size
, result_size
= 0;
1619 off_t delta_data_offset
;
1621 /* Plain object types are the delta base. */
1622 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1623 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1624 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1625 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1626 err
= got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1630 delta_data_offset
= delta
->offset
+ delta
->tslen
;
1631 if (delta_data_offset
>= pack
->filesize
) {
1632 err
= got_error(GOT_ERR_PACK_OFFSET
);
1636 if (delta
->size
> max_size
)
1637 max_size
= delta
->size
;
1642 if (delta_data_offset
> SIZE_MAX
) {
1643 return got_error_fmt(GOT_ERR_RANGE
,
1644 "delta %lld offset would "
1646 (long long)delta_data_offset
);
1649 mapoff
= delta_data_offset
;
1650 err
= got_inflate_to_mem_mmap(&base_buf
,
1651 &base_bufsz
, NULL
, NULL
, pack
->map
,
1652 mapoff
, pack
->filesize
- mapoff
);
1654 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
)
1656 err
= got_error_from_errno("lseek");
1659 err
= got_inflate_to_mem_fd(&base_buf
,
1660 &base_bufsz
, NULL
, NULL
, max_size
,
1669 if (pack
->delta_cache
) {
1670 got_delta_cache_get(&delta_buf
, &delta_len
,
1671 pack
->delta_cache
, delta
->data_offset
);
1673 if (delta_buf
== NULL
) {
1675 err
= read_delta_data(&delta_buf
, &delta_len
, NULL
,
1676 delta
->data_offset
, pack
);
1680 if (pack
->delta_cache
&& !cached
) {
1681 err
= got_delta_cache_add(pack
->delta_cache
,
1682 delta
->data_offset
, delta_buf
, delta_len
);
1685 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1691 err
= got_delta_get_sizes(&base_size
, &result_size
,
1692 delta_buf
, delta_len
);
1698 if (base_size
> max_size
)
1699 max_size
= base_size
;
1700 if (result_size
> max_size
)
1701 max_size
= result_size
;
1703 if (max_size
> base_bufsz
) {
1704 uint8_t *p
= realloc(base_buf
, max_size
);
1706 err
= got_error_from_errno("realloc");
1712 base_bufsz
= max_size
;
1715 if (max_size
> accum_bufsz
) {
1716 uint8_t *p
= realloc(accum_buf
, max_size
);
1718 err
= got_error_from_errno("realloc");
1724 accum_bufsz
= max_size
;
1727 err
= got_delta_apply_in_mem(base_buf
, base_bufsz
,
1728 delta_buf
, delta_len
, accum_buf
,
1729 &accum_size
, max_size
);
1736 if (n
< deltas
->nentries
) {
1737 /* Accumulated delta becomes the new base. */
1738 uint8_t *tmp
= accum_buf
;
1739 size_t tmp_size
= accum_bufsz
;
1740 accum_buf
= base_buf
;
1741 accum_bufsz
= base_bufsz
;
1743 base_bufsz
= tmp_size
;
1754 *outbuf
= accum_buf
;
1755 *outlen
= accum_size
;
1760 const struct got_error
*
1761 got_packfile_extract_object(struct got_pack
*pack
, struct got_object
*obj
,
1762 FILE *outfile
, FILE *base_file
, FILE *accum_file
)
1764 const struct got_error
*err
= NULL
;
1766 if ((obj
->flags
& GOT_OBJ_FLAG_PACKED
) == 0)
1767 return got_error(GOT_ERR_OBJ_NOT_PACKED
);
1769 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0) {
1770 if (obj
->pack_offset
>= pack
->filesize
)
1771 return got_error(GOT_ERR_PACK_OFFSET
);
1776 if (obj
->pack_offset
> SIZE_MAX
) {
1777 return got_error_fmt(GOT_ERR_RANGE
,
1778 "pack offset %lld would overflow size_t",
1779 (long long)obj
->pack_offset
);
1782 mapoff
= obj
->pack_offset
;
1783 err
= got_inflate_to_file_mmap(&obj
->size
, NULL
, NULL
,
1784 pack
->map
, mapoff
, pack
->filesize
- mapoff
,
1787 if (lseek(pack
->fd
, obj
->pack_offset
, SEEK_SET
) == -1)
1788 return got_error_from_errno("lseek");
1789 err
= got_inflate_to_file_fd(&obj
->size
, NULL
, NULL
,
1793 err
= got_pack_dump_delta_chain_to_file(&obj
->size
,
1794 &obj
->deltas
, pack
, outfile
, base_file
, accum_file
);
1799 const struct got_error
*
1800 got_packfile_extract_object_to_mem(uint8_t **buf
, size_t *len
,
1801 struct got_object
*obj
, struct got_pack
*pack
)
1803 const struct got_error
*err
= NULL
;
1805 if ((obj
->flags
& GOT_OBJ_FLAG_PACKED
) == 0)
1806 return got_error(GOT_ERR_OBJ_NOT_PACKED
);
1808 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0) {
1809 if (obj
->pack_offset
>= pack
->filesize
)
1810 return got_error(GOT_ERR_PACK_OFFSET
);
1814 if (obj
->pack_offset
> SIZE_MAX
) {
1815 return got_error_fmt(GOT_ERR_RANGE
,
1816 "pack offset %lld would overflow size_t",
1817 (long long)obj
->pack_offset
);
1820 mapoff
= obj
->pack_offset
;
1821 err
= got_inflate_to_mem_mmap(buf
, len
, NULL
, NULL
,
1822 pack
->map
, mapoff
, pack
->filesize
- mapoff
);
1824 if (lseek(pack
->fd
, obj
->pack_offset
, SEEK_SET
) == -1)
1825 return got_error_from_errno("lseek");
1826 err
= got_inflate_to_mem_fd(buf
, len
, NULL
, NULL
,
1827 obj
->size
, pack
->fd
);
1830 err
= got_pack_dump_delta_chain_to_mem(buf
, len
, &obj
->deltas
,
1836 static const struct got_error
*
1837 read_raw_delta_data(uint8_t **delta_buf
, size_t *delta_len
,
1838 size_t *delta_len_compressed
, uint64_t *base_size
, uint64_t *result_size
,
1839 off_t delta_data_offset
, struct got_pack
*pack
, struct got_packidx
*packidx
)
1841 const struct got_error
*err
= NULL
;
1843 /* Validate decompression and obtain the decompressed size. */
1844 err
= read_delta_data(delta_buf
, delta_len
, delta_len_compressed
,
1845 delta_data_offset
, pack
);
1849 /* Read delta base/result sizes from head of delta stream. */
1850 err
= got_delta_get_sizes(base_size
, result_size
,
1851 *delta_buf
, *delta_len
);
1855 /* Discard decompressed delta and read it again in compressed form. */
1857 *delta_buf
= malloc(*delta_len_compressed
);
1858 if (*delta_buf
== NULL
) {
1859 err
= got_error_from_errno("malloc");
1863 if (delta_data_offset
>= pack
->filesize
) {
1864 err
= got_error(GOT_ERR_PACK_OFFSET
);
1867 memcpy(*delta_buf
, pack
->map
+ delta_data_offset
,
1868 *delta_len_compressed
);
1871 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
) == -1) {
1872 err
= got_error_from_errno("lseek");
1875 n
= read(pack
->fd
, *delta_buf
, *delta_len_compressed
);
1877 err
= got_error_from_errno("read");
1879 } else if (n
!= *delta_len_compressed
) {
1880 err
= got_error(GOT_ERR_IO
);
1889 *delta_len_compressed
= 0;
1896 const struct got_error
*
1897 got_packfile_extract_raw_delta(uint8_t **delta_buf
, size_t *delta_size
,
1898 size_t *delta_compressed_size
, off_t
*delta_offset
,
1899 off_t
*delta_data_offset
, off_t
*base_offset
,
1900 struct got_object_id
*base_id
, uint64_t *base_size
, uint64_t *result_size
,
1901 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
)
1903 const struct got_error
*err
= NULL
;
1907 size_t tslen
, delta_hdrlen
;
1911 *delta_compressed_size
= 0;
1913 *delta_data_offset
= 0;
1918 offset
= got_packidx_get_object_offset(packidx
, idx
);
1920 return got_error(GOT_ERR_BAD_PACKIDX
);
1922 if (offset
>= pack
->filesize
)
1923 return got_error(GOT_ERR_PACK_OFFSET
);
1925 err
= got_pack_parse_object_type_and_size(&type
, &size
, &tslen
,
1930 if (tslen
+ size
< tslen
|| offset
+ size
< size
||
1931 tslen
+ offset
< tslen
)
1932 return got_error(GOT_ERR_PACK_OFFSET
);
1935 case GOT_OBJ_TYPE_OFFSET_DELTA
:
1936 err
= got_pack_parse_offset_delta(base_offset
, &delta_hdrlen
,
1937 pack
, offset
, tslen
);
1941 case GOT_OBJ_TYPE_REF_DELTA
:
1942 err
= got_pack_parse_ref_delta(base_id
, pack
, offset
, tslen
);
1945 delta_hdrlen
= SHA1_DIGEST_LENGTH
;
1948 return got_error_fmt(GOT_ERR_OBJ_TYPE
,
1949 "non-delta object type %d found at offset %lld",
1950 type
, (long long)offset
);
1953 if (tslen
+ delta_hdrlen
< delta_hdrlen
||
1954 offset
+ delta_hdrlen
< delta_hdrlen
)
1955 return got_error(GOT_ERR_BAD_DELTA
);
1957 *delta_data_offset
= offset
+ tslen
+ delta_hdrlen
;
1958 err
= read_raw_delta_data(delta_buf
, delta_size
, delta_compressed_size
,
1959 base_size
, result_size
, *delta_data_offset
, pack
, packidx
);
1963 if (*delta_size
!= size
) {
1964 err
= got_error(GOT_ERR_BAD_DELTA
);
1968 *delta_offset
= offset
;
1974 *delta_compressed_size
= 0;