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"
19 #include <sys/types.h>
20 #include <sys/queue.h>
36 #include "got_error.h"
37 #include "got_object.h"
40 #include "got_lib_delta.h"
41 #include "got_lib_delta_cache.h"
42 #include "got_lib_hash.h"
43 #include "got_lib_object.h"
44 #include "got_lib_object_qid.h"
45 #include "got_lib_object_cache.h"
46 #include "got_lib_object_parse.h"
47 #include "got_lib_object_idset.h"
48 #include "got_lib_privsep.h"
49 #include "got_lib_pack.h"
52 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
55 static volatile sig_atomic_t sigint_received
;
58 catch_sigint(int signo
)
63 static const struct got_error
*
64 open_object(struct got_object
**obj
, struct got_pack
*pack
,
65 struct got_packidx
*packidx
, int idx
, struct got_object_id
*id
,
66 struct got_object_cache
*objcache
)
68 const struct got_error
*err
;
70 err
= got_packfile_open_object(obj
, pack
, packidx
, idx
, id
);
75 err
= got_object_cache_add(objcache
, id
, *obj
);
77 if (err
->code
== GOT_ERR_OBJ_EXISTS
||
78 err
->code
== GOT_ERR_OBJ_TOO_LARGE
)
86 static const struct got_error
*
87 object_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
, struct got_pack
*pack
,
88 struct got_packidx
*packidx
, struct got_object_cache
*objcache
)
90 const struct got_error
*err
= NULL
;
91 struct got_imsg_packed_object iobj
;
92 struct got_object
*obj
;
93 struct got_object_id id
;
96 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
97 if (datalen
!= sizeof(iobj
))
98 return got_error(GOT_ERR_PRIVSEP_LEN
);
99 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
100 memcpy(&id
, &iobj
.id
, sizeof(id
));
102 obj
= got_object_cache_get(objcache
, &id
);
106 err
= open_object(&obj
, pack
, packidx
, iobj
.idx
, &id
,
112 err
= got_privsep_send_obj(ibuf
, obj
);
114 got_object_close(obj
);
118 static const struct got_error
*
119 open_commit(struct got_commit_object
**commit
, struct got_pack
*pack
,
120 struct got_packidx
*packidx
, int obj_idx
, struct got_object_id
*id
,
121 struct got_object_cache
*objcache
)
123 const struct got_error
*err
= NULL
;
124 struct got_object
*obj
= NULL
;
130 obj
= got_object_cache_get(objcache
, id
);
134 err
= open_object(&obj
, pack
, packidx
, obj_idx
, id
,
140 err
= got_packfile_extract_object_to_mem(&buf
, &len
, obj
, pack
);
146 err
= got_object_parse_commit(commit
, buf
, len
, pack
->algo
);
148 got_object_close(obj
);
153 static const struct got_error
*
154 commit_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
, struct got_pack
*pack
,
155 struct got_packidx
*packidx
, struct got_object_cache
*objcache
)
157 const struct got_error
*err
= NULL
;
158 struct got_imsg_packed_object iobj
;
159 struct got_commit_object
*commit
= NULL
;
160 struct got_object_id id
;
163 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
164 if (datalen
!= sizeof(iobj
))
165 return got_error(GOT_ERR_PRIVSEP_LEN
);
166 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
167 memcpy(&id
, &iobj
.id
, sizeof(id
));
169 err
= open_commit(&commit
, pack
, packidx
, iobj
.idx
, &id
, objcache
);
173 err
= got_privsep_send_commit(ibuf
, commit
);
176 got_object_commit_close(commit
);
178 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
181 got_privsep_send_error(ibuf
, err
);
187 static const struct got_error
*
188 open_tree(uint8_t **buf
, size_t *len
,
189 struct got_pack
*pack
, struct got_packidx
*packidx
, int obj_idx
,
190 struct got_object_id
*id
, struct got_object_cache
*objcache
)
192 const struct got_error
*err
= NULL
;
193 struct got_object
*obj
= NULL
;
199 obj
= got_object_cache_get(objcache
, id
);
204 err
= open_object(&obj
, pack
, packidx
, obj_idx
, id
,
210 err
= got_packfile_extract_object_to_mem(buf
, len
, obj
, pack
);
217 got_object_close(obj
);
225 static const struct got_error
*
226 tree_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
, struct got_pack
*pack
,
227 struct got_packidx
*packidx
, struct got_object_cache
*objcache
,
228 struct got_parsed_tree_entry
**entries
, size_t *nentries
,
229 size_t *nentries_alloc
)
231 const struct got_error
*err
= NULL
;
232 struct got_imsg_packed_object iobj
;
235 struct got_object_id id
;
238 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
239 if (datalen
!= sizeof(iobj
))
240 return got_error(GOT_ERR_PRIVSEP_LEN
);
241 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
242 memcpy(&id
, &iobj
.id
, sizeof(id
));
244 err
= open_tree(&buf
, &len
, pack
, packidx
, iobj
.idx
, &id
, objcache
);
248 err
= got_object_parse_tree(entries
, nentries
, nentries_alloc
,
253 err
= got_privsep_send_tree(ibuf
, *entries
, *nentries
);
255 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
258 got_privsep_send_error(ibuf
, err
);
265 static const struct got_error
*
266 receive_file(FILE **f
, struct imsgbuf
*ibuf
, uint32_t imsg_code
)
268 const struct got_error
*err
;
273 err
= got_privsep_recv_imsg(&imsg
, ibuf
, 0);
277 if (imsg
.hdr
.type
!= imsg_code
) {
278 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
282 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
284 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
287 fd
= imsg_get_fd(&imsg
);
289 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
293 *f
= fdopen(fd
, "w+");
295 err
= got_error_from_errno("fdopen");
304 static const struct got_error
*
305 receive_tempfile(FILE **f
, const char *mode
, struct imsg
*imsg
,
306 struct imsgbuf
*ibuf
)
308 const struct got_error
*err
;
312 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
314 return got_error(GOT_ERR_PRIVSEP_LEN
);
316 fd
= imsg_get_fd(imsg
);
318 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
320 *f
= fdopen(fd
, mode
);
322 err
= got_error_from_errno("fdopen");
330 static const struct got_error
*
331 blob_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
, struct got_pack
*pack
,
332 struct got_packidx
*packidx
, struct got_object_cache
*objcache
,
333 FILE *basefile
, FILE *accumfile
)
335 const struct got_error
*err
= NULL
;
336 struct got_imsg_packed_object iobj
;
337 struct got_object
*obj
= NULL
;
338 FILE *outfile
= NULL
;
339 struct got_object_id id
;
344 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
345 if (datalen
!= sizeof(iobj
))
346 return got_error(GOT_ERR_PRIVSEP_LEN
);
347 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
348 memcpy(&id
, &iobj
.id
, sizeof(id
));
350 obj
= got_object_cache_get(objcache
, &id
);
354 err
= open_object(&obj
, pack
, packidx
, iobj
.idx
, &id
,
360 err
= receive_file(&outfile
, ibuf
, GOT_IMSG_BLOB_OUTFD
);
364 if (obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) {
365 err
= got_pack_get_max_delta_object_size(&blob_size
, obj
, pack
);
369 blob_size
= obj
->size
;
371 if (blob_size
<= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX
)
372 err
= got_packfile_extract_object_to_mem(&buf
, &obj
->size
,
375 err
= got_packfile_extract_object(pack
, obj
, outfile
, basefile
,
380 err
= got_privsep_send_blob(ibuf
, obj
->size
, obj
->hdrlen
, buf
);
383 if (outfile
&& fclose(outfile
) == EOF
&& err
== NULL
)
384 err
= got_error_from_errno("fclose");
385 got_object_close(obj
);
386 if (err
&& err
->code
!= GOT_ERR_PRIVSEP_PIPE
)
387 got_privsep_send_error(ibuf
, err
);
392 static const struct got_error
*
393 tag_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
, struct got_pack
*pack
,
394 struct got_packidx
*packidx
, struct got_object_cache
*objcache
)
396 const struct got_error
*err
= NULL
;
397 struct got_imsg_packed_object iobj
;
398 struct got_object
*obj
= NULL
;
399 struct got_tag_object
*tag
= NULL
;
402 struct got_object_id id
;
405 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
406 if (datalen
!= sizeof(iobj
))
407 return got_error(GOT_ERR_PRIVSEP_LEN
);
408 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
409 memcpy(&id
, &iobj
.id
, sizeof(id
));
411 obj
= got_object_cache_get(objcache
, &id
);
415 err
= open_object(&obj
, pack
, packidx
, iobj
.idx
, &id
,
421 err
= got_packfile_extract_object_to_mem(&buf
, &len
, obj
, pack
);
426 err
= got_object_parse_tag(&tag
, buf
, len
, id
.algo
);
430 err
= got_privsep_send_tag(ibuf
, tag
);
433 got_object_close(obj
);
435 got_object_tag_close(tag
);
437 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
440 got_privsep_send_error(ibuf
, err
);
446 static const struct got_error
*
447 tree_path_changed(int *changed
, uint8_t **buf1
, size_t *len1
,
448 uint8_t **buf2
, size_t *len2
, const char *path
,
449 struct got_pack
*pack
, struct got_packidx
*packidx
,
450 struct imsgbuf
*ibuf
, struct got_object_cache
*objcache
)
452 const struct got_error
*err
= NULL
;
453 struct got_parsed_tree_entry pte1
, pte2
;
455 size_t seglen
, digest_len
;
456 size_t remain1
= *len1
, remain2
= *len2
, elen
;
457 uint8_t *next_entry1
= *buf1
;
458 uint8_t *next_entry2
= *buf2
;
460 memset(&pte1
, 0, sizeof(pte1
));
461 memset(&pte2
, 0, sizeof(pte2
));
465 digest_len
= got_hash_digest_length(pack
->algo
);
467 /* We not do support comparing the root path. */
468 if (got_path_is_root_dir(path
))
469 return got_error_path(path
, GOT_ERR_BAD_PATH
);
485 * As an optimization we compare entries in on-disk order
486 * rather than in got_path_cmp() order. We only need to
487 * find out if any entries differ. Parsing all entries and
488 * sorting them slows us down significantly when tree objects
489 * have thousands of entries. We can assume that on-disk entry
490 * ordering is stable, as per got_object_tree_create() and
491 * sort_tree_entries_the_way_git_likes_it(). Other orderings
492 * are incompatible with Git and would yield false positives
495 while (remain1
> 0) {
496 err
= got_object_parse_tree_entry(&pte1
, &elen
,
497 next_entry1
, remain1
, digest_len
, pack
->algo
);
502 if (strncmp(pte1
.name
, seg
, seglen
) != 0 ||
503 pte1
.name
[seglen
] != '\0') {
504 memset(&pte1
, 0, sizeof(pte1
));
509 if (pte1
.name
== NULL
) {
510 err
= got_error(GOT_ERR_NO_OBJ
);
519 while (remain2
> 0) {
520 err
= got_object_parse_tree_entry(&pte2
, &elen
,
521 next_entry2
, remain2
, digest_len
, pack
->algo
);
526 if (strncmp(pte2
.name
, seg
, seglen
) != 0 ||
527 pte2
.name
[seglen
] != '\0') {
528 memset(&pte2
, 0, sizeof(pte2
));
534 if (pte2
.name
== NULL
) {
539 if (pte1
.mode
!= pte2
.mode
) {
544 if (memcmp(pte1
.id
, pte2
.id
, pte1
.digest_len
) == 0) {
549 if (*s
== '\0') { /* final path element */
558 struct got_object_id id1
, id2
;
561 memcpy(id1
.hash
, pte1
.id
, pte1
.digest_len
);
562 id1
.algo
= pack
->algo
;
563 idx
= got_packidx_get_object_idx(packidx
, &id1
);
565 err
= got_error_no_obj(&id1
);
570 err
= open_tree(buf1
, len1
, pack
, packidx
, idx
, &id1
,
572 memset(&pte1
, 0, sizeof(pte1
));
578 memcpy(id2
.hash
, pte2
.id
, pte2
.digest_len
);
579 id2
.algo
= pack
->algo
;
580 idx
= got_packidx_get_object_idx(packidx
, &id2
);
582 err
= got_error_no_obj(&id2
);
587 err
= open_tree(buf2
, len2
, pack
, packidx
, idx
, &id2
,
589 memset(&pte2
, 0, sizeof(pte2
));
600 static const struct got_error
*
601 send_traversed_commits(struct got_object_id
*commit_ids
, size_t ncommits
,
602 struct imsgbuf
*ibuf
)
607 wbuf
= imsg_create(ibuf
, GOT_IMSG_TRAVERSED_COMMITS
, 0, 0,
608 sizeof(struct got_imsg_traversed_commits
) +
609 ncommits
* sizeof(commit_ids
[0]));
611 return got_error_from_errno("imsg_create TRAVERSED_COMMITS");
613 if (imsg_add(wbuf
, &ncommits
, sizeof(ncommits
)) == -1)
614 return got_error_from_errno("imsg_add TRAVERSED_COMMITS");
616 for (i
= 0; i
< ncommits
; i
++) {
617 struct got_object_id
*id
= &commit_ids
[i
];
618 if (imsg_add(wbuf
, id
, sizeof(*id
)) == -1) {
619 return got_error_from_errno(
620 "imsg_add TRAVERSED_COMMITS");
624 imsg_close(ibuf
, wbuf
);
626 return got_privsep_flush_imsg(ibuf
);
629 static const struct got_error
*
630 send_commit_traversal_done(struct imsgbuf
*ibuf
)
632 if (imsg_compose(ibuf
, GOT_IMSG_COMMIT_TRAVERSAL_DONE
, 0, 0, -1,
634 return got_error_from_errno("imsg_compose TRAVERSAL_DONE");
636 return got_privsep_flush_imsg(ibuf
);
639 static const struct got_error
*
640 commit_traversal_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
641 struct got_pack
*pack
, struct got_packidx
*packidx
,
642 struct got_object_cache
*objcache
)
644 const struct got_error
*err
= NULL
;
645 struct got_imsg_commit_traversal_request ctreq
;
646 struct got_object_qid
*pid
;
647 struct got_commit_object
*commit
= NULL
, *pcommit
= NULL
;
648 struct got_object_id id
;
651 const int min_alloc
= 64;
652 int changed
= 0, ncommits
= 0, nallocated
= 0;
653 struct got_object_id
*commit_ids
= NULL
;
655 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
656 if (datalen
< sizeof(ctreq
))
657 return got_error(GOT_ERR_PRIVSEP_LEN
);
658 memcpy(&ctreq
, imsg
->data
, sizeof(ctreq
));
659 memcpy(&id
, &ctreq
.iobj
.id
, sizeof(id
));
661 if (datalen
!= sizeof(ctreq
) + ctreq
.path_len
)
662 return got_error(GOT_ERR_PRIVSEP_LEN
);
663 if (ctreq
.path_len
== 0)
664 return got_error(GOT_ERR_PRIVSEP_LEN
);
666 path
= strndup(imsg
->data
+ sizeof(ctreq
), ctreq
.path_len
);
668 return got_error_from_errno("strndup");
670 nallocated
= min_alloc
;
671 commit_ids
= reallocarray(NULL
, nallocated
, sizeof(*commit_ids
));
672 if (commit_ids
== NULL
)
673 return got_error_from_errno("reallocarray");
676 const size_t max_datalen
= MAX_IMSGSIZE
- IMSG_HEADER_SIZE
;
679 if (sigint_received
) {
680 err
= got_error(GOT_ERR_CANCELLED
);
684 if (commit
== NULL
) {
685 idx
= got_packidx_get_object_idx(packidx
, &id
);
688 err
= open_commit(&commit
, pack
, packidx
,
691 if (err
->code
!= GOT_ERR_NO_OBJ
)
698 if (sizeof(struct got_imsg_traversed_commits
) +
699 (ncommits
+ 1) * sizeof(commit_ids
[0]) >= max_datalen
) {
700 err
= send_traversed_commits(commit_ids
, ncommits
,
707 if (ncommits
> nallocated
) {
708 struct got_object_id
*new;
709 nallocated
+= min_alloc
;
710 new = reallocarray(commit_ids
, nallocated
,
711 sizeof(*commit_ids
));
713 err
= got_error_from_errno("reallocarray");
718 memcpy(&commit_ids
[ncommits
- 1], &id
, sizeof(id
));
720 pid
= STAILQ_FIRST(&commit
->parent_ids
);
724 idx
= got_packidx_get_object_idx(packidx
, &pid
->id
);
728 err
= open_commit(&pcommit
, pack
, packidx
, idx
, &pid
->id
,
731 if (err
->code
!= GOT_ERR_NO_OBJ
)
737 if (path
[0] == '/' && path
[1] == '\0') {
738 if (got_object_id_cmp(pcommit
->tree_id
,
739 commit
->tree_id
) != 0) {
745 uint8_t *buf
= NULL
, *pbuf
= NULL
;
746 size_t len
= 0, plen
= 0;
748 idx
= got_packidx_get_object_idx(packidx
,
752 pidx
= got_packidx_get_object_idx(packidx
,
757 err
= open_tree(&buf
, &len
, pack
, packidx
, idx
,
758 commit
->tree_id
, objcache
);
762 err
= open_tree(&pbuf
, &plen
, pack
, packidx
, pidx
,
763 pcommit
->tree_id
, objcache
);
769 err
= tree_path_changed(&changed
, &buf
, &len
,
770 &pbuf
, &plen
, path
, pack
, packidx
, ibuf
,
776 if (err
->code
!= GOT_ERR_NO_OBJ
)
784 memcpy(&id
, &pid
->id
, sizeof(id
));
785 got_object_commit_close(commit
);
792 err
= send_traversed_commits(commit_ids
, ncommits
, ibuf
);
797 err
= got_privsep_send_commit(ibuf
, commit
);
802 err
= send_commit_traversal_done(ibuf
);
807 got_object_commit_close(commit
);
809 got_object_commit_close(pcommit
);
811 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
814 got_privsep_send_error(ibuf
, err
);
820 static const struct got_error
*
821 raw_object_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
822 struct got_pack
*pack
, struct got_packidx
*packidx
,
823 struct got_object_cache
*objcache
, FILE *basefile
, FILE *accumfile
)
825 const struct got_error
*err
= NULL
;
828 FILE *outfile
= NULL
;
829 struct got_imsg_packed_object iobj
;
830 struct got_object
*obj
;
831 struct got_object_id id
;
834 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
835 if (datalen
!= sizeof(iobj
))
836 return got_error(GOT_ERR_PRIVSEP_LEN
);
837 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
838 memcpy(&id
, &iobj
.id
, sizeof(id
));
840 obj
= got_object_cache_get(objcache
, &id
);
844 err
= open_object(&obj
, pack
, packidx
, iobj
.idx
, &id
,
850 err
= receive_file(&outfile
, ibuf
, GOT_IMSG_RAW_OBJECT_OUTFD
);
854 if (obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) {
855 err
= got_pack_get_max_delta_object_size(&size
, obj
, pack
);
861 if (size
<= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX
)
862 err
= got_packfile_extract_object_to_mem(&buf
, &obj
->size
,
865 err
= got_packfile_extract_object(pack
, obj
, outfile
, basefile
,
870 err
= got_privsep_send_raw_obj(ibuf
, obj
->size
, obj
->hdrlen
, buf
);
873 if (outfile
&& fclose(outfile
) == EOF
&& err
== NULL
)
874 err
= got_error_from_errno("fclose");
875 got_object_close(obj
);
876 if (err
&& err
->code
!= GOT_ERR_PRIVSEP_PIPE
)
877 got_privsep_send_error(ibuf
, err
);
882 static const struct got_error
*
883 get_base_object_id(struct got_object_id
*base_id
, struct got_packidx
*packidx
,
886 const struct got_error
*err
;
889 err
= got_packidx_get_offset_idx(&idx
, packidx
, base_offset
);
893 return got_error(GOT_ERR_BAD_PACKIDX
);
895 return got_packidx_get_object_id(base_id
, packidx
, idx
);
898 static const struct got_error
*
899 raw_delta_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
900 FILE *delta_outfile
, struct got_pack
*pack
,
901 struct got_packidx
*packidx
)
903 const struct got_error
*err
= NULL
;
904 struct got_imsg_raw_delta_request req
;
905 size_t datalen
, delta_size
, delta_compressed_size
;
906 off_t delta_offset
, delta_data_offset
;
907 uint8_t *delta_buf
= NULL
;
908 struct got_object_id id
, base_id
;
909 off_t base_offset
, delta_out_offset
= 0;
910 uint64_t base_size
= 0, result_size
= 0;
913 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
914 if (datalen
!= sizeof(req
))
915 return got_error(GOT_ERR_PRIVSEP_LEN
);
916 memcpy(&req
, imsg
->data
, sizeof(req
));
917 memcpy(&id
, &req
.id
, sizeof(id
));
919 err
= got_packfile_extract_raw_delta(&delta_buf
, &delta_size
,
920 &delta_compressed_size
, &delta_offset
, &delta_data_offset
,
921 &base_offset
, &base_id
, &base_size
, &result_size
,
922 pack
, packidx
, req
.idx
);
927 * If this is an offset delta we must determine the base
928 * object ID ourselves.
930 if (base_offset
!= 0) {
931 err
= get_base_object_id(&base_id
, packidx
, base_offset
);
936 delta_out_offset
= ftello(delta_outfile
);
937 w
= fwrite(delta_buf
, 1, delta_compressed_size
, delta_outfile
);
938 if (w
!= delta_compressed_size
) {
939 err
= got_ferror(delta_outfile
, GOT_ERR_IO
);
942 if (fflush(delta_outfile
) == -1) {
943 err
= got_error_from_errno("fflush");
947 err
= got_privsep_send_raw_delta(ibuf
, base_size
, result_size
,
948 delta_size
, delta_compressed_size
, delta_offset
, delta_out_offset
,
955 struct search_deltas_arg
{
956 struct imsgbuf
*ibuf
;
957 struct got_packidx
*packidx
;
958 struct got_pack
*pack
;
959 struct got_object_idset
*idset
;
960 struct got_imsg_reused_delta deltas
[GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS
];
964 static const struct got_error
*
965 search_delta_for_object(struct got_object_id
*id
, void *data
, void *arg
)
967 const struct got_error
*err
;
968 struct search_deltas_arg
*a
= arg
;
970 uint8_t *delta_buf
= NULL
;
971 uint64_t base_size
, result_size
;
972 size_t delta_size
, delta_compressed_size
;
973 off_t delta_offset
, delta_data_offset
, base_offset
;
974 struct got_object_id base_id
;
977 return got_error(GOT_ERR_CANCELLED
);
979 obj_idx
= got_packidx_get_object_idx(a
->packidx
, id
);
981 return NULL
; /* object not present in our pack file */
983 err
= got_packfile_extract_raw_delta(&delta_buf
, &delta_size
,
984 &delta_compressed_size
, &delta_offset
, &delta_data_offset
,
985 &base_offset
, &base_id
, &base_size
, &result_size
,
986 a
->pack
, a
->packidx
, obj_idx
);
988 if (err
->code
== GOT_ERR_OBJ_TYPE
)
989 return NULL
; /* object not stored as a delta */
994 * If this is an offset delta we must determine the base
995 * object ID ourselves.
997 if (base_offset
!= 0) {
998 err
= get_base_object_id(&base_id
, a
->packidx
, base_offset
);
1003 if (got_object_idset_contains(a
->idset
, &base_id
)) {
1004 struct got_imsg_reused_delta
*delta
;
1006 delta
= &a
->deltas
[a
->ndeltas
++];
1007 memcpy(&delta
->id
, id
, sizeof(delta
->id
));
1008 memcpy(&delta
->base_id
, &base_id
, sizeof(delta
->base_id
));
1009 delta
->base_size
= base_size
;
1010 delta
->result_size
= result_size
;
1011 delta
->delta_size
= delta_size
;
1012 delta
->delta_compressed_size
= delta_compressed_size
;
1013 delta
->delta_offset
= delta_data_offset
;
1015 if (a
->ndeltas
>= GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS
) {
1016 err
= got_privsep_send_reused_deltas(a
->ibuf
,
1017 a
->deltas
, a
->ndeltas
);
1028 static const struct got_error
*
1029 recv_object_ids(struct got_object_idset
*idset
, struct imsgbuf
*ibuf
)
1031 const struct got_error
*err
= NULL
;
1033 struct got_object_id
*ids
;
1037 err
= got_privsep_recv_object_idlist(&done
, &ids
, &nids
, ibuf
);
1040 for (i
= 0; i
< nids
; i
++) {
1041 err
= got_object_idset_add(idset
, &ids
[i
], NULL
);
1053 static const struct got_error
*
1054 recv_object_id_queue(size_t *nids_total
, struct got_object_id_queue
*queue
,
1055 void *data
, struct got_object_idset
*queued_ids
, struct imsgbuf
*ibuf
)
1057 const struct got_error
*err
= NULL
;
1059 struct got_object_qid
*qid
;
1060 struct got_object_id
*ids
;
1065 err
= got_privsep_recv_object_idlist(&done
, &ids
, &nids
, ibuf
);
1068 *nids_total
+= nids
;
1069 for (i
= 0; i
< nids
; i
++) {
1070 err
= got_object_qid_alloc_partial(&qid
);
1073 memcpy(&qid
->id
, &ids
[i
], sizeof(qid
->id
));
1076 STAILQ_INSERT_TAIL(queue
, qid
, entry
);
1078 err
= got_object_idset_add(queued_ids
,
1092 static const struct got_error
*
1093 delta_reuse_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
1094 struct got_pack
*pack
, struct got_packidx
*packidx
)
1096 const struct got_error
*err
= NULL
;
1097 struct got_object_idset
*idset
;
1098 struct search_deltas_arg sda
;
1100 idset
= got_object_idset_alloc();
1102 return got_error_from_errno("got_object_idset_alloc");
1104 err
= recv_object_ids(idset
, ibuf
);
1108 memset(&sda
, 0, sizeof(sda
));
1112 sda
.packidx
= packidx
;
1113 err
= got_object_idset_for_each(idset
, search_delta_for_object
, &sda
);
1117 if (sda
.ndeltas
> 0) {
1118 err
= got_privsep_send_reused_deltas(ibuf
, sda
.deltas
,
1124 err
= got_privsep_send_reused_deltas_done(ibuf
);
1126 got_object_idset_free(idset
);
1130 static const struct got_error
*
1131 receive_packidx(struct got_packidx
**packidx
, struct imsgbuf
*ibuf
)
1133 const struct got_error
*err
= NULL
;
1135 struct got_imsg_packidx ipackidx
;
1137 struct got_packidx
*p
;
1141 err
= got_privsep_recv_imsg(&imsg
, ibuf
, 0);
1145 p
= calloc(1, sizeof(*p
));
1147 err
= got_error_from_errno("calloc");
1151 if (imsg
.hdr
.type
!= GOT_IMSG_PACKIDX
) {
1152 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1156 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
1157 if (datalen
!= sizeof(ipackidx
)) {
1158 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1161 memcpy(&ipackidx
, imsg
.data
, sizeof(ipackidx
));
1163 p
->algo
= ipackidx
.algo
;
1164 p
->fd
= imsg_get_fd(&imsg
);
1165 p
->len
= ipackidx
.len
;
1167 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
1170 if (lseek(p
->fd
, 0, SEEK_SET
) == -1) {
1171 err
= got_error_from_errno("lseek");
1175 #ifndef GOT_PACK_NO_MMAP
1176 if (p
->len
> 0 && p
->len
<= SIZE_MAX
) {
1177 p
->map
= mmap(NULL
, p
->len
, PROT_READ
, MAP_PRIVATE
, p
->fd
, 0);
1178 if (p
->map
== MAP_FAILED
)
1179 p
->map
= NULL
; /* fall back to read(2) */
1182 err
= got_packidx_init_hdr(p
, 1, ipackidx
.packfile_size
);
1186 got_packidx_close(p
);
1193 static const struct got_error
*
1194 send_tree_enumeration_done(struct imsgbuf
*ibuf
)
1196 if (imsg_compose(ibuf
, GOT_IMSG_TREE_ENUMERATION_DONE
, 0, 0, -1,
1198 return got_error_from_errno("imsg_compose TREE_ENUMERATION_DONE");
1200 return got_privsep_flush_imsg(ibuf
);
1203 struct enumerated_tree
{
1204 struct got_object_id id
;
1207 struct got_parsed_tree_entry
*entries
;
1211 static const struct got_error
*
1212 enumerate_tree(int *have_all_entries
, struct imsgbuf
*ibuf
, size_t *totlen
,
1213 struct got_object_id
*tree_id
,
1214 const char *path
, struct got_pack
*pack
, struct got_packidx
*packidx
,
1215 struct got_object_cache
*objcache
, struct got_object_idset
*idset
,
1216 struct enumerated_tree
**trees
, size_t *nalloc
, size_t *ntrees
)
1218 const struct got_error
*err
= NULL
;
1219 struct got_object_id_queue ids
;
1220 struct got_object_qid
*qid
;
1221 uint8_t *buf
= NULL
;
1223 struct got_parsed_tree_entry
*entries
= NULL
;
1224 size_t nentries
= 0, nentries_alloc
= 0, i
;
1225 struct enumerated_tree
*tree
;
1228 *have_all_entries
= 1;
1231 err
= got_object_qid_alloc_partial(&qid
);
1234 memcpy(&qid
->id
, tree_id
, sizeof(*tree_id
));
1235 qid
->data
= strdup(path
);
1236 if (qid
->data
== NULL
) {
1237 err
= got_error_from_errno("strdup");
1240 STAILQ_INSERT_TAIL(&ids
, qid
, entry
);
1243 /* Traverse the tree hierarchy, gather tree object IDs and paths. */
1248 if (sigint_received
) {
1249 err
= got_error(GOT_ERR_CANCELLED
);
1253 qid
= STAILQ_FIRST(&ids
);
1254 STAILQ_REMOVE_HEAD(&ids
, entry
);
1257 idx
= got_packidx_get_object_idx(packidx
, &qid
->id
);
1259 *have_all_entries
= 0;
1263 err
= open_tree(&buf
, &len
, pack
, packidx
, idx
, &qid
->id
,
1266 if (err
->code
!= GOT_ERR_NO_OBJ
)
1270 err
= got_object_parse_tree(&entries
, &nentries
,
1271 &nentries_alloc
, buf
, len
, pack
->algo
);
1275 err
= got_object_idset_add(idset
, &qid
->id
, NULL
);
1279 for (i
= 0; i
< nentries
; i
++) {
1280 struct got_object_qid
*eqid
= NULL
;
1281 struct got_parsed_tree_entry
*pte
= &entries
[i
];
1284 if (!S_ISDIR(pte
->mode
))
1287 err
= got_object_qid_alloc_partial(&eqid
);
1290 eqid
->id
.algo
= pte
->algo
;
1291 memcpy(eqid
->id
.hash
, pte
->id
, pte
->digest_len
);
1293 if (got_object_idset_contains(idset
, &eqid
->id
)) {
1294 got_object_qid_free(eqid
);
1298 if (asprintf(&p
, "%s%s%s", path
,
1299 got_path_is_root_dir(path
) ? "" : "/",
1301 err
= got_error_from_errno("asprintf");
1302 got_object_qid_free(eqid
);
1306 STAILQ_INSERT_TAIL(&ids
, eqid
, entry
);
1309 if (*ntrees
>= *nalloc
) {
1310 struct enumerated_tree
*new;
1311 new = recallocarray(*trees
, *nalloc
, *nalloc
+ 16,
1314 err
= got_error_from_errno("malloc");
1320 tree
= &(*trees
)[*ntrees
];
1322 memcpy(&tree
->id
, &qid
->id
, sizeof(tree
->id
));
1323 tree
->path
= qid
->data
;
1326 tree
->entries
= entries
;
1329 tree
->nentries
= nentries
;
1332 got_object_qid_free(qid
);
1334 } while (!STAILQ_EMPTY(&ids
));
1336 if (*have_all_entries
) {
1339 * We have managed to traverse all entries in the hierarchy.
1340 * Tell the main process what we have found.
1342 for (i
= 0; i
< *ntrees
; i
++) {
1343 tree
= &(*trees
)[i
];
1344 err
= got_privsep_send_enumerated_tree(totlen
,
1345 ibuf
, &tree
->id
, tree
->path
, tree
->entries
,
1353 free(tree
->entries
);
1354 tree
->entries
= NULL
;
1356 *ntrees
= 0; /* don't loop again below to free memory */
1358 err
= send_tree_enumeration_done(ibuf
);
1361 * We can only load fully packed tree hierarchies on
1362 * behalf of the main process, otherwise the main process
1363 * gets a wrong idea about which tree objects have
1364 * already been traversed.
1365 * Indicate a missing entry for the root of this tree.
1366 * The main process should continue by loading this
1367 * entire tree the slow way.
1369 err
= got_privsep_send_enumerated_tree(totlen
, ibuf
,
1370 tree_id
, "/", NULL
, -1);
1377 for (i
= 0; i
< *ntrees
; i
++) {
1378 tree
= &(*trees
)[i
];
1383 free(tree
->entries
);
1384 tree
->entries
= NULL
;
1388 got_object_qid_free(qid
);
1389 got_object_id_queue_free(&ids
);
1391 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
1394 got_privsep_send_error(ibuf
, err
);
1401 static const struct got_error
*
1402 resolve_tag(struct got_object
**obj
, struct got_object_id
*id
,
1403 struct got_packidx
*packidx
, struct got_pack
*pack
,
1404 struct got_object_cache
*objcache
)
1406 const struct got_error
*err
;
1407 struct got_object
*tagged_obj
;
1408 struct got_tag_object
*tag
;
1413 err
= got_packfile_extract_object_to_mem(&buf
, &len
, *obj
, pack
);
1418 err
= got_object_parse_tag(&tag
, buf
, len
, id
->algo
);
1422 idx
= got_packidx_get_object_idx(packidx
, &tag
->id
);
1424 got_object_close(*obj
);
1429 tagged_obj
= got_object_cache_get(objcache
, &tag
->id
);
1431 tagged_obj
->refcnt
++;
1433 err
= open_object(&tagged_obj
, pack
, packidx
,
1434 idx
, &tag
->id
, objcache
);
1439 got_object_close(*obj
);
1442 got_object_tag_close(tag
);
1447 static const struct got_error
*
1448 enumeration_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
1449 struct got_pack
*pack
, struct got_packidx
*packidx
,
1450 struct got_object_cache
*objcache
)
1452 const struct got_error
*err
= NULL
;
1453 struct got_object_id_queue commit_ids
;
1454 const struct got_object_id_queue
*parents
= NULL
;
1455 struct got_object_qid
*qid
= NULL
;
1456 struct got_object
*obj
= NULL
;
1457 struct got_commit_object
*commit
= NULL
;
1458 struct got_object_id
*tree_id
= NULL
;
1460 struct got_object_idset
*idset
, *queued_ids
= NULL
;
1461 int i
, idx
, have_all_entries
= 1;
1462 struct enumerated_tree
*trees
= NULL
;
1463 size_t ntrees
= 0, nalloc
= 16, nids
= 0;
1465 STAILQ_INIT(&commit_ids
);
1467 trees
= calloc(nalloc
, sizeof(*trees
));
1469 return got_error_from_errno("calloc");
1471 idset
= got_object_idset_alloc();
1472 if (idset
== NULL
) {
1473 err
= got_error_from_errno("got_object_idset_alloc");
1477 queued_ids
= got_object_idset_alloc();
1478 if (queued_ids
== NULL
) {
1479 err
= got_error_from_errno("got_object_idset_alloc");
1483 err
= recv_object_id_queue(&nids
, &commit_ids
, NULL
, queued_ids
, ibuf
);
1487 if (STAILQ_EMPTY(&commit_ids
)) {
1488 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1492 err
= recv_object_ids(idset
, ibuf
);
1496 while (!STAILQ_EMPTY(&commit_ids
)) {
1497 if (sigint_received
) {
1498 err
= got_error(GOT_ERR_CANCELLED
);
1502 qid
= STAILQ_FIRST(&commit_ids
);
1503 STAILQ_REMOVE_HEAD(&commit_ids
, entry
);
1505 if (got_object_idset_contains(idset
, &qid
->id
)) {
1506 got_object_qid_free(qid
);
1511 idx
= got_packidx_get_object_idx(packidx
, &qid
->id
);
1513 have_all_entries
= 0;
1517 err
= open_object(&obj
, pack
, packidx
, idx
, &qid
->id
,
1521 if (obj
->type
== GOT_OBJ_TYPE_TAG
) {
1522 while (obj
->type
== GOT_OBJ_TYPE_TAG
) {
1523 err
= resolve_tag(&obj
, &qid
->id
, packidx
,
1531 have_all_entries
= 0;
1534 if (obj
->type
!= GOT_OBJ_TYPE_COMMIT
) {
1535 got_object_qid_free(qid
);
1537 got_object_close(obj
);
1541 err
= open_commit(&commit
, pack
, packidx
, idx
,
1542 &obj
->id
, objcache
);
1545 } else if (obj
->type
== GOT_OBJ_TYPE_COMMIT
) {
1546 err
= open_commit(&commit
, pack
, packidx
, idx
,
1547 &qid
->id
, objcache
);
1551 err
= got_error(GOT_ERR_OBJ_TYPE
);
1554 got_object_close(obj
);
1557 err
= got_privsep_send_enumerated_commit(ibuf
, &qid
->id
,
1558 got_object_commit_get_committer_time(commit
));
1562 tree_id
= got_object_commit_get_tree_id(commit
);
1563 idx
= got_packidx_get_object_idx(packidx
, tree_id
);
1565 have_all_entries
= 0;
1566 err
= got_privsep_send_enumerated_tree(&totlen
, ibuf
,
1567 tree_id
, "/", NULL
, -1);
1573 if (got_object_idset_contains(idset
, tree_id
)) {
1574 got_object_qid_free(qid
);
1576 err
= send_tree_enumeration_done(ibuf
);
1579 got_object_commit_close(commit
);
1584 err
= enumerate_tree(&have_all_entries
, ibuf
, &totlen
,
1585 tree_id
, "/", pack
, packidx
, objcache
, idset
,
1586 &trees
, &nalloc
, &ntrees
);
1590 if (!have_all_entries
)
1593 got_object_qid_free(qid
);
1596 parents
= got_object_commit_get_parent_ids(commit
);
1598 struct got_object_qid
*pid
;
1599 STAILQ_FOREACH(pid
, parents
, entry
) {
1600 if (got_object_idset_contains(idset
, &pid
->id
))
1602 if (got_object_idset_contains(queued_ids
, &pid
->id
))
1604 err
= got_object_qid_alloc_partial(&qid
);
1607 memcpy(&qid
->id
, &pid
->id
, sizeof(qid
->id
));
1608 STAILQ_INSERT_TAIL(&commit_ids
, qid
, entry
);
1613 got_object_commit_close(commit
);
1617 if (have_all_entries
) {
1618 err
= got_privsep_send_object_enumeration_done(ibuf
);
1622 err
= got_privsep_send_object_enumeration_incomplete(ibuf
);
1628 got_object_close(obj
);
1630 got_object_commit_close(commit
);
1631 got_object_qid_free(qid
);
1632 got_object_id_queue_free(&commit_ids
);
1634 got_object_idset_free(idset
);
1636 got_object_idset_free(queued_ids
);
1637 for (i
= 0; i
< ntrees
; i
++) {
1638 struct enumerated_tree
*tree
= &trees
[i
];
1641 free(tree
->entries
);
1647 enum findtwixt_color
{
1654 static const struct got_error
*
1655 paint_commit(struct got_object_qid
*qid
, intptr_t color
)
1657 if (color
< 0 || color
>= COLOR_MAX
)
1658 return got_error(GOT_ERR_RANGE
);
1660 qid
->data
= (void *)color
;
1664 static const struct got_error
*
1665 queue_commit_id(struct got_object_id_queue
*ids
, struct got_object_id
*id
,
1668 const struct got_error
*err
;
1669 struct got_object_qid
*qid
;
1671 err
= got_object_qid_alloc_partial(&qid
);
1675 memcpy(&qid
->id
, id
, sizeof(qid
->id
));
1676 STAILQ_INSERT_TAIL(ids
, qid
, entry
);
1677 return paint_commit(qid
, color
);
1680 static const struct got_error
*
1681 repaint_parent_commits(struct got_object_id
*commit_id
, int commit_idx
,
1682 int color
, struct got_object_idset
*set
, struct got_object_idset
*skip
,
1683 struct got_object_id_queue
*ids
, int *nids
,
1684 struct got_object_id_queue
*painted
, int *npainted
,
1685 struct got_pack
*pack
, struct got_packidx
*packidx
,
1686 struct got_object_cache
*objcache
)
1688 const struct got_error
*err
;
1689 const struct got_object_id_queue
*parents
;
1690 struct got_commit_object
*commit
;
1691 struct got_object_id_queue repaint
;
1693 STAILQ_INIT(&repaint
);
1695 err
= open_commit(&commit
, pack
, packidx
, commit_idx
, commit_id
,
1701 struct got_object_qid
*pid
, *qid
, *tmp
;
1704 parents
= got_object_commit_get_parent_ids(commit
);
1706 STAILQ_FOREACH(pid
, parents
, entry
) {
1707 idx
= got_packidx_get_object_idx(packidx
,
1710 * No need to traverse parents which are not in
1711 * the pack file, are already in the desired
1712 * set, or are marked for skipping already.
1716 if (got_object_idset_contains(set
, &pid
->id
))
1719 got_object_idset_contains(skip
, &pid
->id
))
1722 err
= queue_commit_id(&repaint
, &pid
->id
,
1728 got_object_commit_close(commit
);
1731 pid
= STAILQ_FIRST(&repaint
);
1735 err
= paint_commit(pid
, color
);
1739 if (!got_object_idset_contains(set
, &pid
->id
)) {
1740 err
= got_object_idset_add(set
, &pid
->id
, NULL
);
1745 STAILQ_REMOVE_HEAD(&repaint
, entry
);
1747 /* Insert or replace this commit on the painted list. */
1748 STAILQ_FOREACH(qid
, painted
, entry
) {
1749 if (got_object_id_cmp(&qid
->id
, &pid
->id
) != 0)
1751 err
= paint_commit(qid
, color
);
1754 got_object_qid_free(pid
);
1759 STAILQ_INSERT_TAIL(painted
, pid
, entry
);
1764 * In case this commit is on the caller's list of
1765 * pending commits to traverse, repaint it there.
1767 STAILQ_FOREACH_SAFE(qid
, ids
, entry
, tmp
) {
1768 if (got_object_id_cmp(&qid
->id
, &pid
->id
) != 0)
1770 err
= paint_commit(qid
, color
);
1776 idx
= got_packidx_get_object_idx(packidx
, &pid
->id
);
1779 * Should not happen because we only queue
1780 * parents which exist in our pack file.
1782 err
= got_error(GOT_ERR_NO_OBJ
);
1786 err
= open_commit(&commit
, pack
, packidx
, idx
, &pid
->id
,
1793 got_object_commit_close(commit
);
1794 got_object_id_queue_free(&repaint
);
1799 static const struct got_error
*
1800 paint_commits(struct got_object_id_queue
*ids
, int *nids
,
1801 struct got_object_idset
*keep
, struct got_object_idset
*drop
,
1802 struct got_object_idset
*skip
, struct got_pack
*pack
,
1803 struct got_packidx
*packidx
, struct imsgbuf
*ibuf
,
1804 struct got_object_cache
*objcache
)
1806 const struct got_error
*err
= NULL
;
1807 struct got_commit_object
*commit
= NULL
;
1808 struct got_object_id_queue painted
;
1809 const struct got_object_id_queue
*parents
;
1810 struct got_object_qid
*qid
= NULL
;
1811 int nqueued
= *nids
, nskip
= 0, npainted
= 0;
1813 STAILQ_INIT(&painted
);
1815 while (!STAILQ_EMPTY(ids
) && nskip
!= nqueued
) {
1819 if (sigint_received
) {
1820 err
= got_error(GOT_ERR_CANCELLED
);
1824 qid
= STAILQ_FIRST(ids
);
1825 idx
= got_packidx_get_object_idx(packidx
, &qid
->id
);
1831 STAILQ_REMOVE_HEAD(ids
, entry
);
1833 color
= (intptr_t)qid
->data
;
1834 if (color
== COLOR_SKIP
)
1837 if (got_object_idset_contains(skip
, &qid
->id
)) {
1838 got_object_qid_free(qid
);
1845 if (got_object_idset_contains(drop
, &qid
->id
)) {
1846 err
= paint_commit(qid
, COLOR_SKIP
);
1849 err
= got_object_idset_add(skip
, &qid
->id
,
1853 err
= repaint_parent_commits(&qid
->id
, idx
,
1854 COLOR_SKIP
, skip
, skip
, ids
, nids
,
1855 &painted
, &npainted
, pack
, packidx
,
1861 if (!got_object_idset_contains(keep
, &qid
->id
)) {
1862 err
= got_object_idset_add(keep
, &qid
->id
,
1869 if (got_object_idset_contains(keep
, &qid
->id
)) {
1870 err
= paint_commit(qid
, COLOR_SKIP
);
1873 err
= got_object_idset_add(skip
, &qid
->id
,
1877 err
= repaint_parent_commits(&qid
->id
, idx
,
1878 COLOR_SKIP
, skip
, skip
, ids
, nids
,
1879 &painted
, &npainted
, pack
, packidx
,
1885 if (!got_object_idset_contains(drop
, &qid
->id
)) {
1886 err
= got_object_idset_add(drop
, &qid
->id
,
1893 err
= got_object_idset_add(skip
, &qid
->id
,
1899 /* should not happen */
1900 err
= got_error_fmt(GOT_ERR_NOT_IMPL
,
1901 "%s invalid commit color %"PRIdPTR
, __func__
,
1906 err
= open_commit(&commit
, pack
, packidx
, idx
, &qid
->id
,
1911 parents
= got_object_commit_get_parent_ids(commit
);
1913 struct got_object_qid
*pid
;
1914 color
= (intptr_t)qid
->data
;
1915 STAILQ_FOREACH(pid
, parents
, entry
) {
1916 err
= queue_commit_id(ids
, &pid
->id
, color
);
1920 if (color
== COLOR_SKIP
)
1925 got_object_commit_close(commit
);
1928 STAILQ_INSERT_TAIL(&painted
, qid
, entry
);
1932 err
= got_privsep_send_painted_commits(ibuf
, &painted
,
1938 err
= got_privsep_send_painted_commits(ibuf
, &painted
, &npainted
, 1, 1);
1945 got_object_commit_close(commit
);
1946 got_object_qid_free(qid
);
1951 commit_painting_free(struct got_object_idset
**keep
,
1952 struct got_object_idset
**drop
,
1953 struct got_object_idset
**skip
)
1956 got_object_idset_free(*keep
);
1960 got_object_idset_free(*drop
);
1964 got_object_idset_free(*skip
);
1969 static const struct got_error
*
1970 commit_painting_init(struct imsgbuf
*ibuf
, struct got_object_idset
**keep
,
1971 struct got_object_idset
**drop
, struct got_object_idset
**skip
)
1973 const struct got_error
*err
= NULL
;
1975 *keep
= got_object_idset_alloc();
1976 if (*keep
== NULL
) {
1977 err
= got_error_from_errno("got_object_idset_alloc");
1980 *drop
= got_object_idset_alloc();
1981 if (*drop
== NULL
) {
1982 err
= got_error_from_errno("got_object_idset_alloc");
1985 *skip
= got_object_idset_alloc();
1986 if (*skip
== NULL
) {
1987 err
= got_error_from_errno("got_object_idset_alloc");
1991 err
= recv_object_ids(*keep
, ibuf
);
1994 err
= recv_object_ids(*drop
, ibuf
);
1997 err
= recv_object_ids(*skip
, ibuf
);
2003 commit_painting_free(keep
, drop
, skip
);
2008 static const struct got_error
*
2009 commit_painting_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
2010 struct got_pack
*pack
, struct got_packidx
*packidx
,
2011 struct got_object_cache
*objcache
, struct got_object_idset
*keep
,
2012 struct got_object_idset
*drop
, struct got_object_idset
*skip
)
2014 const struct got_error
*err
= NULL
;
2016 struct got_object_id_queue ids
;
2017 size_t nkeep
= 0, ndrop
= 0, nskip
= 0;
2023 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
2025 return got_error(GOT_ERR_PRIVSEP_LEN
);
2028 err
= recv_object_id_queue(&nkeep
, &ids
, (void *)color
, NULL
, ibuf
);
2031 if (nids
+ nkeep
> INT_MAX
) {
2032 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
2038 err
= recv_object_id_queue(&ndrop
, &ids
, (void *)color
, NULL
, ibuf
);
2041 if (nids
+ ndrop
> INT_MAX
) {
2042 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
2048 err
= recv_object_id_queue(&nskip
, &ids
, (void *)color
, NULL
, ibuf
);
2051 if (nids
+ nskip
> INT_MAX
) {
2052 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
2057 err
= paint_commits(&ids
, &nids
, keep
, drop
, skip
,
2058 pack
, packidx
, ibuf
, objcache
);
2062 err
= got_privsep_send_painted_commits(ibuf
, &ids
, &nids
, 0, 1);
2066 err
= got_privsep_send_painting_commits_done(ibuf
);
2068 got_object_id_queue_free(&ids
);
2072 static const struct got_error
*
2073 receive_pack(struct got_pack
**packp
, struct imsgbuf
*ibuf
)
2075 const struct got_error
*err
= NULL
;
2077 struct got_imsg_pack ipack
;
2079 struct got_pack
*pack
;
2083 err
= got_privsep_recv_imsg(&imsg
, ibuf
, 0);
2087 pack
= calloc(1, sizeof(*pack
));
2089 err
= got_error_from_errno("calloc");
2093 if (imsg
.hdr
.type
!= GOT_IMSG_PACK
) {
2094 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2098 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
2099 if (datalen
!= sizeof(ipack
)) {
2100 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
2103 memcpy(&ipack
, imsg
.data
, sizeof(ipack
));
2105 pack
->algo
= ipack
.algo
;
2106 pack
->filesize
= ipack
.filesize
;
2107 pack
->fd
= imsg_get_fd(&imsg
);
2108 if (pack
->fd
== -1) {
2109 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
2112 if (lseek(pack
->fd
, 0, SEEK_SET
) == -1) {
2113 err
= got_error_from_errno("lseek");
2116 pack
->path_packfile
= strdup(ipack
.path_packfile
);
2117 if (pack
->path_packfile
== NULL
) {
2118 err
= got_error_from_errno("strdup");
2122 err
= got_delta_cache_alloc(&pack
->delta_cache
);
2126 #ifndef GOT_PACK_NO_MMAP
2127 if (pack
->filesize
> 0 && pack
->filesize
<= SIZE_MAX
) {
2128 pack
->map
= mmap(NULL
, pack
->filesize
, PROT_READ
, MAP_PRIVATE
,
2130 if (pack
->map
== MAP_FAILED
)
2131 pack
->map
= NULL
; /* fall back to read(2) */
2137 got_pack_close(pack
);
2145 main(int argc
, char *argv
[])
2147 const struct got_error
*err
= NULL
;
2148 struct imsgbuf ibuf
;
2150 struct got_packidx
*packidx
= NULL
;
2151 struct got_pack
*pack
= NULL
;
2152 struct got_object_cache objcache
;
2153 FILE *basefile
= NULL
, *accumfile
= NULL
, *delta_outfile
= NULL
;
2154 struct got_object_idset
*keep
= NULL
, *drop
= NULL
, *skip
= NULL
;
2155 struct got_parsed_tree_entry
*entries
= NULL
;
2156 size_t nentries
= 0, nentries_alloc
= 0;
2158 //static int attached;
2159 //while (!attached) sleep(1);
2161 signal(SIGINT
, catch_sigint
);
2163 if (imsgbuf_init(&ibuf
, GOT_IMSG_FD_CHILD
) == -1) {
2164 warn("imsgbuf_init");
2167 imsgbuf_allow_fdpass(&ibuf
);
2169 err
= got_object_cache_init(&objcache
, GOT_OBJECT_CACHE_TYPE_OBJ
);
2171 err
= got_error_from_errno("got_object_cache_init");
2172 got_privsep_send_error(&ibuf
, err
);
2173 imsgbuf_clear(&ibuf
);
2178 /* revoke access to most system calls */
2179 if (pledge("stdio recvfd", NULL
) == -1) {
2180 err
= got_error_from_errno("pledge");
2181 got_privsep_send_error(&ibuf
, err
);
2182 imsgbuf_clear(&ibuf
);
2186 /* revoke fs access */
2187 if (landlock_no_fs() == -1) {
2188 err
= got_error_from_errno("landlock_no_fs");
2189 got_privsep_send_error(&ibuf
, err
);
2192 if (cap_enter() == -1) {
2193 err
= got_error_from_errno("cap_enter");
2194 got_privsep_send_error(&ibuf
, err
);
2199 err
= receive_packidx(&packidx
, &ibuf
);
2201 got_privsep_send_error(&ibuf
, err
);
2202 imsgbuf_clear(&ibuf
);
2206 err
= receive_pack(&pack
, &ibuf
);
2208 got_privsep_send_error(&ibuf
, err
);
2209 imsgbuf_clear(&ibuf
);
2214 if (sigint_received
) {
2215 err
= got_error(GOT_ERR_CANCELLED
);
2219 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
2221 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
2226 if (imsg
.hdr
.type
== GOT_IMSG_STOP
) {
2231 switch (imsg
.hdr
.type
) {
2232 case GOT_IMSG_TMPFD
:
2233 if (basefile
== NULL
) {
2234 err
= receive_tempfile(&basefile
, "w+",
2236 } else if (accumfile
== NULL
) {
2237 err
= receive_tempfile(&accumfile
, "w+",
2240 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2242 case GOT_IMSG_PACKED_OBJECT_REQUEST
:
2243 err
= object_request(&imsg
, &ibuf
, pack
, packidx
,
2246 case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST
:
2247 if (basefile
== NULL
|| accumfile
== NULL
) {
2248 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2251 err
= raw_object_request(&imsg
, &ibuf
, pack
, packidx
,
2252 &objcache
, basefile
, accumfile
);
2254 case GOT_IMSG_RAW_DELTA_OUTFD
:
2255 if (delta_outfile
!= NULL
) {
2256 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2259 err
= receive_tempfile(&delta_outfile
, "w",
2262 case GOT_IMSG_RAW_DELTA_REQUEST
:
2263 if (delta_outfile
== NULL
) {
2264 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
2267 err
= raw_delta_request(&imsg
, &ibuf
, delta_outfile
,
2270 case GOT_IMSG_DELTA_REUSE_REQUEST
:
2271 err
= delta_reuse_request(&imsg
, &ibuf
, pack
, packidx
);
2273 case GOT_IMSG_COMMIT_REQUEST
:
2274 err
= commit_request(&imsg
, &ibuf
, pack
, packidx
,
2277 case GOT_IMSG_TREE_REQUEST
:
2278 err
= tree_request(&imsg
, &ibuf
, pack
, packidx
,
2279 &objcache
, &entries
, &nentries
, &nentries_alloc
);
2281 case GOT_IMSG_BLOB_REQUEST
:
2282 if (basefile
== NULL
|| accumfile
== NULL
) {
2283 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2286 err
= blob_request(&imsg
, &ibuf
, pack
, packidx
,
2287 &objcache
, basefile
, accumfile
);
2289 case GOT_IMSG_TAG_REQUEST
:
2290 err
= tag_request(&imsg
, &ibuf
, pack
, packidx
,
2293 case GOT_IMSG_COMMIT_TRAVERSAL_REQUEST
:
2294 err
= commit_traversal_request(&imsg
, &ibuf
, pack
,
2295 packidx
, &objcache
);
2297 case GOT_IMSG_OBJECT_ENUMERATION_REQUEST
:
2298 err
= enumeration_request(&imsg
, &ibuf
, pack
,
2299 packidx
, &objcache
);
2301 case GOT_IMSG_COMMIT_PAINTING_INIT
:
2302 commit_painting_free(&keep
, &drop
, &skip
);
2303 err
= commit_painting_init(&ibuf
, &keep
, &drop
, &skip
);
2305 case GOT_IMSG_COMMIT_PAINTING_REQUEST
:
2306 if (keep
== NULL
|| drop
== NULL
|| skip
== NULL
) {
2307 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2310 err
= commit_painting_request(&imsg
, &ibuf
, pack
,
2311 packidx
, &objcache
, keep
, drop
, skip
);
2313 case GOT_IMSG_COMMIT_PAINTING_DONE
:
2314 commit_painting_free(&keep
, &drop
, &skip
);
2317 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2327 commit_painting_free(&keep
, &drop
, &skip
);
2329 got_packidx_close(packidx
);
2331 got_pack_close(pack
);
2334 got_object_cache_close(&objcache
);
2335 if (basefile
&& fclose(basefile
) == EOF
&& err
== NULL
)
2336 err
= got_error_from_errno("fclose");
2337 if (accumfile
&& fclose(accumfile
) == EOF
&& err
== NULL
)
2338 err
= got_error_from_errno("fclose");
2339 if (delta_outfile
&& fclose(delta_outfile
) == EOF
&& err
== NULL
)
2340 err
= got_error_from_errno("fclose");
2342 if (!sigint_received
&& err
->code
!= GOT_ERR_PRIVSEP_PIPE
) {
2343 fprintf(stderr
, "%s: %s\n", getprogname(), err
->msg
);
2344 got_privsep_send_error(&ibuf
, err
);
2347 imsgbuf_clear(&ibuf
);
2348 if (close(GOT_IMSG_FD_CHILD
) == -1 && err
== NULL
)
2349 err
= got_error_from_errno("close");