fix memory leaks in got-read-pack's enumeration_request()
[got-portable.git] / libexec / got-read-pack / got-read-pack.c
blobd319aef0358edca8c65aba260fd9131471e6bc83
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(struct got_object_id_queue *queue,
1055 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 for (;;) {
1064 err = got_privsep_recv_object_idlist(&done, &ids, &nids, ibuf);
1065 if (err || done)
1066 break;
1067 for (i = 0; i < nids; i++) {
1068 err = got_object_qid_alloc_partial(&qid);
1069 if (err)
1070 return err;
1071 memcpy(&qid->id, &ids[i], sizeof(qid->id));
1072 STAILQ_INSERT_TAIL(queue, qid, entry);
1073 err = got_object_idset_add(queued_ids, &qid->id, NULL);
1074 if (err)
1075 return err;
1079 return err;
1082 static const struct got_error *
1083 delta_reuse_request(struct imsg *imsg, struct imsgbuf *ibuf,
1084 struct got_pack *pack, struct got_packidx *packidx)
1086 const struct got_error *err = NULL;
1087 struct got_object_idset *idset;
1088 struct search_deltas_arg sda;
1090 idset = got_object_idset_alloc();
1091 if (idset == NULL)
1092 return got_error_from_errno("got_object_idset_alloc");
1094 err = recv_object_ids(idset, ibuf);
1095 if (err)
1096 return err;
1098 memset(&sda, 0, sizeof(sda));
1099 sda.ibuf = ibuf;
1100 sda.idset = idset;
1101 sda.pack = pack;
1102 sda.packidx = packidx;
1103 err = got_object_idset_for_each(idset, search_delta_for_object, &sda);
1104 if (err)
1105 goto done;
1107 if (sda.ndeltas > 0) {
1108 err = got_privsep_send_reused_deltas(ibuf, sda.deltas,
1109 sda.ndeltas);
1110 if (err)
1111 goto done;
1114 err = got_privsep_send_reused_deltas_done(ibuf);
1115 done:
1116 got_object_idset_free(idset);
1117 return err;
1120 static const struct got_error *
1121 receive_packidx(struct got_packidx **packidx, struct imsgbuf *ibuf)
1123 const struct got_error *err = NULL;
1124 struct imsg imsg;
1125 struct got_imsg_packidx ipackidx;
1126 size_t datalen;
1127 struct got_packidx *p;
1129 *packidx = NULL;
1131 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1132 if (err)
1133 return err;
1135 p = calloc(1, sizeof(*p));
1136 if (p == NULL) {
1137 err = got_error_from_errno("calloc");
1138 goto done;
1141 if (imsg.hdr.type != GOT_IMSG_PACKIDX) {
1142 err = got_error(GOT_ERR_PRIVSEP_MSG);
1143 goto done;
1146 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1147 if (datalen != sizeof(ipackidx)) {
1148 err = got_error(GOT_ERR_PRIVSEP_LEN);
1149 goto done;
1151 memcpy(&ipackidx, imsg.data, sizeof(ipackidx));
1153 p->algo = ipackidx.algo;
1154 p->fd = imsg_get_fd(&imsg);
1155 p->len = ipackidx.len;
1156 if (p->fd == -1) {
1157 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
1158 goto done;
1160 if (lseek(p->fd, 0, SEEK_SET) == -1) {
1161 err = got_error_from_errno("lseek");
1162 goto done;
1165 #ifndef GOT_PACK_NO_MMAP
1166 if (p->len > 0 && p->len <= SIZE_MAX) {
1167 p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0);
1168 if (p->map == MAP_FAILED)
1169 p->map = NULL; /* fall back to read(2) */
1171 #endif
1172 err = got_packidx_init_hdr(p, 1, ipackidx.packfile_size);
1173 done:
1174 if (err) {
1175 if (p != NULL)
1176 got_packidx_close(p);
1177 } else
1178 *packidx = p;
1179 imsg_free(&imsg);
1180 return err;
1183 static const struct got_error *
1184 send_tree_enumeration_done(struct imsgbuf *ibuf)
1186 if (imsg_compose(ibuf, GOT_IMSG_TREE_ENUMERATION_DONE, 0, 0, -1,
1187 NULL, 0) == -1)
1188 return got_error_from_errno("imsg_compose TREE_ENUMERATION_DONE");
1190 return got_privsep_flush_imsg(ibuf);
1193 struct enumerated_tree {
1194 struct got_object_id id;
1195 char *path;
1196 uint8_t *buf;
1197 struct got_parsed_tree_entry *entries;
1198 int nentries;
1201 static const struct got_error *
1202 enumerate_tree(int *have_all_entries, struct imsgbuf *ibuf, size_t *totlen,
1203 struct got_object_id *tree_id,
1204 const char *path, struct got_pack *pack, struct got_packidx *packidx,
1205 struct got_object_cache *objcache, struct got_object_idset *idset,
1206 struct enumerated_tree **trees, size_t *nalloc, size_t *ntrees)
1208 const struct got_error *err = NULL;
1209 struct got_object_id_queue ids;
1210 struct got_object_qid *qid;
1211 uint8_t *buf = NULL;
1212 size_t len = 0;
1213 struct got_parsed_tree_entry *entries = NULL;
1214 size_t nentries = 0, nentries_alloc = 0, i;
1215 struct enumerated_tree *tree;
1217 *ntrees = 0;
1218 *have_all_entries = 1;
1219 STAILQ_INIT(&ids);
1221 err = got_object_qid_alloc_partial(&qid);
1222 if (err)
1223 return err;
1224 memcpy(&qid->id, tree_id, sizeof(*tree_id));
1225 qid->data = strdup(path);
1226 if (qid->data == NULL) {
1227 err = got_error_from_errno("strdup");
1228 goto done;
1230 STAILQ_INSERT_TAIL(&ids, qid, entry);
1231 qid = NULL;
1233 /* Traverse the tree hierarchy, gather tree object IDs and paths. */
1234 do {
1235 const char *path;
1236 int idx, i;
1238 if (sigint_received) {
1239 err = got_error(GOT_ERR_CANCELLED);
1240 goto done;
1243 qid = STAILQ_FIRST(&ids);
1244 STAILQ_REMOVE_HEAD(&ids, entry);
1245 path = qid->data;
1247 idx = got_packidx_get_object_idx(packidx, &qid->id);
1248 if (idx == -1) {
1249 *have_all_entries = 0;
1250 break;
1253 err = open_tree(&buf, &len, pack, packidx, idx, &qid->id,
1254 objcache);
1255 if (err) {
1256 if (err->code != GOT_ERR_NO_OBJ)
1257 goto done;
1260 err = got_object_parse_tree(&entries, &nentries,
1261 &nentries_alloc, buf, len, pack->algo);
1262 if (err)
1263 goto done;
1265 err = got_object_idset_add(idset, &qid->id, NULL);
1266 if (err)
1267 goto done;
1269 for (i = 0; i < nentries; i++) {
1270 struct got_object_qid *eqid = NULL;
1271 struct got_parsed_tree_entry *pte = &entries[i];
1272 char *p;
1274 if (!S_ISDIR(pte->mode))
1275 continue;
1277 err = got_object_qid_alloc_partial(&eqid);
1278 if (err)
1279 goto done;
1280 eqid->id.algo = pte->algo;
1281 memcpy(eqid->id.hash, pte->id, pte->digest_len);
1283 if (got_object_idset_contains(idset, &eqid->id)) {
1284 got_object_qid_free(eqid);
1285 continue;
1288 if (asprintf(&p, "%s%s%s", path,
1289 got_path_is_root_dir(path) ? "" : "/",
1290 pte->name) == -1) {
1291 err = got_error_from_errno("asprintf");
1292 got_object_qid_free(eqid);
1293 goto done;
1295 eqid->data = p;
1296 STAILQ_INSERT_TAIL(&ids, eqid, entry);
1299 if (*ntrees >= *nalloc) {
1300 struct enumerated_tree *new;
1301 new = recallocarray(*trees, *nalloc, *nalloc + 16,
1302 sizeof(*new));
1303 if (new == NULL) {
1304 err = got_error_from_errno("malloc");
1305 goto done;
1307 *trees = new;
1308 *nalloc += 16;
1310 tree = &(*trees)[*ntrees];
1311 (*ntrees)++;
1312 memcpy(&tree->id, &qid->id, sizeof(tree->id));
1313 tree->path = qid->data;
1314 tree->buf = buf;
1315 buf = NULL;
1316 tree->entries = entries;
1317 entries = NULL;
1318 nentries_alloc = 0;
1319 tree->nentries = nentries;
1320 nentries = 0;
1322 got_object_qid_free(qid);
1323 qid = NULL;
1324 } while (!STAILQ_EMPTY(&ids));
1326 if (*have_all_entries) {
1327 int i;
1329 * We have managed to traverse all entries in the hierarchy.
1330 * Tell the main process what we have found.
1332 for (i = 0; i < *ntrees; i++) {
1333 tree = &(*trees)[i];
1334 err = got_privsep_send_enumerated_tree(totlen,
1335 ibuf, &tree->id, tree->path, tree->entries,
1336 tree->nentries);
1337 if (err)
1338 goto done;
1339 free(tree->buf);
1340 tree->buf = NULL;
1341 free(tree->path);
1342 tree->path = NULL;
1343 free(tree->entries);
1344 tree->entries = NULL;
1346 *ntrees = 0; /* don't loop again below to free memory */
1348 err = send_tree_enumeration_done(ibuf);
1349 } else {
1351 * We can only load fully packed tree hierarchies on
1352 * behalf of the main process, otherwise the main process
1353 * gets a wrong idea about which tree objects have
1354 * already been traversed.
1355 * Indicate a missing entry for the root of this tree.
1356 * The main process should continue by loading this
1357 * entire tree the slow way.
1359 err = got_privsep_send_enumerated_tree(totlen, ibuf,
1360 tree_id, "/", NULL, -1);
1361 if (err)
1362 goto done;
1364 done:
1365 free(buf);
1366 free(entries);
1367 for (i = 0; i < *ntrees; i++) {
1368 tree = &(*trees)[i];
1369 free(tree->buf);
1370 tree->buf = NULL;
1371 free(tree->path);
1372 tree->path = NULL;
1373 free(tree->entries);
1374 tree->entries = NULL;
1376 if (qid)
1377 free(qid->data);
1378 got_object_qid_free(qid);
1379 got_object_id_queue_free(&ids);
1380 if (err) {
1381 if (err->code == GOT_ERR_PRIVSEP_PIPE)
1382 err = NULL;
1383 else
1384 got_privsep_send_error(ibuf, err);
1387 return err;
1391 static const struct got_error *
1392 resolve_tag(struct got_object **obj, struct got_object_id *id,
1393 struct got_packidx *packidx, struct got_pack *pack,
1394 struct got_object_cache *objcache)
1396 const struct got_error *err;
1397 struct got_object *tagged_obj;
1398 struct got_tag_object *tag;
1399 uint8_t *buf;
1400 size_t len;
1401 int idx;
1403 err = got_packfile_extract_object_to_mem(&buf, &len, *obj, pack);
1404 if (err)
1405 return err;
1407 (*obj)->size = len;
1408 err = got_object_parse_tag(&tag, buf, len, id->algo);
1409 if (err)
1410 goto done;
1412 idx = got_packidx_get_object_idx(packidx, &tag->id);
1413 if (idx == -1) {
1414 got_object_close(*obj);
1415 *obj = NULL;
1416 return NULL;
1419 tagged_obj = got_object_cache_get(objcache, &tag->id);
1420 if (tagged_obj) {
1421 tagged_obj->refcnt++;
1422 } else {
1423 err = open_object(&tagged_obj, pack, packidx,
1424 idx, &tag->id, objcache);
1425 if (err)
1426 goto done;
1429 got_object_close(*obj);
1430 *obj = tagged_obj;
1431 done:
1432 got_object_tag_close(tag);
1433 free(buf);
1434 return err;
1437 static const struct got_error *
1438 enumeration_request(struct imsg *imsg, struct imsgbuf *ibuf,
1439 struct got_pack *pack, struct got_packidx *packidx,
1440 struct got_object_cache *objcache)
1442 const struct got_error *err = NULL;
1443 struct got_object_id_queue commit_ids;
1444 const struct got_object_id_queue *parents = NULL;
1445 struct got_object_qid *qid = NULL;
1446 struct got_object *obj = NULL;
1447 struct got_commit_object *commit = NULL;
1448 struct got_object_id *tree_id = NULL;
1449 size_t totlen = 0;
1450 struct got_object_idset *idset, *queued_ids = NULL;
1451 int i, idx, have_all_entries = 1;
1452 struct enumerated_tree *trees = NULL;
1453 size_t ntrees = 0, nalloc = 16;
1455 STAILQ_INIT(&commit_ids);
1457 trees = calloc(nalloc, sizeof(*trees));
1458 if (trees == NULL)
1459 return got_error_from_errno("calloc");
1461 idset = got_object_idset_alloc();
1462 if (idset == NULL) {
1463 err = got_error_from_errno("got_object_idset_alloc");
1464 goto done;
1467 queued_ids = got_object_idset_alloc();
1468 if (queued_ids == NULL) {
1469 err = got_error_from_errno("got_object_idset_alloc");
1470 goto done;
1473 err = recv_object_id_queue(&commit_ids, queued_ids, ibuf);
1474 if (err)
1475 goto done;
1477 if (STAILQ_EMPTY(&commit_ids)) {
1478 err = got_error(GOT_ERR_PRIVSEP_MSG);
1479 goto done;
1482 err = recv_object_ids(idset, ibuf);
1483 if (err)
1484 goto done;
1486 while (!STAILQ_EMPTY(&commit_ids)) {
1487 if (sigint_received) {
1488 err = got_error(GOT_ERR_CANCELLED);
1489 goto done;
1492 qid = STAILQ_FIRST(&commit_ids);
1493 STAILQ_REMOVE_HEAD(&commit_ids, entry);
1495 if (got_object_idset_contains(idset, &qid->id)) {
1496 got_object_qid_free(qid);
1497 qid = NULL;
1498 continue;
1501 idx = got_packidx_get_object_idx(packidx, &qid->id);
1502 if (idx == -1) {
1503 have_all_entries = 0;
1504 break;
1507 err = open_object(&obj, pack, packidx, idx, &qid->id,
1508 objcache);
1509 if (err)
1510 goto done;
1511 if (obj->type == GOT_OBJ_TYPE_TAG) {
1512 while (obj->type == GOT_OBJ_TYPE_TAG) {
1513 err = resolve_tag(&obj, &qid->id, packidx,
1514 pack, objcache);
1515 if (err)
1516 goto done;
1517 if (obj == NULL)
1518 break;
1520 if (obj == NULL) {
1521 have_all_entries = 0;
1522 break;
1524 if (obj->type != GOT_OBJ_TYPE_COMMIT) {
1525 got_object_qid_free(qid);
1526 qid = NULL;
1527 got_object_close(obj);
1528 obj = NULL;
1529 continue;
1531 err = open_commit(&commit, pack, packidx, idx,
1532 &obj->id, objcache);
1533 if (err)
1534 goto done;
1535 } else if (obj->type == GOT_OBJ_TYPE_COMMIT) {
1536 err = open_commit(&commit, pack, packidx, idx,
1537 &qid->id, objcache);
1538 if (err)
1539 goto done;
1540 } else {
1541 err = got_error(GOT_ERR_OBJ_TYPE);
1542 goto done;
1544 got_object_close(obj);
1545 obj = NULL;
1547 err = got_privsep_send_enumerated_commit(ibuf, &qid->id,
1548 got_object_commit_get_committer_time(commit));
1549 if (err)
1550 goto done;
1552 tree_id = got_object_commit_get_tree_id(commit);
1553 idx = got_packidx_get_object_idx(packidx, tree_id);
1554 if (idx == -1) {
1555 have_all_entries = 0;
1556 err = got_privsep_send_enumerated_tree(&totlen, ibuf,
1557 tree_id, "/", NULL, -1);
1558 if (err)
1559 goto done;
1560 break;
1563 if (got_object_idset_contains(idset, tree_id)) {
1564 got_object_qid_free(qid);
1565 qid = NULL;
1566 err = send_tree_enumeration_done(ibuf);
1567 if (err)
1568 goto done;
1569 got_object_commit_close(commit);
1570 commit = NULL;
1571 continue;
1574 err = enumerate_tree(&have_all_entries, ibuf, &totlen,
1575 tree_id, "/", pack, packidx, objcache, idset,
1576 &trees, &nalloc, &ntrees);
1577 if (err)
1578 goto done;
1580 if (!have_all_entries)
1581 break;
1583 got_object_qid_free(qid);
1584 qid = NULL;
1586 parents = got_object_commit_get_parent_ids(commit);
1587 if (parents) {
1588 struct got_object_qid *pid;
1589 STAILQ_FOREACH(pid, parents, entry) {
1590 if (got_object_idset_contains(idset,
1591 &pid->id) ||
1592 got_object_idset_contains(queued_ids,
1593 &pid->id)) {
1594 got_object_commit_close(commit);
1595 commit = NULL;
1596 continue;
1598 err = got_object_qid_alloc_partial(&qid);
1599 if (err)
1600 goto done;
1601 memcpy(&qid->id, &pid->id, sizeof(qid->id));
1602 STAILQ_INSERT_TAIL(&commit_ids, qid, entry);
1603 qid = NULL;
1607 got_object_commit_close(commit);
1608 commit = NULL;
1611 if (have_all_entries) {
1612 err = got_privsep_send_object_enumeration_done(ibuf);
1613 if (err)
1614 goto done;
1615 } else {
1616 err = got_privsep_send_object_enumeration_incomplete(ibuf);
1617 if (err)
1618 goto done;
1620 done:
1621 if (obj)
1622 got_object_close(obj);
1623 if (commit)
1624 got_object_commit_close(commit);
1625 got_object_qid_free(qid);
1626 got_object_id_queue_free(&commit_ids);
1627 if (idset)
1628 got_object_idset_free(idset);
1629 if (queued_ids)
1630 got_object_idset_free(queued_ids);
1631 for (i = 0; i < ntrees; i++) {
1632 struct enumerated_tree *tree = &trees[i];
1633 free(tree->buf);
1634 free(tree->path);
1635 free(tree->entries);
1637 free(trees);
1638 return err;
1641 enum findtwixt_color {
1642 COLOR_KEEP = 0,
1643 COLOR_DROP,
1644 COLOR_SKIP,
1645 COLOR_MAX,
1648 static const struct got_error *
1649 paint_commit(struct got_object_qid *qid, intptr_t color)
1651 if (color < 0 || color >= COLOR_MAX)
1652 return got_error(GOT_ERR_RANGE);
1654 qid->data = (void *)color;
1655 return NULL;
1658 static const struct got_error *
1659 queue_commit_id(struct got_object_id_queue *ids, struct got_object_id *id,
1660 intptr_t color)
1662 const struct got_error *err;
1663 struct got_object_qid *qid;
1665 err = got_object_qid_alloc_partial(&qid);
1666 if (err)
1667 return err;
1669 memcpy(&qid->id, id, sizeof(qid->id));
1670 STAILQ_INSERT_TAIL(ids, qid, entry);
1671 return paint_commit(qid, color);
1674 static const struct got_error *
1675 paint_commits(struct got_object_id_queue *ids, int *nids,
1676 struct got_object_idset *keep, struct got_object_idset *drop,
1677 struct got_object_idset *skip, struct got_pack *pack,
1678 struct got_packidx *packidx, struct imsgbuf *ibuf,
1679 struct got_object_cache *objcache)
1681 const struct got_error *err = NULL;
1682 struct got_commit_object *commit = NULL;
1683 struct got_object_id_queue painted;
1684 const struct got_object_id_queue *parents;
1685 struct got_object_qid *qid = NULL;
1686 int nqueued = *nids, nskip = 0, npainted = 0;
1688 STAILQ_INIT(&painted);
1690 while (!STAILQ_EMPTY(ids) && nskip != nqueued) {
1691 int idx;
1692 intptr_t color;
1694 if (sigint_received) {
1695 err = got_error(GOT_ERR_CANCELLED);
1696 goto done;
1699 qid = STAILQ_FIRST(ids);
1700 idx = got_packidx_get_object_idx(packidx, &qid->id);
1701 if (idx == -1) {
1702 qid = NULL;
1703 break;
1706 STAILQ_REMOVE_HEAD(ids, entry);
1707 nqueued--;
1708 color = (intptr_t)qid->data;
1709 if (color == COLOR_SKIP)
1710 nskip--;
1712 if (got_object_idset_contains(skip, &qid->id)) {
1713 got_object_qid_free(qid);
1714 qid = NULL;
1715 continue;
1718 switch (color) {
1719 case COLOR_KEEP:
1720 if (got_object_idset_contains(keep, &qid->id)) {
1721 got_object_qid_free(qid);
1722 qid = NULL;
1723 continue;
1725 if (got_object_idset_contains(drop, &qid->id)) {
1726 err = paint_commit(qid, COLOR_SKIP);
1727 if (err)
1728 goto done;
1730 err = got_object_idset_add(keep, &qid->id, NULL);
1731 if (err)
1732 goto done;
1733 break;
1734 case COLOR_DROP:
1735 if (got_object_idset_contains(drop, &qid->id)) {
1736 got_object_qid_free(qid);
1737 qid = NULL;
1738 continue;
1740 if (got_object_idset_contains(keep, &qid->id)) {
1741 err = paint_commit(qid, COLOR_SKIP);
1742 if (err)
1743 goto done;
1745 err = got_object_idset_add(drop, &qid->id, NULL);
1746 if (err)
1747 goto done;
1748 break;
1749 case COLOR_SKIP:
1750 if (!got_object_idset_contains(skip, &qid->id)) {
1751 err = got_object_idset_add(skip, &qid->id,
1752 NULL);
1753 if (err)
1754 goto done;
1756 break;
1757 default:
1758 /* should not happen */
1759 err = got_error_fmt(GOT_ERR_NOT_IMPL,
1760 "%s invalid commit color %"PRIdPTR, __func__,
1761 color);
1762 goto done;
1765 err = open_commit(&commit, pack, packidx, idx, &qid->id,
1766 objcache);
1767 if (err)
1768 goto done;
1770 parents = got_object_commit_get_parent_ids(commit);
1771 if (parents) {
1772 struct got_object_qid *pid;
1773 color = (intptr_t)qid->data;
1774 STAILQ_FOREACH(pid, parents, entry) {
1775 err = queue_commit_id(ids, &pid->id, color);
1776 if (err)
1777 goto done;
1778 nqueued++;
1779 if (color == COLOR_SKIP)
1780 nskip++;
1784 got_object_commit_close(commit);
1785 commit = NULL;
1787 STAILQ_INSERT_TAIL(&painted, qid, entry);
1788 qid = NULL;
1789 npainted++;
1791 err = got_privsep_send_painted_commits(ibuf, &painted,
1792 &npainted, 1, 0);
1793 if (err)
1794 goto done;
1797 err = got_privsep_send_painted_commits(ibuf, &painted, &npainted, 1, 1);
1798 if (err)
1799 goto done;
1801 *nids = nqueued;
1802 done:
1803 if (commit)
1804 got_object_commit_close(commit);
1805 got_object_qid_free(qid);
1806 return err;
1809 static void
1810 commit_painting_free(struct got_object_idset **keep,
1811 struct got_object_idset **drop,
1812 struct got_object_idset **skip)
1814 if (*keep) {
1815 got_object_idset_free(*keep);
1816 *keep = NULL;
1818 if (*drop) {
1819 got_object_idset_free(*drop);
1820 *drop = NULL;
1822 if (*skip) {
1823 got_object_idset_free(*skip);
1824 *skip = NULL;
1828 static const struct got_error *
1829 commit_painting_init(struct imsgbuf *ibuf, struct got_object_idset **keep,
1830 struct got_object_idset **drop, struct got_object_idset **skip)
1832 const struct got_error *err = NULL;
1834 *keep = got_object_idset_alloc();
1835 if (*keep == NULL) {
1836 err = got_error_from_errno("got_object_idset_alloc");
1837 goto done;
1839 *drop = got_object_idset_alloc();
1840 if (*drop == NULL) {
1841 err = got_error_from_errno("got_object_idset_alloc");
1842 goto done;
1844 *skip = got_object_idset_alloc();
1845 if (*skip == NULL) {
1846 err = got_error_from_errno("got_object_idset_alloc");
1847 goto done;
1850 err = recv_object_ids(*keep, ibuf);
1851 if (err)
1852 goto done;
1853 err = recv_object_ids(*drop, ibuf);
1854 if (err)
1855 goto done;
1856 err = recv_object_ids(*skip, ibuf);
1857 if (err)
1858 goto done;
1860 done:
1861 if (err)
1862 commit_painting_free(keep, drop, skip);
1864 return err;
1867 static const struct got_error *
1868 commit_painting_request(struct imsg *imsg, struct imsgbuf *ibuf,
1869 struct got_pack *pack, struct got_packidx *packidx,
1870 struct got_object_cache *objcache, struct got_object_idset *keep,
1871 struct got_object_idset *drop, struct got_object_idset *skip)
1873 const struct got_error *err = NULL;
1874 struct got_imsg_commit_painting_request ireq;
1875 struct got_object_id id;
1876 size_t datalen;
1877 struct got_object_id_queue ids;
1878 int nids = 0;
1880 STAILQ_INIT(&ids);
1882 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1883 if (datalen != sizeof(ireq))
1884 return got_error(GOT_ERR_PRIVSEP_LEN);
1885 memcpy(&ireq, imsg->data, sizeof(ireq));
1886 memcpy(&id, &ireq.id, sizeof(id));
1888 err = queue_commit_id(&ids, &id, ireq.color);
1889 if (err)
1890 return err;
1891 nids = 1;
1893 err = paint_commits(&ids, &nids, keep, drop, skip,
1894 pack, packidx, ibuf, objcache);
1895 if (err)
1896 goto done;
1898 err = got_privsep_send_painted_commits(ibuf, &ids, &nids, 0, 1);
1899 if (err)
1900 goto done;
1902 err = got_privsep_send_painting_commits_done(ibuf);
1903 done:
1904 got_object_id_queue_free(&ids);
1905 return err;
1908 static const struct got_error *
1909 receive_pack(struct got_pack **packp, struct imsgbuf *ibuf)
1911 const struct got_error *err = NULL;
1912 struct imsg imsg;
1913 struct got_imsg_pack ipack;
1914 size_t datalen;
1915 struct got_pack *pack;
1917 *packp = NULL;
1919 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
1920 if (err)
1921 return err;
1923 pack = calloc(1, sizeof(*pack));
1924 if (pack == NULL) {
1925 err = got_error_from_errno("calloc");
1926 goto done;
1929 if (imsg.hdr.type != GOT_IMSG_PACK) {
1930 err = got_error(GOT_ERR_PRIVSEP_MSG);
1931 goto done;
1934 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1935 if (datalen != sizeof(ipack)) {
1936 err = got_error(GOT_ERR_PRIVSEP_LEN);
1937 goto done;
1939 memcpy(&ipack, imsg.data, sizeof(ipack));
1941 pack->algo = ipack.algo;
1942 pack->filesize = ipack.filesize;
1943 pack->fd = imsg_get_fd(&imsg);
1944 if (pack->fd == -1) {
1945 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
1946 goto done;
1948 if (lseek(pack->fd, 0, SEEK_SET) == -1) {
1949 err = got_error_from_errno("lseek");
1950 goto done;
1952 pack->path_packfile = strdup(ipack.path_packfile);
1953 if (pack->path_packfile == NULL) {
1954 err = got_error_from_errno("strdup");
1955 goto done;
1958 err = got_delta_cache_alloc(&pack->delta_cache);
1959 if (err)
1960 goto done;
1962 #ifndef GOT_PACK_NO_MMAP
1963 if (pack->filesize > 0 && pack->filesize <= SIZE_MAX) {
1964 pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE,
1965 pack->fd, 0);
1966 if (pack->map == MAP_FAILED)
1967 pack->map = NULL; /* fall back to read(2) */
1969 #endif
1970 done:
1971 if (err) {
1972 if (pack != NULL)
1973 got_pack_close(pack);
1974 } else
1975 *packp = pack;
1976 imsg_free(&imsg);
1977 return err;
1981 main(int argc, char *argv[])
1983 const struct got_error *err = NULL;
1984 struct imsgbuf ibuf;
1985 struct imsg imsg;
1986 struct got_packidx *packidx = NULL;
1987 struct got_pack *pack = NULL;
1988 struct got_object_cache objcache;
1989 FILE *basefile = NULL, *accumfile = NULL, *delta_outfile = NULL;
1990 struct got_object_idset *keep = NULL, *drop = NULL, *skip = NULL;
1991 struct got_parsed_tree_entry *entries = NULL;
1992 size_t nentries = 0, nentries_alloc = 0;
1994 //static int attached;
1995 //while (!attached) sleep(1);
1997 signal(SIGINT, catch_sigint);
1999 if (imsgbuf_init(&ibuf, GOT_IMSG_FD_CHILD) == -1) {
2000 warn("imsgbuf_init");
2001 return 1;
2003 imsgbuf_allow_fdpass(&ibuf);
2005 err = got_object_cache_init(&objcache, GOT_OBJECT_CACHE_TYPE_OBJ);
2006 if (err) {
2007 err = got_error_from_errno("got_object_cache_init");
2008 got_privsep_send_error(&ibuf, err);
2009 return 1;
2012 #ifndef PROFILE
2013 /* revoke access to most system calls */
2014 if (pledge("stdio recvfd", NULL) == -1) {
2015 err = got_error_from_errno("pledge");
2016 got_privsep_send_error(&ibuf, err);
2017 return 1;
2020 /* revoke fs access */
2021 if (landlock_no_fs() == -1) {
2022 err = got_error_from_errno("landlock_no_fs");
2023 got_privsep_send_error(&ibuf, err);
2024 return 1;
2026 if (cap_enter() == -1) {
2027 err = got_error_from_errno("cap_enter");
2028 got_privsep_send_error(&ibuf, err);
2029 return 1;
2031 #endif
2033 err = receive_packidx(&packidx, &ibuf);
2034 if (err) {
2035 got_privsep_send_error(&ibuf, err);
2036 return 1;
2039 err = receive_pack(&pack, &ibuf);
2040 if (err) {
2041 got_privsep_send_error(&ibuf, err);
2042 return 1;
2045 for (;;) {
2046 if (sigint_received) {
2047 err = got_error(GOT_ERR_CANCELLED);
2048 break;
2051 err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
2052 if (err) {
2053 if (err->code == GOT_ERR_PRIVSEP_PIPE)
2054 err = NULL;
2055 break;
2058 if (imsg.hdr.type == GOT_IMSG_STOP) {
2059 imsg_free(&imsg);
2060 break;
2063 switch (imsg.hdr.type) {
2064 case GOT_IMSG_TMPFD:
2065 if (basefile == NULL) {
2066 err = receive_tempfile(&basefile, "w+",
2067 &imsg, &ibuf);
2068 } else if (accumfile == NULL) {
2069 err = receive_tempfile(&accumfile, "w+",
2070 &imsg, &ibuf);
2071 } else
2072 err = got_error(GOT_ERR_PRIVSEP_MSG);
2073 break;
2074 case GOT_IMSG_PACKED_OBJECT_REQUEST:
2075 err = object_request(&imsg, &ibuf, pack, packidx,
2076 &objcache);
2077 break;
2078 case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST:
2079 if (basefile == NULL || accumfile == NULL) {
2080 err = got_error(GOT_ERR_PRIVSEP_MSG);
2081 break;
2083 err = raw_object_request(&imsg, &ibuf, pack, packidx,
2084 &objcache, basefile, accumfile);
2085 break;
2086 case GOT_IMSG_RAW_DELTA_OUTFD:
2087 if (delta_outfile != NULL) {
2088 err = got_error(GOT_ERR_PRIVSEP_MSG);
2089 break;
2091 err = receive_tempfile(&delta_outfile, "w",
2092 &imsg, &ibuf);
2093 break;
2094 case GOT_IMSG_RAW_DELTA_REQUEST:
2095 if (delta_outfile == NULL) {
2096 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
2097 break;
2099 err = raw_delta_request(&imsg, &ibuf, delta_outfile,
2100 pack, packidx);
2101 break;
2102 case GOT_IMSG_DELTA_REUSE_REQUEST:
2103 err = delta_reuse_request(&imsg, &ibuf, pack, packidx);
2104 break;
2105 case GOT_IMSG_COMMIT_REQUEST:
2106 err = commit_request(&imsg, &ibuf, pack, packidx,
2107 &objcache);
2108 break;
2109 case GOT_IMSG_TREE_REQUEST:
2110 err = tree_request(&imsg, &ibuf, pack, packidx,
2111 &objcache, &entries, &nentries, &nentries_alloc);
2112 break;
2113 case GOT_IMSG_BLOB_REQUEST:
2114 if (basefile == NULL || accumfile == NULL) {
2115 err = got_error(GOT_ERR_PRIVSEP_MSG);
2116 break;
2118 err = blob_request(&imsg, &ibuf, pack, packidx,
2119 &objcache, basefile, accumfile);
2120 break;
2121 case GOT_IMSG_TAG_REQUEST:
2122 err = tag_request(&imsg, &ibuf, pack, packidx,
2123 &objcache);
2124 break;
2125 case GOT_IMSG_COMMIT_TRAVERSAL_REQUEST:
2126 err = commit_traversal_request(&imsg, &ibuf, pack,
2127 packidx, &objcache);
2128 break;
2129 case GOT_IMSG_OBJECT_ENUMERATION_REQUEST:
2130 err = enumeration_request(&imsg, &ibuf, pack,
2131 packidx, &objcache);
2132 break;
2133 case GOT_IMSG_COMMIT_PAINTING_INIT:
2134 commit_painting_free(&keep, &drop, &skip);
2135 err = commit_painting_init(&ibuf, &keep, &drop, &skip);
2136 break;
2137 case GOT_IMSG_COMMIT_PAINTING_REQUEST:
2138 if (keep == NULL || drop == NULL || skip == NULL) {
2139 err = got_error(GOT_ERR_PRIVSEP_MSG);
2140 break;
2142 err = commit_painting_request(&imsg, &ibuf, pack,
2143 packidx, &objcache, keep, drop, skip);
2144 break;
2145 case GOT_IMSG_COMMIT_PAINTING_DONE:
2146 commit_painting_free(&keep, &drop, &skip);
2147 break;
2148 default:
2149 err = got_error(GOT_ERR_PRIVSEP_MSG);
2150 break;
2153 imsg_free(&imsg);
2154 if (err)
2155 break;
2158 free(entries);
2159 commit_painting_free(&keep, &drop, &skip);
2160 if (packidx)
2161 got_packidx_close(packidx);
2162 if (pack) {
2163 got_pack_close(pack);
2164 free(pack);
2166 got_object_cache_close(&objcache);
2167 if (basefile && fclose(basefile) == EOF && err == NULL)
2168 err = got_error_from_errno("fclose");
2169 if (accumfile && fclose(accumfile) == EOF && err == NULL)
2170 err = got_error_from_errno("fclose");
2171 if (delta_outfile && fclose(delta_outfile) == EOF && err == NULL)
2172 err = got_error_from_errno("fclose");
2173 if (err) {
2174 if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) {
2175 fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
2176 got_privsep_send_error(&ibuf, err);
2179 imsgbuf_clear(&ibuf);
2180 if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL)
2181 err = got_error_from_errno("close");
2182 return err ? 1 : 0;