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.
18 #include <sys/types.h>
19 #include <sys/queue.h>
34 #include "got_compat.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_object.h"
43 #include "got_lib_object_cache.h"
44 #include "got_lib_object_parse.h"
45 #include "got_lib_object_idset.h"
46 #include "got_lib_privsep.h"
47 #include "got_lib_pack.h"
50 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
53 static volatile sig_atomic_t sigint_received
;
56 catch_sigint(int signo
)
61 static const struct got_error
*
62 open_object(struct got_object
**obj
, struct got_pack
*pack
,
63 struct got_packidx
*packidx
, int idx
, struct got_object_id
*id
,
64 struct got_object_cache
*objcache
)
66 const struct got_error
*err
;
68 err
= got_packfile_open_object(obj
, pack
, packidx
, idx
, id
);
73 err
= got_object_cache_add(objcache
, id
, *obj
);
75 if (err
->code
== GOT_ERR_OBJ_EXISTS
||
76 err
->code
== GOT_ERR_OBJ_TOO_LARGE
)
84 static const struct got_error
*
85 object_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
, struct got_pack
*pack
,
86 struct got_packidx
*packidx
, struct got_object_cache
*objcache
)
88 const struct got_error
*err
= NULL
;
89 struct got_imsg_packed_object iobj
;
90 struct got_object
*obj
;
91 struct got_object_id id
;
94 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
95 if (datalen
!= sizeof(iobj
))
96 return got_error(GOT_ERR_PRIVSEP_LEN
);
97 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
98 memcpy(&id
, &iobj
.id
, sizeof(id
));
100 obj
= got_object_cache_get(objcache
, &id
);
104 err
= open_object(&obj
, pack
, packidx
, iobj
.idx
, &id
,
110 err
= got_privsep_send_obj(ibuf
, obj
);
112 got_object_close(obj
);
116 static const struct got_error
*
117 open_commit(struct got_commit_object
**commit
, struct got_pack
*pack
,
118 struct got_packidx
*packidx
, int obj_idx
, struct got_object_id
*id
,
119 struct got_object_cache
*objcache
)
121 const struct got_error
*err
= NULL
;
122 struct got_object
*obj
= NULL
;
128 obj
= got_object_cache_get(objcache
, id
);
132 err
= open_object(&obj
, pack
, packidx
, obj_idx
, id
,
138 err
= got_packfile_extract_object_to_mem(&buf
, &len
, obj
, pack
);
144 err
= got_object_parse_commit(commit
, buf
, len
);
146 got_object_close(obj
);
151 static const struct got_error
*
152 commit_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
, struct got_pack
*pack
,
153 struct got_packidx
*packidx
, struct got_object_cache
*objcache
)
155 const struct got_error
*err
= NULL
;
156 struct got_imsg_packed_object iobj
;
157 struct got_commit_object
*commit
= NULL
;
158 struct got_object_id id
;
161 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
162 if (datalen
!= sizeof(iobj
))
163 return got_error(GOT_ERR_PRIVSEP_LEN
);
164 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
165 memcpy(&id
, &iobj
.id
, sizeof(id
));
167 err
= open_commit(&commit
, pack
, packidx
, iobj
.idx
, &id
, objcache
);
171 err
= got_privsep_send_commit(ibuf
, commit
);
174 got_object_commit_close(commit
);
176 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
179 got_privsep_send_error(ibuf
, err
);
185 static const struct got_error
*
186 open_tree(uint8_t **buf
, struct got_parsed_tree_entry
**entries
, size_t *nentries
,
187 size_t *nentries_alloc
, struct got_pack
*pack
, struct got_packidx
*packidx
,
188 int obj_idx
, struct got_object_id
*id
, struct got_object_cache
*objcache
)
190 const struct got_error
*err
= NULL
;
191 struct got_object
*obj
= NULL
;
197 obj
= got_object_cache_get(objcache
, id
);
201 err
= open_object(&obj
, pack
, packidx
, obj_idx
, id
,
207 err
= got_packfile_extract_object_to_mem(buf
, &len
, obj
, pack
);
213 err
= got_object_parse_tree(entries
, nentries
, nentries_alloc
,
216 got_object_close(obj
);
224 static const struct got_error
*
225 tree_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
, struct got_pack
*pack
,
226 struct got_packidx
*packidx
, struct got_object_cache
*objcache
,
227 struct got_parsed_tree_entry
**entries
, size_t *nentries
,
228 size_t *nentries_alloc
)
230 const struct got_error
*err
= NULL
;
231 struct got_imsg_packed_object iobj
;
233 struct got_object_id id
;
236 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
237 if (datalen
!= sizeof(iobj
))
238 return got_error(GOT_ERR_PRIVSEP_LEN
);
239 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
240 memcpy(&id
, &iobj
.id
, sizeof(id
));
242 err
= open_tree(&buf
, entries
, nentries
, nentries_alloc
,
243 pack
, packidx
, iobj
.idx
, &id
, objcache
);
247 err
= got_privsep_send_tree(ibuf
, *entries
, *nentries
);
250 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
253 got_privsep_send_error(ibuf
, err
);
259 static const struct got_error
*
260 receive_file(FILE **f
, struct imsgbuf
*ibuf
, uint32_t imsg_code
)
262 const struct got_error
*err
;
266 err
= got_privsep_recv_imsg(&imsg
, ibuf
, 0);
270 if (imsg
.hdr
.type
!= imsg_code
) {
271 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
275 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
277 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
281 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
285 *f
= fdopen(imsg
.fd
, "w+");
287 err
= got_error_from_errno("fdopen");
296 static const struct got_error
*
297 receive_tempfile(FILE **f
, const char *mode
, struct imsg
*imsg
,
298 struct imsgbuf
*ibuf
)
302 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
304 return got_error(GOT_ERR_PRIVSEP_LEN
);
307 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
309 *f
= fdopen(imsg
->fd
, mode
);
311 return got_error_from_errno("fdopen");
317 static const struct got_error
*
318 blob_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
, struct got_pack
*pack
,
319 struct got_packidx
*packidx
, struct got_object_cache
*objcache
,
320 FILE *basefile
, FILE *accumfile
)
322 const struct got_error
*err
= NULL
;
323 struct got_imsg_packed_object iobj
;
324 struct got_object
*obj
= NULL
;
325 FILE *outfile
= NULL
;
326 struct got_object_id id
;
331 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
332 if (datalen
!= sizeof(iobj
))
333 return got_error(GOT_ERR_PRIVSEP_LEN
);
334 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
335 memcpy(&id
, &iobj
.id
, sizeof(id
));
337 obj
= got_object_cache_get(objcache
, &id
);
341 err
= open_object(&obj
, pack
, packidx
, iobj
.idx
, &id
,
347 err
= receive_file(&outfile
, ibuf
, GOT_IMSG_BLOB_OUTFD
);
351 if (obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) {
352 err
= got_pack_get_max_delta_object_size(&blob_size
, obj
, pack
);
356 blob_size
= obj
->size
;
358 if (blob_size
<= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX
)
359 err
= got_packfile_extract_object_to_mem(&buf
, &obj
->size
,
362 err
= got_packfile_extract_object(pack
, obj
, outfile
, basefile
,
367 err
= got_privsep_send_blob(ibuf
, obj
->size
, obj
->hdrlen
, buf
);
370 if (outfile
&& fclose(outfile
) == EOF
&& err
== NULL
)
371 err
= got_error_from_errno("fclose");
372 got_object_close(obj
);
373 if (err
&& err
->code
!= GOT_ERR_PRIVSEP_PIPE
)
374 got_privsep_send_error(ibuf
, err
);
379 static const struct got_error
*
380 tag_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
, struct got_pack
*pack
,
381 struct got_packidx
*packidx
, struct got_object_cache
*objcache
)
383 const struct got_error
*err
= NULL
;
384 struct got_imsg_packed_object iobj
;
385 struct got_object
*obj
= NULL
;
386 struct got_tag_object
*tag
= NULL
;
389 struct got_object_id id
;
392 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
393 if (datalen
!= sizeof(iobj
))
394 return got_error(GOT_ERR_PRIVSEP_LEN
);
395 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
396 memcpy(&id
, &iobj
.id
, sizeof(id
));
398 obj
= got_object_cache_get(objcache
, &id
);
402 err
= open_object(&obj
, pack
, packidx
, iobj
.idx
, &id
,
408 err
= got_packfile_extract_object_to_mem(&buf
, &len
, obj
, pack
);
413 err
= got_object_parse_tag(&tag
, buf
, len
);
417 err
= got_privsep_send_tag(ibuf
, tag
);
420 got_object_close(obj
);
422 got_object_tag_close(tag
);
424 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
427 got_privsep_send_error(ibuf
, err
);
433 static struct got_parsed_tree_entry
*
434 find_entry_by_name(struct got_parsed_tree_entry
*entries
, int nentries
,
435 const char *name
, size_t len
)
437 struct got_parsed_tree_entry
*pte
;
440 /* Note that tree entries are sorted in strncmp() order. */
441 for (i
= 0; i
< nentries
; i
++) {
443 cmp
= strncmp(pte
->name
, name
, len
);
448 if (pte
->name
[len
] == '\0')
454 static const struct got_error
*
455 tree_path_changed(int *changed
, uint8_t **buf1
, uint8_t **buf2
,
456 struct got_parsed_tree_entry
**entries1
, size_t *nentries1
,
457 size_t *nentries_alloc1
,
458 struct got_parsed_tree_entry
**entries2
, size_t *nentries2
,
459 size_t *nentries_alloc2
,
460 const char *path
, struct got_pack
*pack
, struct got_packidx
*packidx
,
461 struct imsgbuf
*ibuf
, struct got_object_cache
*objcache
)
463 const struct got_error
*err
= NULL
;
464 struct got_parsed_tree_entry
*pte1
= NULL
, *pte2
= NULL
;
470 /* We not do support comparing the root path. */
471 if (got_path_is_root_dir(path
))
472 return got_error_path(path
, GOT_ERR_BAD_PATH
);
487 pte1
= find_entry_by_name(*entries1
, *nentries1
, seg
, seglen
);
489 err
= got_error(GOT_ERR_NO_OBJ
);
493 pte2
= find_entry_by_name(*entries2
, *nentries2
, seg
, seglen
);
499 if (pte1
->mode
!= pte2
->mode
) {
504 if (memcmp(pte1
->id
, pte2
->id
, SHA1_DIGEST_LENGTH
) == 0) {
509 if (*s
== '\0') { /* final path element */
518 struct got_object_id id1
, id2
;
521 memcpy(id1
.sha1
, pte1
->id
, SHA1_DIGEST_LENGTH
);
522 idx
= got_packidx_get_object_idx(packidx
, &id1
);
524 err
= got_error_no_obj(&id1
);
530 err
= open_tree(buf1
, entries1
, nentries1
,
531 nentries_alloc1
, pack
, packidx
, idx
, &id1
,
537 memcpy(id2
.sha1
, pte2
->id
, SHA1_DIGEST_LENGTH
);
538 idx
= got_packidx_get_object_idx(packidx
, &id2
);
540 err
= got_error_no_obj(&id2
);
546 err
= open_tree(buf2
, entries2
, nentries2
,
547 nentries_alloc2
, pack
, packidx
, idx
, &id2
,
558 static const struct got_error
*
559 send_traversed_commits(struct got_object_id
*commit_ids
, size_t ncommits
,
560 struct imsgbuf
*ibuf
)
565 wbuf
= imsg_create(ibuf
, GOT_IMSG_TRAVERSED_COMMITS
, 0, 0,
566 sizeof(struct got_imsg_traversed_commits
) +
567 ncommits
* sizeof(commit_ids
[0]));
569 return got_error_from_errno("imsg_create TRAVERSED_COMMITS");
571 if (imsg_add(wbuf
, &ncommits
, sizeof(ncommits
)) == -1)
572 return got_error_from_errno("imsg_add TRAVERSED_COMMITS");
574 for (i
= 0; i
< ncommits
; i
++) {
575 struct got_object_id
*id
= &commit_ids
[i
];
576 if (imsg_add(wbuf
, id
, sizeof(*id
)) == -1) {
577 return got_error_from_errno(
578 "imsg_add TRAVERSED_COMMITS");
583 imsg_close(ibuf
, wbuf
);
585 return got_privsep_flush_imsg(ibuf
);
588 static const struct got_error
*
589 send_commit_traversal_done(struct imsgbuf
*ibuf
)
591 if (imsg_compose(ibuf
, GOT_IMSG_COMMIT_TRAVERSAL_DONE
, 0, 0, -1,
593 return got_error_from_errno("imsg_compose TRAVERSAL_DONE");
595 return got_privsep_flush_imsg(ibuf
);
598 static const struct got_error
*
599 commit_traversal_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
600 struct got_pack
*pack
, struct got_packidx
*packidx
,
601 struct got_object_cache
*objcache
)
603 const struct got_error
*err
= NULL
;
604 struct got_imsg_commit_traversal_request ctreq
;
605 struct got_object_qid
*pid
;
606 struct got_commit_object
*commit
= NULL
, *pcommit
= NULL
;
607 struct got_parsed_tree_entry
*entries
= NULL
, *pentries
= NULL
;
608 size_t nentries
= 0, nentries_alloc
= 0;
609 size_t pnentries
= 0, pnentries_alloc
= 0;
610 struct got_object_id id
;
613 const int min_alloc
= 64;
614 int changed
= 0, ncommits
= 0, nallocated
= 0;
615 struct got_object_id
*commit_ids
= NULL
;
617 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
618 if (datalen
< sizeof(ctreq
))
619 return got_error(GOT_ERR_PRIVSEP_LEN
);
620 memcpy(&ctreq
, imsg
->data
, sizeof(ctreq
));
621 memcpy(&id
, &ctreq
.iobj
.id
, sizeof(id
));
623 if (datalen
!= sizeof(ctreq
) + ctreq
.path_len
)
624 return got_error(GOT_ERR_PRIVSEP_LEN
);
625 if (ctreq
.path_len
== 0)
626 return got_error(GOT_ERR_PRIVSEP_LEN
);
628 path
= strndup(imsg
->data
+ sizeof(ctreq
), ctreq
.path_len
);
630 return got_error_from_errno("strndup");
632 nallocated
= min_alloc
;
633 commit_ids
= reallocarray(NULL
, nallocated
, sizeof(*commit_ids
));
634 if (commit_ids
== NULL
)
635 return got_error_from_errno("reallocarray");
638 const size_t max_datalen
= MAX_IMSGSIZE
- IMSG_HEADER_SIZE
;
641 if (sigint_received
) {
642 err
= got_error(GOT_ERR_CANCELLED
);
646 if (commit
== NULL
) {
647 idx
= got_packidx_get_object_idx(packidx
, &id
);
650 err
= open_commit(&commit
, pack
, packidx
,
653 if (err
->code
!= GOT_ERR_NO_OBJ
)
660 if (sizeof(struct got_imsg_traversed_commits
) +
661 ncommits
* sizeof(commit_ids
[0]) >= max_datalen
) {
662 err
= send_traversed_commits(commit_ids
, ncommits
,
669 if (ncommits
> nallocated
) {
670 struct got_object_id
*new;
671 nallocated
+= min_alloc
;
672 new = reallocarray(commit_ids
, nallocated
,
673 sizeof(*commit_ids
));
675 err
= got_error_from_errno("reallocarray");
680 memcpy(&commit_ids
[ncommits
- 1], &id
, sizeof(id
));
682 pid
= STAILQ_FIRST(&commit
->parent_ids
);
686 idx
= got_packidx_get_object_idx(packidx
, &pid
->id
);
690 err
= open_commit(&pcommit
, pack
, packidx
, idx
, &pid
->id
,
693 if (err
->code
!= GOT_ERR_NO_OBJ
)
699 if (path
[0] == '/' && path
[1] == '\0') {
700 if (got_object_id_cmp(pcommit
->tree_id
,
701 commit
->tree_id
) != 0) {
707 uint8_t *buf
= NULL
, *pbuf
= NULL
;
709 idx
= got_packidx_get_object_idx(packidx
,
713 pidx
= got_packidx_get_object_idx(packidx
,
718 err
= open_tree(&buf
, &entries
, &nentries
,
719 &nentries_alloc
, pack
, packidx
, idx
,
720 commit
->tree_id
, objcache
);
723 err
= open_tree(&pbuf
, &pentries
, &pnentries
,
724 &pnentries_alloc
, pack
, packidx
, pidx
,
725 pcommit
->tree_id
, objcache
);
731 err
= tree_path_changed(&changed
, &buf
, &pbuf
,
732 &entries
, &nentries
, &nentries_alloc
,
733 &pentries
, &pnentries
, &pnentries_alloc
,
734 path
, pack
, packidx
, ibuf
, objcache
);
741 if (err
->code
!= GOT_ERR_NO_OBJ
)
749 memcpy(&id
, &pid
->id
, sizeof(id
));
750 got_object_commit_close(commit
);
757 err
= send_traversed_commits(commit_ids
, ncommits
, ibuf
);
762 err
= got_privsep_send_commit(ibuf
, commit
);
767 err
= send_commit_traversal_done(ibuf
);
772 got_object_commit_close(commit
);
774 got_object_commit_close(pcommit
);
778 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
781 got_privsep_send_error(ibuf
, err
);
787 static const struct got_error
*
788 raw_object_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
789 struct got_pack
*pack
, struct got_packidx
*packidx
,
790 struct got_object_cache
*objcache
, FILE *basefile
, FILE *accumfile
)
792 const struct got_error
*err
= NULL
;
795 FILE *outfile
= NULL
;
796 struct got_imsg_packed_object iobj
;
797 struct got_object
*obj
;
798 struct got_object_id id
;
801 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
802 if (datalen
!= sizeof(iobj
))
803 return got_error(GOT_ERR_PRIVSEP_LEN
);
804 memcpy(&iobj
, imsg
->data
, sizeof(iobj
));
805 memcpy(&id
, &iobj
.id
, sizeof(id
));
807 obj
= got_object_cache_get(objcache
, &id
);
811 err
= open_object(&obj
, pack
, packidx
, iobj
.idx
, &id
,
817 err
= receive_file(&outfile
, ibuf
, GOT_IMSG_RAW_OBJECT_OUTFD
);
821 if (obj
->flags
& GOT_OBJ_FLAG_DELTIFIED
) {
822 err
= got_pack_get_max_delta_object_size(&size
, obj
, pack
);
828 if (size
<= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX
)
829 err
= got_packfile_extract_object_to_mem(&buf
, &obj
->size
,
832 err
= got_packfile_extract_object(pack
, obj
, outfile
, basefile
,
837 err
= got_privsep_send_raw_obj(ibuf
, obj
->size
, obj
->hdrlen
, buf
);
840 if (outfile
&& fclose(outfile
) == EOF
&& err
== NULL
)
841 err
= got_error_from_errno("fclose");
842 got_object_close(obj
);
843 if (err
&& err
->code
!= GOT_ERR_PRIVSEP_PIPE
)
844 got_privsep_send_error(ibuf
, err
);
849 static const struct got_error
*
850 get_base_object_id(struct got_object_id
*base_id
, struct got_packidx
*packidx
,
853 const struct got_error
*err
;
856 err
= got_packidx_get_offset_idx(&idx
, packidx
, base_offset
);
860 return got_error(GOT_ERR_BAD_PACKIDX
);
862 return got_packidx_get_object_id(base_id
, packidx
, idx
);
865 static const struct got_error
*
866 raw_delta_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
867 FILE *delta_outfile
, struct got_pack
*pack
,
868 struct got_packidx
*packidx
)
870 const struct got_error
*err
= NULL
;
871 struct got_imsg_raw_delta_request req
;
872 size_t datalen
, delta_size
, delta_compressed_size
;
873 off_t delta_offset
, delta_data_offset
;
874 uint8_t *delta_buf
= NULL
;
875 struct got_object_id id
, base_id
;
876 off_t base_offset
, delta_out_offset
= 0;
877 uint64_t base_size
= 0, result_size
= 0;
880 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
881 if (datalen
!= sizeof(req
))
882 return got_error(GOT_ERR_PRIVSEP_LEN
);
883 memcpy(&req
, imsg
->data
, sizeof(req
));
884 memcpy(&id
, &req
.id
, sizeof(id
));
888 err
= got_packfile_extract_raw_delta(&delta_buf
, &delta_size
,
889 &delta_compressed_size
, &delta_offset
, &delta_data_offset
,
890 &base_offset
, &base_id
, &base_size
, &result_size
,
891 pack
, packidx
, req
.idx
);
896 * If this is an offset delta we must determine the base
897 * object ID ourselves.
899 if (base_offset
!= 0) {
900 err
= get_base_object_id(&base_id
, packidx
, base_offset
);
905 delta_out_offset
= ftello(delta_outfile
);
906 w
= fwrite(delta_buf
, 1, delta_compressed_size
, delta_outfile
);
907 if (w
!= delta_compressed_size
) {
908 err
= got_ferror(delta_outfile
, GOT_ERR_IO
);
911 if (fflush(delta_outfile
) == -1) {
912 err
= got_error_from_errno("fflush");
916 err
= got_privsep_send_raw_delta(ibuf
, base_size
, result_size
,
917 delta_size
, delta_compressed_size
, delta_offset
, delta_out_offset
,
924 struct search_deltas_arg
{
925 struct imsgbuf
*ibuf
;
926 struct got_packidx
*packidx
;
927 struct got_pack
*pack
;
928 struct got_object_idset
*idset
;
929 struct got_imsg_reused_delta deltas
[GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS
];
933 static const struct got_error
*
934 search_delta_for_object(struct got_object_id
*id
, void *data
, void *arg
)
936 const struct got_error
*err
;
937 struct search_deltas_arg
*a
= arg
;
939 uint8_t *delta_buf
= NULL
;
940 uint64_t base_size
, result_size
;
941 size_t delta_size
, delta_compressed_size
;
942 off_t delta_offset
, delta_data_offset
, base_offset
;
943 struct got_object_id base_id
;
946 return got_error(GOT_ERR_CANCELLED
);
948 obj_idx
= got_packidx_get_object_idx(a
->packidx
, id
);
950 return NULL
; /* object not present in our pack file */
952 err
= got_packfile_extract_raw_delta(&delta_buf
, &delta_size
,
953 &delta_compressed_size
, &delta_offset
, &delta_data_offset
,
954 &base_offset
, &base_id
, &base_size
, &result_size
,
955 a
->pack
, a
->packidx
, obj_idx
);
957 if (err
->code
== GOT_ERR_OBJ_TYPE
)
958 return NULL
; /* object not stored as a delta */
963 * If this is an offset delta we must determine the base
964 * object ID ourselves.
966 if (base_offset
!= 0) {
967 err
= get_base_object_id(&base_id
, a
->packidx
, base_offset
);
972 if (got_object_idset_contains(a
->idset
, &base_id
)) {
973 struct got_imsg_reused_delta
*delta
;
975 delta
= &a
->deltas
[a
->ndeltas
++];
976 memcpy(&delta
->id
, id
, sizeof(delta
->id
));
977 memcpy(&delta
->base_id
, &base_id
, sizeof(delta
->base_id
));
978 delta
->base_size
= base_size
;
979 delta
->result_size
= result_size
;
980 delta
->delta_size
= delta_size
;
981 delta
->delta_compressed_size
= delta_compressed_size
;
982 delta
->delta_offset
= delta_data_offset
;
984 if (a
->ndeltas
>= GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS
) {
985 err
= got_privsep_send_reused_deltas(a
->ibuf
,
986 a
->deltas
, a
->ndeltas
);
997 static const struct got_error
*
998 recv_object_ids(struct got_object_idset
*idset
, struct imsgbuf
*ibuf
)
1000 const struct got_error
*err
= NULL
;
1002 struct got_object_id
*ids
;
1006 err
= got_privsep_recv_object_idlist(&done
, &ids
, &nids
, ibuf
);
1009 for (i
= 0; i
< nids
; i
++) {
1010 err
= got_object_idset_add(idset
, &ids
[i
], NULL
);
1022 static const struct got_error
*
1023 recv_object_id_queue(struct got_object_id_queue
*queue
,
1024 struct got_object_idset
*queued_ids
, struct imsgbuf
*ibuf
)
1026 const struct got_error
*err
= NULL
;
1028 struct got_object_qid
*qid
;
1029 struct got_object_id
*ids
;
1033 err
= got_privsep_recv_object_idlist(&done
, &ids
, &nids
, ibuf
);
1036 for (i
= 0; i
< nids
; i
++) {
1037 err
= got_object_qid_alloc_partial(&qid
);
1040 memcpy(&qid
->id
, &ids
[i
], sizeof(qid
->id
));
1041 STAILQ_INSERT_TAIL(queue
, qid
, entry
);
1042 err
= got_object_idset_add(queued_ids
, &qid
->id
, NULL
);
1051 static const struct got_error
*
1052 delta_reuse_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
1053 struct got_pack
*pack
, struct got_packidx
*packidx
)
1055 const struct got_error
*err
= NULL
;
1056 struct got_object_idset
*idset
;
1057 struct search_deltas_arg sda
;
1059 idset
= got_object_idset_alloc();
1061 return got_error_from_errno("got_object_idset_alloc");
1063 err
= recv_object_ids(idset
, ibuf
);
1067 memset(&sda
, 0, sizeof(sda
));
1071 sda
.packidx
= packidx
;
1072 err
= got_object_idset_for_each(idset
, search_delta_for_object
, &sda
);
1076 if (sda
.ndeltas
> 0) {
1077 err
= got_privsep_send_reused_deltas(ibuf
, sda
.deltas
,
1083 err
= got_privsep_send_reused_deltas_done(ibuf
);
1085 got_object_idset_free(idset
);
1089 static const struct got_error
*
1090 receive_packidx(struct got_packidx
**packidx
, struct imsgbuf
*ibuf
)
1092 const struct got_error
*err
= NULL
;
1094 struct got_imsg_packidx ipackidx
;
1096 struct got_packidx
*p
;
1100 err
= got_privsep_recv_imsg(&imsg
, ibuf
, 0);
1104 p
= calloc(1, sizeof(*p
));
1106 err
= got_error_from_errno("calloc");
1110 if (imsg
.hdr
.type
!= GOT_IMSG_PACKIDX
) {
1111 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1115 if (imsg
.fd
== -1) {
1116 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
1120 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
1121 if (datalen
!= sizeof(ipackidx
)) {
1122 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1125 memcpy(&ipackidx
, imsg
.data
, sizeof(ipackidx
));
1127 p
->len
= ipackidx
.len
;
1128 p
->fd
= dup(imsg
.fd
);
1130 err
= got_error_from_errno("dup");
1133 if (lseek(p
->fd
, 0, SEEK_SET
) == -1) {
1134 err
= got_error_from_errno("lseek");
1138 #ifndef GOT_PACK_NO_MMAP
1139 if (p
->len
> 0 && p
->len
<= SIZE_MAX
) {
1140 p
->map
= mmap(NULL
, p
->len
, PROT_READ
, MAP_PRIVATE
, p
->fd
, 0);
1141 if (p
->map
== MAP_FAILED
)
1142 p
->map
= NULL
; /* fall back to read(2) */
1145 err
= got_packidx_init_hdr(p
, 1, ipackidx
.packfile_size
);
1150 got_packidx_close(p
);
1157 static const struct got_error
*
1158 send_tree_enumeration_done(struct imsgbuf
*ibuf
)
1160 if (imsg_compose(ibuf
, GOT_IMSG_TREE_ENUMERATION_DONE
, 0, 0, -1,
1162 return got_error_from_errno("imsg_compose TREE_ENUMERATION_DONE");
1164 return got_privsep_flush_imsg(ibuf
);
1167 struct enumerated_tree
{
1168 struct got_object_id id
;
1171 struct got_parsed_tree_entry
*entries
;
1175 static const struct got_error
*
1176 enumerate_tree(int *have_all_entries
, struct imsgbuf
*ibuf
, size_t *totlen
,
1177 struct got_object_id
*tree_id
,
1178 const char *path
, struct got_pack
*pack
, struct got_packidx
*packidx
,
1179 struct got_object_cache
*objcache
, struct got_object_idset
*idset
,
1180 struct enumerated_tree
**trees
, size_t *nalloc
, size_t *ntrees
)
1182 const struct got_error
*err
= NULL
;
1183 struct got_object_id_queue ids
;
1184 struct got_object_qid
*qid
;
1185 uint8_t *buf
= NULL
;
1186 struct got_parsed_tree_entry
*entries
= NULL
;
1187 size_t nentries
= 0, nentries_alloc
= 0, i
;
1188 struct enumerated_tree
*tree
;
1191 *have_all_entries
= 1;
1194 err
= got_object_qid_alloc_partial(&qid
);
1197 memcpy(&qid
->id
, tree_id
, sizeof(*tree_id
));
1198 qid
->data
= strdup(path
);
1199 if (qid
->data
== NULL
) {
1200 err
= got_error_from_errno("strdup");
1203 STAILQ_INSERT_TAIL(&ids
, qid
, entry
);
1206 /* Traverse the tree hierarchy, gather tree object IDs and paths. */
1211 if (sigint_received
) {
1212 err
= got_error(GOT_ERR_CANCELLED
);
1216 qid
= STAILQ_FIRST(&ids
);
1217 STAILQ_REMOVE_HEAD(&ids
, entry
);
1220 idx
= got_packidx_get_object_idx(packidx
, &qid
->id
);
1222 *have_all_entries
= 0;
1226 err
= open_tree(&buf
, &entries
, &nentries
, &nentries_alloc
,
1227 pack
, packidx
, idx
, &qid
->id
, objcache
);
1229 if (err
->code
!= GOT_ERR_NO_OBJ
)
1233 err
= got_object_idset_add(idset
, &qid
->id
, NULL
);
1237 for (i
= 0; i
< nentries
; i
++) {
1238 struct got_object_qid
*eqid
= NULL
;
1239 struct got_parsed_tree_entry
*pte
= &entries
[i
];
1242 if (!S_ISDIR(pte
->mode
))
1245 err
= got_object_qid_alloc_partial(&eqid
);
1248 memcpy(eqid
->id
.sha1
, pte
->id
, sizeof(eqid
->id
.sha1
));
1250 if (got_object_idset_contains(idset
, &eqid
->id
)) {
1251 got_object_qid_free(eqid
);
1255 if (asprintf(&p
, "%s%s%s", path
,
1256 got_path_is_root_dir(path
) ? "" : "/",
1258 err
= got_error_from_errno("asprintf");
1259 got_object_qid_free(eqid
);
1263 STAILQ_INSERT_TAIL(&ids
, eqid
, entry
);
1266 if (*ntrees
>= *nalloc
) {
1267 struct enumerated_tree
*new;
1268 new = recallocarray(*trees
, *nalloc
, *nalloc
+ 16,
1271 err
= got_error_from_errno("malloc");
1277 tree
= &(*trees
)[*ntrees
];
1279 memcpy(&tree
->id
, &qid
->id
, sizeof(tree
->id
));
1280 tree
->path
= qid
->data
;
1283 tree
->entries
= entries
;
1286 tree
->nentries
= nentries
;
1289 got_object_qid_free(qid
);
1291 } while (!STAILQ_EMPTY(&ids
));
1293 if (*have_all_entries
) {
1296 * We have managed to traverse all entries in the hierarchy.
1297 * Tell the main process what we have found.
1299 for (i
= 0; i
< *ntrees
; i
++) {
1300 tree
= &(*trees
)[i
];
1301 err
= got_privsep_send_enumerated_tree(totlen
,
1302 ibuf
, &tree
->id
, tree
->path
, tree
->entries
,
1310 free(tree
->entries
);
1311 tree
->entries
= NULL
;
1313 *ntrees
= 0; /* don't loop again below to free memory */
1315 err
= send_tree_enumeration_done(ibuf
);
1318 * We can only load fully packed tree hierarchies on
1319 * behalf of the main process, otherwise the main process
1320 * gets a wrong idea about which tree objects have
1321 * already been traversed.
1322 * Indicate a missing entry for the root of this tree.
1323 * The main process should continue by loading this
1324 * entire tree the slow way.
1326 err
= got_privsep_send_enumerated_tree(totlen
, ibuf
,
1327 tree_id
, "/", NULL
, -1);
1334 for (i
= 0; i
< *ntrees
; i
++) {
1335 tree
= &(*trees
)[i
];
1340 free(tree
->entries
);
1341 tree
->entries
= NULL
;
1345 got_object_qid_free(qid
);
1346 got_object_id_queue_free(&ids
);
1348 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
1351 got_privsep_send_error(ibuf
, err
);
1357 static const struct got_error
*
1358 enumeration_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
1359 struct got_pack
*pack
, struct got_packidx
*packidx
,
1360 struct got_object_cache
*objcache
)
1362 const struct got_error
*err
= NULL
;
1363 struct got_object_id_queue commit_ids
;
1364 const struct got_object_id_queue
*parents
= NULL
;
1365 struct got_object_qid
*qid
= NULL
;
1366 struct got_object
*obj
= NULL
;
1367 struct got_commit_object
*commit
= NULL
;
1368 struct got_object_id
*tree_id
= NULL
;
1370 struct got_object_idset
*idset
, *queued_ids
= NULL
;
1371 int i
, idx
, have_all_entries
= 1;
1372 struct enumerated_tree
*trees
= NULL
;
1373 size_t ntrees
= 0, nalloc
= 16;
1375 STAILQ_INIT(&commit_ids
);
1377 trees
= calloc(nalloc
, sizeof(*trees
));
1379 return got_error_from_errno("calloc");
1381 idset
= got_object_idset_alloc();
1382 if (idset
== NULL
) {
1383 err
= got_error_from_errno("got_object_idset_alloc");
1387 queued_ids
= got_object_idset_alloc();
1388 if (queued_ids
== NULL
) {
1389 err
= got_error_from_errno("got_object_idset_alloc");
1393 err
= recv_object_id_queue(&commit_ids
, queued_ids
, ibuf
);
1397 if (STAILQ_EMPTY(&commit_ids
)) {
1398 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1402 err
= recv_object_ids(idset
, ibuf
);
1406 while (!STAILQ_EMPTY(&commit_ids
)) {
1407 if (sigint_received
) {
1408 err
= got_error(GOT_ERR_CANCELLED
);
1412 qid
= STAILQ_FIRST(&commit_ids
);
1413 STAILQ_REMOVE_HEAD(&commit_ids
, entry
);
1415 if (got_object_idset_contains(idset
, &qid
->id
)) {
1416 got_object_qid_free(qid
);
1421 idx
= got_packidx_get_object_idx(packidx
, &qid
->id
);
1423 have_all_entries
= 0;
1427 err
= open_object(&obj
, pack
, packidx
, idx
, &qid
->id
,
1431 if (obj
->type
== GOT_OBJ_TYPE_TAG
) {
1432 struct got_tag_object
*tag
;
1435 err
= got_packfile_extract_object_to_mem(&buf
,
1440 err
= got_object_parse_tag(&tag
, buf
, len
);
1445 idx
= got_packidx_get_object_idx(packidx
, &tag
->id
);
1447 have_all_entries
= 0;
1450 err
= open_commit(&commit
, pack
, packidx
, idx
,
1451 &tag
->id
, objcache
);
1452 got_object_tag_close(tag
);
1456 } else if (obj
->type
== GOT_OBJ_TYPE_COMMIT
) {
1457 err
= open_commit(&commit
, pack
, packidx
, idx
,
1458 &qid
->id
, objcache
);
1462 err
= got_error(GOT_ERR_OBJ_TYPE
);
1465 got_object_close(obj
);
1468 err
= got_privsep_send_enumerated_commit(ibuf
, &qid
->id
,
1469 got_object_commit_get_committer_time(commit
));
1473 tree_id
= got_object_commit_get_tree_id(commit
);
1474 idx
= got_packidx_get_object_idx(packidx
, tree_id
);
1476 have_all_entries
= 0;
1477 err
= got_privsep_send_enumerated_tree(&totlen
, ibuf
,
1478 tree_id
, "/", NULL
, -1);
1484 if (got_object_idset_contains(idset
, tree_id
)) {
1485 got_object_qid_free(qid
);
1487 err
= send_tree_enumeration_done(ibuf
);
1493 err
= enumerate_tree(&have_all_entries
, ibuf
, &totlen
,
1494 tree_id
, "/", pack
, packidx
, objcache
, idset
,
1495 &trees
, &nalloc
, &ntrees
);
1499 if (!have_all_entries
)
1502 got_object_qid_free(qid
);
1505 parents
= got_object_commit_get_parent_ids(commit
);
1507 struct got_object_qid
*pid
;
1508 STAILQ_FOREACH(pid
, parents
, entry
) {
1509 if (got_object_idset_contains(idset
, &pid
->id
))
1511 if (got_object_idset_contains(queued_ids
, &pid
->id
))
1513 err
= got_object_qid_alloc_partial(&qid
);
1516 memcpy(&qid
->id
, &pid
->id
, sizeof(qid
->id
));
1517 STAILQ_INSERT_TAIL(&commit_ids
, qid
, entry
);
1522 got_object_commit_close(commit
);
1526 if (have_all_entries
) {
1527 err
= got_privsep_send_object_enumeration_done(ibuf
);
1531 err
= got_privsep_send_object_enumeration_incomplete(ibuf
);
1537 got_object_close(obj
);
1539 got_object_commit_close(commit
);
1540 got_object_qid_free(qid
);
1541 got_object_id_queue_free(&commit_ids
);
1543 got_object_idset_free(idset
);
1545 got_object_idset_free(queued_ids
);
1546 for (i
= 0; i
< ntrees
; i
++) {
1547 struct enumerated_tree
*tree
= &trees
[i
];
1550 free(tree
->entries
);
1556 enum findtwixt_color
{
1563 static const struct got_error
*
1564 paint_commit(struct got_object_qid
*qid
, intptr_t color
)
1566 if (color
< 0 || color
>= COLOR_MAX
)
1567 return got_error(GOT_ERR_RANGE
);
1569 qid
->data
= (void *)color
;
1573 static const struct got_error
*
1574 queue_commit_id(struct got_object_id_queue
*ids
, struct got_object_id
*id
,
1577 const struct got_error
*err
;
1578 struct got_object_qid
*qid
;
1580 err
= got_object_qid_alloc_partial(&qid
);
1584 memcpy(&qid
->id
, id
, sizeof(qid
->id
));
1585 STAILQ_INSERT_TAIL(ids
, qid
, entry
);
1586 return paint_commit(qid
, color
);
1589 static const struct got_error
*
1590 paint_commits(struct got_object_id_queue
*ids
, int *nids
,
1591 struct got_object_idset
*keep
, struct got_object_idset
*drop
,
1592 struct got_object_idset
*skip
, struct got_pack
*pack
,
1593 struct got_packidx
*packidx
, struct imsgbuf
*ibuf
,
1594 struct got_object_cache
*objcache
)
1596 const struct got_error
*err
= NULL
;
1597 struct got_commit_object
*commit
= NULL
;
1598 struct got_object_id_queue painted
;
1599 const struct got_object_id_queue
*parents
;
1600 struct got_object_qid
*qid
= NULL
;
1601 int nqueued
= *nids
, nskip
= 0, npainted
= 0;
1603 STAILQ_INIT(&painted
);
1605 while (!STAILQ_EMPTY(ids
) && nskip
!= nqueued
) {
1609 if (sigint_received
) {
1610 err
= got_error(GOT_ERR_CANCELLED
);
1614 qid
= STAILQ_FIRST(ids
);
1615 idx
= got_packidx_get_object_idx(packidx
, &qid
->id
);
1621 STAILQ_REMOVE_HEAD(ids
, entry
);
1623 color
= (intptr_t)qid
->data
;
1624 if (color
== COLOR_SKIP
)
1627 if (got_object_idset_contains(skip
, &qid
->id
)) {
1628 got_object_qid_free(qid
);
1635 if (got_object_idset_contains(keep
, &qid
->id
)) {
1636 got_object_qid_free(qid
);
1640 if (got_object_idset_contains(drop
, &qid
->id
)) {
1641 err
= paint_commit(qid
, COLOR_SKIP
);
1645 err
= got_object_idset_add(keep
, &qid
->id
, NULL
);
1650 if (got_object_idset_contains(drop
, &qid
->id
)) {
1651 got_object_qid_free(qid
);
1655 if (got_object_idset_contains(keep
, &qid
->id
)) {
1656 err
= paint_commit(qid
, COLOR_SKIP
);
1660 err
= got_object_idset_add(drop
, &qid
->id
, NULL
);
1665 if (!got_object_idset_contains(skip
, &qid
->id
)) {
1666 err
= got_object_idset_add(skip
, &qid
->id
,
1673 /* should not happen */
1674 err
= got_error_fmt(GOT_ERR_NOT_IMPL
,
1675 "%s invalid commit color %"PRIdPTR
, __func__
,
1680 err
= open_commit(&commit
, pack
, packidx
, idx
, &qid
->id
,
1685 parents
= got_object_commit_get_parent_ids(commit
);
1687 struct got_object_qid
*pid
;
1688 color
= (intptr_t)qid
->data
;
1689 STAILQ_FOREACH(pid
, parents
, entry
) {
1690 err
= queue_commit_id(ids
, &pid
->id
, color
);
1694 if (color
== COLOR_SKIP
)
1699 got_object_commit_close(commit
);
1702 STAILQ_INSERT_TAIL(&painted
, qid
, entry
);
1706 err
= got_privsep_send_painted_commits(ibuf
, &painted
,
1712 err
= got_privsep_send_painted_commits(ibuf
, &painted
, &npainted
, 1, 1);
1719 got_object_commit_close(commit
);
1720 got_object_qid_free(qid
);
1725 commit_painting_free(struct got_object_idset
**keep
,
1726 struct got_object_idset
**drop
,
1727 struct got_object_idset
**skip
)
1730 got_object_idset_free(*keep
);
1734 got_object_idset_free(*drop
);
1738 got_object_idset_free(*skip
);
1743 static const struct got_error
*
1744 commit_painting_init(struct imsgbuf
*ibuf
, struct got_object_idset
**keep
,
1745 struct got_object_idset
**drop
, struct got_object_idset
**skip
)
1747 const struct got_error
*err
= NULL
;
1749 *keep
= got_object_idset_alloc();
1750 if (*keep
== NULL
) {
1751 err
= got_error_from_errno("got_object_idset_alloc");
1754 *drop
= got_object_idset_alloc();
1755 if (*drop
== NULL
) {
1756 err
= got_error_from_errno("got_object_idset_alloc");
1759 *skip
= got_object_idset_alloc();
1760 if (*skip
== NULL
) {
1761 err
= got_error_from_errno("got_object_idset_alloc");
1765 err
= recv_object_ids(*keep
, ibuf
);
1768 err
= recv_object_ids(*drop
, ibuf
);
1771 err
= recv_object_ids(*skip
, ibuf
);
1777 commit_painting_free(keep
, drop
, skip
);
1782 static const struct got_error
*
1783 commit_painting_request(struct imsg
*imsg
, struct imsgbuf
*ibuf
,
1784 struct got_pack
*pack
, struct got_packidx
*packidx
,
1785 struct got_object_cache
*objcache
, struct got_object_idset
*keep
,
1786 struct got_object_idset
*drop
, struct got_object_idset
*skip
)
1788 const struct got_error
*err
= NULL
;
1789 struct got_imsg_commit_painting_request ireq
;
1790 struct got_object_id id
;
1792 struct got_object_id_queue ids
;
1797 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
1798 if (datalen
!= sizeof(ireq
))
1799 return got_error(GOT_ERR_PRIVSEP_LEN
);
1800 memcpy(&ireq
, imsg
->data
, sizeof(ireq
));
1801 memcpy(&id
, &ireq
.id
, sizeof(id
));
1803 err
= queue_commit_id(&ids
, &id
, ireq
.color
);
1808 err
= paint_commits(&ids
, &nids
, keep
, drop
, skip
,
1809 pack
, packidx
, ibuf
, objcache
);
1813 err
= got_privsep_send_painted_commits(ibuf
, &ids
, &nids
, 0, 1);
1817 err
= got_privsep_send_painting_commits_done(ibuf
);
1819 got_object_id_queue_free(&ids
);
1823 static const struct got_error
*
1824 receive_pack(struct got_pack
**packp
, struct imsgbuf
*ibuf
)
1826 const struct got_error
*err
= NULL
;
1828 struct got_imsg_pack ipack
;
1830 struct got_pack
*pack
;
1834 err
= got_privsep_recv_imsg(&imsg
, ibuf
, 0);
1838 pack
= calloc(1, sizeof(*pack
));
1840 err
= got_error_from_errno("calloc");
1844 if (imsg
.hdr
.type
!= GOT_IMSG_PACK
) {
1845 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1849 if (imsg
.fd
== -1) {
1850 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
1854 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
1855 if (datalen
!= sizeof(ipack
)) {
1856 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1859 memcpy(&ipack
, imsg
.data
, sizeof(ipack
));
1861 pack
->filesize
= ipack
.filesize
;
1862 pack
->fd
= dup(imsg
.fd
);
1863 if (pack
->fd
== -1) {
1864 err
= got_error_from_errno("dup");
1867 if (lseek(pack
->fd
, 0, SEEK_SET
) == -1) {
1868 err
= got_error_from_errno("lseek");
1871 pack
->path_packfile
= strdup(ipack
.path_packfile
);
1872 if (pack
->path_packfile
== NULL
) {
1873 err
= got_error_from_errno("strdup");
1877 err
= got_delta_cache_alloc(&pack
->delta_cache
);
1881 #ifndef GOT_PACK_NO_MMAP
1882 if (pack
->filesize
> 0 && pack
->filesize
<= SIZE_MAX
) {
1883 pack
->map
= mmap(NULL
, pack
->filesize
, PROT_READ
, MAP_PRIVATE
,
1885 if (pack
->map
== MAP_FAILED
)
1886 pack
->map
= NULL
; /* fall back to read(2) */
1901 main(int argc
, char *argv
[])
1903 const struct got_error
*err
= NULL
;
1904 struct imsgbuf ibuf
;
1906 struct got_packidx
*packidx
= NULL
;
1907 struct got_pack
*pack
= NULL
;
1908 struct got_object_cache objcache
;
1909 FILE *basefile
= NULL
, *accumfile
= NULL
, *delta_outfile
= NULL
;
1910 struct got_object_idset
*keep
= NULL
, *drop
= NULL
, *skip
= NULL
;
1911 struct got_parsed_tree_entry
*entries
= NULL
;
1912 size_t nentries
= 0, nentries_alloc
= 0;
1914 //static int attached;
1915 //while (!attached) sleep(1);
1917 signal(SIGINT
, catch_sigint
);
1919 imsg_init(&ibuf
, GOT_IMSG_FD_CHILD
);
1921 err
= got_object_cache_init(&objcache
, GOT_OBJECT_CACHE_TYPE_OBJ
);
1923 err
= got_error_from_errno("got_object_cache_init");
1924 got_privsep_send_error(&ibuf
, err
);
1929 /* revoke access to most system calls */
1930 if (pledge("stdio recvfd", NULL
) == -1) {
1931 err
= got_error_from_errno("pledge");
1932 got_privsep_send_error(&ibuf
, err
);
1936 /* revoke fs access */
1937 if (landlock_no_fs() == -1) {
1938 err
= got_error_from_errno("landlock_no_fs");
1939 got_privsep_send_error(&ibuf
, err
);
1942 if (cap_enter() == -1) {
1943 err
= got_error_from_errno("cap_enter");
1944 got_privsep_send_error(&ibuf
, err
);
1949 err
= receive_packidx(&packidx
, &ibuf
);
1951 got_privsep_send_error(&ibuf
, err
);
1955 err
= receive_pack(&pack
, &ibuf
);
1957 got_privsep_send_error(&ibuf
, err
);
1964 if (sigint_received
) {
1965 err
= got_error(GOT_ERR_CANCELLED
);
1969 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
1971 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
1976 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
1979 switch (imsg
.hdr
.type
) {
1980 case GOT_IMSG_TMPFD
:
1981 if (basefile
== NULL
) {
1982 err
= receive_tempfile(&basefile
, "w+",
1984 } else if (accumfile
== NULL
) {
1985 err
= receive_tempfile(&accumfile
, "w+",
1988 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1990 case GOT_IMSG_PACKED_OBJECT_REQUEST
:
1991 err
= object_request(&imsg
, &ibuf
, pack
, packidx
,
1994 case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST
:
1995 if (basefile
== NULL
|| accumfile
== NULL
) {
1996 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1999 err
= raw_object_request(&imsg
, &ibuf
, pack
, packidx
,
2000 &objcache
, basefile
, accumfile
);
2002 case GOT_IMSG_RAW_DELTA_OUTFD
:
2003 if (delta_outfile
!= NULL
) {
2004 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2007 err
= receive_tempfile(&delta_outfile
, "w",
2010 case GOT_IMSG_RAW_DELTA_REQUEST
:
2011 if (delta_outfile
== NULL
) {
2012 err
= got_error(GOT_ERR_PRIVSEP_NO_FD
);
2015 err
= raw_delta_request(&imsg
, &ibuf
, delta_outfile
,
2018 case GOT_IMSG_DELTA_REUSE_REQUEST
:
2019 err
= delta_reuse_request(&imsg
, &ibuf
, pack
, packidx
);
2021 case GOT_IMSG_COMMIT_REQUEST
:
2022 err
= commit_request(&imsg
, &ibuf
, pack
, packidx
,
2025 case GOT_IMSG_TREE_REQUEST
:
2026 err
= tree_request(&imsg
, &ibuf
, pack
, packidx
,
2027 &objcache
, &entries
, &nentries
, &nentries_alloc
);
2029 case GOT_IMSG_BLOB_REQUEST
:
2030 if (basefile
== NULL
|| accumfile
== NULL
) {
2031 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2034 err
= blob_request(&imsg
, &ibuf
, pack
, packidx
,
2035 &objcache
, basefile
, accumfile
);
2037 case GOT_IMSG_TAG_REQUEST
:
2038 err
= tag_request(&imsg
, &ibuf
, pack
, packidx
,
2041 case GOT_IMSG_COMMIT_TRAVERSAL_REQUEST
:
2042 err
= commit_traversal_request(&imsg
, &ibuf
, pack
,
2043 packidx
, &objcache
);
2045 case GOT_IMSG_OBJECT_ENUMERATION_REQUEST
:
2046 err
= enumeration_request(&imsg
, &ibuf
, pack
,
2047 packidx
, &objcache
);
2049 case GOT_IMSG_COMMIT_PAINTING_INIT
:
2050 commit_painting_free(&keep
, &drop
, &skip
);
2051 err
= commit_painting_init(&ibuf
, &keep
, &drop
, &skip
);
2053 case GOT_IMSG_COMMIT_PAINTING_REQUEST
:
2054 if (keep
== NULL
|| drop
== NULL
|| skip
== NULL
) {
2055 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2058 err
= commit_painting_request(&imsg
, &ibuf
, pack
,
2059 packidx
, &objcache
, keep
, drop
, skip
);
2061 case GOT_IMSG_COMMIT_PAINTING_DONE
:
2062 commit_painting_free(&keep
, &drop
, &skip
);
2065 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
2069 if (imsg
.fd
!= -1 && close(imsg
.fd
) == -1 && err
== NULL
)
2070 err
= got_error_from_errno("close");
2077 commit_painting_free(&keep
, &drop
, &skip
);
2079 got_packidx_close(packidx
);
2081 got_pack_close(pack
);
2082 got_object_cache_close(&objcache
);
2084 if (basefile
&& fclose(basefile
) == EOF
&& err
== NULL
)
2085 err
= got_error_from_errno("fclose");
2086 if (accumfile
&& fclose(accumfile
) == EOF
&& err
== NULL
)
2087 err
= got_error_from_errno("fclose");
2088 if (delta_outfile
&& fclose(delta_outfile
) == EOF
&& err
== NULL
)
2089 err
= got_error_from_errno("fclose");
2091 if (!sigint_received
&& err
->code
!= GOT_ERR_PRIVSEP_PIPE
) {
2092 fprintf(stderr
, "%s: %s\n", getprogname(), err
->msg
);
2093 got_privsep_send_error(&ibuf
, err
);
2096 if (close(GOT_IMSG_FD_CHILD
) == -1 && err
== NULL
)
2097 err
= got_error_from_errno("close");