reduce indentation in repaint_parent_commits(); no functional change
[got-portable.git] / libexec / got-read-pack / got-read-pack.c
blob8c6db6edfbedb53647b5c05a25be937195605680
1 /*
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"
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/uio.h>
22 #include <sys/time.h>
23 #include <sys/mman.h>
25 #include <err.h>
26 #include <inttypes.h>
27 #include <limits.h>
28 #include <signal.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <zlib.h>
36 #include "got_error.h"
37 #include "got_object.h"
38 #include "got_path.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"
51 #ifndef nitems
52 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
53 #endif
55 static volatile sig_atomic_t sigint_received;
57 static void
58 catch_sigint(int signo)
60 sigint_received = 1;
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);
71 if (err)
72 return err;
73 (*obj)->refcnt++;
75 err = got_object_cache_add(objcache, id, *obj);
76 if (err) {
77 if (err->code == GOT_ERR_OBJ_EXISTS ||
78 err->code == GOT_ERR_OBJ_TOO_LARGE)
79 err = NULL;
80 return err;
82 (*obj)->refcnt++;
83 return NULL;
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;
94 size_t datalen;
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);
103 if (obj) {
104 obj->refcnt++;
105 } else {
106 err = open_object(&obj, pack, packidx, iobj.idx, &id,
107 objcache);
108 if (err)
109 goto done;
112 err = got_privsep_send_obj(ibuf, obj);
113 done:
114 got_object_close(obj);
115 return err;
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;
125 uint8_t *buf = NULL;
126 size_t len;
128 *commit = NULL;
130 obj = got_object_cache_get(objcache, id);
131 if (obj) {
132 obj->refcnt++;
133 } else {
134 err = open_object(&obj, pack, packidx, obj_idx, id,
135 objcache);
136 if (err)
137 return err;
140 err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack);
141 if (err)
142 goto done;
144 obj->size = len;
146 err = got_object_parse_commit(commit, buf, len, pack->algo);
147 done:
148 got_object_close(obj);
149 free(buf);
150 return err;
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;
161 size_t datalen;
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);
170 if (err)
171 goto done;
173 err = got_privsep_send_commit(ibuf, commit);
174 done:
175 if (commit)
176 got_object_commit_close(commit);
177 if (err) {
178 if (err->code == GOT_ERR_PRIVSEP_PIPE)
179 err = NULL;
180 else
181 got_privsep_send_error(ibuf, err);
184 return 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;
194 int cached = 0;
196 *buf = NULL;
197 *len = 0;
199 obj = got_object_cache_get(objcache, id);
200 if (obj) {
201 obj->refcnt++;
202 cached = 1;
203 } else {
204 err = open_object(&obj, pack, packidx, obj_idx, id,
205 objcache);
206 if (err)
207 return err;
210 err = got_packfile_extract_object_to_mem(buf, len, obj, pack);
211 if (err)
212 goto done;
214 if (!cached)
215 obj->size = *len;
216 done:
217 got_object_close(obj);
218 if (err) {
219 free(*buf);
220 *buf = NULL;
222 return err;
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;
233 uint8_t *buf = NULL;
234 size_t len = 0;
235 struct got_object_id id;
236 size_t datalen;
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);
245 if (err)
246 return err;
248 err = got_object_parse_tree(entries, nentries, nentries_alloc,
249 buf, len, id.algo);
250 if (err)
251 goto done;
253 err = got_privsep_send_tree(ibuf, *entries, *nentries);
254 if (err) {
255 if (err->code == GOT_ERR_PRIVSEP_PIPE)
256 err = NULL;
257 else
258 got_privsep_send_error(ibuf, err);
260 done:
261 free(buf);
262 return 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;
269 struct imsg imsg;
270 size_t datalen;
271 int fd;
273 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
274 if (err)
275 return err;
277 if (imsg.hdr.type != imsg_code) {
278 err = got_error(GOT_ERR_PRIVSEP_MSG);
279 goto done;
282 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
283 if (datalen != 0) {
284 err = got_error(GOT_ERR_PRIVSEP_LEN);
285 goto done;
287 fd = imsg_get_fd(&imsg);
288 if (fd == -1) {
289 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
290 goto done;
293 *f = fdopen(fd, "w+");
294 if (*f == NULL) {
295 err = got_error_from_errno("fdopen");
296 close(fd);
297 goto done;
299 done:
300 imsg_free(&imsg);
301 return err;
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;
309 size_t datalen;
310 int fd;
312 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
313 if (datalen != 0)
314 return got_error(GOT_ERR_PRIVSEP_LEN);
316 fd = imsg_get_fd(imsg);
317 if (fd == -1)
318 return got_error(GOT_ERR_PRIVSEP_NO_FD);
320 *f = fdopen(fd, mode);
321 if (*f == NULL) {
322 err = got_error_from_errno("fdopen");
323 close(fd);
324 return err;
327 return NULL;
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;
340 size_t datalen;
341 uint64_t blob_size;
342 uint8_t *buf = NULL;
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);
351 if (obj) {
352 obj->refcnt++;
353 } else {
354 err = open_object(&obj, pack, packidx, iobj.idx, &id,
355 objcache);
356 if (err)
357 return err;
360 err = receive_file(&outfile, ibuf, GOT_IMSG_BLOB_OUTFD);
361 if (err)
362 goto done;
364 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
365 err = got_pack_get_max_delta_object_size(&blob_size, obj, pack);
366 if (err)
367 goto done;
368 } else
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,
373 obj, pack);
374 else
375 err = got_packfile_extract_object(pack, obj, outfile, basefile,
376 accumfile);
377 if (err)
378 goto done;
380 err = got_privsep_send_blob(ibuf, obj->size, obj->hdrlen, buf);
381 done:
382 free(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);
389 return 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;
400 uint8_t *buf = NULL;
401 size_t len;
402 struct got_object_id id;
403 size_t datalen;
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);
412 if (obj) {
413 obj->refcnt++;
414 } else {
415 err = open_object(&obj, pack, packidx, iobj.idx, &id,
416 objcache);
417 if (err)
418 return err;
421 err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack);
422 if (err)
423 goto done;
425 obj->size = len;
426 err = got_object_parse_tag(&tag, buf, len, id.algo);
427 if (err)
428 goto done;
430 err = got_privsep_send_tag(ibuf, tag);
431 done:
432 free(buf);
433 got_object_close(obj);
434 if (tag)
435 got_object_tag_close(tag);
436 if (err) {
437 if (err->code == GOT_ERR_PRIVSEP_PIPE)
438 err = NULL;
439 else
440 got_privsep_send_error(ibuf, err);
443 return 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;
454 const char *seg, *s;
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));
463 *changed = 0;
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);
471 s = path;
472 while (*s == '/')
473 s++;
474 seg = s;
475 seglen = 0;
476 while (*s) {
477 if (*s != '/') {
478 s++;
479 seglen++;
480 if (*s)
481 continue;
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
493 * here, too.
495 while (remain1 > 0) {
496 err = got_object_parse_tree_entry(&pte1, &elen,
497 next_entry1, remain1, digest_len, pack->algo);
498 if (err)
499 return err;
500 next_entry1 += elen;
501 remain1 -= elen;
502 if (strncmp(pte1.name, seg, seglen) != 0 ||
503 pte1.name[seglen] != '\0') {
504 memset(&pte1, 0, sizeof(pte1));
505 continue;
506 } else
507 break;
509 if (pte1.name == NULL) {
510 err = got_error(GOT_ERR_NO_OBJ);
511 break;
514 if (remain2 == 0) {
515 *changed = 1;
516 break;
519 while (remain2 > 0) {
520 err = got_object_parse_tree_entry(&pte2, &elen,
521 next_entry2, remain2, digest_len, pack->algo);
522 if (err)
523 return err;
524 next_entry2 += elen;
525 remain2 -= elen;
526 if (strncmp(pte2.name, seg, seglen) != 0 ||
527 pte2.name[seglen] != '\0') {
528 memset(&pte2, 0, sizeof(pte2));
529 continue;
530 } else
531 break;
534 if (pte2.name == NULL) {
535 *changed = 1;
536 break;
539 if (pte1.mode != pte2.mode) {
540 *changed = 1;
541 break;
544 if (memcmp(pte1.id, pte2.id, pte1.digest_len) == 0) {
545 *changed = 0;
546 break;
549 if (*s == '\0') { /* final path element */
550 *changed = 1;
551 break;
554 seg = s + 1;
555 s++;
556 seglen = 0;
557 if (*s) {
558 struct got_object_id id1, id2;
559 int idx;
561 memcpy(id1.hash, pte1.id, pte1.digest_len);
562 id1.algo = pack->algo;
563 idx = got_packidx_get_object_idx(packidx, &id1);
564 if (idx == -1) {
565 err = got_error_no_obj(&id1);
566 break;
568 free(*buf1);
569 *buf1 = NULL;
570 err = open_tree(buf1, len1, pack, packidx, idx, &id1,
571 objcache);
572 memset(&pte1, 0, sizeof(pte1));
573 if (err)
574 break;
575 next_entry1 = *buf1;
576 remain1 = *len1;
578 memcpy(id2.hash, pte2.id, pte2.digest_len);
579 id2.algo = pack->algo;
580 idx = got_packidx_get_object_idx(packidx, &id2);
581 if (idx == -1) {
582 err = got_error_no_obj(&id2);
583 break;
585 free(*buf2);
586 *buf2 = NULL;
587 err = open_tree(buf2, len2, pack, packidx, idx, &id2,
588 objcache);
589 memset(&pte2, 0, sizeof(pte2));
590 if (err)
591 break;
592 next_entry2 = *buf2;
593 remain2 = *len2;
597 return err;
600 static const struct got_error *
601 send_traversed_commits(struct got_object_id *commit_ids, size_t ncommits,
602 struct imsgbuf *ibuf)
604 struct ibuf *wbuf;
605 size_t i;
607 wbuf = imsg_create(ibuf, GOT_IMSG_TRAVERSED_COMMITS, 0, 0,
608 sizeof(struct got_imsg_traversed_commits) +
609 ncommits * sizeof(commit_ids[0]));
610 if (wbuf == NULL)
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,
633 NULL, 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;
649 size_t datalen;
650 char *path = NULL;
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);
667 if (path == NULL)
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");
675 do {
676 const size_t max_datalen = MAX_IMSGSIZE - IMSG_HEADER_SIZE;
677 int idx;
679 if (sigint_received) {
680 err = got_error(GOT_ERR_CANCELLED);
681 goto done;
684 if (commit == NULL) {
685 idx = got_packidx_get_object_idx(packidx, &id);
686 if (idx == -1)
687 break;
688 err = open_commit(&commit, pack, packidx,
689 idx, &id, objcache);
690 if (err) {
691 if (err->code != GOT_ERR_NO_OBJ)
692 goto done;
693 err = NULL;
694 break;
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,
701 ibuf);
702 if (err)
703 goto done;
704 ncommits = 0;
706 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));
712 if (new == NULL) {
713 err = got_error_from_errno("reallocarray");
714 goto done;
716 commit_ids = new;
718 memcpy(&commit_ids[ncommits - 1], &id, sizeof(id));
720 pid = STAILQ_FIRST(&commit->parent_ids);
721 if (pid == NULL)
722 break;
724 idx = got_packidx_get_object_idx(packidx, &pid->id);
725 if (idx == -1)
726 break;
728 err = open_commit(&pcommit, pack, packidx, idx, &pid->id,
729 objcache);
730 if (err) {
731 if (err->code != GOT_ERR_NO_OBJ)
732 goto done;
733 err = NULL;
734 break;
737 if (path[0] == '/' && path[1] == '\0') {
738 if (got_object_id_cmp(pcommit->tree_id,
739 commit->tree_id) != 0) {
740 changed = 1;
741 break;
743 } else {
744 int pidx;
745 uint8_t *buf = NULL, *pbuf = NULL;
746 size_t len = 0, plen = 0;
748 idx = got_packidx_get_object_idx(packidx,
749 commit->tree_id);
750 if (idx == -1)
751 break;
752 pidx = got_packidx_get_object_idx(packidx,
753 pcommit->tree_id);
754 if (pidx == -1)
755 break;
757 err = open_tree(&buf, &len, pack, packidx, idx,
758 commit->tree_id, objcache);
759 if (err)
760 goto done;
762 err = open_tree(&pbuf, &plen, pack, packidx, pidx,
763 pcommit->tree_id, objcache);
764 if (err) {
765 free(buf);
766 goto done;
769 err = tree_path_changed(&changed, &buf, &len,
770 &pbuf, &plen, path, pack, packidx, ibuf,
771 objcache);
773 free(buf);
774 free(pbuf);
775 if (err) {
776 if (err->code != GOT_ERR_NO_OBJ)
777 goto done;
778 err = NULL;
779 break;
783 if (!changed) {
784 memcpy(&id, &pid->id, sizeof(id));
785 got_object_commit_close(commit);
786 commit = pcommit;
787 pcommit = NULL;
789 } while (!changed);
791 if (ncommits > 0) {
792 err = send_traversed_commits(commit_ids, ncommits, ibuf);
793 if (err)
794 goto done;
796 if (changed) {
797 err = got_privsep_send_commit(ibuf, commit);
798 if (err)
799 goto done;
802 err = send_commit_traversal_done(ibuf);
803 done:
804 free(path);
805 free(commit_ids);
806 if (commit)
807 got_object_commit_close(commit);
808 if (pcommit)
809 got_object_commit_close(pcommit);
810 if (err) {
811 if (err->code == GOT_ERR_PRIVSEP_PIPE)
812 err = NULL;
813 else
814 got_privsep_send_error(ibuf, err);
817 return 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;
826 uint8_t *buf = NULL;
827 uint64_t size = 0;
828 FILE *outfile = NULL;
829 struct got_imsg_packed_object iobj;
830 struct got_object *obj;
831 struct got_object_id id;
832 size_t datalen;
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);
841 if (obj) {
842 obj->refcnt++;
843 } else {
844 err = open_object(&obj, pack, packidx, iobj.idx, &id,
845 objcache);
846 if (err)
847 return err;
850 err = receive_file(&outfile, ibuf, GOT_IMSG_RAW_OBJECT_OUTFD);
851 if (err)
852 return err;
854 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
855 err = got_pack_get_max_delta_object_size(&size, obj, pack);
856 if (err)
857 goto done;
858 } else
859 size = obj->size;
861 if (size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX)
862 err = got_packfile_extract_object_to_mem(&buf, &obj->size,
863 obj, pack);
864 else
865 err = got_packfile_extract_object(pack, obj, outfile, basefile,
866 accumfile);
867 if (err)
868 goto done;
870 err = got_privsep_send_raw_obj(ibuf, obj->size, obj->hdrlen, buf);
871 done:
872 free(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);
879 return err;
882 static const struct got_error *
883 get_base_object_id(struct got_object_id *base_id, struct got_packidx *packidx,
884 off_t base_offset)
886 const struct got_error *err;
887 int idx;
889 err = got_packidx_get_offset_idx(&idx, packidx, base_offset);
890 if (err)
891 return err;
892 if (idx == -1)
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;
911 size_t w;
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);
923 if (err)
924 goto done;
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);
932 if (err)
933 goto done;
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);
940 goto done;
942 if (fflush(delta_outfile) == -1) {
943 err = got_error_from_errno("fflush");
944 goto done;
947 err = got_privsep_send_raw_delta(ibuf, base_size, result_size,
948 delta_size, delta_compressed_size, delta_offset, delta_out_offset,
949 &base_id);
950 done:
951 free(delta_buf);
952 return err;
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];
961 size_t 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;
969 int obj_idx;
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;
976 if (sigint_received)
977 return got_error(GOT_ERR_CANCELLED);
979 obj_idx = got_packidx_get_object_idx(a->packidx, id);
980 if (obj_idx == -1)
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);
987 if (err) {
988 if (err->code == GOT_ERR_OBJ_TYPE)
989 return NULL; /* object not stored as a delta */
990 return err;
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);
999 if (err)
1000 goto done;
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);
1018 if (err)
1019 goto done;
1020 a->ndeltas = 0;
1023 done:
1024 free(delta_buf);
1025 return err;
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;
1032 int done = 0;
1033 struct got_object_id *ids;
1034 size_t nids, i;
1036 for (;;) {
1037 err = got_privsep_recv_object_idlist(&done, &ids, &nids, ibuf);
1038 if (err || done)
1039 break;
1040 for (i = 0; i < nids; i++) {
1041 err = got_object_idset_add(idset, &ids[i], NULL);
1042 if (err) {
1043 free(ids);
1044 return err;
1047 free(ids);
1050 return err;
1053 static const struct got_error *
1054 recv_object_id_queue(size_t *nids_total, struct got_object_id_queue *queue,
1055 void *data, struct got_object_idset *queued_ids, struct imsgbuf *ibuf)
1057 const struct got_error *err = NULL;
1058 int done = 0;
1059 struct got_object_qid *qid;
1060 struct got_object_id *ids;
1061 size_t nids, i;
1063 *nids_total = 0;
1064 for (;;) {
1065 err = got_privsep_recv_object_idlist(&done, &ids, &nids, ibuf);
1066 if (err || done)
1067 break;
1068 *nids_total += nids;
1069 for (i = 0; i < nids; i++) {
1070 err = got_object_qid_alloc_partial(&qid);
1071 if (err)
1072 goto done;
1073 memcpy(&qid->id, &ids[i], sizeof(qid->id));
1074 if (data)
1075 qid->data = data;
1076 STAILQ_INSERT_TAIL(queue, qid, entry);
1077 if (queued_ids) {
1078 err = got_object_idset_add(queued_ids,
1079 &qid->id, NULL);
1080 if (err)
1081 goto done;
1084 free(ids);
1085 ids = NULL;
1087 done:
1088 free(ids);
1089 return err;
1092 static const struct got_error *
1093 delta_reuse_request(struct imsg *imsg, struct imsgbuf *ibuf,
1094 struct got_pack *pack, struct got_packidx *packidx)
1096 const struct got_error *err = NULL;
1097 struct got_object_idset *idset;
1098 struct search_deltas_arg sda;
1100 idset = got_object_idset_alloc();
1101 if (idset == NULL)
1102 return got_error_from_errno("got_object_idset_alloc");
1104 err = recv_object_ids(idset, ibuf);
1105 if (err)
1106 return err;
1108 memset(&sda, 0, sizeof(sda));
1109 sda.ibuf = ibuf;
1110 sda.idset = idset;
1111 sda.pack = pack;
1112 sda.packidx = packidx;
1113 err = got_object_idset_for_each(idset, search_delta_for_object, &sda);
1114 if (err)
1115 goto done;
1117 if (sda.ndeltas > 0) {
1118 err = got_privsep_send_reused_deltas(ibuf, sda.deltas,
1119 sda.ndeltas);
1120 if (err)
1121 goto done;
1124 err = got_privsep_send_reused_deltas_done(ibuf);
1125 done:
1126 got_object_idset_free(idset);
1127 return err;
1130 static const struct got_error *
1131 receive_packidx(struct got_packidx **packidx, struct imsgbuf *ibuf)
1133 const struct got_error *err = NULL;
1134 struct imsg imsg;
1135 struct got_imsg_packidx ipackidx;
1136 size_t datalen;
1137 struct got_packidx *p;
1139 *packidx = NULL;
1141 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1142 if (err)
1143 return err;
1145 p = calloc(1, sizeof(*p));
1146 if (p == NULL) {
1147 err = got_error_from_errno("calloc");
1148 goto done;
1151 if (imsg.hdr.type != GOT_IMSG_PACKIDX) {
1152 err = got_error(GOT_ERR_PRIVSEP_MSG);
1153 goto done;
1156 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1157 if (datalen != sizeof(ipackidx)) {
1158 err = got_error(GOT_ERR_PRIVSEP_LEN);
1159 goto done;
1161 memcpy(&ipackidx, imsg.data, sizeof(ipackidx));
1163 p->algo = ipackidx.algo;
1164 p->fd = imsg_get_fd(&imsg);
1165 p->len = ipackidx.len;
1166 if (p->fd == -1) {
1167 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
1168 goto done;
1170 if (lseek(p->fd, 0, SEEK_SET) == -1) {
1171 err = got_error_from_errno("lseek");
1172 goto done;
1175 #ifndef GOT_PACK_NO_MMAP
1176 if (p->len > 0 && p->len <= SIZE_MAX) {
1177 p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0);
1178 if (p->map == MAP_FAILED)
1179 p->map = NULL; /* fall back to read(2) */
1181 #endif
1182 err = got_packidx_init_hdr(p, 1, ipackidx.packfile_size);
1183 done:
1184 if (err) {
1185 if (p != NULL)
1186 got_packidx_close(p);
1187 } else
1188 *packidx = p;
1189 imsg_free(&imsg);
1190 return err;
1193 static const struct got_error *
1194 send_tree_enumeration_done(struct imsgbuf *ibuf)
1196 if (imsg_compose(ibuf, GOT_IMSG_TREE_ENUMERATION_DONE, 0, 0, -1,
1197 NULL, 0) == -1)
1198 return got_error_from_errno("imsg_compose TREE_ENUMERATION_DONE");
1200 return got_privsep_flush_imsg(ibuf);
1203 struct enumerated_tree {
1204 struct got_object_id id;
1205 char *path;
1206 uint8_t *buf;
1207 struct got_parsed_tree_entry *entries;
1208 int nentries;
1211 static const struct got_error *
1212 enumerate_tree(int *have_all_entries, struct imsgbuf *ibuf, size_t *totlen,
1213 struct got_object_id *tree_id,
1214 const char *path, struct got_pack *pack, struct got_packidx *packidx,
1215 struct got_object_cache *objcache, struct got_object_idset *idset,
1216 struct enumerated_tree **trees, size_t *nalloc, size_t *ntrees)
1218 const struct got_error *err = NULL;
1219 struct got_object_id_queue ids;
1220 struct got_object_qid *qid;
1221 uint8_t *buf = NULL;
1222 size_t len = 0;
1223 struct got_parsed_tree_entry *entries = NULL;
1224 size_t nentries = 0, nentries_alloc = 0, i;
1225 struct enumerated_tree *tree;
1227 *ntrees = 0;
1228 *have_all_entries = 1;
1229 STAILQ_INIT(&ids);
1231 err = got_object_qid_alloc_partial(&qid);
1232 if (err)
1233 return err;
1234 memcpy(&qid->id, tree_id, sizeof(*tree_id));
1235 qid->data = strdup(path);
1236 if (qid->data == NULL) {
1237 err = got_error_from_errno("strdup");
1238 goto done;
1240 STAILQ_INSERT_TAIL(&ids, qid, entry);
1241 qid = NULL;
1243 /* Traverse the tree hierarchy, gather tree object IDs and paths. */
1244 do {
1245 const char *path;
1246 int idx, i;
1248 if (sigint_received) {
1249 err = got_error(GOT_ERR_CANCELLED);
1250 goto done;
1253 qid = STAILQ_FIRST(&ids);
1254 STAILQ_REMOVE_HEAD(&ids, entry);
1255 path = qid->data;
1257 idx = got_packidx_get_object_idx(packidx, &qid->id);
1258 if (idx == -1) {
1259 *have_all_entries = 0;
1260 break;
1263 err = open_tree(&buf, &len, pack, packidx, idx, &qid->id,
1264 objcache);
1265 if (err) {
1266 if (err->code != GOT_ERR_NO_OBJ)
1267 goto done;
1270 err = got_object_parse_tree(&entries, &nentries,
1271 &nentries_alloc, buf, len, pack->algo);
1272 if (err)
1273 goto done;
1275 err = got_object_idset_add(idset, &qid->id, NULL);
1276 if (err)
1277 goto done;
1279 for (i = 0; i < nentries; i++) {
1280 struct got_object_qid *eqid = NULL;
1281 struct got_parsed_tree_entry *pte = &entries[i];
1282 char *p;
1284 if (!S_ISDIR(pte->mode))
1285 continue;
1287 err = got_object_qid_alloc_partial(&eqid);
1288 if (err)
1289 goto done;
1290 eqid->id.algo = pte->algo;
1291 memcpy(eqid->id.hash, pte->id, pte->digest_len);
1293 if (got_object_idset_contains(idset, &eqid->id)) {
1294 got_object_qid_free(eqid);
1295 continue;
1298 if (asprintf(&p, "%s%s%s", path,
1299 got_path_is_root_dir(path) ? "" : "/",
1300 pte->name) == -1) {
1301 err = got_error_from_errno("asprintf");
1302 got_object_qid_free(eqid);
1303 goto done;
1305 eqid->data = p;
1306 STAILQ_INSERT_TAIL(&ids, eqid, entry);
1309 if (*ntrees >= *nalloc) {
1310 struct enumerated_tree *new;
1311 new = recallocarray(*trees, *nalloc, *nalloc + 16,
1312 sizeof(*new));
1313 if (new == NULL) {
1314 err = got_error_from_errno("malloc");
1315 goto done;
1317 *trees = new;
1318 *nalloc += 16;
1320 tree = &(*trees)[*ntrees];
1321 (*ntrees)++;
1322 memcpy(&tree->id, &qid->id, sizeof(tree->id));
1323 tree->path = qid->data;
1324 tree->buf = buf;
1325 buf = NULL;
1326 tree->entries = entries;
1327 entries = NULL;
1328 nentries_alloc = 0;
1329 tree->nentries = nentries;
1330 nentries = 0;
1332 got_object_qid_free(qid);
1333 qid = NULL;
1334 } while (!STAILQ_EMPTY(&ids));
1336 if (*have_all_entries) {
1337 int i;
1339 * We have managed to traverse all entries in the hierarchy.
1340 * Tell the main process what we have found.
1342 for (i = 0; i < *ntrees; i++) {
1343 tree = &(*trees)[i];
1344 err = got_privsep_send_enumerated_tree(totlen,
1345 ibuf, &tree->id, tree->path, tree->entries,
1346 tree->nentries);
1347 if (err)
1348 goto done;
1349 free(tree->buf);
1350 tree->buf = NULL;
1351 free(tree->path);
1352 tree->path = NULL;
1353 free(tree->entries);
1354 tree->entries = NULL;
1356 *ntrees = 0; /* don't loop again below to free memory */
1358 err = send_tree_enumeration_done(ibuf);
1359 } else {
1361 * We can only load fully packed tree hierarchies on
1362 * behalf of the main process, otherwise the main process
1363 * gets a wrong idea about which tree objects have
1364 * already been traversed.
1365 * Indicate a missing entry for the root of this tree.
1366 * The main process should continue by loading this
1367 * entire tree the slow way.
1369 err = got_privsep_send_enumerated_tree(totlen, ibuf,
1370 tree_id, "/", NULL, -1);
1371 if (err)
1372 goto done;
1374 done:
1375 free(buf);
1376 free(entries);
1377 for (i = 0; i < *ntrees; i++) {
1378 tree = &(*trees)[i];
1379 free(tree->buf);
1380 tree->buf = NULL;
1381 free(tree->path);
1382 tree->path = NULL;
1383 free(tree->entries);
1384 tree->entries = NULL;
1386 if (qid)
1387 free(qid->data);
1388 got_object_qid_free(qid);
1389 got_object_id_queue_free(&ids);
1390 if (err) {
1391 if (err->code == GOT_ERR_PRIVSEP_PIPE)
1392 err = NULL;
1393 else
1394 got_privsep_send_error(ibuf, err);
1397 return err;
1401 static const struct got_error *
1402 resolve_tag(struct got_object **obj, struct got_object_id *id,
1403 struct got_packidx *packidx, struct got_pack *pack,
1404 struct got_object_cache *objcache)
1406 const struct got_error *err;
1407 struct got_object *tagged_obj;
1408 struct got_tag_object *tag;
1409 uint8_t *buf;
1410 size_t len;
1411 int idx;
1413 err = got_packfile_extract_object_to_mem(&buf, &len, *obj, pack);
1414 if (err)
1415 return err;
1417 (*obj)->size = len;
1418 err = got_object_parse_tag(&tag, buf, len, id->algo);
1419 if (err)
1420 goto done;
1422 idx = got_packidx_get_object_idx(packidx, &tag->id);
1423 if (idx == -1) {
1424 got_object_close(*obj);
1425 *obj = NULL;
1426 return NULL;
1429 tagged_obj = got_object_cache_get(objcache, &tag->id);
1430 if (tagged_obj) {
1431 tagged_obj->refcnt++;
1432 } else {
1433 err = open_object(&tagged_obj, pack, packidx,
1434 idx, &tag->id, objcache);
1435 if (err)
1436 goto done;
1439 got_object_close(*obj);
1440 *obj = tagged_obj;
1441 done:
1442 got_object_tag_close(tag);
1443 free(buf);
1444 return err;
1447 static const struct got_error *
1448 enumeration_request(struct imsg *imsg, struct imsgbuf *ibuf,
1449 struct got_pack *pack, struct got_packidx *packidx,
1450 struct got_object_cache *objcache)
1452 const struct got_error *err = NULL;
1453 struct got_object_id_queue commit_ids;
1454 const struct got_object_id_queue *parents = NULL;
1455 struct got_object_qid *qid = NULL;
1456 struct got_object *obj = NULL;
1457 struct got_commit_object *commit = NULL;
1458 struct got_object_id *tree_id = NULL;
1459 size_t totlen = 0;
1460 struct got_object_idset *idset, *queued_ids = NULL;
1461 int i, idx, have_all_entries = 1;
1462 struct enumerated_tree *trees = NULL;
1463 size_t ntrees = 0, nalloc = 16, nids = 0;
1465 STAILQ_INIT(&commit_ids);
1467 trees = calloc(nalloc, sizeof(*trees));
1468 if (trees == NULL)
1469 return got_error_from_errno("calloc");
1471 idset = got_object_idset_alloc();
1472 if (idset == NULL) {
1473 err = got_error_from_errno("got_object_idset_alloc");
1474 goto done;
1477 queued_ids = got_object_idset_alloc();
1478 if (queued_ids == NULL) {
1479 err = got_error_from_errno("got_object_idset_alloc");
1480 goto done;
1483 err = recv_object_id_queue(&nids, &commit_ids, NULL, queued_ids, ibuf);
1484 if (err)
1485 goto done;
1487 if (STAILQ_EMPTY(&commit_ids)) {
1488 err = got_error(GOT_ERR_PRIVSEP_MSG);
1489 goto done;
1492 err = recv_object_ids(idset, ibuf);
1493 if (err)
1494 goto done;
1496 while (!STAILQ_EMPTY(&commit_ids)) {
1497 if (sigint_received) {
1498 err = got_error(GOT_ERR_CANCELLED);
1499 goto done;
1502 qid = STAILQ_FIRST(&commit_ids);
1503 STAILQ_REMOVE_HEAD(&commit_ids, entry);
1505 if (got_object_idset_contains(idset, &qid->id)) {
1506 got_object_qid_free(qid);
1507 qid = NULL;
1508 continue;
1511 idx = got_packidx_get_object_idx(packidx, &qid->id);
1512 if (idx == -1) {
1513 have_all_entries = 0;
1514 break;
1517 err = open_object(&obj, pack, packidx, idx, &qid->id,
1518 objcache);
1519 if (err)
1520 goto done;
1521 if (obj->type == GOT_OBJ_TYPE_TAG) {
1522 while (obj->type == GOT_OBJ_TYPE_TAG) {
1523 err = resolve_tag(&obj, &qid->id, packidx,
1524 pack, objcache);
1525 if (err)
1526 goto done;
1527 if (obj == NULL)
1528 break;
1530 if (obj == NULL) {
1531 have_all_entries = 0;
1532 break;
1534 if (obj->type != GOT_OBJ_TYPE_COMMIT) {
1535 got_object_qid_free(qid);
1536 qid = NULL;
1537 got_object_close(obj);
1538 obj = NULL;
1539 continue;
1541 err = open_commit(&commit, pack, packidx, idx,
1542 &obj->id, objcache);
1543 if (err)
1544 goto done;
1545 } else if (obj->type == GOT_OBJ_TYPE_COMMIT) {
1546 err = open_commit(&commit, pack, packidx, idx,
1547 &qid->id, objcache);
1548 if (err)
1549 goto done;
1550 } else {
1551 err = got_error(GOT_ERR_OBJ_TYPE);
1552 goto done;
1554 got_object_close(obj);
1555 obj = NULL;
1557 err = got_privsep_send_enumerated_commit(ibuf, &qid->id,
1558 got_object_commit_get_committer_time(commit));
1559 if (err)
1560 goto done;
1562 tree_id = got_object_commit_get_tree_id(commit);
1563 idx = got_packidx_get_object_idx(packidx, tree_id);
1564 if (idx == -1) {
1565 have_all_entries = 0;
1566 err = got_privsep_send_enumerated_tree(&totlen, ibuf,
1567 tree_id, "/", NULL, -1);
1568 if (err)
1569 goto done;
1570 break;
1573 if (got_object_idset_contains(idset, tree_id)) {
1574 got_object_qid_free(qid);
1575 qid = NULL;
1576 err = send_tree_enumeration_done(ibuf);
1577 if (err)
1578 goto done;
1579 got_object_commit_close(commit);
1580 commit = NULL;
1581 continue;
1584 err = enumerate_tree(&have_all_entries, ibuf, &totlen,
1585 tree_id, "/", pack, packidx, objcache, idset,
1586 &trees, &nalloc, &ntrees);
1587 if (err)
1588 goto done;
1590 if (!have_all_entries)
1591 break;
1593 got_object_qid_free(qid);
1594 qid = NULL;
1596 parents = got_object_commit_get_parent_ids(commit);
1597 if (parents) {
1598 struct got_object_qid *pid;
1599 STAILQ_FOREACH(pid, parents, entry) {
1600 if (got_object_idset_contains(idset, &pid->id))
1601 continue;
1602 if (got_object_idset_contains(queued_ids, &pid->id))
1603 continue;
1604 err = got_object_qid_alloc_partial(&qid);
1605 if (err)
1606 goto done;
1607 memcpy(&qid->id, &pid->id, sizeof(qid->id));
1608 STAILQ_INSERT_TAIL(&commit_ids, qid, entry);
1609 qid = NULL;
1613 got_object_commit_close(commit);
1614 commit = NULL;
1617 if (have_all_entries) {
1618 err = got_privsep_send_object_enumeration_done(ibuf);
1619 if (err)
1620 goto done;
1621 } else {
1622 err = got_privsep_send_object_enumeration_incomplete(ibuf);
1623 if (err)
1624 goto done;
1626 done:
1627 if (obj)
1628 got_object_close(obj);
1629 if (commit)
1630 got_object_commit_close(commit);
1631 got_object_qid_free(qid);
1632 got_object_id_queue_free(&commit_ids);
1633 if (idset)
1634 got_object_idset_free(idset);
1635 if (queued_ids)
1636 got_object_idset_free(queued_ids);
1637 for (i = 0; i < ntrees; i++) {
1638 struct enumerated_tree *tree = &trees[i];
1639 free(tree->buf);
1640 free(tree->path);
1641 free(tree->entries);
1643 free(trees);
1644 return err;
1647 enum findtwixt_color {
1648 COLOR_KEEP = 0,
1649 COLOR_DROP,
1650 COLOR_SKIP,
1651 COLOR_MAX,
1654 static const struct got_error *
1655 paint_commit(struct got_object_qid *qid, intptr_t color)
1657 if (color < 0 || color >= COLOR_MAX)
1658 return got_error(GOT_ERR_RANGE);
1660 qid->data = (void *)color;
1661 return NULL;
1664 static const struct got_error *
1665 queue_commit_id(struct got_object_id_queue *ids, struct got_object_id *id,
1666 intptr_t color)
1668 const struct got_error *err;
1669 struct got_object_qid *qid;
1671 err = got_object_qid_alloc_partial(&qid);
1672 if (err)
1673 return err;
1675 memcpy(&qid->id, id, sizeof(qid->id));
1676 STAILQ_INSERT_TAIL(ids, qid, entry);
1677 return paint_commit(qid, color);
1680 static const struct got_error *
1681 repaint_parent_commits(struct got_object_id *commit_id, int commit_idx,
1682 int color, struct got_object_idset *set, struct got_object_idset *skip,
1683 struct got_object_id_queue *ids, int *nids,
1684 struct got_object_id_queue *painted, int *npainted,
1685 struct got_pack *pack, struct got_packidx *packidx,
1686 struct got_object_cache *objcache)
1688 const struct got_error *err;
1689 const struct got_object_id_queue *parents;
1690 struct got_commit_object *commit;
1691 struct got_object_id_queue repaint;
1693 STAILQ_INIT(&repaint);
1695 err = open_commit(&commit, pack, packidx, commit_idx, commit_id,
1696 objcache);
1697 if (err)
1698 return err;
1700 while (commit) {
1701 struct got_object_qid *pid, *qid, *tmp;
1702 int idx;
1704 parents = got_object_commit_get_parent_ids(commit);
1705 if (parents) {
1706 STAILQ_FOREACH(pid, parents, entry) {
1707 idx = got_packidx_get_object_idx(packidx,
1708 &pid->id);
1710 * No need to traverse parents which are not in
1711 * the pack file, are already in the desired
1712 * set, or are marked for skipping already.
1714 if (idx == -1)
1715 continue;
1716 if (got_object_idset_contains(set, &pid->id))
1717 continue;
1718 if (set != skip &&
1719 got_object_idset_contains(skip, &pid->id))
1720 continue;
1722 err = queue_commit_id(&repaint, &pid->id,
1723 color);
1724 if (err)
1725 goto done;
1728 got_object_commit_close(commit);
1729 commit = NULL;
1731 pid = STAILQ_FIRST(&repaint);
1732 if (pid == NULL)
1733 break;
1735 err = paint_commit(pid, color);
1736 if (err)
1737 break;
1739 if (!got_object_idset_contains(set, &pid->id)) {
1740 err = got_object_idset_add(set, &pid->id, NULL);
1741 if (err)
1742 break;
1745 STAILQ_REMOVE_HEAD(&repaint, entry);
1747 /* Insert or replace this commit on the painted list. */
1748 STAILQ_FOREACH(qid, painted, entry) {
1749 if (got_object_id_cmp(&qid->id, &pid->id) != 0)
1750 continue;
1751 err = paint_commit(qid, color);
1752 if (err)
1753 goto done;
1754 got_object_qid_free(pid);
1755 pid = qid;
1756 break;
1758 if (qid == NULL) {
1759 STAILQ_INSERT_TAIL(painted, pid, entry);
1760 (*npainted)++;
1764 * In case this commit is on the caller's list of
1765 * pending commits to traverse, repaint it there.
1767 STAILQ_FOREACH_SAFE(qid, ids, entry, tmp) {
1768 if (got_object_id_cmp(&qid->id, &pid->id) != 0)
1769 continue;
1770 err = paint_commit(qid, color);
1771 if (err)
1772 goto done;
1773 break;
1776 idx = got_packidx_get_object_idx(packidx, &pid->id);
1777 if (idx == -1) {
1779 * Should not happen because we only queue
1780 * parents which exist in our pack file.
1782 err = got_error(GOT_ERR_NO_OBJ);
1783 break;
1786 err = open_commit(&commit, pack, packidx, idx, &pid->id,
1787 objcache);
1788 if (err)
1789 break;
1791 done:
1792 if (commit)
1793 got_object_commit_close(commit);
1794 got_object_id_queue_free(&repaint);
1796 return err;
1799 static const struct got_error *
1800 paint_commits(struct got_object_id_queue *ids, int *nids,
1801 struct got_object_idset *keep, struct got_object_idset *drop,
1802 struct got_object_idset *skip, struct got_pack *pack,
1803 struct got_packidx *packidx, struct imsgbuf *ibuf,
1804 struct got_object_cache *objcache)
1806 const struct got_error *err = NULL;
1807 struct got_commit_object *commit = NULL;
1808 struct got_object_id_queue painted;
1809 const struct got_object_id_queue *parents;
1810 struct got_object_qid *qid = NULL;
1811 int nqueued = *nids, nskip = 0, npainted = 0;
1813 STAILQ_INIT(&painted);
1815 while (!STAILQ_EMPTY(ids) && nskip != nqueued) {
1816 int idx;
1817 intptr_t color;
1819 if (sigint_received) {
1820 err = got_error(GOT_ERR_CANCELLED);
1821 goto done;
1824 qid = STAILQ_FIRST(ids);
1825 idx = got_packidx_get_object_idx(packidx, &qid->id);
1826 if (idx == -1) {
1827 qid = NULL;
1828 break;
1831 STAILQ_REMOVE_HEAD(ids, entry);
1832 nqueued--;
1833 color = (intptr_t)qid->data;
1834 if (color == COLOR_SKIP)
1835 nskip--;
1837 if (got_object_idset_contains(skip, &qid->id)) {
1838 got_object_qid_free(qid);
1839 qid = NULL;
1840 continue;
1843 switch (color) {
1844 case COLOR_KEEP:
1845 if (got_object_idset_contains(drop, &qid->id)) {
1846 err = paint_commit(qid, COLOR_SKIP);
1847 if (err)
1848 goto done;
1849 err = got_object_idset_add(skip, &qid->id,
1850 NULL);
1851 if (err)
1852 goto done;
1853 err = repaint_parent_commits(&qid->id, idx,
1854 COLOR_SKIP, skip, skip, ids, nids,
1855 &painted, &npainted, pack, packidx,
1856 objcache);
1857 if (err)
1858 goto done;
1859 break;
1861 if (!got_object_idset_contains(keep, &qid->id)) {
1862 err = got_object_idset_add(keep, &qid->id,
1863 NULL);
1864 if (err)
1865 goto done;
1867 break;
1868 case COLOR_DROP:
1869 if (got_object_idset_contains(keep, &qid->id)) {
1870 err = paint_commit(qid, COLOR_SKIP);
1871 if (err)
1872 goto done;
1873 err = got_object_idset_add(skip, &qid->id,
1874 NULL);
1875 if (err)
1876 goto done;
1877 err = repaint_parent_commits(&qid->id, idx,
1878 COLOR_SKIP, skip, skip, ids, nids,
1879 &painted, &npainted, pack, packidx,
1880 objcache);
1881 if (err)
1882 goto done;
1883 break;
1885 if (!got_object_idset_contains(drop, &qid->id)) {
1886 err = got_object_idset_add(drop, &qid->id,
1887 NULL);
1888 if (err)
1889 goto done;
1891 break;
1892 case COLOR_SKIP:
1893 err = got_object_idset_add(skip, &qid->id,
1894 NULL);
1895 if (err)
1896 goto done;
1897 break;
1898 default:
1899 /* should not happen */
1900 err = got_error_fmt(GOT_ERR_NOT_IMPL,
1901 "%s invalid commit color %"PRIdPTR, __func__,
1902 color);
1903 goto done;
1906 err = open_commit(&commit, pack, packidx, idx, &qid->id,
1907 objcache);
1908 if (err)
1909 goto done;
1911 parents = got_object_commit_get_parent_ids(commit);
1912 if (parents) {
1913 struct got_object_qid *pid;
1914 color = (intptr_t)qid->data;
1915 STAILQ_FOREACH(pid, parents, entry) {
1916 err = queue_commit_id(ids, &pid->id, color);
1917 if (err)
1918 goto done;
1919 nqueued++;
1920 if (color == COLOR_SKIP)
1921 nskip++;
1925 got_object_commit_close(commit);
1926 commit = NULL;
1928 STAILQ_INSERT_TAIL(&painted, qid, entry);
1929 qid = NULL;
1930 npainted++;
1932 err = got_privsep_send_painted_commits(ibuf, &painted,
1933 &npainted, 1, 0);
1934 if (err)
1935 goto done;
1938 err = got_privsep_send_painted_commits(ibuf, &painted, &npainted, 1, 1);
1939 if (err)
1940 goto done;
1942 *nids = nqueued;
1943 done:
1944 if (commit)
1945 got_object_commit_close(commit);
1946 got_object_qid_free(qid);
1947 return err;
1950 static void
1951 commit_painting_free(struct got_object_idset **keep,
1952 struct got_object_idset **drop,
1953 struct got_object_idset **skip)
1955 if (*keep) {
1956 got_object_idset_free(*keep);
1957 *keep = NULL;
1959 if (*drop) {
1960 got_object_idset_free(*drop);
1961 *drop = NULL;
1963 if (*skip) {
1964 got_object_idset_free(*skip);
1965 *skip = NULL;
1969 static const struct got_error *
1970 commit_painting_init(struct imsgbuf *ibuf, struct got_object_idset **keep,
1971 struct got_object_idset **drop, struct got_object_idset **skip)
1973 const struct got_error *err = NULL;
1975 *keep = got_object_idset_alloc();
1976 if (*keep == NULL) {
1977 err = got_error_from_errno("got_object_idset_alloc");
1978 goto done;
1980 *drop = got_object_idset_alloc();
1981 if (*drop == NULL) {
1982 err = got_error_from_errno("got_object_idset_alloc");
1983 goto done;
1985 *skip = got_object_idset_alloc();
1986 if (*skip == NULL) {
1987 err = got_error_from_errno("got_object_idset_alloc");
1988 goto done;
1991 err = recv_object_ids(*keep, ibuf);
1992 if (err)
1993 goto done;
1994 err = recv_object_ids(*drop, ibuf);
1995 if (err)
1996 goto done;
1997 err = recv_object_ids(*skip, ibuf);
1998 if (err)
1999 goto done;
2001 done:
2002 if (err)
2003 commit_painting_free(keep, drop, skip);
2005 return err;
2008 static const struct got_error *
2009 commit_painting_request(struct imsg *imsg, struct imsgbuf *ibuf,
2010 struct got_pack *pack, struct got_packidx *packidx,
2011 struct got_object_cache *objcache, struct got_object_idset *keep,
2012 struct got_object_idset *drop, struct got_object_idset *skip)
2014 const struct got_error *err = NULL;
2015 size_t datalen;
2016 struct got_object_id_queue ids;
2017 size_t nkeep = 0, ndrop = 0, nskip = 0;
2018 int nids = 0;
2019 uintptr_t color;
2021 STAILQ_INIT(&ids);
2023 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
2024 if (datalen != 0)
2025 return got_error(GOT_ERR_PRIVSEP_LEN);
2027 color = COLOR_KEEP;
2028 err = recv_object_id_queue(&nkeep, &ids, (void *)color, NULL, ibuf);
2029 if (err)
2030 goto done;
2031 if (nids + nkeep > INT_MAX) {
2032 err = got_error(GOT_ERR_PRIVSEP_LEN);
2033 goto done;
2035 nids += nkeep;
2037 color = COLOR_DROP;
2038 err = recv_object_id_queue(&ndrop, &ids, (void *)color, NULL, ibuf);
2039 if (err)
2040 goto done;
2041 if (nids + ndrop > INT_MAX) {
2042 err = got_error(GOT_ERR_PRIVSEP_LEN);
2043 goto done;
2045 nids += ndrop;
2047 color = COLOR_SKIP;
2048 err = recv_object_id_queue(&nskip, &ids, (void *)color, NULL, ibuf);
2049 if (err)
2050 goto done;
2051 if (nids + nskip > INT_MAX) {
2052 err = got_error(GOT_ERR_PRIVSEP_LEN);
2053 goto done;
2055 nids += nskip;
2057 err = paint_commits(&ids, &nids, keep, drop, skip,
2058 pack, packidx, ibuf, objcache);
2059 if (err)
2060 goto done;
2062 err = got_privsep_send_painted_commits(ibuf, &ids, &nids, 0, 1);
2063 if (err)
2064 goto done;
2066 err = got_privsep_send_painting_commits_done(ibuf);
2067 done:
2068 got_object_id_queue_free(&ids);
2069 return err;
2072 static const struct got_error *
2073 receive_pack(struct got_pack **packp, struct imsgbuf *ibuf)
2075 const struct got_error *err = NULL;
2076 struct imsg imsg;
2077 struct got_imsg_pack ipack;
2078 size_t datalen;
2079 struct got_pack *pack;
2081 *packp = NULL;
2083 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
2084 if (err)
2085 return err;
2087 pack = calloc(1, sizeof(*pack));
2088 if (pack == NULL) {
2089 err = got_error_from_errno("calloc");
2090 goto done;
2093 if (imsg.hdr.type != GOT_IMSG_PACK) {
2094 err = got_error(GOT_ERR_PRIVSEP_MSG);
2095 goto done;
2098 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
2099 if (datalen != sizeof(ipack)) {
2100 err = got_error(GOT_ERR_PRIVSEP_LEN);
2101 goto done;
2103 memcpy(&ipack, imsg.data, sizeof(ipack));
2105 pack->algo = ipack.algo;
2106 pack->filesize = ipack.filesize;
2107 pack->fd = imsg_get_fd(&imsg);
2108 if (pack->fd == -1) {
2109 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
2110 goto done;
2112 if (lseek(pack->fd, 0, SEEK_SET) == -1) {
2113 err = got_error_from_errno("lseek");
2114 goto done;
2116 pack->path_packfile = strdup(ipack.path_packfile);
2117 if (pack->path_packfile == NULL) {
2118 err = got_error_from_errno("strdup");
2119 goto done;
2122 err = got_delta_cache_alloc(&pack->delta_cache);
2123 if (err)
2124 goto done;
2126 #ifndef GOT_PACK_NO_MMAP
2127 if (pack->filesize > 0 && pack->filesize <= SIZE_MAX) {
2128 pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE,
2129 pack->fd, 0);
2130 if (pack->map == MAP_FAILED)
2131 pack->map = NULL; /* fall back to read(2) */
2133 #endif
2134 done:
2135 if (err) {
2136 if (pack != NULL)
2137 got_pack_close(pack);
2138 } else
2139 *packp = pack;
2140 imsg_free(&imsg);
2141 return err;
2145 main(int argc, char *argv[])
2147 const struct got_error *err = NULL;
2148 struct imsgbuf ibuf;
2149 struct imsg imsg;
2150 struct got_packidx *packidx = NULL;
2151 struct got_pack *pack = NULL;
2152 struct got_object_cache objcache;
2153 FILE *basefile = NULL, *accumfile = NULL, *delta_outfile = NULL;
2154 struct got_object_idset *keep = NULL, *drop = NULL, *skip = NULL;
2155 struct got_parsed_tree_entry *entries = NULL;
2156 size_t nentries = 0, nentries_alloc = 0;
2158 //static int attached;
2159 //while (!attached) sleep(1);
2161 signal(SIGINT, catch_sigint);
2163 if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) {
2164 warn("imsgbuf_init");
2165 return 1;
2167 imsgbuf_allow_fdpass(&ibuf);
2169 err = got_object_cache_init(&objcache, GOT_OBJECT_CACHE_TYPE_OBJ);
2170 if (err) {
2171 err = got_error_from_errno("got_object_cache_init");
2172 got_privsep_send_error(&ibuf, err);
2173 imsgbuf_clear(&ibuf);
2174 return 1;
2177 #ifndef PROFILE
2178 /* revoke access to most system calls */
2179 if (pledge("stdio recvfd", NULL) == -1) {
2180 err = got_error_from_errno("pledge");
2181 got_privsep_send_error(&ibuf, err);
2182 imsgbuf_clear(&ibuf);
2183 return 1;
2186 /* revoke fs access */
2187 if (landlock_no_fs() == -1) {
2188 err = got_error_from_errno("landlock_no_fs");
2189 got_privsep_send_error(&ibuf, err);
2190 return 1;
2192 if (cap_enter() == -1) {
2193 err = got_error_from_errno("cap_enter");
2194 got_privsep_send_error(&ibuf, err);
2195 return 1;
2197 #endif
2199 err = receive_packidx(&packidx, &ibuf);
2200 if (err) {
2201 got_privsep_send_error(&ibuf, err);
2202 imsgbuf_clear(&ibuf);
2203 return 1;
2206 err = receive_pack(&pack, &ibuf);
2207 if (err) {
2208 got_privsep_send_error(&ibuf, err);
2209 imsgbuf_clear(&ibuf);
2210 return 1;
2213 for (;;) {
2214 if (sigint_received) {
2215 err = got_error(GOT_ERR_CANCELLED);
2216 break;
2219 err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
2220 if (err) {
2221 if (err->code == GOT_ERR_PRIVSEP_PIPE)
2222 err = NULL;
2223 break;
2226 if (imsg.hdr.type == GOT_IMSG_STOP) {
2227 imsg_free(&imsg);
2228 break;
2231 switch (imsg.hdr.type) {
2232 case GOT_IMSG_TMPFD:
2233 if (basefile == NULL) {
2234 err = receive_tempfile(&basefile, "w+",
2235 &imsg, &ibuf);
2236 } else if (accumfile == NULL) {
2237 err = receive_tempfile(&accumfile, "w+",
2238 &imsg, &ibuf);
2239 } else
2240 err = got_error(GOT_ERR_PRIVSEP_MSG);
2241 break;
2242 case GOT_IMSG_PACKED_OBJECT_REQUEST:
2243 err = object_request(&imsg, &ibuf, pack, packidx,
2244 &objcache);
2245 break;
2246 case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST:
2247 if (basefile == NULL || accumfile == NULL) {
2248 err = got_error(GOT_ERR_PRIVSEP_MSG);
2249 break;
2251 err = raw_object_request(&imsg, &ibuf, pack, packidx,
2252 &objcache, basefile, accumfile);
2253 break;
2254 case GOT_IMSG_RAW_DELTA_OUTFD:
2255 if (delta_outfile != NULL) {
2256 err = got_error(GOT_ERR_PRIVSEP_MSG);
2257 break;
2259 err = receive_tempfile(&delta_outfile, "w",
2260 &imsg, &ibuf);
2261 break;
2262 case GOT_IMSG_RAW_DELTA_REQUEST:
2263 if (delta_outfile == NULL) {
2264 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
2265 break;
2267 err = raw_delta_request(&imsg, &ibuf, delta_outfile,
2268 pack, packidx);
2269 break;
2270 case GOT_IMSG_DELTA_REUSE_REQUEST:
2271 err = delta_reuse_request(&imsg, &ibuf, pack, packidx);
2272 break;
2273 case GOT_IMSG_COMMIT_REQUEST:
2274 err = commit_request(&imsg, &ibuf, pack, packidx,
2275 &objcache);
2276 break;
2277 case GOT_IMSG_TREE_REQUEST:
2278 err = tree_request(&imsg, &ibuf, pack, packidx,
2279 &objcache, &entries, &nentries, &nentries_alloc);
2280 break;
2281 case GOT_IMSG_BLOB_REQUEST:
2282 if (basefile == NULL || accumfile == NULL) {
2283 err = got_error(GOT_ERR_PRIVSEP_MSG);
2284 break;
2286 err = blob_request(&imsg, &ibuf, pack, packidx,
2287 &objcache, basefile, accumfile);
2288 break;
2289 case GOT_IMSG_TAG_REQUEST:
2290 err = tag_request(&imsg, &ibuf, pack, packidx,
2291 &objcache);
2292 break;
2293 case GOT_IMSG_COMMIT_TRAVERSAL_REQUEST:
2294 err = commit_traversal_request(&imsg, &ibuf, pack,
2295 packidx, &objcache);
2296 break;
2297 case GOT_IMSG_OBJECT_ENUMERATION_REQUEST:
2298 err = enumeration_request(&imsg, &ibuf, pack,
2299 packidx, &objcache);
2300 break;
2301 case GOT_IMSG_COMMIT_PAINTING_INIT:
2302 commit_painting_free(&keep, &drop, &skip);
2303 err = commit_painting_init(&ibuf, &keep, &drop, &skip);
2304 break;
2305 case GOT_IMSG_COMMIT_PAINTING_REQUEST:
2306 if (keep == NULL || drop == NULL || skip == NULL) {
2307 err = got_error(GOT_ERR_PRIVSEP_MSG);
2308 break;
2310 err = commit_painting_request(&imsg, &ibuf, pack,
2311 packidx, &objcache, keep, drop, skip);
2312 break;
2313 case GOT_IMSG_COMMIT_PAINTING_DONE:
2314 commit_painting_free(&keep, &drop, &skip);
2315 break;
2316 default:
2317 err = got_error(GOT_ERR_PRIVSEP_MSG);
2318 break;
2321 imsg_free(&imsg);
2322 if (err)
2323 break;
2326 free(entries);
2327 commit_painting_free(&keep, &drop, &skip);
2328 if (packidx)
2329 got_packidx_close(packidx);
2330 if (pack) {
2331 got_pack_close(pack);
2332 free(pack);
2334 got_object_cache_close(&objcache);
2335 if (basefile && fclose(basefile) == EOF && err == NULL)
2336 err = got_error_from_errno("fclose");
2337 if (accumfile && fclose(accumfile) == EOF && err == NULL)
2338 err = got_error_from_errno("fclose");
2339 if (delta_outfile && fclose(delta_outfile) == EOF && err == NULL)
2340 err = got_error_from_errno("fclose");
2341 if (err) {
2342 if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) {
2343 fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
2344 got_privsep_send_error(&ibuf, err);
2347 imsgbuf_clear(&ibuf);
2348 if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL)
2349 err = got_error_from_errno("close");
2350 return err ? 1 : 0;