Blob


1 /*
2 * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
3 *
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.
7 *
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.
15 */
17 #include <sys/types.h>
18 #include <sys/uio.h>
19 #include <sys/time.h>
20 #include <sys/mman.h>
22 #include <limits.h>
23 #include <signal.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <zlib.h>
31 #include "got_compat.h"
33 #include "got_error.h"
34 #include "got_object.h"
35 #include "got_path.h"
37 #include "got_lib_delta.h"
38 #include "got_lib_delta_cache.h"
39 #include "got_lib_object.h"
40 #include "got_lib_object_cache.h"
41 #include "got_lib_object_parse.h"
42 #include "got_lib_privsep.h"
43 #include "got_lib_pack.h"
45 static volatile sig_atomic_t sigint_received;
47 static void
48 catch_sigint(int signo)
49 {
50 sigint_received = 1;
51 }
53 static const struct got_error *
54 open_object(struct got_object **obj, struct got_pack *pack,
55 struct got_packidx *packidx, int idx, struct got_object_id *id,
56 struct got_object_cache *objcache)
57 {
58 const struct got_error *err;
60 err = got_packfile_open_object(obj, pack, packidx, idx, id);
61 if (err)
62 return err;
63 (*obj)->refcnt++;
65 err = got_object_cache_add(objcache, id, *obj);
66 if (err) {
67 if (err->code == GOT_ERR_OBJ_EXISTS ||
68 err->code == GOT_ERR_OBJ_TOO_LARGE)
69 err = NULL;
70 return err;
71 }
72 (*obj)->refcnt++;
73 return NULL;
74 }
76 static const struct got_error *
77 object_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
78 struct got_packidx *packidx, struct got_object_cache *objcache)
79 {
80 const struct got_error *err = NULL;
81 struct got_imsg_packed_object iobj;
82 struct got_object *obj;
83 struct got_object_id id;
84 size_t datalen;
86 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
87 if (datalen != sizeof(iobj))
88 return got_error(GOT_ERR_PRIVSEP_LEN);
89 memcpy(&iobj, imsg->data, sizeof(iobj));
90 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
92 obj = got_object_cache_get(objcache, &id);
93 if (obj) {
94 obj->refcnt++;
95 } else {
96 err = open_object(&obj, pack, packidx, iobj.idx, &id,
97 objcache);
98 if (err)
99 goto done;
102 err = got_privsep_send_obj(ibuf, obj);
103 done:
104 got_object_close(obj);
105 return err;
108 static const struct got_error *
109 open_commit(struct got_commit_object **commit, struct got_pack *pack,
110 struct got_packidx *packidx, int obj_idx, struct got_object_id *id,
111 struct got_object_cache *objcache)
113 const struct got_error *err = NULL;
114 struct got_object *obj = NULL;
115 uint8_t *buf = NULL;
116 size_t len;
118 *commit = NULL;
120 obj = got_object_cache_get(objcache, id);
121 if (obj) {
122 obj->refcnt++;
123 } else {
124 err = open_object(&obj, pack, packidx, obj_idx, id,
125 objcache);
126 if (err)
127 return err;
130 err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack);
131 if (err)
132 goto done;
134 obj->size = len;
136 err = got_object_parse_commit(commit, buf, len);
137 done:
138 got_object_close(obj);
139 free(buf);
140 return err;
143 static const struct got_error *
144 commit_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
145 struct got_packidx *packidx, struct got_object_cache *objcache)
147 const struct got_error *err = NULL;
148 struct got_imsg_packed_object iobj;
149 struct got_commit_object *commit = NULL;
150 struct got_object_id id;
151 size_t datalen;
153 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
154 if (datalen != sizeof(iobj))
155 return got_error(GOT_ERR_PRIVSEP_LEN);
156 memcpy(&iobj, imsg->data, sizeof(iobj));
157 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
159 err = open_commit(&commit, pack, packidx, iobj.idx, &id, objcache);
160 if (err)
161 goto done;
163 err = got_privsep_send_commit(ibuf, commit);
164 done:
165 if (commit)
166 got_object_commit_close(commit);
167 if (err) {
168 if (err->code == GOT_ERR_PRIVSEP_PIPE)
169 err = NULL;
170 else
171 got_privsep_send_error(ibuf, err);
174 return err;
177 static const struct got_error *
178 open_tree(uint8_t **buf, struct got_pathlist_head *entries, int *nentries,
179 struct got_pack *pack, struct got_packidx *packidx, int obj_idx,
180 struct got_object_id *id, struct got_object_cache *objcache)
182 const struct got_error *err = NULL;
183 struct got_object *obj = NULL;
184 size_t len;
186 *buf = NULL;
187 *nentries = 0;
189 obj = got_object_cache_get(objcache, id);
190 if (obj) {
191 obj->refcnt++;
192 } else {
193 err = open_object(&obj, pack, packidx, obj_idx, id,
194 objcache);
195 if (err)
196 return err;
199 err = got_packfile_extract_object_to_mem(buf, &len, obj, pack);
200 if (err)
201 goto done;
203 obj->size = len;
205 err = got_object_parse_tree(entries, nentries, *buf, len);
206 done:
207 got_object_close(obj);
208 if (err) {
209 free(*buf);
210 *buf = NULL;
212 return err;
215 static const struct got_error *
216 tree_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
217 struct got_packidx *packidx, struct got_object_cache *objcache)
219 const struct got_error *err = NULL;
220 struct got_imsg_packed_object iobj;
221 struct got_pathlist_head entries;
222 int nentries = 0;
223 uint8_t *buf = NULL;
224 struct got_object_id id;
225 size_t datalen;
227 TAILQ_INIT(&entries);
229 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
230 if (datalen != sizeof(iobj))
231 return got_error(GOT_ERR_PRIVSEP_LEN);
232 memcpy(&iobj, imsg->data, sizeof(iobj));
233 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
235 err = open_tree(&buf, &entries, &nentries, pack, packidx, iobj.idx,
236 &id, objcache);
237 if (err)
238 return err;
240 err = got_privsep_send_tree(ibuf, &entries, nentries);
241 got_object_parsed_tree_entries_free(&entries);
242 free(buf);
243 if (err) {
244 if (err->code == GOT_ERR_PRIVSEP_PIPE)
245 err = NULL;
246 else
247 got_privsep_send_error(ibuf, err);
250 return err;
253 static const struct got_error *
254 receive_file(FILE **f, struct imsgbuf *ibuf, uint32_t imsg_code)
256 const struct got_error *err;
257 struct imsg imsg;
258 size_t datalen;
260 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
261 if (err)
262 return err;
264 if (imsg.hdr.type != imsg_code) {
265 err = got_error(GOT_ERR_PRIVSEP_MSG);
266 goto done;
269 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
270 if (datalen != 0) {
271 err = got_error(GOT_ERR_PRIVSEP_LEN);
272 goto done;
274 if (imsg.fd == -1) {
275 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
276 goto done;
279 *f = fdopen(imsg.fd, "w+");
280 if (*f == NULL) {
281 err = got_error_from_errno("fdopen");
282 close(imsg.fd);
283 goto done;
285 done:
286 imsg_free(&imsg);
287 return err;
290 static const struct got_error *
291 receive_tempfile(FILE **basefile, FILE **accumfile, struct imsg *imsg,
292 struct imsgbuf *ibuf)
294 size_t datalen;
295 FILE **f;
297 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
298 if (datalen != 0)
299 return got_error(GOT_ERR_PRIVSEP_LEN);
301 if (imsg->fd == -1)
302 return got_error(GOT_ERR_PRIVSEP_NO_FD);
304 if (*basefile == NULL)
305 f = basefile;
306 else if (*accumfile == NULL)
307 f = accumfile;
308 else
309 return got_error(GOT_ERR_PRIVSEP_MSG);
311 *f = fdopen(imsg->fd, "w+");
312 if (*f == NULL)
313 return got_error_from_errno("fdopen");
314 imsg->fd = -1;
316 return NULL;
319 static const struct got_error *
320 blob_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
321 struct got_packidx *packidx, struct got_object_cache *objcache,
322 FILE *basefile, FILE *accumfile)
324 const struct got_error *err = NULL;
325 struct got_imsg_packed_object iobj;
326 struct got_object *obj = NULL;
327 FILE *outfile = NULL;
328 struct got_object_id id;
329 size_t datalen;
330 uint64_t blob_size;
331 uint8_t *buf = NULL;
333 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
334 if (datalen != sizeof(iobj))
335 return got_error(GOT_ERR_PRIVSEP_LEN);
336 memcpy(&iobj, imsg->data, sizeof(iobj));
337 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
339 obj = got_object_cache_get(objcache, &id);
340 if (obj) {
341 obj->refcnt++;
342 } else {
343 err = open_object(&obj, pack, packidx, iobj.idx, &id,
344 objcache);
345 if (err)
346 return err;
349 err = receive_file(&outfile, ibuf, GOT_IMSG_BLOB_OUTFD);
350 if (err)
351 goto done;
353 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
354 err = got_pack_get_max_delta_object_size(&blob_size, obj, pack);
355 if (err)
356 goto done;
357 } else
358 blob_size = obj->size;
360 if (blob_size <= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX)
361 err = got_packfile_extract_object_to_mem(&buf, &obj->size,
362 obj, pack);
363 else
364 err = got_packfile_extract_object(pack, obj, outfile, basefile,
365 accumfile);
366 if (err)
367 goto done;
369 err = got_privsep_send_blob(ibuf, obj->size, obj->hdrlen, buf);
370 done:
371 free(buf);
372 if (outfile && fclose(outfile) == EOF && err == NULL)
373 err = got_error_from_errno("fclose");
374 got_object_close(obj);
375 if (err && err->code != GOT_ERR_PRIVSEP_PIPE)
376 got_privsep_send_error(ibuf, err);
378 return err;
381 static const struct got_error *
382 tag_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
383 struct got_packidx *packidx, struct got_object_cache *objcache)
385 const struct got_error *err = NULL;
386 struct got_imsg_packed_object iobj;
387 struct got_object *obj = NULL;
388 struct got_tag_object *tag = NULL;
389 uint8_t *buf = NULL;
390 size_t len;
391 struct got_object_id id;
392 size_t datalen;
394 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
395 if (datalen != sizeof(iobj))
396 return got_error(GOT_ERR_PRIVSEP_LEN);
397 memcpy(&iobj, imsg->data, sizeof(iobj));
398 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
400 obj = got_object_cache_get(objcache, &id);
401 if (obj) {
402 obj->refcnt++;
403 } else {
404 err = open_object(&obj, pack, packidx, iobj.idx, &id,
405 objcache);
406 if (err)
407 return err;
410 err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack);
411 if (err)
412 goto done;
414 obj->size = len;
415 err = got_object_parse_tag(&tag, buf, len);
416 if (err)
417 goto done;
419 err = got_privsep_send_tag(ibuf, tag);
420 done:
421 free(buf);
422 got_object_close(obj);
423 if (tag)
424 got_object_tag_close(tag);
425 if (err) {
426 if (err->code == GOT_ERR_PRIVSEP_PIPE)
427 err = NULL;
428 else
429 got_privsep_send_error(ibuf, err);
432 return err;
435 static struct got_parsed_tree_entry *
436 find_entry_by_name(struct got_pathlist_head *entries, int nentries,
437 const char *name, size_t len)
439 struct got_pathlist_entry *pe;
441 /* Note that tree entries are sorted in strncmp() order. */
442 TAILQ_FOREACH(pe, entries, entry) {
443 int cmp = strncmp(pe->path, name, len);
444 if (cmp < 0)
445 continue;
446 if (cmp > 0)
447 break;
448 if (pe->path[len] == '\0')
449 return (struct got_parsed_tree_entry *)pe->data;
451 return NULL;
454 static const struct got_error *
455 tree_path_changed(int *changed, uint8_t **buf1, uint8_t **buf2,
456 struct got_pathlist_head *entries1, int *nentries1,
457 struct got_pathlist_head *entries2, int *nentries2,
458 const char *path, struct got_pack *pack, struct got_packidx *packidx,
459 struct imsgbuf *ibuf, struct got_object_cache *objcache)
461 const struct got_error *err = NULL;
462 struct got_parsed_tree_entry *pte1 = NULL, *pte2 = NULL;
463 const char *seg, *s;
464 size_t seglen;
466 *changed = 0;
468 /* We not do support comparing the root path. */
469 if (got_path_is_root_dir(path))
470 return got_error_path(path, GOT_ERR_BAD_PATH);
472 s = path;
473 while (*s == '/')
474 s++;
475 seg = s;
476 seglen = 0;
477 while (*s) {
478 if (*s != '/') {
479 s++;
480 seglen++;
481 if (*s)
482 continue;
485 pte1 = find_entry_by_name(entries1, *nentries1, seg, seglen);
486 if (pte1 == NULL) {
487 err = got_error(GOT_ERR_NO_OBJ);
488 break;
491 pte2 = find_entry_by_name(entries2, *nentries2, seg, seglen);
492 if (pte2 == NULL) {
493 *changed = 1;
494 break;
497 if (pte1->mode != pte2->mode) {
498 *changed = 1;
499 break;
502 if (memcmp(pte1->id, pte2->id, SHA1_DIGEST_LENGTH) == 0) {
503 *changed = 0;
504 break;
507 if (*s == '\0') { /* final path element */
508 *changed = 1;
509 break;
512 seg = s + 1;
513 s++;
514 seglen = 0;
515 if (*s) {
516 struct got_object_id id1, id2;
517 int idx;
519 memcpy(id1.sha1, pte1->id, SHA1_DIGEST_LENGTH);
520 idx = got_packidx_get_object_idx(packidx, &id1);
521 if (idx == -1) {
522 err = got_error_no_obj(&id1);
523 break;
525 got_object_parsed_tree_entries_free(entries1);
526 *nentries1 = 0;
527 free(*buf1);
528 *buf1 = NULL;
529 err = open_tree(buf1, entries1, nentries1, pack,
530 packidx, idx, &id1, objcache);
531 pte1 = NULL;
532 if (err)
533 break;
535 memcpy(id2.sha1, pte2->id, SHA1_DIGEST_LENGTH);
536 idx = got_packidx_get_object_idx(packidx, &id2);
537 if (idx == -1) {
538 err = got_error_no_obj(&id2);
539 break;
541 got_object_parsed_tree_entries_free(entries2);
542 *nentries2 = 0;
543 free(*buf2);
544 *buf2 = NULL;
545 err = open_tree(buf2, entries2, nentries2, pack,
546 packidx, idx, &id2, objcache);
547 pte2 = NULL;
548 if (err)
549 break;
553 return err;
556 static const struct got_error *
557 send_traversed_commits(struct got_object_id *commit_ids, size_t ncommits,
558 struct imsgbuf *ibuf)
560 const struct got_error *err;
561 struct ibuf *wbuf;
562 size_t i;
564 wbuf = imsg_create(ibuf, GOT_IMSG_TRAVERSED_COMMITS, 0, 0,
565 sizeof(struct got_imsg_traversed_commits) +
566 ncommits * SHA1_DIGEST_LENGTH);
567 if (wbuf == NULL)
568 return got_error_from_errno("imsg_create TRAVERSED_COMMITS");
570 if (imsg_add(wbuf, &ncommits, sizeof(ncommits)) == -1) {
571 err = got_error_from_errno("imsg_add TRAVERSED_COMMITS");
572 ibuf_free(wbuf);
573 return err;
575 for (i = 0; i < ncommits; i++) {
576 struct got_object_id *id = &commit_ids[i];
577 if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH) == -1) {
578 err = got_error_from_errno(
579 "imsg_add TRAVERSED_COMMITS");
580 ibuf_free(wbuf);
581 return err;
585 wbuf->fd = -1;
586 imsg_close(ibuf, wbuf);
588 return got_privsep_flush_imsg(ibuf);
591 static const struct got_error *
592 send_commit_traversal_done(struct imsgbuf *ibuf)
594 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_TRAVERSAL_DONE, 0, 0, -1,
595 NULL, 0) == -1)
596 return got_error_from_errno("imsg_compose TRAVERSAL_DONE");
598 return got_privsep_flush_imsg(ibuf);
602 static const struct got_error *
603 commit_traversal_request(struct imsg *imsg, struct imsgbuf *ibuf,
604 struct got_pack *pack, struct got_packidx *packidx,
605 struct got_object_cache *objcache)
607 const struct got_error *err = NULL;
608 struct got_imsg_packed_object iobj;
609 struct got_object_qid *pid;
610 struct got_commit_object *commit = NULL, *pcommit = NULL;
611 struct got_pathlist_head entries, pentries;
612 int nentries = 0, pnentries = 0;
613 struct got_object_id id;
614 size_t datalen, path_len;
615 char *path = NULL;
616 const int min_alloc = 64;
617 int changed = 0, ncommits = 0, nallocated = 0;
618 struct got_object_id *commit_ids = NULL;
620 TAILQ_INIT(&entries);
621 TAILQ_INIT(&pentries);
623 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
624 if (datalen < sizeof(iobj))
625 return got_error(GOT_ERR_PRIVSEP_LEN);
626 memcpy(&iobj, imsg->data, sizeof(iobj));
627 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
629 path_len = datalen - sizeof(iobj) - 1;
630 if (path_len < 0)
631 return got_error(GOT_ERR_PRIVSEP_LEN);
632 if (path_len > 0) {
633 path = imsg->data + sizeof(iobj);
634 if (path[path_len] != '\0')
635 return got_error(GOT_ERR_PRIVSEP_LEN);
638 nallocated = min_alloc;
639 commit_ids = reallocarray(NULL, nallocated, sizeof(*commit_ids));
640 if (commit_ids == NULL)
641 return got_error_from_errno("reallocarray");
643 do {
644 const size_t max_datalen = MAX_IMSGSIZE - IMSG_HEADER_SIZE;
645 int idx;
647 if (sigint_received) {
648 err = got_error(GOT_ERR_CANCELLED);
649 goto done;
652 if (commit == NULL) {
653 idx = got_packidx_get_object_idx(packidx, &id);
654 if (idx == -1)
655 break;
656 err = open_commit(&commit, pack, packidx,
657 idx, &id, objcache);
658 if (err) {
659 if (err->code != GOT_ERR_NO_OBJ)
660 goto done;
661 err = NULL;
662 break;
666 if (sizeof(struct got_imsg_traversed_commits) +
667 ncommits * SHA1_DIGEST_LENGTH >= max_datalen) {
668 err = send_traversed_commits(commit_ids, ncommits,
669 ibuf);
670 if (err)
671 goto done;
672 ncommits = 0;
674 ncommits++;
675 if (ncommits > nallocated) {
676 struct got_object_id *new;
677 nallocated += min_alloc;
678 new = reallocarray(commit_ids, nallocated,
679 sizeof(*commit_ids));
680 if (new == NULL) {
681 err = got_error_from_errno("reallocarray");
682 goto done;
684 commit_ids = new;
686 memcpy(commit_ids[ncommits - 1].sha1, id.sha1,
687 SHA1_DIGEST_LENGTH);
689 pid = STAILQ_FIRST(&commit->parent_ids);
690 if (pid == NULL)
691 break;
693 idx = got_packidx_get_object_idx(packidx, pid->id);
694 if (idx == -1)
695 break;
697 err = open_commit(&pcommit, pack, packidx, idx, pid->id,
698 objcache);
699 if (err) {
700 if (err->code != GOT_ERR_NO_OBJ)
701 goto done;
702 err = NULL;
703 break;
706 if (path[0] == '/' && path[1] == '\0') {
707 if (got_object_id_cmp(pcommit->tree_id,
708 commit->tree_id) != 0) {
709 changed = 1;
710 break;
712 } else {
713 int pidx;
714 uint8_t *buf = NULL, *pbuf = NULL;
716 idx = got_packidx_get_object_idx(packidx,
717 commit->tree_id);
718 if (idx == -1)
719 break;
720 pidx = got_packidx_get_object_idx(packidx,
721 pcommit->tree_id);
722 if (pidx == -1)
723 break;
725 err = open_tree(&buf, &entries, &nentries, pack,
726 packidx, idx, commit->tree_id, objcache);
727 if (err)
728 goto done;
729 err = open_tree(&pbuf, &pentries, &pnentries, pack,
730 packidx, pidx, pcommit->tree_id, objcache);
731 if (err) {
732 free(buf);
733 goto done;
736 err = tree_path_changed(&changed, &buf, &pbuf,
737 &entries, &nentries, &pentries, &pnentries, path,
738 pack, packidx, ibuf, objcache);
740 got_object_parsed_tree_entries_free(&entries);
741 nentries = 0;
742 free(buf);
743 got_object_parsed_tree_entries_free(&pentries);
744 pnentries = 0;
745 free(pbuf);
746 if (err) {
747 if (err->code != GOT_ERR_NO_OBJ)
748 goto done;
749 err = NULL;
750 break;
754 if (!changed) {
755 memcpy(id.sha1, pid->id->sha1, SHA1_DIGEST_LENGTH);
756 got_object_commit_close(commit);
757 commit = pcommit;
758 pcommit = NULL;
760 } while (!changed);
762 if (ncommits > 0) {
763 err = send_traversed_commits(commit_ids, ncommits, ibuf);
764 if (err)
765 goto done;
767 if (changed) {
768 err = got_privsep_send_commit(ibuf, commit);
769 if (err)
770 goto done;
773 err = send_commit_traversal_done(ibuf);
774 done:
775 free(commit_ids);
776 if (commit)
777 got_object_commit_close(commit);
778 if (pcommit)
779 got_object_commit_close(pcommit);
780 if (nentries != 0)
781 got_object_parsed_tree_entries_free(&entries);
782 if (pnentries != 0)
783 got_object_parsed_tree_entries_free(&pentries);
784 if (err) {
785 if (err->code == GOT_ERR_PRIVSEP_PIPE)
786 err = NULL;
787 else
788 got_privsep_send_error(ibuf, err);
791 return err;
794 static const struct got_error *
795 raw_object_request(struct imsg *imsg, struct imsgbuf *ibuf,
796 struct got_pack *pack, struct got_packidx *packidx,
797 struct got_object_cache *objcache, FILE *basefile, FILE *accumfile)
799 const struct got_error *err = NULL;
800 uint8_t *buf = NULL;
801 uint64_t size = 0;
802 FILE *outfile = NULL;
803 struct got_imsg_packed_object iobj;
804 struct got_object *obj;
805 struct got_object_id id;
806 size_t datalen;
808 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
809 if (datalen != sizeof(iobj))
810 return got_error(GOT_ERR_PRIVSEP_LEN);
811 memcpy(&iobj, imsg->data, sizeof(iobj));
812 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
814 obj = got_object_cache_get(objcache, &id);
815 if (obj) {
816 obj->refcnt++;
817 } else {
818 err = open_object(&obj, pack, packidx, iobj.idx, &id,
819 objcache);
820 if (err)
821 return err;
824 err = receive_file(&outfile, ibuf, GOT_IMSG_RAW_OBJECT_OUTFD);
825 if (err)
826 return err;
828 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
829 err = got_pack_get_max_delta_object_size(&size, obj, pack);
830 if (err)
831 goto done;
832 } else
833 size = obj->size;
835 if (size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX)
836 err = got_packfile_extract_object_to_mem(&buf, &obj->size,
837 obj, pack);
838 else
839 err = got_packfile_extract_object(pack, obj, outfile, basefile,
840 accumfile);
841 if (err)
842 goto done;
844 err = got_privsep_send_raw_obj(ibuf, obj->size, obj->hdrlen, buf);
845 done:
846 free(buf);
847 if (outfile && fclose(outfile) == EOF && err == NULL)
848 err = got_error_from_errno("fclose");
849 got_object_close(obj);
850 if (err && err->code != GOT_ERR_PRIVSEP_PIPE)
851 got_privsep_send_error(ibuf, err);
853 return err;
858 static const struct got_error *
859 receive_packidx(struct got_packidx **packidx, struct imsgbuf *ibuf)
861 const struct got_error *err = NULL;
862 struct imsg imsg;
863 struct got_imsg_packidx ipackidx;
864 size_t datalen;
865 struct got_packidx *p;
867 *packidx = NULL;
869 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
870 if (err)
871 return err;
873 p = calloc(1, sizeof(*p));
874 if (p == NULL) {
875 err = got_error_from_errno("calloc");
876 goto done;
879 if (imsg.hdr.type != GOT_IMSG_PACKIDX) {
880 err = got_error(GOT_ERR_PRIVSEP_MSG);
881 goto done;
884 if (imsg.fd == -1) {
885 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
886 goto done;
889 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
890 if (datalen != sizeof(ipackidx)) {
891 err = got_error(GOT_ERR_PRIVSEP_LEN);
892 goto done;
894 memcpy(&ipackidx, imsg.data, sizeof(ipackidx));
896 p->len = ipackidx.len;
897 p->fd = dup(imsg.fd);
898 if (p->fd == -1) {
899 err = got_error_from_errno("dup");
900 goto done;
902 if (lseek(p->fd, 0, SEEK_SET) == -1) {
903 err = got_error_from_errno("lseek");
904 goto done;
907 #ifndef GOT_PACK_NO_MMAP
908 p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0);
909 if (p->map == MAP_FAILED)
910 p->map = NULL; /* fall back to read(2) */
911 #endif
912 err = got_packidx_init_hdr(p, 1, ipackidx.packfile_size);
913 done:
914 if (err) {
915 if (imsg.fd != -1)
916 close(imsg.fd);
917 got_packidx_close(p);
918 } else
919 *packidx = p;
920 imsg_free(&imsg);
921 return err;
924 static const struct got_error *
925 receive_pack(struct got_pack **packp, struct imsgbuf *ibuf)
927 const struct got_error *err = NULL;
928 struct imsg imsg;
929 struct got_imsg_pack ipack;
930 size_t datalen;
931 struct got_pack *pack;
933 *packp = NULL;
935 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
936 if (err)
937 return err;
939 pack = calloc(1, sizeof(*pack));
940 if (pack == NULL) {
941 err = got_error_from_errno("calloc");
942 goto done;
945 if (imsg.hdr.type != GOT_IMSG_PACK) {
946 err = got_error(GOT_ERR_PRIVSEP_MSG);
947 goto done;
950 if (imsg.fd == -1) {
951 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
952 goto done;
955 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
956 if (datalen != sizeof(ipack)) {
957 err = got_error(GOT_ERR_PRIVSEP_LEN);
958 goto done;
960 memcpy(&ipack, imsg.data, sizeof(ipack));
962 pack->filesize = ipack.filesize;
963 pack->fd = dup(imsg.fd);
964 if (pack->fd == -1) {
965 err = got_error_from_errno("dup");
966 goto done;
968 if (lseek(pack->fd, 0, SEEK_SET) == -1) {
969 err = got_error_from_errno("lseek");
970 goto done;
972 pack->path_packfile = strdup(ipack.path_packfile);
973 if (pack->path_packfile == NULL) {
974 err = got_error_from_errno("strdup");
975 goto done;
978 pack->delta_cache = got_delta_cache_alloc(100,
979 GOT_DELTA_RESULT_SIZE_CACHED_MAX);
980 if (pack->delta_cache == NULL) {
981 err = got_error_from_errno("got_delta_cache_alloc");
982 goto done;
985 #ifndef GOT_PACK_NO_MMAP
986 pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE,
987 pack->fd, 0);
988 if (pack->map == MAP_FAILED)
989 pack->map = NULL; /* fall back to read(2) */
990 #endif
991 done:
992 if (err) {
993 if (imsg.fd != -1)
994 close(imsg.fd);
995 free(pack);
996 } else
997 *packp = pack;
998 imsg_free(&imsg);
999 return err;
1002 int
1003 main(int argc, char *argv[])
1005 const struct got_error *err = NULL;
1006 struct imsgbuf ibuf;
1007 struct imsg imsg;
1008 struct got_packidx *packidx = NULL;
1009 struct got_pack *pack = NULL;
1010 struct got_object_cache objcache;
1011 FILE *basefile = NULL, *accumfile = NULL;
1013 //static int attached;
1014 //while (!attached) sleep(1);
1016 signal(SIGINT, catch_sigint);
1018 imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
1020 err = got_object_cache_init(&objcache, GOT_OBJECT_CACHE_TYPE_OBJ);
1021 if (err) {
1022 err = got_error_from_errno("got_object_cache_init");
1023 got_privsep_send_error(&ibuf, err);
1024 return 1;
1027 #ifndef PROFILE
1028 /* revoke access to most system calls */
1029 if (pledge("stdio recvfd", NULL) == -1) {
1030 err = got_error_from_errno("pledge");
1031 got_privsep_send_error(&ibuf, err);
1032 return 1;
1034 #endif
1036 err = receive_packidx(&packidx, &ibuf);
1037 if (err) {
1038 got_privsep_send_error(&ibuf, err);
1039 return 1;
1042 err = receive_pack(&pack, &ibuf);
1043 if (err) {
1044 got_privsep_send_error(&ibuf, err);
1045 return 1;
1048 for (;;) {
1049 imsg.fd = -1;
1051 if (sigint_received) {
1052 err = got_error(GOT_ERR_CANCELLED);
1053 break;
1056 err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
1057 if (err) {
1058 if (err->code == GOT_ERR_PRIVSEP_PIPE)
1059 err = NULL;
1060 break;
1063 if (imsg.hdr.type == GOT_IMSG_STOP)
1064 break;
1066 switch (imsg.hdr.type) {
1067 case GOT_IMSG_TMPFD:
1068 err = receive_tempfile(&basefile, &accumfile,
1069 &imsg, &ibuf);
1070 break;
1071 case GOT_IMSG_PACKED_OBJECT_REQUEST:
1072 err = object_request(&imsg, &ibuf, pack, packidx,
1073 &objcache);
1074 break;
1075 case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST:
1076 if (basefile == NULL || accumfile == NULL) {
1077 err = got_error(GOT_ERR_PRIVSEP_MSG);
1078 break;
1080 err = raw_object_request(&imsg, &ibuf, pack, packidx,
1081 &objcache, basefile, accumfile);
1082 break;
1083 case GOT_IMSG_COMMIT_REQUEST:
1084 err = commit_request(&imsg, &ibuf, pack, packidx,
1085 &objcache);
1086 break;
1087 case GOT_IMSG_TREE_REQUEST:
1088 err = tree_request(&imsg, &ibuf, pack, packidx,
1089 &objcache);
1090 break;
1091 case GOT_IMSG_BLOB_REQUEST:
1092 if (basefile == NULL || accumfile == NULL) {
1093 err = got_error(GOT_ERR_PRIVSEP_MSG);
1094 break;
1096 err = blob_request(&imsg, &ibuf, pack, packidx,
1097 &objcache, basefile, accumfile);
1098 break;
1099 case GOT_IMSG_TAG_REQUEST:
1100 err = tag_request(&imsg, &ibuf, pack, packidx,
1101 &objcache);
1102 break;
1103 case GOT_IMSG_COMMIT_TRAVERSAL_REQUEST:
1104 err = commit_traversal_request(&imsg, &ibuf, pack,
1105 packidx, &objcache);
1106 break;
1107 default:
1108 err = got_error(GOT_ERR_PRIVSEP_MSG);
1109 break;
1112 if (imsg.fd != -1 && close(imsg.fd) == -1 && err == NULL)
1113 err = got_error_from_errno("close");
1114 imsg_free(&imsg);
1115 if (err)
1116 break;
1119 if (packidx)
1120 got_packidx_close(packidx);
1121 if (pack)
1122 got_pack_close(pack);
1123 got_object_cache_close(&objcache);
1124 imsg_clear(&ibuf);
1125 if (basefile && fclose(basefile) == EOF && err == NULL)
1126 err = got_error_from_errno("fclose");
1127 if (accumfile && fclose(accumfile) == EOF && err == NULL)
1128 err = got_error_from_errno("fclose");
1129 if (err) {
1130 if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) {
1131 fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
1132 got_privsep_send_error(&ibuf, err);
1135 if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL)
1136 err = got_error_from_errno("close");
1137 return err ? 1 : 0;