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(struct got_object_id_queue
*queue
,
1055 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
;
1064 err
= got_privsep_recv_object_idlist(&done
, &ids
, &nids
, ibuf
);
1067 for (i
= 0; i
< nids
; i
++) {
1068 err
= got_object_qid_alloc_partial(&qid
);
1071 memcpy(&qid
->id
, &ids
[i
], sizeof(qid
->id
));
1072 STAILQ_INSERT_TAIL(queue
, qid
, entry
);
1073 err
= got_object_idset_add(queued_ids
, &qid
->id
, NULL
);
1082 static const struct got_error
*
1083 delta_reuse_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
1084 struct got_pack
*pack
, struct got_packidx
*packidx
)
1086 const struct got_error
*err
= NULL
;
1087 struct got_object_idset
*idset
;
1088 struct search_deltas_arg sda
;
1090 idset
= got_object_idset_alloc();
1092 return got_error_from_errno("got_object_idset_alloc");
1094 err
= recv_object_ids(idset
, ibuf
);
1098 memset(&sda
, 0, sizeof(sda
));
1102 sda
.packidx
= packidx
;
1103 err
= got_object_idset_for_each(idset
, search_delta_for_object
, &sda
);
1107 if (sda
.ndeltas
> 0) {
1108 err
= got_privsep_send_reused_deltas(ibuf
, sda
.deltas
,
1114 err
= got_privsep_send_reused_deltas_done(ibuf
);
1116 got_object_idset_free(idset
);
1120 static const struct got_error
*
1121 receive_packidx(struct got_packidx
**packidx
, struct imsgbuf
*ibuf
)
1123 const struct got_error
*err
= NULL
;
1125 struct got_imsg_packidx ipackidx
;
1127 struct got_packidx
*p
;
1131 err
= got_privsep_recv_imsg(&imsg
, ibuf
, 0);
1135 p
= calloc(1, sizeof(*p
));
1137 err
= got_error_from_errno("calloc");
1141 if (imsg
.hdr
.type
!= GOT_IMSG_PACKIDX
) {
1142 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1146 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
1147 if (datalen
!= sizeof(ipackidx
)) {
1148 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1151 memcpy(&ipackidx
, imsg
.data
, sizeof(ipackidx
));
1153 p
->algo
= ipackidx
.algo
;
1154 p
->fd
= imsg_get_fd(&imsg
);
1155 p
->len
= ipackidx
.len
;
1157 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
1160 if (lseek(p
->fd
, 0, SEEK_SET
) == -1) {
1161 err
= got_error_from_errno("lseek");
1165 #ifndef GOT_PACK_NO_MMAP
1166 if (p
->len
> 0 && p
->len
<= SIZE_MAX
) {
1167 p
->map
= mmap(NULL
, p
->len
, PROT_READ
, MAP_PRIVATE
, p
->fd
, 0);
1168 if (p
->map
== MAP_FAILED
)
1169 p
->map
= NULL
; /* fall back to read(2) */
1172 err
= got_packidx_init_hdr(p
, 1, ipackidx
.packfile_size
);
1176 got_packidx_close(p
);
1183 static const struct got_error
*
1184 send_tree_enumeration_done(struct imsgbuf
*ibuf
)
1186 if (imsg_compose(ibuf
, GOT_IMSG_TREE_ENUMERATION_DONE
, 0, 0, -1,
1188 return got_error_from_errno("imsg_compose TREE_ENUMERATION_DONE");
1190 return got_privsep_flush_imsg(ibuf
);
1193 struct enumerated_tree
{
1194 struct got_object_id id
;
1197 struct got_parsed_tree_entry
*entries
;
1201 static const struct got_error
*
1202 enumerate_tree(int *have_all_entries
, struct imsgbuf
*ibuf
, size_t *totlen
,
1203 struct got_object_id
*tree_id
,
1204 const char *path
, struct got_pack
*pack
, struct got_packidx
*packidx
,
1205 struct got_object_cache
*objcache
, struct got_object_idset
*idset
,
1206 struct enumerated_tree
**trees
, size_t *nalloc
, size_t *ntrees
)
1208 const struct got_error
*err
= NULL
;
1209 struct got_object_id_queue ids
;
1210 struct got_object_qid
*qid
;
1211 uint8_t *buf
= NULL
;
1213 struct got_parsed_tree_entry
*entries
= NULL
;
1214 size_t nentries
= 0, nentries_alloc
= 0, i
;
1215 struct enumerated_tree
*tree
;
1218 *have_all_entries
= 1;
1221 err
= got_object_qid_alloc_partial(&qid
);
1224 memcpy(&qid
->id
, tree_id
, sizeof(*tree_id
));
1225 qid
->data
= strdup(path
);
1226 if (qid
->data
== NULL
) {
1227 err
= got_error_from_errno("strdup");
1230 STAILQ_INSERT_TAIL(&ids
, qid
, entry
);
1233 /* Traverse the tree hierarchy, gather tree object IDs and paths. */
1238 if (sigint_received
) {
1239 err
= got_error(GOT_ERR_CANCELLED
);
1243 qid
= STAILQ_FIRST(&ids
);
1244 STAILQ_REMOVE_HEAD(&ids
, entry
);
1247 idx
= got_packidx_get_object_idx(packidx
, &qid
->id
);
1249 *have_all_entries
= 0;
1253 err
= open_tree(&buf
, &len
, pack
, packidx
, idx
, &qid
->id
,
1256 if (err
->code
!= GOT_ERR_NO_OBJ
)
1260 err
= got_object_parse_tree(&entries
, &nentries
,
1261 &nentries_alloc
, buf
, len
, pack
->algo
);
1265 err
= got_object_idset_add(idset
, &qid
->id
, NULL
);
1269 for (i
= 0; i
< nentries
; i
++) {
1270 struct got_object_qid
*eqid
= NULL
;
1271 struct got_parsed_tree_entry
*pte
= &entries
[i
];
1274 if (!S_ISDIR(pte
->mode
))
1277 err
= got_object_qid_alloc_partial(&eqid
);
1280 eqid
->id
.algo
= pte
->algo
;
1281 memcpy(eqid
->id
.hash
, pte
->id
, pte
->digest_len
);
1283 if (got_object_idset_contains(idset
, &eqid
->id
)) {
1284 got_object_qid_free(eqid
);
1288 if (asprintf(&p
, "%s%s%s", path
,
1289 got_path_is_root_dir(path
) ? "" : "/",
1291 err
= got_error_from_errno("asprintf");
1292 got_object_qid_free(eqid
);
1296 STAILQ_INSERT_TAIL(&ids
, eqid
, entry
);
1299 if (*ntrees
>= *nalloc
) {
1300 struct enumerated_tree
*new;
1301 new = recallocarray(*trees
, *nalloc
, *nalloc
+ 16,
1304 err
= got_error_from_errno("malloc");
1310 tree
= &(*trees
)[*ntrees
];
1312 memcpy(&tree
->id
, &qid
->id
, sizeof(tree
->id
));
1313 tree
->path
= qid
->data
;
1316 tree
->entries
= entries
;
1319 tree
->nentries
= nentries
;
1322 got_object_qid_free(qid
);
1324 } while (!STAILQ_EMPTY(&ids
));
1326 if (*have_all_entries
) {
1329 * We have managed to traverse all entries in the hierarchy.
1330 * Tell the main process what we have found.
1332 for (i
= 0; i
< *ntrees
; i
++) {
1333 tree
= &(*trees
)[i
];
1334 err
= got_privsep_send_enumerated_tree(totlen
,
1335 ibuf
, &tree
->id
, tree
->path
, tree
->entries
,
1343 free(tree
->entries
);
1344 tree
->entries
= NULL
;
1346 *ntrees
= 0; /* don't loop again below to free memory */
1348 err
= send_tree_enumeration_done(ibuf
);
1351 * We can only load fully packed tree hierarchies on
1352 * behalf of the main process, otherwise the main process
1353 * gets a wrong idea about which tree objects have
1354 * already been traversed.
1355 * Indicate a missing entry for the root of this tree.
1356 * The main process should continue by loading this
1357 * entire tree the slow way.
1359 err
= got_privsep_send_enumerated_tree(totlen
, ibuf
,
1360 tree_id
, "/", NULL
, -1);
1367 for (i
= 0; i
< *ntrees
; i
++) {
1368 tree
= &(*trees
)[i
];
1373 free(tree
->entries
);
1374 tree
->entries
= NULL
;
1378 got_object_qid_free(qid
);
1379 got_object_id_queue_free(&ids
);
1381 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
1384 got_privsep_send_error(ibuf
, err
);
1391 static const struct got_error
*
1392 resolve_tag(struct got_object
**obj
, struct got_object_id
*id
,
1393 struct got_packidx
*packidx
, struct got_pack
*pack
,
1394 struct got_object_cache
*objcache
)
1396 const struct got_error
*err
;
1397 struct got_object
*tagged_obj
;
1398 struct got_tag_object
*tag
;
1403 err
= got_packfile_extract_object_to_mem(&buf
, &len
, *obj
, pack
);
1408 err
= got_object_parse_tag(&tag
, buf
, len
, id
->algo
);
1412 idx
= got_packidx_get_object_idx(packidx
, &tag
->id
);
1414 got_object_close(*obj
);
1419 tagged_obj
= got_object_cache_get(objcache
, &tag
->id
);
1421 tagged_obj
->refcnt
++;
1423 err
= open_object(&tagged_obj
, pack
, packidx
,
1424 idx
, &tag
->id
, objcache
);
1429 got_object_close(*obj
);
1432 got_object_tag_close(tag
);
1437 static const struct got_error
*
1438 enumeration_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
1439 struct got_pack
*pack
, struct got_packidx
*packidx
,
1440 struct got_object_cache
*objcache
)
1442 const struct got_error
*err
= NULL
;
1443 struct got_object_id_queue commit_ids
;
1444 const struct got_object_id_queue
*parents
= NULL
;
1445 struct got_object_qid
*qid
= NULL
;
1446 struct got_object
*obj
= NULL
;
1447 struct got_commit_object
*commit
= NULL
;
1448 struct got_object_id
*tree_id
= NULL
;
1450 struct got_object_idset
*idset
, *queued_ids
= NULL
;
1451 int i
, idx
, have_all_entries
= 1;
1452 struct enumerated_tree
*trees
= NULL
;
1453 size_t ntrees
= 0, nalloc
= 16;
1455 STAILQ_INIT(&commit_ids
);
1457 trees
= calloc(nalloc
, sizeof(*trees
));
1459 return got_error_from_errno("calloc");
1461 idset
= got_object_idset_alloc();
1462 if (idset
== NULL
) {
1463 err
= got_error_from_errno("got_object_idset_alloc");
1467 queued_ids
= got_object_idset_alloc();
1468 if (queued_ids
== NULL
) {
1469 err
= got_error_from_errno("got_object_idset_alloc");
1473 err
= recv_object_id_queue(&commit_ids
, queued_ids
, ibuf
);
1477 if (STAILQ_EMPTY(&commit_ids
)) {
1478 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1482 err
= recv_object_ids(idset
, ibuf
);
1486 while (!STAILQ_EMPTY(&commit_ids
)) {
1487 if (sigint_received
) {
1488 err
= got_error(GOT_ERR_CANCELLED
);
1492 qid
= STAILQ_FIRST(&commit_ids
);
1493 STAILQ_REMOVE_HEAD(&commit_ids
, entry
);
1495 if (got_object_idset_contains(idset
, &qid
->id
)) {
1496 got_object_qid_free(qid
);
1501 idx
= got_packidx_get_object_idx(packidx
, &qid
->id
);
1503 have_all_entries
= 0;
1507 err
= open_object(&obj
, pack
, packidx
, idx
, &qid
->id
,
1511 if (obj
->type
== GOT_OBJ_TYPE_TAG
) {
1512 while (obj
->type
== GOT_OBJ_TYPE_TAG
) {
1513 err
= resolve_tag(&obj
, &qid
->id
, packidx
,
1521 have_all_entries
= 0;
1524 if (obj
->type
!= GOT_OBJ_TYPE_COMMIT
) {
1525 got_object_qid_free(qid
);
1527 got_object_close(obj
);
1531 err
= open_commit(&commit
, pack
, packidx
, idx
,
1532 &obj
->id
, objcache
);
1535 } else if (obj
->type
== GOT_OBJ_TYPE_COMMIT
) {
1536 err
= open_commit(&commit
, pack
, packidx
, idx
,
1537 &qid
->id
, objcache
);
1541 err
= got_error(GOT_ERR_OBJ_TYPE
);
1544 got_object_close(obj
);
1547 err
= got_privsep_send_enumerated_commit(ibuf
, &qid
->id
,
1548 got_object_commit_get_committer_time(commit
));
1552 tree_id
= got_object_commit_get_tree_id(commit
);
1553 idx
= got_packidx_get_object_idx(packidx
, tree_id
);
1555 have_all_entries
= 0;
1556 err
= got_privsep_send_enumerated_tree(&totlen
, ibuf
,
1557 tree_id
, "/", NULL
, -1);
1563 if (got_object_idset_contains(idset
, tree_id
)) {
1564 got_object_qid_free(qid
);
1566 err
= send_tree_enumeration_done(ibuf
);
1569 got_object_commit_close(commit
);
1574 err
= enumerate_tree(&have_all_entries
, ibuf
, &totlen
,
1575 tree_id
, "/", pack
, packidx
, objcache
, idset
,
1576 &trees
, &nalloc
, &ntrees
);
1580 if (!have_all_entries
)
1583 got_object_qid_free(qid
);
1586 parents
= got_object_commit_get_parent_ids(commit
);
1588 struct got_object_qid
*pid
;
1589 STAILQ_FOREACH(pid
, parents
, entry
) {
1590 if (got_object_idset_contains(idset
,
1592 got_object_idset_contains(queued_ids
,
1594 got_object_commit_close(commit
);
1598 err
= got_object_qid_alloc_partial(&qid
);
1601 memcpy(&qid
->id
, &pid
->id
, sizeof(qid
->id
));
1602 STAILQ_INSERT_TAIL(&commit_ids
, qid
, entry
);
1607 got_object_commit_close(commit
);
1611 if (have_all_entries
) {
1612 err
= got_privsep_send_object_enumeration_done(ibuf
);
1616 err
= got_privsep_send_object_enumeration_incomplete(ibuf
);
1622 got_object_close(obj
);
1624 got_object_commit_close(commit
);
1625 got_object_qid_free(qid
);
1626 got_object_id_queue_free(&commit_ids
);
1628 got_object_idset_free(idset
);
1630 got_object_idset_free(queued_ids
);
1631 for (i
= 0; i
< ntrees
; i
++) {
1632 struct enumerated_tree
*tree
= &trees
[i
];
1635 free(tree
->entries
);
1641 enum findtwixt_color
{
1648 static const struct got_error
*
1649 paint_commit(struct got_object_qid
*qid
, intptr_t color
)
1651 if (color
< 0 || color
>= COLOR_MAX
)
1652 return got_error(GOT_ERR_RANGE
);
1654 qid
->data
= (void *)color
;
1658 static const struct got_error
*
1659 queue_commit_id(struct got_object_id_queue
*ids
, struct got_object_id
*id
,
1662 const struct got_error
*err
;
1663 struct got_object_qid
*qid
;
1665 err
= got_object_qid_alloc_partial(&qid
);
1669 memcpy(&qid
->id
, id
, sizeof(qid
->id
));
1670 STAILQ_INSERT_TAIL(ids
, qid
, entry
);
1671 return paint_commit(qid
, color
);
1674 static const struct got_error
*
1675 paint_commits(struct got_object_id_queue
*ids
, int *nids
,
1676 struct got_object_idset
*keep
, struct got_object_idset
*drop
,
1677 struct got_object_idset
*skip
, struct got_pack
*pack
,
1678 struct got_packidx
*packidx
, struct imsgbuf
*ibuf
,
1679 struct got_object_cache
*objcache
)
1681 const struct got_error
*err
= NULL
;
1682 struct got_commit_object
*commit
= NULL
;
1683 struct got_object_id_queue painted
;
1684 const struct got_object_id_queue
*parents
;
1685 struct got_object_qid
*qid
= NULL
;
1686 int nqueued
= *nids
, nskip
= 0, npainted
= 0;
1688 STAILQ_INIT(&painted
);
1690 while (!STAILQ_EMPTY(ids
) && nskip
!= nqueued
) {
1694 if (sigint_received
) {
1695 err
= got_error(GOT_ERR_CANCELLED
);
1699 qid
= STAILQ_FIRST(ids
);
1700 idx
= got_packidx_get_object_idx(packidx
, &qid
->id
);
1706 STAILQ_REMOVE_HEAD(ids
, entry
);
1708 color
= (intptr_t)qid
->data
;
1709 if (color
== COLOR_SKIP
)
1712 if (got_object_idset_contains(skip
, &qid
->id
)) {
1713 got_object_qid_free(qid
);
1720 if (got_object_idset_contains(keep
, &qid
->id
)) {
1721 got_object_qid_free(qid
);
1725 if (got_object_idset_contains(drop
, &qid
->id
)) {
1726 err
= paint_commit(qid
, COLOR_SKIP
);
1730 err
= got_object_idset_add(keep
, &qid
->id
, NULL
);
1735 if (got_object_idset_contains(drop
, &qid
->id
)) {
1736 got_object_qid_free(qid
);
1740 if (got_object_idset_contains(keep
, &qid
->id
)) {
1741 err
= paint_commit(qid
, COLOR_SKIP
);
1745 err
= got_object_idset_add(drop
, &qid
->id
, NULL
);
1750 if (!got_object_idset_contains(skip
, &qid
->id
)) {
1751 err
= got_object_idset_add(skip
, &qid
->id
,
1758 /* should not happen */
1759 err
= got_error_fmt(GOT_ERR_NOT_IMPL
,
1760 "%s invalid commit color %"PRIdPTR
, __func__
,
1765 err
= open_commit(&commit
, pack
, packidx
, idx
, &qid
->id
,
1770 parents
= got_object_commit_get_parent_ids(commit
);
1772 struct got_object_qid
*pid
;
1773 color
= (intptr_t)qid
->data
;
1774 STAILQ_FOREACH(pid
, parents
, entry
) {
1775 err
= queue_commit_id(ids
, &pid
->id
, color
);
1779 if (color
== COLOR_SKIP
)
1784 got_object_commit_close(commit
);
1787 STAILQ_INSERT_TAIL(&painted
, qid
, entry
);
1791 err
= got_privsep_send_painted_commits(ibuf
, &painted
,
1797 err
= got_privsep_send_painted_commits(ibuf
, &painted
, &npainted
, 1, 1);
1804 got_object_commit_close(commit
);
1805 got_object_qid_free(qid
);
1810 commit_painting_free(struct got_object_idset
**keep
,
1811 struct got_object_idset
**drop
,
1812 struct got_object_idset
**skip
)
1815 got_object_idset_free(*keep
);
1819 got_object_idset_free(*drop
);
1823 got_object_idset_free(*skip
);
1828 static const struct got_error
*
1829 commit_painting_init(struct imsgbuf
*ibuf
, struct got_object_idset
**keep
,
1830 struct got_object_idset
**drop
, struct got_object_idset
**skip
)
1832 const struct got_error
*err
= NULL
;
1834 *keep
= got_object_idset_alloc();
1835 if (*keep
== NULL
) {
1836 err
= got_error_from_errno("got_object_idset_alloc");
1839 *drop
= got_object_idset_alloc();
1840 if (*drop
== NULL
) {
1841 err
= got_error_from_errno("got_object_idset_alloc");
1844 *skip
= got_object_idset_alloc();
1845 if (*skip
== NULL
) {
1846 err
= got_error_from_errno("got_object_idset_alloc");
1850 err
= recv_object_ids(*keep
, ibuf
);
1853 err
= recv_object_ids(*drop
, ibuf
);
1856 err
= recv_object_ids(*skip
, ibuf
);
1862 commit_painting_free(keep
, drop
, skip
);
1867 static const struct got_error
*
1868 commit_painting_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
1869 struct got_pack
*pack
, struct got_packidx
*packidx
,
1870 struct got_object_cache
*objcache
, struct got_object_idset
*keep
,
1871 struct got_object_idset
*drop
, struct got_object_idset
*skip
)
1873 const struct got_error
*err
= NULL
;
1874 struct got_imsg_commit_painting_request ireq
;
1875 struct got_object_id id
;
1877 struct got_object_id_queue ids
;
1882 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1883 if (datalen
!= sizeof(ireq
))
1884 return got_error(GOT_ERR_PRIVSEP_LEN
);
1885 memcpy(&ireq
, imsg
->data
, sizeof(ireq
));
1886 memcpy(&id
, &ireq
.id
, sizeof(id
));
1888 err
= queue_commit_id(&ids
, &id
, ireq
.color
);
1893 err
= paint_commits(&ids
, &nids
, keep
, drop
, skip
,
1894 pack
, packidx
, ibuf
, objcache
);
1898 err
= got_privsep_send_painted_commits(ibuf
, &ids
, &nids
, 0, 1);
1902 err
= got_privsep_send_painting_commits_done(ibuf
);
1904 got_object_id_queue_free(&ids
);
1908 static const struct got_error
*
1909 receive_pack(struct got_pack
**packp
, struct imsgbuf
*ibuf
)
1911 const struct got_error
*err
= NULL
;
1913 struct got_imsg_pack ipack
;
1915 struct got_pack
*pack
;
1919 err
= got_privsep_recv_imsg(&imsg
, ibuf
, 0);
1923 pack
= calloc(1, sizeof(*pack
));
1925 err
= got_error_from_errno("calloc");
1929 if (imsg
.hdr
.type
!= GOT_IMSG_PACK
) {
1930 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1934 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
1935 if (datalen
!= sizeof(ipack
)) {
1936 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1939 memcpy(&ipack
, imsg
.data
, sizeof(ipack
));
1941 pack
->algo
= ipack
.algo
;
1942 pack
->filesize
= ipack
.filesize
;
1943 pack
->fd
= imsg_get_fd(&imsg
);
1944 if (pack
->fd
== -1) {
1945 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
1948 if (lseek(pack
->fd
, 0, SEEK_SET
) == -1) {
1949 err
= got_error_from_errno("lseek");
1952 pack
->path_packfile
= strdup(ipack
.path_packfile
);
1953 if (pack
->path_packfile
== NULL
) {
1954 err
= got_error_from_errno("strdup");
1958 err
= got_delta_cache_alloc(&pack
->delta_cache
);
1962 #ifndef GOT_PACK_NO_MMAP
1963 if (pack
->filesize
> 0 && pack
->filesize
<= SIZE_MAX
) {
1964 pack
->map
= mmap(NULL
, pack
->filesize
, PROT_READ
, MAP_PRIVATE
,
1966 if (pack
->map
== MAP_FAILED
)
1967 pack
->map
= NULL
; /* fall back to read(2) */
1973 got_pack_close(pack
);
1981 main(int argc
, char *argv
[])
1983 const struct got_error
*err
= NULL
;
1984 struct imsgbuf ibuf
;
1986 struct got_packidx
*packidx
= NULL
;
1987 struct got_pack
*pack
= NULL
;
1988 struct got_object_cache objcache
;
1989 FILE *basefile
= NULL
, *accumfile
= NULL
, *delta_outfile
= NULL
;
1990 struct got_object_idset
*keep
= NULL
, *drop
= NULL
, *skip
= NULL
;
1991 struct got_parsed_tree_entry
*entries
= NULL
;
1992 size_t nentries
= 0, nentries_alloc
= 0;
1994 //static int attached;
1995 //while (!attached) sleep(1);
1997 signal(SIGINT
, catch_sigint
);
1999 if (imsgbuf_init(&ibuf
, GOT_IMSG_FD_CHILD
) == -1) {
2000 warn("imsgbuf_init");
2003 imsgbuf_allow_fdpass(&ibuf
);
2005 err
= got_object_cache_init(&objcache
, GOT_OBJECT_CACHE_TYPE_OBJ
);
2007 err
= got_error_from_errno("got_object_cache_init");
2008 got_privsep_send_error(&ibuf
, err
);
2013 /* revoke access to most system calls */
2014 if (pledge("stdio recvfd", NULL
) == -1) {
2015 err
= got_error_from_errno("pledge");
2016 got_privsep_send_error(&ibuf
, err
);
2020 /* revoke fs access */
2021 if (landlock_no_fs() == -1) {
2022 err
= got_error_from_errno("landlock_no_fs");
2023 got_privsep_send_error(&ibuf
, err
);
2026 if (cap_enter() == -1) {
2027 err
= got_error_from_errno("cap_enter");
2028 got_privsep_send_error(&ibuf
, err
);
2033 err
= receive_packidx(&packidx
, &ibuf
);
2035 got_privsep_send_error(&ibuf
, err
);
2039 err
= receive_pack(&pack
, &ibuf
);
2041 got_privsep_send_error(&ibuf
, err
);
2046 if (sigint_received
) {
2047 err
= got_error(GOT_ERR_CANCELLED
);
2051 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
2053 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
2058 if (imsg
.hdr
.type
== GOT_IMSG_STOP
) {
2063 switch (imsg
.hdr
.type
) {
2064 case GOT_IMSG_TMPFD
:
2065 if (basefile
== NULL
) {
2066 err
= receive_tempfile(&basefile
, "w+",
2068 } else if (accumfile
== NULL
) {
2069 err
= receive_tempfile(&accumfile
, "w+",
2072 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2074 case GOT_IMSG_PACKED_OBJECT_REQUEST
:
2075 err
= object_request(&imsg
, &ibuf
, pack
, packidx
,
2078 case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST
:
2079 if (basefile
== NULL
|| accumfile
== NULL
) {
2080 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2083 err
= raw_object_request(&imsg
, &ibuf
, pack
, packidx
,
2084 &objcache
, basefile
, accumfile
);
2086 case GOT_IMSG_RAW_DELTA_OUTFD
:
2087 if (delta_outfile
!= NULL
) {
2088 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2091 err
= receive_tempfile(&delta_outfile
, "w",
2094 case GOT_IMSG_RAW_DELTA_REQUEST
:
2095 if (delta_outfile
== NULL
) {
2096 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
2099 err
= raw_delta_request(&imsg
, &ibuf
, delta_outfile
,
2102 case GOT_IMSG_DELTA_REUSE_REQUEST
:
2103 err
= delta_reuse_request(&imsg
, &ibuf
, pack
, packidx
);
2105 case GOT_IMSG_COMMIT_REQUEST
:
2106 err
= commit_request(&imsg
, &ibuf
, pack
, packidx
,
2109 case GOT_IMSG_TREE_REQUEST
:
2110 err
= tree_request(&imsg
, &ibuf
, pack
, packidx
,
2111 &objcache
, &entries
, &nentries
, &nentries_alloc
);
2113 case GOT_IMSG_BLOB_REQUEST
:
2114 if (basefile
== NULL
|| accumfile
== NULL
) {
2115 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2118 err
= blob_request(&imsg
, &ibuf
, pack
, packidx
,
2119 &objcache
, basefile
, accumfile
);
2121 case GOT_IMSG_TAG_REQUEST
:
2122 err
= tag_request(&imsg
, &ibuf
, pack
, packidx
,
2125 case GOT_IMSG_COMMIT_TRAVERSAL_REQUEST
:
2126 err
= commit_traversal_request(&imsg
, &ibuf
, pack
,
2127 packidx
, &objcache
);
2129 case GOT_IMSG_OBJECT_ENUMERATION_REQUEST
:
2130 err
= enumeration_request(&imsg
, &ibuf
, pack
,
2131 packidx
, &objcache
);
2133 case GOT_IMSG_COMMIT_PAINTING_INIT
:
2134 commit_painting_free(&keep
, &drop
, &skip
);
2135 err
= commit_painting_init(&ibuf
, &keep
, &drop
, &skip
);
2137 case GOT_IMSG_COMMIT_PAINTING_REQUEST
:
2138 if (keep
== NULL
|| drop
== NULL
|| skip
== NULL
) {
2139 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2142 err
= commit_painting_request(&imsg
, &ibuf
, pack
,
2143 packidx
, &objcache
, keep
, drop
, skip
);
2145 case GOT_IMSG_COMMIT_PAINTING_DONE
:
2146 commit_painting_free(&keep
, &drop
, &skip
);
2149 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2159 commit_painting_free(&keep
, &drop
, &skip
);
2161 got_packidx_close(packidx
);
2163 got_pack_close(pack
);
2166 got_object_cache_close(&objcache
);
2167 if (basefile
&& fclose(basefile
) == EOF
&& err
== NULL
)
2168 err
= got_error_from_errno("fclose");
2169 if (accumfile
&& fclose(accumfile
) == EOF
&& err
== NULL
)
2170 err
= got_error_from_errno("fclose");
2171 if (delta_outfile
&& fclose(delta_outfile
) == EOF
&& err
== NULL
)
2172 err
= got_error_from_errno("fclose");
2174 if (!sigint_received
&& err
->code
!= GOT_ERR_PRIVSEP_PIPE
) {
2175 fprintf(stderr
, "%s: %s\n", getprogname(), err
->msg
);
2176 got_privsep_send_error(&ibuf
, err
);
2179 imsgbuf_clear(&ibuf
);
2180 if (close(GOT_IMSG_FD_CHILD
) == -1 && err
== NULL
)
2181 err
= got_error_from_errno("close");