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>
37 #include "got_error.h"
38 #include "got_object.h"
41 #include "got_lib_delta.h"
42 #include "got_lib_delta_cache.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);
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;
272 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
276 if (imsg.hdr.type != imsg_code) {
277 err = got_error(GOT_ERR_PRIVSEP_MSG);
281 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
283 err = got_error(GOT_ERR_PRIVSEP_LEN);
287 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
291 *f = fdopen(imsg.fd, "w+");
293 err = got_error_from_errno("fdopen");
302 static const struct got_error *
303 receive_tempfile(FILE **f, const char *mode, struct imsg *imsg,
304 struct imsgbuf *ibuf)
308 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
310 return got_error(GOT_ERR_PRIVSEP_LEN);
313 return got_error(GOT_ERR_PRIVSEP_NO_FD);
315 *f = fdopen(imsg->fd, mode);
317 return got_error_from_errno("fdopen");
323 static const struct got_error *
324 blob_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
325 struct got_packidx *packidx, struct got_object_cache *objcache,
326 FILE *basefile, FILE *accumfile)
328 const struct got_error *err = NULL;
329 struct got_imsg_packed_object iobj;
330 struct got_object *obj = NULL;
331 FILE *outfile = NULL;
332 struct got_object_id id;
337 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
338 if (datalen != sizeof(iobj))
339 return got_error(GOT_ERR_PRIVSEP_LEN);
340 memcpy(&iobj, imsg->data, sizeof(iobj));
341 memcpy(&id, &iobj.id, sizeof(id));
343 obj = got_object_cache_get(objcache, &id);
347 err = open_object(&obj, pack, packidx, iobj.idx, &id,
353 err = receive_file(&outfile, ibuf, GOT_IMSG_BLOB_OUTFD);
357 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
358 err = got_pack_get_max_delta_object_size(&blob_size, obj, pack);
362 blob_size = obj->size;
364 if (blob_size <= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX)
365 err = got_packfile_extract_object_to_mem(&buf, &obj->size,
368 err = got_packfile_extract_object(pack, obj, outfile, basefile,
373 err = got_privsep_send_blob(ibuf, obj->size, obj->hdrlen, buf);
376 if (outfile && fclose(outfile) == EOF && err == NULL)
377 err = got_error_from_errno("fclose");
378 got_object_close(obj);
379 if (err && err->code != GOT_ERR_PRIVSEP_PIPE)
380 got_privsep_send_error(ibuf, err);
385 static const struct got_error *
386 tag_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
387 struct got_packidx *packidx, struct got_object_cache *objcache)
389 const struct got_error *err = NULL;
390 struct got_imsg_packed_object iobj;
391 struct got_object *obj = NULL;
392 struct got_tag_object *tag = NULL;
395 struct got_object_id id;
398 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
399 if (datalen != sizeof(iobj))
400 return got_error(GOT_ERR_PRIVSEP_LEN);
401 memcpy(&iobj, imsg->data, sizeof(iobj));
402 memcpy(&id, &iobj.id, sizeof(id));
404 obj = got_object_cache_get(objcache, &id);
408 err = open_object(&obj, pack, packidx, iobj.idx, &id,
414 err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack);
419 err = got_object_parse_tag(&tag, buf, len);
423 err = got_privsep_send_tag(ibuf, tag);
426 got_object_close(obj);
428 got_object_tag_close(tag);
430 if (err->code == GOT_ERR_PRIVSEP_PIPE)
433 got_privsep_send_error(ibuf, err);
439 static const struct got_error *
440 tree_path_changed(int *changed, uint8_t **buf1, size_t *len1,
441 uint8_t **buf2, size_t *len2, const char *path,
442 struct got_pack *pack, struct got_packidx *packidx,
443 struct imsgbuf *ibuf, struct got_object_cache *objcache)
445 const struct got_error *err = NULL;
446 struct got_parsed_tree_entry pte1, pte2;
449 size_t remain1 = *len1, remain2 = *len2, elen;
450 uint8_t *next_entry1 = *buf1;
451 uint8_t *next_entry2 = *buf2;
453 memset(&pte1, 0, sizeof(pte1));
454 memset(&pte2, 0, sizeof(pte2));
458 /* We not do support comparing the root path. */
459 if (got_path_is_root_dir(path))
460 return got_error_path(path, GOT_ERR_BAD_PATH);
476 * As an optimization we compare entries in on-disk order
477 * rather than in got_path_cmp() order. We only need to
478 * find out if any entries differ. Parsing all entries and
479 * sorting them slows us down significantly when tree objects
480 * have thousands of entries. We can assume that on-disk entry
481 * ordering is stable, as per got_object_tree_create() and
482 * sort_tree_entries_the_way_git_likes_it(). Other orderings
483 * are incompatible with Git and would yield false positives
486 while (remain1 > 0) {
487 err = got_object_parse_tree_entry(&pte1, &elen,
488 next_entry1, remain1);
493 if (strncmp(pte1.name, seg, seglen) != 0 ||
494 pte1.name[seglen] != '\0') {
495 memset(&pte1, 0, sizeof(pte1));
500 if (pte1.name == NULL) {
501 err = got_error(GOT_ERR_NO_OBJ);
510 while (remain2 > 0) {
511 err = got_object_parse_tree_entry(&pte2, &elen,
512 next_entry2, remain2);
517 if (strncmp(pte2.name, seg, seglen) != 0 ||
518 pte2.name[seglen] != '\0') {
519 memset(&pte2, 0, sizeof(pte2));
525 if (pte2.name == NULL) {
530 if (pte1.mode != pte2.mode) {
535 if (memcmp(pte1.id, pte2.id, SHA1_DIGEST_LENGTH) == 0) {
540 if (*s == '\0') { /* final path element */
549 struct got_object_id id1, id2;
552 memcpy(id1.sha1, pte1.id, SHA1_DIGEST_LENGTH);
553 idx = got_packidx_get_object_idx(packidx, &id1);
555 err = got_error_no_obj(&id1);
560 err = open_tree(buf1, len1, pack, packidx, idx, &id1,
562 memset(&pte1, 0, sizeof(pte1));
568 memcpy(id2.sha1, pte2.id, SHA1_DIGEST_LENGTH);
569 idx = got_packidx_get_object_idx(packidx, &id2);
571 err = got_error_no_obj(&id2);
576 err = open_tree(buf2, len2, pack, packidx, idx, &id2,
578 memset(&pte2, 0, sizeof(pte2));
589 static const struct got_error *
590 send_traversed_commits(struct got_object_id *commit_ids, size_t ncommits,
591 struct imsgbuf *ibuf)
596 wbuf = imsg_create(ibuf, GOT_IMSG_TRAVERSED_COMMITS, 0, 0,
597 sizeof(struct got_imsg_traversed_commits) +
598 ncommits * sizeof(commit_ids[0]));
600 return got_error_from_errno("imsg_create TRAVERSED_COMMITS");
602 if (imsg_add(wbuf, &ncommits, sizeof(ncommits)) == -1)
603 return got_error_from_errno("imsg_add TRAVERSED_COMMITS");
605 for (i = 0; i < ncommits; i++) {
606 struct got_object_id *id = &commit_ids[i];
607 if (imsg_add(wbuf, id, sizeof(*id)) == -1) {
608 return got_error_from_errno(
609 "imsg_add TRAVERSED_COMMITS");
614 imsg_close(ibuf, wbuf);
616 return got_privsep_flush_imsg(ibuf);
619 static const struct got_error *
620 send_commit_traversal_done(struct imsgbuf *ibuf)
622 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_TRAVERSAL_DONE, 0, 0, -1,
624 return got_error_from_errno("imsg_compose TRAVERSAL_DONE");
626 return got_privsep_flush_imsg(ibuf);
629 static const struct got_error *
630 commit_traversal_request(struct imsg *imsg, struct imsgbuf *ibuf,
631 struct got_pack *pack, struct got_packidx *packidx,
632 struct got_object_cache *objcache)
634 const struct got_error *err = NULL;
635 struct got_imsg_commit_traversal_request ctreq;
636 struct got_object_qid *pid;
637 struct got_commit_object *commit = NULL, *pcommit = NULL;
638 struct got_object_id id;
641 const int min_alloc = 64;
642 int changed = 0, ncommits = 0, nallocated = 0;
643 struct got_object_id *commit_ids = NULL;
645 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
646 if (datalen < sizeof(ctreq))
647 return got_error(GOT_ERR_PRIVSEP_LEN);
648 memcpy(&ctreq, imsg->data, sizeof(ctreq));
649 memcpy(&id, &ctreq.iobj.id, sizeof(id));
651 if (datalen != sizeof(ctreq) + ctreq.path_len)
652 return got_error(GOT_ERR_PRIVSEP_LEN);
653 if (ctreq.path_len == 0)
654 return got_error(GOT_ERR_PRIVSEP_LEN);
656 path = strndup(imsg->data + sizeof(ctreq), ctreq.path_len);
658 return got_error_from_errno("strndup");
660 nallocated = min_alloc;
661 commit_ids = reallocarray(NULL, nallocated, sizeof(*commit_ids));
662 if (commit_ids == NULL)
663 return got_error_from_errno("reallocarray");
666 const size_t max_datalen = MAX_IMSGSIZE - IMSG_HEADER_SIZE;
669 if (sigint_received) {
670 err = got_error(GOT_ERR_CANCELLED);
674 if (commit == NULL) {
675 idx = got_packidx_get_object_idx(packidx, &id);
678 err = open_commit(&commit, pack, packidx,
681 if (err->code != GOT_ERR_NO_OBJ)
688 if (sizeof(struct got_imsg_traversed_commits) +
689 ncommits * sizeof(commit_ids[0]) >= max_datalen) {
690 err = send_traversed_commits(commit_ids, ncommits,
697 if (ncommits > nallocated) {
698 struct got_object_id *new;
699 nallocated += min_alloc;
700 new = reallocarray(commit_ids, nallocated,
701 sizeof(*commit_ids));
703 err = got_error_from_errno("reallocarray");
708 memcpy(&commit_ids[ncommits - 1], &id, sizeof(id));
710 pid = STAILQ_FIRST(&commit->parent_ids);
714 idx = got_packidx_get_object_idx(packidx, &pid->id);
718 err = open_commit(&pcommit, pack, packidx, idx, &pid->id,
721 if (err->code != GOT_ERR_NO_OBJ)
727 if (path[0] == '/' && path[1] == '\0') {
728 if (got_object_id_cmp(pcommit->tree_id,
729 commit->tree_id) != 0) {
735 uint8_t *buf = NULL, *pbuf = NULL;
736 size_t len = 0, plen = 0;
738 idx = got_packidx_get_object_idx(packidx,
742 pidx = got_packidx_get_object_idx(packidx,
747 err = open_tree(&buf, &len, pack, packidx, idx,
748 commit->tree_id, objcache);
752 err = open_tree(&pbuf, &plen, pack, packidx, pidx,
753 pcommit->tree_id, objcache);
759 err = tree_path_changed(&changed, &buf, &len,
760 &pbuf, &plen, path, pack, packidx, ibuf,
766 if (err->code != GOT_ERR_NO_OBJ)
774 memcpy(&id, &pid->id, sizeof(id));
775 got_object_commit_close(commit);
782 err = send_traversed_commits(commit_ids, ncommits, ibuf);
787 err = got_privsep_send_commit(ibuf, commit);
792 err = send_commit_traversal_done(ibuf);
797 got_object_commit_close(commit);
799 got_object_commit_close(pcommit);
801 if (err->code == GOT_ERR_PRIVSEP_PIPE)
804 got_privsep_send_error(ibuf, err);
810 static const struct got_error *
811 raw_object_request(struct imsg *imsg, struct imsgbuf *ibuf,
812 struct got_pack *pack, struct got_packidx *packidx,
813 struct got_object_cache *objcache, FILE *basefile, FILE *accumfile)
815 const struct got_error *err = NULL;
818 FILE *outfile = NULL;
819 struct got_imsg_packed_object iobj;
820 struct got_object *obj;
821 struct got_object_id id;
824 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
825 if (datalen != sizeof(iobj))
826 return got_error(GOT_ERR_PRIVSEP_LEN);
827 memcpy(&iobj, imsg->data, sizeof(iobj));
828 memcpy(&id, &iobj.id, sizeof(id));
830 obj = got_object_cache_get(objcache, &id);
834 err = open_object(&obj, pack, packidx, iobj.idx, &id,
840 err = receive_file(&outfile, ibuf, GOT_IMSG_RAW_OBJECT_OUTFD);
844 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
845 err = got_pack_get_max_delta_object_size(&size, obj, pack);
851 if (size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX)
852 err = got_packfile_extract_object_to_mem(&buf, &obj->size,
855 err = got_packfile_extract_object(pack, obj, outfile, basefile,
860 err = got_privsep_send_raw_obj(ibuf, obj->size, obj->hdrlen, buf);
863 if (outfile && fclose(outfile) == EOF && err == NULL)
864 err = got_error_from_errno("fclose");
865 got_object_close(obj);
866 if (err && err->code != GOT_ERR_PRIVSEP_PIPE)
867 got_privsep_send_error(ibuf, err);
872 static const struct got_error *
873 get_base_object_id(struct got_object_id *base_id, struct got_packidx *packidx,
876 const struct got_error *err;
879 err = got_packidx_get_offset_idx(&idx, packidx, base_offset);
883 return got_error(GOT_ERR_BAD_PACKIDX);
885 return got_packidx_get_object_id(base_id, packidx, idx);
888 static const struct got_error *
889 raw_delta_request(struct imsg *imsg, struct imsgbuf *ibuf,
890 FILE *delta_outfile, struct got_pack *pack,
891 struct got_packidx *packidx)
893 const struct got_error *err = NULL;
894 struct got_imsg_raw_delta_request req;
895 size_t datalen, delta_size, delta_compressed_size;
896 off_t delta_offset, delta_data_offset;
897 uint8_t *delta_buf = NULL;
898 struct got_object_id id, base_id;
899 off_t base_offset, delta_out_offset = 0;
900 uint64_t base_size = 0, result_size = 0;
903 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
904 if (datalen != sizeof(req))
905 return got_error(GOT_ERR_PRIVSEP_LEN);
906 memcpy(&req, imsg->data, sizeof(req));
907 memcpy(&id, &req.id, sizeof(id));
911 err = got_packfile_extract_raw_delta(&delta_buf, &delta_size,
912 &delta_compressed_size, &delta_offset, &delta_data_offset,
913 &base_offset, &base_id, &base_size, &result_size,
914 pack, packidx, req.idx);
919 * If this is an offset delta we must determine the base
920 * object ID ourselves.
922 if (base_offset != 0) {
923 err = get_base_object_id(&base_id, packidx, base_offset);
928 delta_out_offset = ftello(delta_outfile);
929 w = fwrite(delta_buf, 1, delta_compressed_size, delta_outfile);
930 if (w != delta_compressed_size) {
931 err = got_ferror(delta_outfile, GOT_ERR_IO);
934 if (fflush(delta_outfile) == -1) {
935 err = got_error_from_errno("fflush");
939 err = got_privsep_send_raw_delta(ibuf, base_size, result_size,
940 delta_size, delta_compressed_size, delta_offset, delta_out_offset,
947 struct search_deltas_arg {
948 struct imsgbuf *ibuf;
949 struct got_packidx *packidx;
950 struct got_pack *pack;
951 struct got_object_idset *idset;
952 struct got_imsg_reused_delta deltas[GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS];
956 static const struct got_error *
957 search_delta_for_object(struct got_object_id *id, void *data, void *arg)
959 const struct got_error *err;
960 struct search_deltas_arg *a = arg;
962 uint8_t *delta_buf = NULL;
963 uint64_t base_size, result_size;
964 size_t delta_size, delta_compressed_size;
965 off_t delta_offset, delta_data_offset, base_offset;
966 struct got_object_id base_id;
969 return got_error(GOT_ERR_CANCELLED);
971 obj_idx = got_packidx_get_object_idx(a->packidx, id);
973 return NULL; /* object not present in our pack file */
975 err = got_packfile_extract_raw_delta(&delta_buf, &delta_size,
976 &delta_compressed_size, &delta_offset, &delta_data_offset,
977 &base_offset, &base_id, &base_size, &result_size,
978 a->pack, a->packidx, obj_idx);
980 if (err->code == GOT_ERR_OBJ_TYPE)
981 return NULL; /* object not stored as a delta */
986 * If this is an offset delta we must determine the base
987 * object ID ourselves.
989 if (base_offset != 0) {
990 err = get_base_object_id(&base_id, a->packidx, base_offset);
995 if (got_object_idset_contains(a->idset, &base_id)) {
996 struct got_imsg_reused_delta *delta;
998 delta = &a->deltas[a->ndeltas++];
999 memcpy(&delta->id, id, sizeof(delta->id));
1000 memcpy(&delta->base_id, &base_id, sizeof(delta->base_id));
1001 delta->base_size = base_size;
1002 delta->result_size = result_size;
1003 delta->delta_size = delta_size;
1004 delta->delta_compressed_size = delta_compressed_size;
1005 delta->delta_offset = delta_data_offset;
1007 if (a->ndeltas >= GOT_IMSG_REUSED_DELTAS_MAX_NDELTAS) {
1008 err = got_privsep_send_reused_deltas(a->ibuf,
1009 a->deltas, a->ndeltas);
1020 static const struct got_error *
1021 recv_object_ids(struct got_object_idset *idset, struct imsgbuf *ibuf)
1023 const struct got_error *err = NULL;
1025 struct got_object_id *ids;
1029 err = got_privsep_recv_object_idlist(&done, &ids, &nids, ibuf);
1032 for (i = 0; i < nids; i++) {
1033 err = got_object_idset_add(idset, &ids[i], NULL);
1045 static const struct got_error *
1046 recv_object_id_queue(struct got_object_id_queue *queue,
1047 struct got_object_idset *queued_ids, struct imsgbuf *ibuf)
1049 const struct got_error *err = NULL;
1051 struct got_object_qid *qid;
1052 struct got_object_id *ids;
1056 err = got_privsep_recv_object_idlist(&done, &ids, &nids, ibuf);
1059 for (i = 0; i < nids; i++) {
1060 err = got_object_qid_alloc_partial(&qid);
1063 memcpy(&qid->id, &ids[i], sizeof(qid->id));
1064 STAILQ_INSERT_TAIL(queue, qid, entry);
1065 err = got_object_idset_add(queued_ids, &qid->id, NULL);
1074 static const struct got_error *
1075 delta_reuse_request(struct imsg *imsg, struct imsgbuf *ibuf,
1076 struct got_pack *pack, struct got_packidx *packidx)
1078 const struct got_error *err = NULL;
1079 struct got_object_idset *idset;
1080 struct search_deltas_arg sda;
1082 idset = got_object_idset_alloc();
1084 return got_error_from_errno("got_object_idset_alloc");
1086 err = recv_object_ids(idset, ibuf);
1090 memset(&sda, 0, sizeof(sda));
1094 sda.packidx = packidx;
1095 err = got_object_idset_for_each(idset, search_delta_for_object, &sda);
1099 if (sda.ndeltas > 0) {
1100 err = got_privsep_send_reused_deltas(ibuf, sda.deltas,
1106 err = got_privsep_send_reused_deltas_done(ibuf);
1108 got_object_idset_free(idset);
1112 static const struct got_error *
1113 receive_packidx(struct got_packidx **packidx, struct imsgbuf *ibuf)
1115 const struct got_error *err = NULL;
1117 struct got_imsg_packidx ipackidx;
1119 struct got_packidx *p;
1123 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1127 p = calloc(1, sizeof(*p));
1129 err = got_error_from_errno("calloc");
1133 if (imsg.hdr.type != GOT_IMSG_PACKIDX) {
1134 err = got_error(GOT_ERR_PRIVSEP_MSG);
1138 if (imsg.fd == -1) {
1139 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
1143 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1144 if (datalen != sizeof(ipackidx)) {
1145 err = got_error(GOT_ERR_PRIVSEP_LEN);
1148 memcpy(&ipackidx, imsg.data, sizeof(ipackidx));
1150 p->len = ipackidx.len;
1151 p->fd = dup(imsg.fd);
1153 err = got_error_from_errno("dup");
1156 if (lseek(p->fd, 0, SEEK_SET) == -1) {
1157 err = got_error_from_errno("lseek");
1161 #ifndef GOT_PACK_NO_MMAP
1162 if (p->len > 0 && p->len <= SIZE_MAX) {
1163 p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0);
1164 if (p->map == MAP_FAILED)
1165 p->map = NULL; /* fall back to read(2) */
1168 err = got_packidx_init_hdr(p, 1, ipackidx.packfile_size);
1173 got_packidx_close(p);
1180 static const struct got_error *
1181 send_tree_enumeration_done(struct imsgbuf *ibuf)
1183 if (imsg_compose(ibuf, GOT_IMSG_TREE_ENUMERATION_DONE, 0, 0, -1,
1185 return got_error_from_errno("imsg_compose TREE_ENUMERATION_DONE");
1187 return got_privsep_flush_imsg(ibuf);
1190 struct enumerated_tree {
1191 struct got_object_id id;
1194 struct got_parsed_tree_entry *entries;
1198 static const struct got_error *
1199 enumerate_tree(int *have_all_entries, struct imsgbuf *ibuf, size_t *totlen,
1200 struct got_object_id *tree_id,
1201 const char *path, struct got_pack *pack, struct got_packidx *packidx,
1202 struct got_object_cache *objcache, struct got_object_idset *idset,
1203 struct enumerated_tree **trees, size_t *nalloc, size_t *ntrees)
1205 const struct got_error *err = NULL;
1206 struct got_object_id_queue ids;
1207 struct got_object_qid *qid;
1208 uint8_t *buf = NULL;
1210 struct got_parsed_tree_entry *entries = NULL;
1211 size_t nentries = 0, nentries_alloc = 0, i;
1212 struct enumerated_tree *tree;
1215 *have_all_entries = 1;
1218 err = got_object_qid_alloc_partial(&qid);
1221 memcpy(&qid->id, tree_id, sizeof(*tree_id));
1222 qid->data = strdup(path);
1223 if (qid->data == NULL) {
1224 err = got_error_from_errno("strdup");
1227 STAILQ_INSERT_TAIL(&ids, qid, entry);
1230 /* Traverse the tree hierarchy, gather tree object IDs and paths. */
1235 if (sigint_received) {
1236 err = got_error(GOT_ERR_CANCELLED);
1240 qid = STAILQ_FIRST(&ids);
1241 STAILQ_REMOVE_HEAD(&ids, entry);
1244 idx = got_packidx_get_object_idx(packidx, &qid->id);
1246 *have_all_entries = 0;
1250 err = open_tree(&buf, &len, pack, packidx, idx, &qid->id,
1253 if (err->code != GOT_ERR_NO_OBJ)
1257 err = got_object_parse_tree(&entries, &nentries,
1258 &nentries_alloc, buf, len);
1262 err = got_object_idset_add(idset, &qid->id, NULL);
1266 for (i = 0; i < nentries; i++) {
1267 struct got_object_qid *eqid = NULL;
1268 struct got_parsed_tree_entry *pte = &entries[i];
1271 if (!S_ISDIR(pte->mode))
1274 err = got_object_qid_alloc_partial(&eqid);
1277 memcpy(eqid->id.sha1, pte->id, sizeof(eqid->id.sha1));
1279 if (got_object_idset_contains(idset, &eqid->id)) {
1280 got_object_qid_free(eqid);
1284 if (asprintf(&p, "%s%s%s", path,
1285 got_path_is_root_dir(path) ? "" : "/",
1287 err = got_error_from_errno("asprintf");
1288 got_object_qid_free(eqid);
1292 STAILQ_INSERT_TAIL(&ids, eqid, entry);
1295 if (*ntrees >= *nalloc) {
1296 struct enumerated_tree *new;
1297 new = recallocarray(*trees, *nalloc, *nalloc + 16,
1300 err = got_error_from_errno("malloc");
1306 tree = &(*trees)[*ntrees];
1308 memcpy(&tree->id, &qid->id, sizeof(tree->id));
1309 tree->path = qid->data;
1312 tree->entries = entries;
1315 tree->nentries = nentries;
1318 got_object_qid_free(qid);
1320 } while (!STAILQ_EMPTY(&ids));
1322 if (*have_all_entries) {
1325 * We have managed to traverse all entries in the hierarchy.
1326 * Tell the main process what we have found.
1328 for (i = 0; i < *ntrees; i++) {
1329 tree = &(*trees)[i];
1330 err = got_privsep_send_enumerated_tree(totlen,
1331 ibuf, &tree->id, tree->path, tree->entries,
1339 free(tree->entries);
1340 tree->entries = NULL;
1342 *ntrees = 0; /* don't loop again below to free memory */
1344 err = send_tree_enumeration_done(ibuf);
1347 * We can only load fully packed tree hierarchies on
1348 * behalf of the main process, otherwise the main process
1349 * gets a wrong idea about which tree objects have
1350 * already been traversed.
1351 * Indicate a missing entry for the root of this tree.
1352 * The main process should continue by loading this
1353 * entire tree the slow way.
1355 err = got_privsep_send_enumerated_tree(totlen, ibuf,
1356 tree_id, "/", NULL, -1);
1363 for (i = 0; i < *ntrees; i++) {
1364 tree = &(*trees)[i];
1369 free(tree->entries);
1370 tree->entries = NULL;
1374 got_object_qid_free(qid);
1375 got_object_id_queue_free(&ids);
1377 if (err->code == GOT_ERR_PRIVSEP_PIPE)
1380 got_privsep_send_error(ibuf, err);
1386 static const struct got_error *
1387 enumeration_request(struct imsg *imsg, struct imsgbuf *ibuf,
1388 struct got_pack *pack, struct got_packidx *packidx,
1389 struct got_object_cache *objcache)
1391 const struct got_error *err = NULL;
1392 struct got_object_id_queue commit_ids;
1393 const struct got_object_id_queue *parents = NULL;
1394 struct got_object_qid *qid = NULL;
1395 struct got_object *obj = NULL;
1396 struct got_commit_object *commit = NULL;
1397 struct got_object_id *tree_id = NULL;
1399 struct got_object_idset *idset, *queued_ids = NULL;
1400 int i, idx, have_all_entries = 1;
1401 struct enumerated_tree *trees = NULL;
1402 size_t ntrees = 0, nalloc = 16;
1404 STAILQ_INIT(&commit_ids);
1406 trees = calloc(nalloc, sizeof(*trees));
1408 return got_error_from_errno("calloc");
1410 idset = got_object_idset_alloc();
1411 if (idset == NULL) {
1412 err = got_error_from_errno("got_object_idset_alloc");
1416 queued_ids = got_object_idset_alloc();
1417 if (queued_ids == NULL) {
1418 err = got_error_from_errno("got_object_idset_alloc");
1422 err = recv_object_id_queue(&commit_ids, queued_ids, ibuf);
1426 if (STAILQ_EMPTY(&commit_ids)) {
1427 err = got_error(GOT_ERR_PRIVSEP_MSG);
1431 err = recv_object_ids(idset, ibuf);
1435 while (!STAILQ_EMPTY(&commit_ids)) {
1436 if (sigint_received) {
1437 err = got_error(GOT_ERR_CANCELLED);
1441 qid = STAILQ_FIRST(&commit_ids);
1442 STAILQ_REMOVE_HEAD(&commit_ids, entry);
1444 if (got_object_idset_contains(idset, &qid->id)) {
1445 got_object_qid_free(qid);
1450 idx = got_packidx_get_object_idx(packidx, &qid->id);
1452 have_all_entries = 0;
1456 err = open_object(&obj, pack, packidx, idx, &qid->id,
1460 if (obj->type == GOT_OBJ_TYPE_TAG) {
1461 struct got_tag_object *tag;
1464 err = got_packfile_extract_object_to_mem(&buf,
1469 err = got_object_parse_tag(&tag, buf, len);
1474 idx = got_packidx_get_object_idx(packidx, &tag->id);
1476 have_all_entries = 0;
1479 err = open_commit(&commit, pack, packidx, idx,
1480 &tag->id, objcache);
1481 got_object_tag_close(tag);
1485 } else if (obj->type == GOT_OBJ_TYPE_COMMIT) {
1486 err = open_commit(&commit, pack, packidx, idx,
1487 &qid->id, objcache);
1491 err = got_error(GOT_ERR_OBJ_TYPE);
1494 got_object_close(obj);
1497 err = got_privsep_send_enumerated_commit(ibuf, &qid->id,
1498 got_object_commit_get_committer_time(commit));
1502 tree_id = got_object_commit_get_tree_id(commit);
1503 idx = got_packidx_get_object_idx(packidx, tree_id);
1505 have_all_entries = 0;
1506 err = got_privsep_send_enumerated_tree(&totlen, ibuf,
1507 tree_id, "/", NULL, -1);
1513 if (got_object_idset_contains(idset, tree_id)) {
1514 got_object_qid_free(qid);
1516 err = send_tree_enumeration_done(ibuf);
1522 err = enumerate_tree(&have_all_entries, ibuf, &totlen,
1523 tree_id, "/", pack, packidx, objcache, idset,
1524 &trees, &nalloc, &ntrees);
1528 if (!have_all_entries)
1531 got_object_qid_free(qid);
1534 parents = got_object_commit_get_parent_ids(commit);
1536 struct got_object_qid *pid;
1537 STAILQ_FOREACH(pid, parents, entry) {
1538 if (got_object_idset_contains(idset, &pid->id))
1540 if (got_object_idset_contains(queued_ids, &pid->id))
1542 err = got_object_qid_alloc_partial(&qid);
1545 memcpy(&qid->id, &pid->id, sizeof(qid->id));
1546 STAILQ_INSERT_TAIL(&commit_ids, qid, entry);
1551 got_object_commit_close(commit);
1555 if (have_all_entries) {
1556 err = got_privsep_send_object_enumeration_done(ibuf);
1560 err = got_privsep_send_object_enumeration_incomplete(ibuf);
1566 got_object_close(obj);
1568 got_object_commit_close(commit);
1569 got_object_qid_free(qid);
1570 got_object_id_queue_free(&commit_ids);
1572 got_object_idset_free(idset);
1574 got_object_idset_free(queued_ids);
1575 for (i = 0; i < ntrees; i++) {
1576 struct enumerated_tree *tree = &trees[i];
1579 free(tree->entries);
1585 enum findtwixt_color {
1592 static const struct got_error *
1593 paint_commit(struct got_object_qid *qid, intptr_t color)
1595 if (color < 0 || color >= COLOR_MAX)
1596 return got_error(GOT_ERR_RANGE);
1598 qid->data = (void *)color;
1602 static const struct got_error *
1603 queue_commit_id(struct got_object_id_queue *ids, struct got_object_id *id,
1606 const struct got_error *err;
1607 struct got_object_qid *qid;
1609 err = got_object_qid_alloc_partial(&qid);
1613 memcpy(&qid->id, id, sizeof(qid->id));
1614 STAILQ_INSERT_TAIL(ids, qid, entry);
1615 return paint_commit(qid, color);
1618 static const struct got_error *
1619 paint_commits(struct got_object_id_queue *ids, int *nids,
1620 struct got_object_idset *keep, struct got_object_idset *drop,
1621 struct got_object_idset *skip, struct got_pack *pack,
1622 struct got_packidx *packidx, struct imsgbuf *ibuf,
1623 struct got_object_cache *objcache)
1625 const struct got_error *err = NULL;
1626 struct got_commit_object *commit = NULL;
1627 struct got_object_id_queue painted;
1628 const struct got_object_id_queue *parents;
1629 struct got_object_qid *qid = NULL;
1630 int nqueued = *nids, nskip = 0, npainted = 0;
1632 STAILQ_INIT(&painted);
1634 while (!STAILQ_EMPTY(ids) && nskip != nqueued) {
1638 if (sigint_received) {
1639 err = got_error(GOT_ERR_CANCELLED);
1643 qid = STAILQ_FIRST(ids);
1644 idx = got_packidx_get_object_idx(packidx, &qid->id);
1650 STAILQ_REMOVE_HEAD(ids, entry);
1652 color = (intptr_t)qid->data;
1653 if (color == COLOR_SKIP)
1656 if (got_object_idset_contains(skip, &qid->id)) {
1657 got_object_qid_free(qid);
1664 if (got_object_idset_contains(keep, &qid->id)) {
1665 got_object_qid_free(qid);
1669 if (got_object_idset_contains(drop, &qid->id)) {
1670 err = paint_commit(qid, COLOR_SKIP);
1674 err = got_object_idset_add(keep, &qid->id, NULL);
1679 if (got_object_idset_contains(drop, &qid->id)) {
1680 got_object_qid_free(qid);
1684 if (got_object_idset_contains(keep, &qid->id)) {
1685 err = paint_commit(qid, COLOR_SKIP);
1689 err = got_object_idset_add(drop, &qid->id, NULL);
1694 if (!got_object_idset_contains(skip, &qid->id)) {
1695 err = got_object_idset_add(skip, &qid->id,
1702 /* should not happen */
1703 err = got_error_fmt(GOT_ERR_NOT_IMPL,
1704 "%s invalid commit color %"PRIdPTR, __func__,
1709 err = open_commit(&commit, pack, packidx, idx, &qid->id,
1714 parents = got_object_commit_get_parent_ids(commit);
1716 struct got_object_qid *pid;
1717 color = (intptr_t)qid->data;
1718 STAILQ_FOREACH(pid, parents, entry) {
1719 err = queue_commit_id(ids, &pid->id, color);
1723 if (color == COLOR_SKIP)
1728 got_object_commit_close(commit);
1731 STAILQ_INSERT_TAIL(&painted, qid, entry);
1735 err = got_privsep_send_painted_commits(ibuf, &painted,
1741 err = got_privsep_send_painted_commits(ibuf, &painted, &npainted, 1, 1);
1748 got_object_commit_close(commit);
1749 got_object_qid_free(qid);
1754 commit_painting_free(struct got_object_idset **keep,
1755 struct got_object_idset **drop,
1756 struct got_object_idset **skip)
1759 got_object_idset_free(*keep);
1763 got_object_idset_free(*drop);
1767 got_object_idset_free(*skip);
1772 static const struct got_error *
1773 commit_painting_init(struct imsgbuf *ibuf, struct got_object_idset **keep,
1774 struct got_object_idset **drop, struct got_object_idset **skip)
1776 const struct got_error *err = NULL;
1778 *keep = got_object_idset_alloc();
1779 if (*keep == NULL) {
1780 err = got_error_from_errno("got_object_idset_alloc");
1783 *drop = got_object_idset_alloc();
1784 if (*drop == NULL) {
1785 err = got_error_from_errno("got_object_idset_alloc");
1788 *skip = got_object_idset_alloc();
1789 if (*skip == NULL) {
1790 err = got_error_from_errno("got_object_idset_alloc");
1794 err = recv_object_ids(*keep, ibuf);
1797 err = recv_object_ids(*drop, ibuf);
1800 err = recv_object_ids(*skip, ibuf);
1806 commit_painting_free(keep, drop, skip);
1811 static const struct got_error *
1812 commit_painting_request(struct imsg *imsg, struct imsgbuf *ibuf,
1813 struct got_pack *pack, struct got_packidx *packidx,
1814 struct got_object_cache *objcache, struct got_object_idset *keep,
1815 struct got_object_idset *drop, struct got_object_idset *skip)
1817 const struct got_error *err = NULL;
1818 struct got_imsg_commit_painting_request ireq;
1819 struct got_object_id id;
1821 struct got_object_id_queue ids;
1826 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1827 if (datalen != sizeof(ireq))
1828 return got_error(GOT_ERR_PRIVSEP_LEN);
1829 memcpy(&ireq, imsg->data, sizeof(ireq));
1830 memcpy(&id, &ireq.id, sizeof(id));
1832 err = queue_commit_id(&ids, &id, ireq.color);
1837 err = paint_commits(&ids, &nids, keep, drop, skip,
1838 pack, packidx, ibuf, objcache);
1842 err = got_privsep_send_painted_commits(ibuf, &ids, &nids, 0, 1);
1846 err = got_privsep_send_painting_commits_done(ibuf);
1848 got_object_id_queue_free(&ids);
1852 static const struct got_error *
1853 receive_pack(struct got_pack **packp, struct imsgbuf *ibuf)
1855 const struct got_error *err = NULL;
1857 struct got_imsg_pack ipack;
1859 struct got_pack *pack;
1863 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1867 pack = calloc(1, sizeof(*pack));
1869 err = got_error_from_errno("calloc");
1873 if (imsg.hdr.type != GOT_IMSG_PACK) {
1874 err = got_error(GOT_ERR_PRIVSEP_MSG);
1878 if (imsg.fd == -1) {
1879 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
1883 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1884 if (datalen != sizeof(ipack)) {
1885 err = got_error(GOT_ERR_PRIVSEP_LEN);
1888 memcpy(&ipack, imsg.data, sizeof(ipack));
1890 pack->filesize = ipack.filesize;
1891 pack->fd = dup(imsg.fd);
1892 if (pack->fd == -1) {
1893 err = got_error_from_errno("dup");
1896 if (lseek(pack->fd, 0, SEEK_SET) == -1) {
1897 err = got_error_from_errno("lseek");
1900 pack->path_packfile = strdup(ipack.path_packfile);
1901 if (pack->path_packfile == NULL) {
1902 err = got_error_from_errno("strdup");
1906 err = got_delta_cache_alloc(&pack->delta_cache);
1910 #ifndef GOT_PACK_NO_MMAP
1911 if (pack->filesize > 0 && pack->filesize <= SIZE_MAX) {
1912 pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE,
1914 if (pack->map == MAP_FAILED)
1915 pack->map = NULL; /* fall back to read(2) */
1930 main(int argc, char *argv[])
1932 const struct got_error *err = NULL;
1933 struct imsgbuf ibuf;
1935 struct got_packidx *packidx = NULL;
1936 struct got_pack *pack = NULL;
1937 struct got_object_cache objcache;
1938 FILE *basefile = NULL, *accumfile = NULL, *delta_outfile = NULL;
1939 struct got_object_idset *keep = NULL, *drop = NULL, *skip = NULL;
1940 struct got_parsed_tree_entry *entries = NULL;
1941 size_t nentries = 0, nentries_alloc = 0;
1943 //static int attached;
1944 //while (!attached) sleep(1);
1946 signal(SIGINT, catch_sigint);
1948 imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
1950 err = got_object_cache_init(&objcache, GOT_OBJECT_CACHE_TYPE_OBJ);
1952 err = got_error_from_errno("got_object_cache_init");
1953 got_privsep_send_error(&ibuf, err);
1958 /* revoke access to most system calls */
1959 if (pledge("stdio recvfd", NULL) == -1) {
1960 err = got_error_from_errno("pledge");
1961 got_privsep_send_error(&ibuf, err);
1966 err = receive_packidx(&packidx, &ibuf);
1968 got_privsep_send_error(&ibuf, err);
1972 err = receive_pack(&pack, &ibuf);
1974 got_privsep_send_error(&ibuf, err);
1981 if (sigint_received) {
1982 err = got_error(GOT_ERR_CANCELLED);
1986 err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
1988 if (err->code == GOT_ERR_PRIVSEP_PIPE)
1993 if (imsg.hdr.type == GOT_IMSG_STOP)
1996 switch (imsg.hdr.type) {
1997 case GOT_IMSG_TMPFD:
1998 if (basefile == NULL) {
1999 err = receive_tempfile(&basefile, "w+",
2001 } else if (accumfile == NULL) {
2002 err = receive_tempfile(&accumfile, "w+",
2005 err = got_error(GOT_ERR_PRIVSEP_MSG);
2007 case GOT_IMSG_PACKED_OBJECT_REQUEST:
2008 err = object_request(&imsg, &ibuf, pack, packidx,
2011 case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST:
2012 if (basefile == NULL || accumfile == NULL) {
2013 err = got_error(GOT_ERR_PRIVSEP_MSG);
2016 err = raw_object_request(&imsg, &ibuf, pack, packidx,
2017 &objcache, basefile, accumfile);
2019 case GOT_IMSG_RAW_DELTA_OUTFD:
2020 if (delta_outfile != NULL) {
2021 err = got_error(GOT_ERR_PRIVSEP_MSG);
2024 err = receive_tempfile(&delta_outfile, "w",
2027 case GOT_IMSG_RAW_DELTA_REQUEST:
2028 if (delta_outfile == NULL) {
2029 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
2032 err = raw_delta_request(&imsg, &ibuf, delta_outfile,
2035 case GOT_IMSG_DELTA_REUSE_REQUEST:
2036 err = delta_reuse_request(&imsg, &ibuf, pack, packidx);
2038 case GOT_IMSG_COMMIT_REQUEST:
2039 err = commit_request(&imsg, &ibuf, pack, packidx,
2042 case GOT_IMSG_TREE_REQUEST:
2043 err = tree_request(&imsg, &ibuf, pack, packidx,
2044 &objcache, &entries, &nentries, &nentries_alloc);
2046 case GOT_IMSG_BLOB_REQUEST:
2047 if (basefile == NULL || accumfile == NULL) {
2048 err = got_error(GOT_ERR_PRIVSEP_MSG);
2051 err = blob_request(&imsg, &ibuf, pack, packidx,
2052 &objcache, basefile, accumfile);
2054 case GOT_IMSG_TAG_REQUEST:
2055 err = tag_request(&imsg, &ibuf, pack, packidx,
2058 case GOT_IMSG_COMMIT_TRAVERSAL_REQUEST:
2059 err = commit_traversal_request(&imsg, &ibuf, pack,
2060 packidx, &objcache);
2062 case GOT_IMSG_OBJECT_ENUMERATION_REQUEST:
2063 err = enumeration_request(&imsg, &ibuf, pack,
2064 packidx, &objcache);
2066 case GOT_IMSG_COMMIT_PAINTING_INIT:
2067 commit_painting_free(&keep, &drop, &skip);
2068 err = commit_painting_init(&ibuf, &keep, &drop, &skip);
2070 case GOT_IMSG_COMMIT_PAINTING_REQUEST:
2071 if (keep == NULL || drop == NULL || skip == NULL) {
2072 err = got_error(GOT_ERR_PRIVSEP_MSG);
2075 err = commit_painting_request(&imsg, &ibuf, pack,
2076 packidx, &objcache, keep, drop, skip);
2078 case GOT_IMSG_COMMIT_PAINTING_DONE:
2079 commit_painting_free(&keep, &drop, &skip);
2082 err = got_error(GOT_ERR_PRIVSEP_MSG);
2086 if (imsg.fd != -1 && close(imsg.fd) == -1 && err == NULL)
2087 err = got_error_from_errno("close");
2094 commit_painting_free(&keep, &drop, &skip);
2096 got_packidx_close(packidx);
2098 got_pack_close(pack);
2099 got_object_cache_close(&objcache);
2101 if (basefile && fclose(basefile) == EOF && err == NULL)
2102 err = got_error_from_errno("fclose");
2103 if (accumfile && fclose(accumfile) == EOF && err == NULL)
2104 err = got_error_from_errno("fclose");
2105 if (delta_outfile && fclose(delta_outfile) == EOF && err == NULL)
2106 err = got_error_from_errno("fclose");
2108 if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) {
2109 fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
2110 got_privsep_send_error(&ibuf, err);
2113 if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL)
2114 err = got_error_from_errno("close");