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>
21 #include <sys/resource.h>
22 #include <sys/socket.h>
34 #include "got_error.h"
35 #include "got_object.h"
38 #include "got_lib_sha1.h"
39 #include "got_lib_delta.h"
40 #include "got_lib_delta_cache.h"
41 #include "got_lib_inflate.h"
42 #include "got_lib_object.h"
43 #include "got_lib_object_parse.h"
44 #include "got_lib_privsep.h"
45 #include "got_lib_pack.h"
48 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
52 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
55 static const struct got_error
*
56 verify_fanout_table(uint32_t *fanout_table
)
60 for (i
= 0; i
< 0xff - 1; i
++) {
61 if (be32toh(fanout_table
[i
]) > be32toh(fanout_table
[i
+ 1]))
62 return got_error(GOT_ERR_BAD_PACKIDX
);
68 const struct got_error
*
69 got_packidx_init_hdr(struct got_packidx
*p
, int verify
, off_t packfile_size
)
71 const struct got_error
*err
= NULL
;
72 struct got_packidx_v2_hdr
*h
;
74 uint8_t sha1
[SHA1_DIGEST_LENGTH
];
75 size_t nobj
, len_fanout
, len_ids
, offset
, remain
;
85 if (remain
< sizeof(*h
->magic
)) {
86 err
= got_error(GOT_ERR_BAD_PACKIDX
);
90 h
->magic
= (uint32_t *)(p
->map
+ offset
);
92 h
->magic
= malloc(sizeof(*h
->magic
));
93 if (h
->magic
== NULL
) {
94 err
= got_error_from_errno("malloc");
97 n
= read(p
->fd
, h
->magic
, sizeof(*h
->magic
));
99 err
= got_error_from_errno("read");
101 } else if (n
!= sizeof(*h
->magic
)) {
102 err
= got_error(GOT_ERR_BAD_PACKIDX
);
106 if (*h
->magic
!= htobe32(GOT_PACKIDX_V2_MAGIC
)) {
107 err
= got_error(GOT_ERR_BAD_PACKIDX
);
110 offset
+= sizeof(*h
->magic
);
111 remain
-= sizeof(*h
->magic
);
114 SHA1Update(&ctx
, (uint8_t *)h
->magic
, sizeof(*h
->magic
));
116 if (remain
< sizeof(*h
->version
)) {
117 err
= got_error(GOT_ERR_BAD_PACKIDX
);
121 h
->version
= (uint32_t *)(p
->map
+ offset
);
123 h
->version
= malloc(sizeof(*h
->version
));
124 if (h
->version
== NULL
) {
125 err
= got_error_from_errno("malloc");
128 n
= read(p
->fd
, h
->version
, sizeof(*h
->version
));
130 err
= got_error_from_errno("read");
132 } else if (n
!= sizeof(*h
->version
)) {
133 err
= got_error(GOT_ERR_BAD_PACKIDX
);
137 if (*h
->version
!= htobe32(GOT_PACKIDX_VERSION
)) {
138 err
= got_error(GOT_ERR_BAD_PACKIDX
);
141 offset
+= sizeof(*h
->version
);
142 remain
-= sizeof(*h
->version
);
145 SHA1Update(&ctx
, (uint8_t *)h
->version
, sizeof(*h
->version
));
148 sizeof(*h
->fanout_table
) * GOT_PACKIDX_V2_FANOUT_TABLE_ITEMS
;
149 if (remain
< len_fanout
) {
150 err
= got_error(GOT_ERR_BAD_PACKIDX
);
154 h
->fanout_table
= (uint32_t *)(p
->map
+ offset
);
156 h
->fanout_table
= malloc(len_fanout
);
157 if (h
->fanout_table
== NULL
) {
158 err
= got_error_from_errno("malloc");
161 n
= read(p
->fd
, h
->fanout_table
, len_fanout
);
163 err
= got_error_from_errno("read");
165 } else if (n
!= len_fanout
) {
166 err
= got_error(GOT_ERR_BAD_PACKIDX
);
170 err
= verify_fanout_table(h
->fanout_table
);
174 SHA1Update(&ctx
, (uint8_t *)h
->fanout_table
, len_fanout
);
175 offset
+= len_fanout
;
176 remain
-= len_fanout
;
178 nobj
= be32toh(h
->fanout_table
[0xff]);
179 len_ids
= nobj
* sizeof(*h
->sorted_ids
);
180 if (len_ids
<= nobj
|| len_ids
> remain
) {
181 err
= got_error(GOT_ERR_BAD_PACKIDX
);
186 (struct got_packidx_object_id
*)((uint8_t*)(p
->map
+ offset
));
188 h
->sorted_ids
= malloc(len_ids
);
189 if (h
->sorted_ids
== NULL
) {
190 err
= got_error(GOT_ERR_BAD_PACKIDX
);
193 n
= read(p
->fd
, h
->sorted_ids
, len_ids
);
195 err
= got_error_from_errno("read");
196 else if (n
!= len_ids
) {
197 err
= got_error(GOT_ERR_BAD_PACKIDX
);
202 SHA1Update(&ctx
, (uint8_t *)h
->sorted_ids
, len_ids
);
206 if (remain
< nobj
* sizeof(*h
->crc32
)) {
207 err
= got_error(GOT_ERR_BAD_PACKIDX
);
211 h
->crc32
= (uint32_t *)((uint8_t*)(p
->map
+ offset
));
213 h
->crc32
= malloc(nobj
* sizeof(*h
->crc32
));
214 if (h
->crc32
== NULL
) {
215 err
= got_error_from_errno("malloc");
218 n
= read(p
->fd
, h
->crc32
, nobj
* sizeof(*h
->crc32
));
220 err
= got_error_from_errno("read");
221 else if (n
!= nobj
* sizeof(*h
->crc32
)) {
222 err
= got_error(GOT_ERR_BAD_PACKIDX
);
227 SHA1Update(&ctx
, (uint8_t *)h
->crc32
, nobj
* sizeof(*h
->crc32
));
228 remain
-= nobj
* sizeof(*h
->crc32
);
229 offset
+= nobj
* sizeof(*h
->crc32
);
231 if (remain
< nobj
* sizeof(*h
->offsets
)) {
232 err
= got_error(GOT_ERR_BAD_PACKIDX
);
236 h
->offsets
= (uint32_t *)((uint8_t*)(p
->map
+ offset
));
238 h
->offsets
= malloc(nobj
* sizeof(*h
->offsets
));
239 if (h
->offsets
== NULL
) {
240 err
= got_error_from_errno("malloc");
243 n
= read(p
->fd
, h
->offsets
, nobj
* sizeof(*h
->offsets
));
245 err
= got_error_from_errno("read");
246 else if (n
!= nobj
* sizeof(*h
->offsets
)) {
247 err
= got_error(GOT_ERR_BAD_PACKIDX
);
252 SHA1Update(&ctx
, (uint8_t *)h
->offsets
,
253 nobj
* sizeof(*h
->offsets
));
254 remain
-= nobj
* sizeof(*h
->offsets
);
255 offset
+= nobj
* sizeof(*h
->offsets
);
257 /* Large file offsets are contained only in files > 2GB. */
258 if (verify
|| packfile_size
> 0x7fffffff) {
259 for (i
= 0; i
< nobj
; i
++) {
260 uint32_t o
= h
->offsets
[i
];
261 if (o
& htobe32(GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
))
265 if (p
->nlargeobj
== 0)
267 else if (packfile_size
<= 0x7fffffff) {
268 err
= got_error(GOT_ERR_BAD_PACKIDX
);
272 if (remain
< p
->nlargeobj
* sizeof(*h
->large_offsets
)) {
273 err
= got_error(GOT_ERR_BAD_PACKIDX
);
277 h
->large_offsets
= (uint64_t *)((uint8_t*)(p
->map
+ offset
));
279 h
->large_offsets
= malloc(p
->nlargeobj
*
280 sizeof(*h
->large_offsets
));
281 if (h
->large_offsets
== NULL
) {
282 err
= got_error_from_errno("malloc");
285 n
= read(p
->fd
, h
->large_offsets
,
286 p
->nlargeobj
* sizeof(*h
->large_offsets
));
288 err
= got_error_from_errno("read");
289 else if (n
!= p
->nlargeobj
* sizeof(*h
->large_offsets
)) {
290 err
= got_error(GOT_ERR_BAD_PACKIDX
);
295 SHA1Update(&ctx
, (uint8_t*)h
->large_offsets
,
296 p
->nlargeobj
* sizeof(*h
->large_offsets
));
297 remain
-= p
->nlargeobj
* sizeof(*h
->large_offsets
);
298 offset
+= p
->nlargeobj
* sizeof(*h
->large_offsets
);
301 if (remain
< sizeof(*h
->trailer
)) {
302 err
= got_error(GOT_ERR_BAD_PACKIDX
);
307 (struct got_packidx_trailer
*)((uint8_t*)(p
->map
+ offset
));
309 h
->trailer
= malloc(sizeof(*h
->trailer
));
310 if (h
->trailer
== NULL
) {
311 err
= got_error_from_errno("malloc");
314 n
= read(p
->fd
, h
->trailer
, sizeof(*h
->trailer
));
316 err
= got_error_from_errno("read");
317 else if (n
!= sizeof(*h
->trailer
)) {
318 err
= got_error(GOT_ERR_BAD_PACKIDX
);
323 SHA1Update(&ctx
, h
->trailer
->packfile_sha1
, SHA1_DIGEST_LENGTH
);
324 SHA1Final(sha1
, &ctx
);
325 if (memcmp(h
->trailer
->packidx_sha1
, sha1
,
326 SHA1_DIGEST_LENGTH
) != 0)
327 err
= got_error(GOT_ERR_PACKIDX_CSUM
);
333 const struct got_error
*
334 got_packidx_open(struct got_packidx
**packidx
,
335 int dir_fd
, const char *relpath
, int verify
)
337 const struct got_error
*err
= NULL
;
338 struct got_packidx
*p
= NULL
;
340 struct stat idx_sb
, pack_sb
;
344 err
= got_packidx_get_packfile_path(&pack_relpath
, relpath
);
349 * Ensure that a corresponding pack file exists.
350 * Some Git repositories have this problem. Git seems to ignore
351 * the existence of lonely pack index files but we do not.
353 if (fstatat(dir_fd
, pack_relpath
, &pack_sb
, 0) == -1) {
354 if (errno
== ENOENT
) {
355 err
= got_error_fmt(GOT_ERR_LONELY_PACKIDX
,
358 err
= got_error_from_errno2("fstatat", pack_relpath
);
362 p
= calloc(1, sizeof(*p
));
364 err
= got_error_from_errno("calloc");
368 p
->fd
= openat(dir_fd
, relpath
, O_RDONLY
| O_NOFOLLOW
| O_CLOEXEC
);
370 err
= got_error_from_errno2("openat", relpath
);
374 if (fstat(p
->fd
, &idx_sb
) != 0) {
375 err
= got_error_from_errno2("fstat", relpath
);
378 p
->len
= idx_sb
.st_size
;
379 if (p
->len
< sizeof(p
->hdr
)) {
380 err
= got_error(GOT_ERR_BAD_PACKIDX
);
384 p
->path_packidx
= strdup(relpath
);
385 if (p
->path_packidx
== NULL
) {
386 err
= got_error_from_errno("strdup");
390 #ifndef GOT_PACK_NO_MMAP
391 p
->map
= mmap(NULL
, p
->len
, PROT_READ
, MAP_PRIVATE
, p
->fd
, 0);
392 if (p
->map
== MAP_FAILED
) {
393 if (errno
!= ENOMEM
) {
394 err
= got_error_from_errno("mmap");
397 p
->map
= NULL
; /* fall back to read(2) */
401 err
= got_packidx_init_hdr(p
, verify
, pack_sb
.st_size
);
405 got_packidx_close(p
);
412 const struct got_error
*
413 got_packidx_close(struct got_packidx
*packidx
)
415 const struct got_error
*err
= NULL
;
417 free(packidx
->path_packidx
);
419 if (munmap(packidx
->map
, packidx
->len
) == -1)
420 err
= got_error_from_errno("munmap");
422 free(packidx
->hdr
.magic
);
423 free(packidx
->hdr
.version
);
424 free(packidx
->hdr
.fanout_table
);
425 free(packidx
->hdr
.sorted_ids
);
426 free(packidx
->hdr
.crc32
);
427 free(packidx
->hdr
.offsets
);
428 free(packidx
->hdr
.large_offsets
);
429 free(packidx
->hdr
.trailer
);
431 if (close(packidx
->fd
) == -1 && err
== NULL
)
432 err
= got_error_from_errno("close");
433 free(packidx
->sorted_offsets
);
434 free(packidx
->sorted_large_offsets
);
440 const struct got_error
*
441 got_packidx_get_packfile_path(char **path_packfile
, const char *path_packidx
)
445 /* Packfile path contains ".pack" instead of ".idx", so add one byte. */
446 size
= strlen(path_packidx
) + 2;
447 if (size
< GOT_PACKFILE_NAMELEN
+ 1)
448 return got_error_path(path_packidx
, GOT_ERR_BAD_PATH
);
450 *path_packfile
= malloc(size
);
451 if (*path_packfile
== NULL
)
452 return got_error_from_errno("malloc");
454 /* Copy up to and excluding ".idx". */
455 if (strlcpy(*path_packfile
, path_packidx
,
456 size
- strlen(GOT_PACKIDX_SUFFIX
) - 1) >= size
)
457 return got_error(GOT_ERR_NO_SPACE
);
459 if (strlcat(*path_packfile
, GOT_PACKFILE_SUFFIX
, size
) >= size
)
460 return got_error(GOT_ERR_NO_SPACE
);
466 got_packidx_get_object_offset(struct got_packidx
*packidx
, int idx
)
468 uint32_t offset
= be32toh(packidx
->hdr
.offsets
[idx
]);
469 if (offset
& GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
) {
471 idx
= offset
& GOT_PACKIDX_OFFSET_VAL_MASK
;
472 if (idx
< 0 || idx
>= packidx
->nlargeobj
||
473 packidx
->hdr
.large_offsets
== NULL
)
475 loffset
= be64toh(packidx
->hdr
.large_offsets
[idx
]);
476 return (loffset
> INT64_MAX
? -1 : (off_t
)loffset
);
478 return (off_t
)(offset
& GOT_PACKIDX_OFFSET_VAL_MASK
);
482 got_packidx_get_object_idx(struct got_packidx
*packidx
,
483 struct got_object_id
*id
)
485 u_int8_t id0
= id
->sha1
[0];
486 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
487 int left
= 0, right
= totobj
- 1;
490 left
= be32toh(packidx
->hdr
.fanout_table
[id0
- 1]);
492 while (left
<= right
) {
493 struct got_packidx_object_id
*oid
;
496 i
= ((left
+ right
) / 2);
497 oid
= &packidx
->hdr
.sorted_ids
[i
];
498 cmp
= memcmp(id
->sha1
, oid
->sha1
, SHA1_DIGEST_LENGTH
);
511 offset_cmp(const void *pa
, const void *pb
)
513 const struct got_pack_offset_index
*a
, *b
;
515 a
= (const struct got_pack_offset_index
*)pa
;
516 b
= (const struct got_pack_offset_index
*)pb
;
518 if (a
->offset
< b
->offset
)
520 else if (a
->offset
> b
->offset
)
527 large_offset_cmp(const void *pa
, const void *pb
)
529 const struct got_pack_large_offset_index
*a
, *b
;
531 a
= (const struct got_pack_large_offset_index
*)pa
;
532 b
= (const struct got_pack_large_offset_index
*)pb
;
534 if (a
->offset
< b
->offset
)
536 else if (a
->offset
> b
->offset
)
542 static const struct got_error
*
543 build_offset_index(struct got_packidx
*p
)
545 uint32_t nobj
= be32toh(p
->hdr
.fanout_table
[0xff]);
546 unsigned int i
, j
, k
;
548 p
->sorted_offsets
= calloc(nobj
- p
->nlargeobj
,
549 sizeof(p
->sorted_offsets
[0]));
550 if (p
->sorted_offsets
== NULL
)
551 return got_error_from_errno("calloc");
553 if (p
->nlargeobj
> 0) {
554 p
->sorted_large_offsets
= calloc(p
->nlargeobj
,
555 sizeof(p
->sorted_large_offsets
[0]));
556 if (p
->sorted_large_offsets
== NULL
)
557 return got_error_from_errno("calloc");
562 for (i
= 0; i
< nobj
; i
++) {
563 uint32_t offset
= be32toh(p
->hdr
.offsets
[i
]);
564 if (offset
& GOT_PACKIDX_OFFSET_VAL_IS_LARGE_IDX
) {
567 idx
= offset
& GOT_PACKIDX_OFFSET_VAL_MASK
;
568 if (idx
>= p
->nlargeobj
||
570 p
->hdr
.large_offsets
== NULL
)
571 return got_error(GOT_ERR_BAD_PACKIDX
);
572 loffset
= be64toh(p
->hdr
.large_offsets
[idx
]);
573 p
->sorted_large_offsets
[j
].offset
= loffset
;
574 p
->sorted_large_offsets
[j
].idx
= i
;
577 p
->sorted_offsets
[k
].offset
= offset
;
578 p
->sorted_offsets
[k
].idx
= i
;
582 if (j
!= p
->nlargeobj
|| k
!= nobj
- p
->nlargeobj
)
583 return got_error(GOT_ERR_BAD_PACKIDX
);
585 qsort(p
->sorted_offsets
, nobj
- p
->nlargeobj
,
586 sizeof(p
->sorted_offsets
[0]), offset_cmp
);
588 if (p
->sorted_large_offsets
)
589 qsort(p
->sorted_large_offsets
, p
->nlargeobj
,
590 sizeof(p
->sorted_large_offsets
[0]), large_offset_cmp
);
595 const struct got_error
*
596 got_packidx_get_offset_idx(int *idx
, struct got_packidx
*packidx
, off_t offset
)
598 const struct got_error
*err
;
599 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
604 if (packidx
->sorted_offsets
== NULL
) {
605 err
= build_offset_index(packidx
);
610 if (offset
>= 0x7fffffff) {
612 left
= 0, right
= packidx
->nlargeobj
- 1;
613 while (left
<= right
) {
614 i
= ((left
+ right
) / 2);
615 lo
= packidx
->sorted_large_offsets
[i
].offset
;
617 *idx
= packidx
->sorted_large_offsets
[i
].idx
;
619 } else if (offset
> lo
)
621 else if (offset
< lo
)
626 left
= 0, right
= totobj
- packidx
->nlargeobj
- 1;
627 while (left
<= right
) {
628 i
= ((left
+ right
) / 2);
629 o
= packidx
->sorted_offsets
[i
].offset
;
631 *idx
= packidx
->sorted_offsets
[i
].idx
;
633 } else if (offset
> o
)
643 const struct got_error
*
644 got_packidx_get_object_id(struct got_object_id
*id
,
645 struct got_packidx
*packidx
, int idx
)
647 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
648 struct got_packidx_object_id
*oid
;
650 if (idx
< 0 || idx
>= totobj
)
651 return got_error(GOT_ERR_NO_OBJ
);
653 oid
= &packidx
->hdr
.sorted_ids
[idx
];
654 memcpy(id
->sha1
, oid
->sha1
, SHA1_DIGEST_LENGTH
);
658 const struct got_error
*
659 got_packidx_match_id_str_prefix(struct got_object_id_queue
*matched_ids
,
660 struct got_packidx
*packidx
, const char *id_str_prefix
)
662 const struct got_error
*err
= NULL
;
664 uint32_t totobj
= be32toh(packidx
->hdr
.fanout_table
[0xff]);
666 size_t prefix_len
= strlen(id_str_prefix
);
667 struct got_packidx_object_id
*oid
;
670 STAILQ_INIT(matched_ids
);
673 return got_error_path(id_str_prefix
, GOT_ERR_BAD_OBJ_ID_STR
);
675 hex
[0] = id_str_prefix
[0];
676 hex
[1] = id_str_prefix
[1];
678 if (!got_parse_xdigit(&id0
, hex
))
679 return got_error_path(id_str_prefix
, GOT_ERR_BAD_OBJ_ID_STR
);
682 i
= be32toh(packidx
->hdr
.fanout_table
[id0
- 1]);
683 oid
= &packidx
->hdr
.sorted_ids
[i
];
684 while (i
< totobj
&& oid
->sha1
[0] == id0
) {
685 char id_str
[SHA1_DIGEST_STRING_LENGTH
];
686 struct got_object_qid
*qid
;
689 if (!got_sha1_digest_to_str(oid
->sha1
, id_str
, sizeof(id_str
)))
690 return got_error(GOT_ERR_NO_SPACE
);
692 cmp
= strncmp(id_str
, id_str_prefix
, prefix_len
);
694 oid
= &packidx
->hdr
.sorted_ids
[++i
];
699 err
= got_object_qid_alloc_partial(&qid
);
702 memcpy(qid
->id
.sha1
, oid
->sha1
, SHA1_DIGEST_LENGTH
);
703 STAILQ_INSERT_TAIL(matched_ids
, qid
, entry
);
705 oid
= &packidx
->hdr
.sorted_ids
[++i
];
709 got_object_id_queue_free(matched_ids
);
714 set_max_datasize(void)
718 if (getrlimit(RLIMIT_DATA
, &rl
) != 0)
721 rl
.rlim_cur
= rl
.rlim_max
;
722 setrlimit(RLIMIT_DATA
, &rl
);
725 const struct got_error
*
726 got_pack_start_privsep_child(struct got_pack
*pack
, struct got_packidx
*packidx
)
728 const struct got_error
*err
= NULL
;
731 struct imsgbuf
*ibuf
;
733 ibuf
= calloc(1, sizeof(*ibuf
));
735 return got_error_from_errno("calloc");
737 pack
->privsep_child
= calloc(1, sizeof(*pack
->privsep_child
));
738 if (pack
->privsep_child
== NULL
) {
739 err
= got_error_from_errno("calloc");
743 pack
->child_has_tempfiles
= 0;
744 pack
->child_has_delta_outfd
= 0;
746 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
747 err
= got_error_from_errno("socketpair");
753 err
= got_error_from_errno("fork");
755 } else if (pid
== 0) {
757 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_PACK
,
758 pack
->path_packfile
);
762 if (close(imsg_fds
[1]) == -1)
763 return got_error_from_errno("close");
764 pack
->privsep_child
->imsg_fd
= imsg_fds
[0];
765 pack
->privsep_child
->pid
= pid
;
766 imsg_init(ibuf
, imsg_fds
[0]);
767 pack
->privsep_child
->ibuf
= ibuf
;
769 err
= got_privsep_init_pack_child(ibuf
, pack
, packidx
);
771 const struct got_error
*child_err
;
772 err
= got_privsep_send_stop(pack
->privsep_child
->imsg_fd
);
773 child_err
= got_privsep_wait_for_child(
774 pack
->privsep_child
->pid
);
775 if (child_err
&& err
== NULL
)
781 free(pack
->privsep_child
);
782 pack
->privsep_child
= NULL
;
787 static const struct got_error
*
788 pack_stop_privsep_child(struct got_pack
*pack
)
790 const struct got_error
*err
= NULL
;
792 if (pack
->privsep_child
== NULL
)
795 err
= got_privsep_send_stop(pack
->privsep_child
->imsg_fd
);
798 err
= got_privsep_wait_for_child(pack
->privsep_child
->pid
);
799 if (close(pack
->privsep_child
->imsg_fd
) == -1 && err
== NULL
)
800 err
= got_error_from_errno("close");
801 free(pack
->privsep_child
->ibuf
);
802 free(pack
->privsep_child
);
803 pack
->privsep_child
= NULL
;
807 const struct got_error
*
808 got_pack_close(struct got_pack
*pack
)
810 const struct got_error
*err
= NULL
;
812 err
= pack_stop_privsep_child(pack
);
813 if (pack
->map
&& munmap(pack
->map
, pack
->filesize
) == -1 && !err
)
814 err
= got_error_from_errno("munmap");
815 if (pack
->fd
!= -1 && close(pack
->fd
) == -1 && err
== NULL
)
816 err
= got_error_from_errno("close");
818 free(pack
->path_packfile
);
819 pack
->path_packfile
= NULL
;
821 if (pack
->delta_cache
) {
822 got_delta_cache_free(pack
->delta_cache
);
823 pack
->delta_cache
= NULL
;
827 * Leave accumfd and basefd alone. They are managed by the
828 * repository layer and can be reused.
834 const struct got_error
*
835 got_pack_parse_object_type_and_size(uint8_t *type
, uint64_t *size
, size_t *len
,
836 struct got_pack
*pack
, off_t offset
)
846 if (offset
>= pack
->filesize
)
847 return got_error(GOT_ERR_PACK_OFFSET
);
850 mapoff
= (size_t)offset
;
852 if (lseek(pack
->fd
, offset
, SEEK_SET
) == -1)
853 return got_error_from_errno("lseek");
857 /* We do not support size values which don't fit in 64 bit. */
859 return got_error(GOT_ERR_NO_SPACE
);
862 if (mapoff
+ sizeof(sizeN
) >= pack
->filesize
)
863 return got_error(GOT_ERR_BAD_PACKFILE
);
864 sizeN
= *(pack
->map
+ mapoff
);
865 mapoff
+= sizeof(sizeN
);
867 ssize_t n
= read(pack
->fd
, &sizeN
, sizeof(sizeN
));
869 return got_error_from_errno("read");
870 if (n
!= sizeof(sizeN
))
871 return got_error(GOT_ERR_BAD_PACKFILE
);
873 *len
+= sizeof(sizeN
);
876 t
= (sizeN
& GOT_PACK_OBJ_SIZE0_TYPE_MASK
) >>
877 GOT_PACK_OBJ_SIZE0_TYPE_MASK_SHIFT
;
878 s
= (sizeN
& GOT_PACK_OBJ_SIZE0_VAL_MASK
);
880 size_t shift
= 4 + 7 * (i
- 1);
881 s
|= ((sizeN
& GOT_PACK_OBJ_SIZE_VAL_MASK
) << shift
);
884 } while (sizeN
& GOT_PACK_OBJ_SIZE_MORE
);
891 static const struct got_error
*
892 open_plain_object(struct got_object
**obj
, struct got_object_id
*id
,
893 uint8_t type
, off_t offset
, size_t size
, int idx
)
895 *obj
= calloc(1, sizeof(**obj
));
897 return got_error_from_errno("calloc");
900 (*obj
)->flags
= GOT_OBJ_FLAG_PACKED
;
901 (*obj
)->pack_idx
= idx
;
904 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
905 (*obj
)->pack_offset
= offset
;
910 static const struct got_error
*
911 parse_negative_offset(int64_t *offset
, size_t *len
, struct got_pack
*pack
,
922 /* We do not support offset values which don't fit in 64 bit. */
924 return got_error(GOT_ERR_NO_SPACE
);
928 mapoff
= (size_t)delta_offset
+ *len
;
929 if (mapoff
+ sizeof(offN
) >= pack
->filesize
)
930 return got_error(GOT_ERR_PACK_OFFSET
);
931 offN
= *(pack
->map
+ mapoff
);
934 n
= read(pack
->fd
, &offN
, sizeof(offN
));
936 return got_error_from_errno("read");
937 if (n
!= sizeof(offN
))
938 return got_error(GOT_ERR_BAD_PACKFILE
);
940 *len
+= sizeof(offN
);
943 o
= (offN
& GOT_PACK_OBJ_DELTA_OFF_VAL_MASK
);
947 o
+= (offN
& GOT_PACK_OBJ_DELTA_OFF_VAL_MASK
);
950 } while (offN
& GOT_PACK_OBJ_DELTA_OFF_MORE
);
956 const struct got_error
*
957 got_pack_parse_offset_delta(off_t
*base_offset
, size_t *len
,
958 struct got_pack
*pack
, off_t offset
, int tslen
)
960 const struct got_error
*err
;
966 err
= parse_negative_offset(&negoffset
, &negofflen
, pack
,
971 /* Compute the base object's offset (must be in the same pack file). */
972 *base_offset
= (offset
- negoffset
);
973 if (*base_offset
<= 0)
974 return got_error(GOT_ERR_BAD_PACKFILE
);
980 static const struct got_error
*
981 read_delta_data(uint8_t **delta_buf
, size_t *delta_len
,
982 size_t *delta_compressed_len
, size_t delta_data_offset
,
983 struct got_pack
*pack
)
985 const struct got_error
*err
= NULL
;
989 if (delta_data_offset
>= pack
->filesize
)
990 return got_error(GOT_ERR_PACK_OFFSET
);
991 err
= got_inflate_to_mem_mmap(delta_buf
, delta_len
,
992 &consumed
, NULL
, pack
->map
, delta_data_offset
,
993 pack
->filesize
- delta_data_offset
);
997 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
) == -1)
998 return got_error_from_errno("lseek");
999 err
= got_inflate_to_mem_fd(delta_buf
, delta_len
,
1000 &consumed
, NULL
, 0, pack
->fd
);
1005 if (delta_compressed_len
)
1006 *delta_compressed_len
= consumed
;
1011 static const struct got_error
*
1012 add_delta(struct got_delta_chain
*deltas
, off_t delta_offset
, size_t tslen
,
1013 int delta_type
, size_t delta_size
, size_t delta_data_offset
)
1015 struct got_delta
*delta
;
1017 delta
= got_delta_open(delta_offset
, tslen
, delta_type
, delta_size
,
1020 return got_error_from_errno("got_delta_open");
1021 /* delta is freed in got_object_close() */
1023 STAILQ_INSERT_HEAD(&deltas
->entries
, delta
, entry
);
1027 static const struct got_error
*
1028 resolve_offset_delta(struct got_delta_chain
*deltas
,
1029 struct got_packidx
*packidx
, struct got_pack
*pack
, off_t delta_offset
,
1030 size_t tslen
, int delta_type
, size_t delta_size
, unsigned int recursion
)
1033 const struct got_error
*err
;
1038 off_t delta_data_offset
;
1041 err
= got_pack_parse_offset_delta(&base_offset
, &consumed
, pack
,
1042 delta_offset
, tslen
);
1046 delta_data_offset
= delta_offset
+ tslen
+ consumed
;
1047 if (delta_data_offset
>= pack
->filesize
)
1048 return got_error(GOT_ERR_PACK_OFFSET
);
1050 if (pack
->map
== NULL
) {
1051 delta_data_offset
= lseek(pack
->fd
, 0, SEEK_CUR
);
1052 if (delta_data_offset
== -1)
1053 return got_error_from_errno("lseek");
1056 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
, delta_size
,
1061 /* An offset delta must be in the same packfile. */
1062 if (base_offset
>= pack
->filesize
)
1063 return got_error(GOT_ERR_PACK_OFFSET
);
1065 err
= got_pack_parse_object_type_and_size(&base_type
, &base_size
,
1066 &base_tslen
, pack
, base_offset
);
1070 return got_pack_resolve_delta_chain(deltas
, packidx
, pack
, base_offset
,
1071 base_tslen
, base_type
, base_size
, recursion
- 1);
1074 const struct got_error
*
1075 got_pack_parse_ref_delta(struct got_object_id
*id
,
1076 struct got_pack
*pack
, off_t delta_offset
, int tslen
)
1079 size_t mapoff
= delta_offset
+ tslen
;
1080 if (mapoff
+ sizeof(*id
) >= pack
->filesize
)
1081 return got_error(GOT_ERR_PACK_OFFSET
);
1082 memcpy(id
, pack
->map
+ mapoff
, sizeof(*id
));
1085 n
= read(pack
->fd
, id
, sizeof(*id
));
1087 return got_error_from_errno("read");
1088 if (n
!= sizeof(*id
))
1089 return got_error(GOT_ERR_BAD_PACKFILE
);
1095 static const struct got_error
*
1096 resolve_ref_delta(struct got_delta_chain
*deltas
, struct got_packidx
*packidx
,
1097 struct got_pack
*pack
, off_t delta_offset
, size_t tslen
, int delta_type
,
1098 size_t delta_size
, unsigned int recursion
)
1100 const struct got_error
*err
;
1101 struct got_object_id id
;
1107 off_t delta_data_offset
;
1109 if (delta_offset
+ tslen
>= pack
->filesize
)
1110 return got_error(GOT_ERR_PACK_OFFSET
);
1112 err
= got_pack_parse_ref_delta(&id
, pack
, delta_offset
, tslen
);
1116 delta_data_offset
= delta_offset
+ tslen
+ sizeof(id
);
1118 delta_data_offset
= lseek(pack
->fd
, 0, SEEK_CUR
);
1119 if (delta_data_offset
== -1)
1120 return got_error_from_errno("lseek");
1123 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
, delta_size
,
1128 /* Delta base must be in the same pack file. */
1129 idx
= got_packidx_get_object_idx(packidx
, &id
);
1131 return got_error(GOT_ERR_NO_OBJ
);
1133 base_offset
= got_packidx_get_object_offset(packidx
, idx
);
1134 if (base_offset
== (uint64_t)-1)
1135 return got_error(GOT_ERR_BAD_PACKIDX
);
1137 if (base_offset
>= pack
->filesize
)
1138 return got_error(GOT_ERR_PACK_OFFSET
);
1140 err
= got_pack_parse_object_type_and_size(&base_type
, &base_size
,
1141 &base_tslen
, pack
, base_offset
);
1145 return got_pack_resolve_delta_chain(deltas
, packidx
, pack
, base_offset
,
1146 base_tslen
, base_type
, base_size
, recursion
- 1);
1149 const struct got_error
*
1150 got_pack_resolve_delta_chain(struct got_delta_chain
*deltas
,
1151 struct got_packidx
*packidx
, struct got_pack
*pack
, off_t delta_offset
,
1152 size_t tslen
, int delta_type
, size_t delta_size
, unsigned int recursion
)
1154 const struct got_error
*err
= NULL
;
1156 if (--recursion
== 0)
1157 return got_error(GOT_ERR_RECURSION
);
1159 switch (delta_type
) {
1160 case GOT_OBJ_TYPE_COMMIT
:
1161 case GOT_OBJ_TYPE_TREE
:
1162 case GOT_OBJ_TYPE_BLOB
:
1163 case GOT_OBJ_TYPE_TAG
:
1164 /* Plain types are the final delta base. Recursion ends. */
1165 err
= add_delta(deltas
, delta_offset
, tslen
, delta_type
,
1168 case GOT_OBJ_TYPE_OFFSET_DELTA
:
1169 err
= resolve_offset_delta(deltas
, packidx
, pack
,
1170 delta_offset
, tslen
, delta_type
, delta_size
, recursion
- 1);
1172 case GOT_OBJ_TYPE_REF_DELTA
:
1173 err
= resolve_ref_delta(deltas
, packidx
, pack
,
1174 delta_offset
, tslen
, delta_type
, delta_size
, recursion
- 1);
1177 return got_error(GOT_ERR_OBJ_TYPE
);
1183 static const struct got_error
*
1184 open_delta_object(struct got_object
**obj
, struct got_packidx
*packidx
,
1185 struct got_pack
*pack
, struct got_object_id
*id
, off_t offset
,
1186 size_t tslen
, int delta_type
, size_t delta_size
, int idx
)
1188 const struct got_error
*err
= NULL
;
1191 *obj
= calloc(1, sizeof(**obj
));
1193 return got_error_from_errno("calloc");
1197 (*obj
)->size
= 0; /* Not known because deltas aren't applied yet. */
1198 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
1199 (*obj
)->pack_offset
= offset
+ tslen
;
1201 STAILQ_INIT(&(*obj
)->deltas
.entries
);
1202 (*obj
)->flags
|= GOT_OBJ_FLAG_DELTIFIED
;
1203 (*obj
)->flags
|= GOT_OBJ_FLAG_PACKED
;
1204 (*obj
)->pack_idx
= idx
;
1206 err
= got_pack_resolve_delta_chain(&(*obj
)->deltas
, packidx
, pack
,
1207 offset
, tslen
, delta_type
, delta_size
,
1208 GOT_DELTA_CHAIN_RECURSION_MAX
);
1212 err
= got_delta_chain_get_base_type(&resolved_type
, &(*obj
)->deltas
);
1215 (*obj
)->type
= resolved_type
;
1218 got_object_close(*obj
);
1224 const struct got_error
*
1225 got_packfile_open_object(struct got_object
**obj
, struct got_pack
*pack
,
1226 struct got_packidx
*packidx
, int idx
, struct got_object_id
*id
)
1228 const struct got_error
*err
= NULL
;
1236 offset
= got_packidx_get_object_offset(packidx
, idx
);
1237 if (offset
== (uint64_t)-1)
1238 return got_error(GOT_ERR_BAD_PACKIDX
);
1240 err
= got_pack_parse_object_type_and_size(&type
, &size
, &tslen
,
1246 case GOT_OBJ_TYPE_COMMIT
:
1247 case GOT_OBJ_TYPE_TREE
:
1248 case GOT_OBJ_TYPE_BLOB
:
1249 case GOT_OBJ_TYPE_TAG
:
1250 err
= open_plain_object(obj
, id
, type
, offset
+ tslen
,
1253 case GOT_OBJ_TYPE_OFFSET_DELTA
:
1254 case GOT_OBJ_TYPE_REF_DELTA
:
1255 err
= open_delta_object(obj
, packidx
, pack
, id
, offset
,
1256 tslen
, type
, size
, idx
);
1259 err
= got_error(GOT_ERR_OBJ_TYPE
);
1266 const struct got_error
*
1267 got_pack_get_delta_chain_max_size(uint64_t *max_size
,
1268 struct got_delta_chain
*deltas
, struct got_pack
*pack
)
1270 struct got_delta
*delta
;
1271 uint64_t base_size
= 0, result_size
= 0;
1274 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1275 /* Plain object types are the delta base. */
1276 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1277 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1278 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1279 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1280 const struct got_error
*err
;
1285 got_delta_cache_get(&delta_buf
, &delta_len
,
1286 pack
->delta_cache
, delta
->data_offset
);
1287 if (delta_buf
== NULL
) {
1289 err
= read_delta_data(&delta_buf
, &delta_len
,
1290 NULL
, delta
->data_offset
, pack
);
1293 err
= got_delta_cache_add(pack
->delta_cache
,
1294 delta
->data_offset
, delta_buf
, delta_len
);
1297 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1302 err
= got_delta_get_sizes(&base_size
, &result_size
,
1303 delta_buf
, delta_len
);
1309 base_size
= delta
->size
;
1310 if (base_size
> *max_size
)
1311 *max_size
= base_size
;
1312 if (result_size
> *max_size
)
1313 *max_size
= result_size
;
1319 const struct got_error
*
1320 got_pack_get_max_delta_object_size(uint64_t *size
, struct got_object
*obj
,
1321 struct got_pack
*pack
)
1323 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0)
1324 return got_error(GOT_ERR_OBJ_TYPE
);
1326 return got_pack_get_delta_chain_max_size(size
, &obj
->deltas
, pack
);
1329 const struct got_error
*
1330 got_pack_dump_delta_chain_to_file(size_t *result_size
,
1331 struct got_delta_chain
*deltas
, struct got_pack
*pack
, FILE *outfile
,
1332 FILE *base_file
, FILE *accum_file
)
1334 const struct got_error
*err
= NULL
;
1335 struct got_delta
*delta
;
1336 uint8_t *base_buf
= NULL
, *accum_buf
= NULL
, *delta_buf
;
1337 size_t base_bufsz
= 0, accum_bufsz
= 0, accum_size
= 0, delta_len
;
1338 /* We process small enough files entirely in memory for speed. */
1339 const size_t max_bufsize
= GOT_DELTA_RESULT_SIZE_CACHED_MAX
;
1340 uint64_t max_size
= 0;
1345 if (STAILQ_EMPTY(&deltas
->entries
))
1346 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1348 if (fseeko(base_file
, 0L, SEEK_SET
) == -1)
1349 return got_error_from_errno("fseeko");
1350 if (fseeko(accum_file
, 0L, SEEK_SET
) == -1)
1351 return got_error_from_errno("fseeko");
1353 /* Deltas are ordered in ascending order. */
1354 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1355 uint64_t base_size
, result_size
= 0;
1359 off_t delta_data_offset
;
1361 /* Plain object types are the delta base. */
1362 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1363 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1364 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1365 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1366 err
= got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1370 delta_data_offset
= delta
->offset
+ delta
->tslen
;
1371 if (delta_data_offset
>= pack
->filesize
) {
1372 err
= got_error(GOT_ERR_PACK_OFFSET
);
1375 if (pack
->map
== NULL
) {
1376 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
)
1378 err
= got_error_from_errno("lseek");
1382 if (delta
->size
> max_size
)
1383 max_size
= delta
->size
;
1384 if (max_size
> max_bufsize
) {
1386 mapoff
= (size_t)delta_data_offset
;
1387 err
= got_inflate_to_file_mmap(
1388 &base_bufsz
, NULL
, NULL
, pack
->map
,
1389 mapoff
, pack
->filesize
- mapoff
,
1392 err
= got_inflate_to_file_fd(
1393 &base_bufsz
, NULL
, NULL
, pack
->fd
,
1396 accum_buf
= malloc(max_size
);
1397 if (accum_buf
== NULL
) {
1398 err
= got_error_from_errno("malloc");
1401 accum_bufsz
= max_size
;
1403 mapoff
= (size_t)delta_data_offset
;
1404 err
= got_inflate_to_mem_mmap(&base_buf
,
1405 &base_bufsz
, NULL
, NULL
,
1407 pack
->filesize
- mapoff
);
1409 err
= got_inflate_to_mem_fd(&base_buf
,
1410 &base_bufsz
, NULL
, NULL
, max_size
,
1416 if (base_buf
== NULL
)
1421 got_delta_cache_get(&delta_buf
, &delta_len
,
1422 pack
->delta_cache
, delta
->data_offset
);
1423 if (delta_buf
== NULL
) {
1425 err
= read_delta_data(&delta_buf
, &delta_len
, NULL
,
1426 delta
->data_offset
, pack
);
1429 err
= got_delta_cache_add(pack
->delta_cache
,
1430 delta
->data_offset
, delta_buf
, delta_len
);
1433 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1439 err
= got_delta_get_sizes(&base_size
, &result_size
,
1440 delta_buf
, delta_len
);
1443 if (base_size
> max_size
)
1444 max_size
= base_size
;
1445 if (result_size
> max_size
)
1446 max_size
= result_size
;
1448 if (base_buf
&& max_size
> max_bufsize
) {
1449 /* Switch from buffers to temporary files. */
1450 size_t w
= fwrite(base_buf
, 1, base_bufsz
,
1452 if (w
!= base_bufsz
) {
1453 err
= got_ferror(outfile
, GOT_ERR_IO
);
1462 if (base_buf
&& max_size
> base_bufsz
) {
1463 uint8_t *p
= realloc(base_buf
, max_size
);
1465 err
= got_error_from_errno("realloc");
1469 base_bufsz
= max_size
;
1472 if (accum_buf
&& max_size
> accum_bufsz
) {
1473 uint8_t *p
= realloc(accum_buf
, max_size
);
1475 err
= got_error_from_errno("realloc");
1479 accum_bufsz
= max_size
;
1483 err
= got_delta_apply_in_mem(base_buf
, base_bufsz
,
1484 delta_buf
, delta_len
, accum_buf
,
1485 &accum_size
, max_size
);
1488 err
= got_delta_apply(base_file
, delta_buf
,
1490 /* Final delta application writes to output file. */
1491 ++n
< deltas
->nentries
? accum_file
: outfile
,
1499 if (n
< deltas
->nentries
) {
1500 /* Accumulated delta becomes the new base. */
1502 uint8_t *tmp
= accum_buf
;
1503 size_t tmp_size
= accum_bufsz
;
1504 accum_buf
= base_buf
;
1505 accum_bufsz
= base_bufsz
;
1507 base_bufsz
= tmp_size
;
1509 FILE *tmp
= accum_file
;
1510 accum_file
= base_file
;
1521 size_t len
= fwrite(accum_buf
, 1, accum_size
, outfile
);
1523 if (len
!= accum_size
)
1524 err
= got_ferror(outfile
, GOT_ERR_IO
);
1528 *result_size
= accum_size
;
1532 const struct got_error
*
1533 got_pack_dump_delta_chain_to_mem(uint8_t **outbuf
, size_t *outlen
,
1534 struct got_delta_chain
*deltas
, struct got_pack
*pack
)
1536 const struct got_error
*err
= NULL
;
1537 struct got_delta
*delta
;
1538 uint8_t *base_buf
= NULL
, *accum_buf
= NULL
, *delta_buf
;
1539 size_t base_bufsz
= 0, accum_bufsz
= 0, accum_size
= 0, delta_len
;
1540 uint64_t max_size
= 0;
1546 if (STAILQ_EMPTY(&deltas
->entries
))
1547 return got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1549 /* Deltas are ordered in ascending order. */
1550 STAILQ_FOREACH(delta
, &deltas
->entries
, entry
) {
1551 uint64_t base_size
, result_size
= 0;
1554 size_t delta_data_offset
;
1556 /* Plain object types are the delta base. */
1557 if (delta
->type
!= GOT_OBJ_TYPE_COMMIT
&&
1558 delta
->type
!= GOT_OBJ_TYPE_TREE
&&
1559 delta
->type
!= GOT_OBJ_TYPE_BLOB
&&
1560 delta
->type
!= GOT_OBJ_TYPE_TAG
) {
1561 err
= got_error(GOT_ERR_BAD_DELTA_CHAIN
);
1565 delta_data_offset
= delta
->offset
+ delta
->tslen
;
1566 if (delta_data_offset
>= pack
->filesize
) {
1567 err
= got_error(GOT_ERR_PACK_OFFSET
);
1571 if (delta
->size
> max_size
)
1572 max_size
= delta
->size
;
1575 size_t mapoff
= (size_t)delta_data_offset
;
1576 err
= got_inflate_to_mem_mmap(&base_buf
,
1577 &base_bufsz
, NULL
, NULL
, pack
->map
,
1578 mapoff
, pack
->filesize
- mapoff
);
1580 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
)
1582 err
= got_error_from_errno("lseek");
1585 err
= got_inflate_to_mem_fd(&base_buf
,
1586 &base_bufsz
, NULL
, NULL
, max_size
,
1595 got_delta_cache_get(&delta_buf
, &delta_len
,
1596 pack
->delta_cache
, delta
->data_offset
);
1597 if (delta_buf
== NULL
) {
1599 err
= read_delta_data(&delta_buf
, &delta_len
, NULL
,
1600 delta
->data_offset
, pack
);
1603 err
= got_delta_cache_add(pack
->delta_cache
,
1604 delta
->data_offset
, delta_buf
, delta_len
);
1607 else if (err
->code
!= GOT_ERR_NO_SPACE
) {
1613 err
= got_delta_get_sizes(&base_size
, &result_size
,
1614 delta_buf
, delta_len
);
1617 if (base_size
> max_size
)
1618 max_size
= base_size
;
1619 if (result_size
> max_size
)
1620 max_size
= result_size
;
1622 if (max_size
> base_bufsz
) {
1623 uint8_t *p
= realloc(base_buf
, max_size
);
1625 err
= got_error_from_errno("realloc");
1629 base_bufsz
= max_size
;
1632 if (max_size
> accum_bufsz
) {
1633 uint8_t *p
= realloc(accum_buf
, max_size
);
1635 err
= got_error_from_errno("realloc");
1639 accum_bufsz
= max_size
;
1642 err
= got_delta_apply_in_mem(base_buf
, base_bufsz
,
1643 delta_buf
, delta_len
, accum_buf
,
1644 &accum_size
, max_size
);
1651 if (n
< deltas
->nentries
) {
1652 /* Accumulated delta becomes the new base. */
1653 uint8_t *tmp
= accum_buf
;
1654 size_t tmp_size
= accum_bufsz
;
1655 accum_buf
= base_buf
;
1656 accum_bufsz
= base_bufsz
;
1658 base_bufsz
= tmp_size
;
1669 *outbuf
= accum_buf
;
1670 *outlen
= accum_size
;
1675 const struct got_error
*
1676 got_packfile_extract_object(struct got_pack
*pack
, struct got_object
*obj
,
1677 FILE *outfile
, FILE *base_file
, FILE *accum_file
)
1679 const struct got_error
*err
= NULL
;
1681 if ((obj
->flags
& GOT_OBJ_FLAG_PACKED
) == 0)
1682 return got_error(GOT_ERR_OBJ_NOT_PACKED
);
1684 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0) {
1685 if (obj
->pack_offset
>= pack
->filesize
)
1686 return got_error(GOT_ERR_PACK_OFFSET
);
1689 size_t mapoff
= (size_t)obj
->pack_offset
;
1690 err
= got_inflate_to_file_mmap(&obj
->size
, NULL
, NULL
,
1691 pack
->map
, mapoff
, pack
->filesize
- mapoff
,
1694 if (lseek(pack
->fd
, obj
->pack_offset
, SEEK_SET
) == -1)
1695 return got_error_from_errno("lseek");
1696 err
= got_inflate_to_file_fd(&obj
->size
, NULL
, NULL
,
1700 err
= got_pack_dump_delta_chain_to_file(&obj
->size
,
1701 &obj
->deltas
, pack
, outfile
, base_file
, accum_file
);
1706 const struct got_error
*
1707 got_packfile_extract_object_to_mem(uint8_t **buf
, size_t *len
,
1708 struct got_object
*obj
, struct got_pack
*pack
)
1710 const struct got_error
*err
= NULL
;
1712 if ((obj
->flags
& GOT_OBJ_FLAG_PACKED
) == 0)
1713 return got_error(GOT_ERR_OBJ_NOT_PACKED
);
1715 if ((obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) == 0) {
1716 if (obj
->pack_offset
>= pack
->filesize
)
1717 return got_error(GOT_ERR_PACK_OFFSET
);
1719 size_t mapoff
= (size_t)obj
->pack_offset
;
1720 err
= got_inflate_to_mem_mmap(buf
, len
, NULL
, NULL
,
1721 pack
->map
, mapoff
, pack
->filesize
- mapoff
);
1723 if (lseek(pack
->fd
, obj
->pack_offset
, SEEK_SET
) == -1)
1724 return got_error_from_errno("lseek");
1725 err
= got_inflate_to_mem_fd(buf
, len
, NULL
, NULL
,
1726 obj
->size
, pack
->fd
);
1729 err
= got_pack_dump_delta_chain_to_mem(buf
, len
, &obj
->deltas
,
1735 static const struct got_error
*
1736 read_raw_delta_data(uint8_t **delta_buf
, size_t *delta_len
,
1737 size_t *delta_len_compressed
, uint64_t *base_size
, uint64_t *result_size
,
1738 off_t delta_data_offset
, struct got_pack
*pack
, struct got_packidx
*packidx
)
1740 const struct got_error
*err
= NULL
;
1742 /* Validate decompression and obtain the decompressed size. */
1743 err
= read_delta_data(delta_buf
, delta_len
, delta_len_compressed
,
1744 delta_data_offset
, pack
);
1748 /* Read delta base/result sizes from head of delta stream. */
1749 err
= got_delta_get_sizes(base_size
, result_size
,
1750 *delta_buf
, *delta_len
);
1754 /* Discard decompressed delta and read it again in compressed form. */
1756 *delta_buf
= malloc(*delta_len_compressed
);
1757 if (*delta_buf
== NULL
) {
1758 err
= got_error_from_errno("malloc");
1762 if (delta_data_offset
>= pack
->filesize
)
1763 err
= got_error(GOT_ERR_PACK_OFFSET
);
1764 memcpy(*delta_buf
, pack
->map
+ delta_data_offset
,
1765 *delta_len_compressed
);
1768 if (lseek(pack
->fd
, delta_data_offset
, SEEK_SET
) == -1) {
1769 err
= got_error_from_errno("lseek");
1772 n
= read(pack
->fd
, *delta_buf
, *delta_len_compressed
);
1774 err
= got_error_from_errno("read");
1776 } else if (n
!= *delta_len_compressed
) {
1777 err
= got_error(GOT_ERR_IO
);
1786 *delta_len_compressed
= 0;
1793 const struct got_error
*
1794 got_packfile_extract_raw_delta(uint8_t **delta_buf
, size_t *delta_size
,
1795 size_t *delta_compressed_size
, off_t
*delta_offset
, off_t
*base_offset
,
1796 struct got_object_id
*base_id
, uint64_t *base_size
, uint64_t *result_size
,
1797 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
)
1799 const struct got_error
*err
= NULL
;
1803 size_t tslen
, delta_hdrlen
;
1804 off_t delta_data_offset
;
1808 *delta_compressed_size
= 0;
1814 offset
= got_packidx_get_object_offset(packidx
, idx
);
1815 if (offset
== (uint64_t)-1)
1816 return got_error(GOT_ERR_BAD_PACKIDX
);
1818 if (offset
>= pack
->filesize
)
1819 return got_error(GOT_ERR_PACK_OFFSET
);
1821 err
= got_pack_parse_object_type_and_size(&type
, &size
, &tslen
,
1826 if (tslen
+ size
< tslen
|| offset
+ size
< size
||
1827 tslen
+ offset
< tslen
)
1828 return got_error(GOT_ERR_PACK_OFFSET
);
1831 case GOT_OBJ_TYPE_OFFSET_DELTA
:
1832 err
= got_pack_parse_offset_delta(base_offset
, &delta_hdrlen
,
1833 pack
, offset
, tslen
);
1837 case GOT_OBJ_TYPE_REF_DELTA
:
1838 err
= got_pack_parse_ref_delta(base_id
, pack
, offset
, tslen
);
1841 delta_hdrlen
= SHA1_DIGEST_LENGTH
;
1844 return got_error_fmt(GOT_ERR_OBJ_TYPE
,
1845 "non-delta object type %d found at offset %llu",
1849 if (tslen
+ delta_hdrlen
< delta_hdrlen
||
1850 offset
+ delta_hdrlen
< delta_hdrlen
)
1851 return got_error(GOT_ERR_BAD_DELTA
);
1853 delta_data_offset
= offset
+ tslen
+ delta_hdrlen
;
1854 err
= read_raw_delta_data(delta_buf
, delta_size
, delta_compressed_size
,
1855 base_size
, result_size
, delta_data_offset
, pack
, packidx
);
1859 if (*delta_size
!= size
) {
1860 err
= got_error(GOT_ERR_BAD_DELTA
);
1864 *delta_offset
= offset
;
1870 *delta_compressed_size
= 0;