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 blob_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
292 struct got_packidx *packidx, struct got_object_cache *objcache)
294 const struct got_error *err = NULL;
295 struct got_imsg_packed_object iobj;
296 struct got_object *obj = NULL;
297 FILE *outfile = NULL, *basefile = NULL, *accumfile = NULL;
298 struct got_object_id id;
299 size_t datalen;
300 uint64_t blob_size;
301 uint8_t *buf = NULL;
303 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
304 if (datalen != sizeof(iobj))
305 return got_error(GOT_ERR_PRIVSEP_LEN);
306 memcpy(&iobj, imsg->data, sizeof(iobj));
307 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
309 obj = got_object_cache_get(objcache, &id);
310 if (obj) {
311 obj->refcnt++;
312 } else {
313 err = open_object(&obj, pack, packidx, iobj.idx, &id,
314 objcache);
315 if (err)
316 return err;
319 err = receive_file(&outfile, ibuf, GOT_IMSG_BLOB_OUTFD);
320 if (err)
321 goto done;
322 err = receive_file(&basefile, ibuf, GOT_IMSG_TMPFD);
323 if (err)
324 goto done;
325 err = receive_file(&accumfile, ibuf, GOT_IMSG_TMPFD);
326 if (err)
327 goto done;
329 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
330 err = got_pack_get_max_delta_object_size(&blob_size, obj, pack);
331 if (err)
332 goto done;
333 } else
334 blob_size = obj->size;
336 if (blob_size <= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX)
337 err = got_packfile_extract_object_to_mem(&buf, &obj->size,
338 obj, pack);
339 else
340 err = got_packfile_extract_object(pack, obj, outfile, basefile,
341 accumfile);
342 if (err)
343 goto done;
345 err = got_privsep_send_blob(ibuf, obj->size, obj->hdrlen, buf);
346 done:
347 free(buf);
348 if (outfile && fclose(outfile) == EOF && err == NULL)
349 err = got_error_from_errno("fclose");
350 if (basefile && fclose(basefile) == EOF && err == NULL)
351 err = got_error_from_errno("fclose");
352 if (accumfile && fclose(accumfile) == EOF && err == NULL)
353 err = got_error_from_errno("fclose");
354 got_object_close(obj);
355 if (err && err->code != GOT_ERR_PRIVSEP_PIPE)
356 got_privsep_send_error(ibuf, err);
358 return err;
361 static const struct got_error *
362 tag_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
363 struct got_packidx *packidx, struct got_object_cache *objcache)
365 const struct got_error *err = NULL;
366 struct got_imsg_packed_object iobj;
367 struct got_object *obj = NULL;
368 struct got_tag_object *tag = NULL;
369 uint8_t *buf = NULL;
370 size_t len;
371 struct got_object_id id;
372 size_t datalen;
374 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
375 if (datalen != sizeof(iobj))
376 return got_error(GOT_ERR_PRIVSEP_LEN);
377 memcpy(&iobj, imsg->data, sizeof(iobj));
378 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
380 obj = got_object_cache_get(objcache, &id);
381 if (obj) {
382 obj->refcnt++;
383 } else {
384 err = open_object(&obj, pack, packidx, iobj.idx, &id,
385 objcache);
386 if (err)
387 return err;
390 err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack);
391 if (err)
392 goto done;
394 obj->size = len;
395 err = got_object_parse_tag(&tag, buf, len);
396 if (err)
397 goto done;
399 err = got_privsep_send_tag(ibuf, tag);
400 done:
401 free(buf);
402 got_object_close(obj);
403 if (tag)
404 got_object_tag_close(tag);
405 if (err) {
406 if (err->code == GOT_ERR_PRIVSEP_PIPE)
407 err = NULL;
408 else
409 got_privsep_send_error(ibuf, err);
412 return err;
415 static struct got_parsed_tree_entry *
416 find_entry_by_name(struct got_pathlist_head *entries, int nentries,
417 const char *name, size_t len)
419 struct got_pathlist_entry *pe;
421 /* Note that tree entries are sorted in strncmp() order. */
422 TAILQ_FOREACH(pe, entries, entry) {
423 int cmp = strncmp(pe->path, name, len);
424 if (cmp < 0)
425 continue;
426 if (cmp > 0)
427 break;
428 if (pe->path[len] == '\0')
429 return (struct got_parsed_tree_entry *)pe->data;
431 return NULL;
434 static const struct got_error *
435 tree_path_changed(int *changed, uint8_t **buf1, uint8_t **buf2,
436 struct got_pathlist_head *entries1, int *nentries1,
437 struct got_pathlist_head *entries2, int *nentries2,
438 const char *path, struct got_pack *pack, struct got_packidx *packidx,
439 struct imsgbuf *ibuf, struct got_object_cache *objcache)
441 const struct got_error *err = NULL;
442 struct got_parsed_tree_entry *pte1 = NULL, *pte2 = NULL;
443 const char *seg, *s;
444 size_t seglen;
446 *changed = 0;
448 /* We not do support comparing the root path. */
449 if (got_path_is_root_dir(path))
450 return got_error_path(path, GOT_ERR_BAD_PATH);
452 s = path;
453 while (*s == '/')
454 s++;
455 seg = s;
456 seglen = 0;
457 while (*s) {
458 if (*s != '/') {
459 s++;
460 seglen++;
461 if (*s)
462 continue;
465 pte1 = find_entry_by_name(entries1, *nentries1, seg, seglen);
466 if (pte1 == NULL) {
467 err = got_error(GOT_ERR_NO_OBJ);
468 break;
471 pte2 = find_entry_by_name(entries2, *nentries2, seg, seglen);
472 if (pte2 == NULL) {
473 *changed = 1;
474 break;
477 if (pte1->mode != pte2->mode) {
478 *changed = 1;
479 break;
482 if (memcmp(pte1->id, pte2->id, SHA1_DIGEST_LENGTH) == 0) {
483 *changed = 0;
484 break;
487 if (*s == '\0') { /* final path element */
488 *changed = 1;
489 break;
492 seg = s + 1;
493 s++;
494 seglen = 0;
495 if (*s) {
496 struct got_object_id id1, id2;
497 int idx;
499 memcpy(id1.sha1, pte1->id, SHA1_DIGEST_LENGTH);
500 idx = got_packidx_get_object_idx(packidx, &id1);
501 if (idx == -1) {
502 err = got_error_no_obj(&id1);
503 break;
505 got_object_parsed_tree_entries_free(entries1);
506 *nentries1 = 0;
507 free(*buf1);
508 *buf1 = NULL;
509 err = open_tree(buf1, entries1, nentries1, pack,
510 packidx, idx, &id1, objcache);
511 pte1 = NULL;
512 if (err)
513 break;
515 memcpy(id2.sha1, pte2->id, SHA1_DIGEST_LENGTH);
516 idx = got_packidx_get_object_idx(packidx, &id2);
517 if (idx == -1) {
518 err = got_error_no_obj(&id2);
519 break;
521 got_object_parsed_tree_entries_free(entries2);
522 *nentries2 = 0;
523 free(*buf2);
524 *buf2 = NULL;
525 err = open_tree(buf2, entries2, nentries2, pack,
526 packidx, idx, &id2, objcache);
527 pte2 = NULL;
528 if (err)
529 break;
533 return err;
536 static const struct got_error *
537 send_traversed_commits(struct got_object_id *commit_ids, size_t ncommits,
538 struct imsgbuf *ibuf)
540 const struct got_error *err;
541 struct ibuf *wbuf;
542 size_t i;
544 wbuf = imsg_create(ibuf, GOT_IMSG_TRAVERSED_COMMITS, 0, 0,
545 sizeof(struct got_imsg_traversed_commits) +
546 ncommits * SHA1_DIGEST_LENGTH);
547 if (wbuf == NULL)
548 return got_error_from_errno("imsg_create TRAVERSED_COMMITS");
550 if (imsg_add(wbuf, &ncommits, sizeof(ncommits)) == -1) {
551 err = got_error_from_errno("imsg_add TRAVERSED_COMMITS");
552 ibuf_free(wbuf);
553 return err;
555 for (i = 0; i < ncommits; i++) {
556 struct got_object_id *id = &commit_ids[i];
557 if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH) == -1) {
558 err = got_error_from_errno(
559 "imsg_add TRAVERSED_COMMITS");
560 ibuf_free(wbuf);
561 return err;
565 wbuf->fd = -1;
566 imsg_close(ibuf, wbuf);
568 return got_privsep_flush_imsg(ibuf);
571 static const struct got_error *
572 send_commit_traversal_done(struct imsgbuf *ibuf)
574 if (imsg_compose(ibuf, GOT_IMSG_COMMIT_TRAVERSAL_DONE, 0, 0, -1,
575 NULL, 0) == -1)
576 return got_error_from_errno("imsg_compose TRAVERSAL_DONE");
578 return got_privsep_flush_imsg(ibuf);
582 static const struct got_error *
583 commit_traversal_request(struct imsg *imsg, struct imsgbuf *ibuf,
584 struct got_pack *pack, struct got_packidx *packidx,
585 struct got_object_cache *objcache)
587 const struct got_error *err = NULL;
588 struct got_imsg_packed_object iobj;
589 struct got_object_qid *pid;
590 struct got_commit_object *commit = NULL, *pcommit = NULL;
591 struct got_pathlist_head entries, pentries;
592 int nentries = 0, pnentries = 0;
593 struct got_object_id id;
594 size_t datalen, path_len;
595 char *path = NULL;
596 const int min_alloc = 64;
597 int changed = 0, ncommits = 0, nallocated = 0;
598 struct got_object_id *commit_ids = NULL;
600 TAILQ_INIT(&entries);
601 TAILQ_INIT(&pentries);
603 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
604 if (datalen < sizeof(iobj))
605 return got_error(GOT_ERR_PRIVSEP_LEN);
606 memcpy(&iobj, imsg->data, sizeof(iobj));
607 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
609 path_len = datalen - sizeof(iobj) - 1;
610 if (path_len < 0)
611 return got_error(GOT_ERR_PRIVSEP_LEN);
612 if (path_len > 0) {
613 path = imsg->data + sizeof(iobj);
614 if (path[path_len] != '\0')
615 return got_error(GOT_ERR_PRIVSEP_LEN);
618 nallocated = min_alloc;
619 commit_ids = reallocarray(NULL, nallocated, sizeof(*commit_ids));
620 if (commit_ids == NULL)
621 return got_error_from_errno("reallocarray");
623 do {
624 const size_t max_datalen = MAX_IMSGSIZE - IMSG_HEADER_SIZE;
625 int idx;
627 if (sigint_received) {
628 err = got_error(GOT_ERR_CANCELLED);
629 goto done;
632 if (commit == NULL) {
633 idx = got_packidx_get_object_idx(packidx, &id);
634 if (idx == -1)
635 break;
636 err = open_commit(&commit, pack, packidx,
637 idx, &id, objcache);
638 if (err) {
639 if (err->code != GOT_ERR_NO_OBJ)
640 goto done;
641 err = NULL;
642 break;
646 if (sizeof(struct got_imsg_traversed_commits) +
647 ncommits * SHA1_DIGEST_LENGTH >= max_datalen) {
648 err = send_traversed_commits(commit_ids, ncommits,
649 ibuf);
650 if (err)
651 goto done;
652 ncommits = 0;
654 ncommits++;
655 if (ncommits > nallocated) {
656 struct got_object_id *new;
657 nallocated += min_alloc;
658 new = reallocarray(commit_ids, nallocated,
659 sizeof(*commit_ids));
660 if (new == NULL) {
661 err = got_error_from_errno("reallocarray");
662 goto done;
664 commit_ids = new;
666 memcpy(commit_ids[ncommits - 1].sha1, id.sha1,
667 SHA1_DIGEST_LENGTH);
669 pid = STAILQ_FIRST(&commit->parent_ids);
670 if (pid == NULL)
671 break;
673 idx = got_packidx_get_object_idx(packidx, pid->id);
674 if (idx == -1)
675 break;
677 err = open_commit(&pcommit, pack, packidx, idx, pid->id,
678 objcache);
679 if (err) {
680 if (err->code != GOT_ERR_NO_OBJ)
681 goto done;
682 err = NULL;
683 break;
686 if (path[0] == '/' && path[1] == '\0') {
687 if (got_object_id_cmp(pcommit->tree_id,
688 commit->tree_id) != 0) {
689 changed = 1;
690 break;
692 } else {
693 int pidx;
694 uint8_t *buf = NULL, *pbuf = NULL;
696 idx = got_packidx_get_object_idx(packidx,
697 commit->tree_id);
698 if (idx == -1)
699 break;
700 pidx = got_packidx_get_object_idx(packidx,
701 pcommit->tree_id);
702 if (pidx == -1)
703 break;
705 err = open_tree(&buf, &entries, &nentries, pack,
706 packidx, idx, commit->tree_id, objcache);
707 if (err)
708 goto done;
709 err = open_tree(&pbuf, &pentries, &pnentries, pack,
710 packidx, pidx, pcommit->tree_id, objcache);
711 if (err) {
712 free(buf);
713 goto done;
716 err = tree_path_changed(&changed, &buf, &pbuf,
717 &entries, &nentries, &pentries, &pnentries, path,
718 pack, packidx, ibuf, objcache);
720 got_object_parsed_tree_entries_free(&entries);
721 nentries = 0;
722 free(buf);
723 got_object_parsed_tree_entries_free(&pentries);
724 pnentries = 0;
725 free(pbuf);
726 if (err) {
727 if (err->code != GOT_ERR_NO_OBJ)
728 goto done;
729 err = NULL;
730 break;
734 if (!changed) {
735 memcpy(id.sha1, pid->id->sha1, SHA1_DIGEST_LENGTH);
736 got_object_commit_close(commit);
737 commit = pcommit;
738 pcommit = NULL;
740 } while (!changed);
742 if (ncommits > 0) {
743 err = send_traversed_commits(commit_ids, ncommits, ibuf);
744 if (err)
745 goto done;
747 if (changed) {
748 err = got_privsep_send_commit(ibuf, commit);
749 if (err)
750 goto done;
753 err = send_commit_traversal_done(ibuf);
754 done:
755 free(commit_ids);
756 if (commit)
757 got_object_commit_close(commit);
758 if (pcommit)
759 got_object_commit_close(pcommit);
760 if (nentries != 0)
761 got_object_parsed_tree_entries_free(&entries);
762 if (pnentries != 0)
763 got_object_parsed_tree_entries_free(&pentries);
764 if (err) {
765 if (err->code == GOT_ERR_PRIVSEP_PIPE)
766 err = NULL;
767 else
768 got_privsep_send_error(ibuf, err);
771 return err;
774 static const struct got_error *
775 raw_object_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
776 struct got_packidx *packidx, struct got_object_cache *objcache)
778 const struct got_error *err = NULL;
779 uint8_t *buf = NULL;
780 uint64_t size = 0;
781 FILE *outfile = NULL, *basefile = NULL, *accumfile = NULL;
782 struct got_imsg_packed_object iobj;
783 struct got_object *obj;
784 struct got_object_id id;
785 size_t datalen;
787 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
788 if (datalen != sizeof(iobj))
789 return got_error(GOT_ERR_PRIVSEP_LEN);
790 memcpy(&iobj, imsg->data, sizeof(iobj));
791 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
793 obj = got_object_cache_get(objcache, &id);
794 if (obj) {
795 obj->refcnt++;
796 } else {
797 err = open_object(&obj, pack, packidx, iobj.idx, &id,
798 objcache);
799 if (err)
800 return err;
803 err = receive_file(&outfile, ibuf, GOT_IMSG_RAW_OBJECT_OUTFD);
804 if (err)
805 return err;
806 err = receive_file(&basefile, ibuf, GOT_IMSG_TMPFD);
807 if (err)
808 goto done;
809 err = receive_file(&accumfile, ibuf, GOT_IMSG_TMPFD);
810 if (err)
811 goto done;
813 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
814 err = got_pack_get_max_delta_object_size(&size, obj, pack);
815 if (err)
816 goto done;
817 } else
818 size = obj->size;
820 if (size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX)
821 err = got_packfile_extract_object_to_mem(&buf, &obj->size,
822 obj, pack);
823 else
824 err = got_packfile_extract_object(pack, obj, outfile, basefile,
825 accumfile);
826 if (err)
827 goto done;
829 err = got_privsep_send_raw_obj(ibuf, obj->size, obj->hdrlen, buf);
830 done:
831 free(buf);
832 if (outfile && fclose(outfile) == EOF && err == NULL)
833 err = got_error_from_errno("fclose");
834 if (basefile && fclose(basefile) == EOF && err == NULL)
835 err = got_error_from_errno("fclose");
836 if (accumfile && fclose(accumfile) == EOF && err == NULL)
837 err = got_error_from_errno("fclose");
838 got_object_close(obj);
839 if (err && err->code != GOT_ERR_PRIVSEP_PIPE)
840 got_privsep_send_error(ibuf, err);
842 return err;
847 static const struct got_error *
848 receive_packidx(struct got_packidx **packidx, struct imsgbuf *ibuf)
850 const struct got_error *err = NULL;
851 struct imsg imsg;
852 struct got_imsg_packidx ipackidx;
853 size_t datalen;
854 struct got_packidx *p;
856 *packidx = NULL;
858 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
859 if (err)
860 return err;
862 p = calloc(1, sizeof(*p));
863 if (p == NULL) {
864 err = got_error_from_errno("calloc");
865 goto done;
868 if (imsg.hdr.type != GOT_IMSG_PACKIDX) {
869 err = got_error(GOT_ERR_PRIVSEP_MSG);
870 goto done;
873 if (imsg.fd == -1) {
874 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
875 goto done;
878 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
879 if (datalen != sizeof(ipackidx)) {
880 err = got_error(GOT_ERR_PRIVSEP_LEN);
881 goto done;
883 memcpy(&ipackidx, imsg.data, sizeof(ipackidx));
885 p->len = ipackidx.len;
886 p->fd = dup(imsg.fd);
887 if (p->fd == -1) {
888 err = got_error_from_errno("dup");
889 goto done;
891 if (lseek(p->fd, 0, SEEK_SET) == -1) {
892 err = got_error_from_errno("lseek");
893 goto done;
896 #ifndef GOT_PACK_NO_MMAP
897 p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0);
898 if (p->map == MAP_FAILED)
899 p->map = NULL; /* fall back to read(2) */
900 #endif
901 err = got_packidx_init_hdr(p, 1, ipackidx.packfile_size);
902 done:
903 if (err) {
904 if (imsg.fd != -1)
905 close(imsg.fd);
906 got_packidx_close(p);
907 } else
908 *packidx = p;
909 imsg_free(&imsg);
910 return err;
913 static const struct got_error *
914 receive_pack(struct got_pack **packp, struct imsgbuf *ibuf)
916 const struct got_error *err = NULL;
917 struct imsg imsg;
918 struct got_imsg_pack ipack;
919 size_t datalen;
920 struct got_pack *pack;
922 *packp = NULL;
924 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
925 if (err)
926 return err;
928 pack = calloc(1, sizeof(*pack));
929 if (pack == NULL) {
930 err = got_error_from_errno("calloc");
931 goto done;
934 if (imsg.hdr.type != GOT_IMSG_PACK) {
935 err = got_error(GOT_ERR_PRIVSEP_MSG);
936 goto done;
939 if (imsg.fd == -1) {
940 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
941 goto done;
944 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
945 if (datalen != sizeof(ipack)) {
946 err = got_error(GOT_ERR_PRIVSEP_LEN);
947 goto done;
949 memcpy(&ipack, imsg.data, sizeof(ipack));
951 pack->filesize = ipack.filesize;
952 pack->fd = dup(imsg.fd);
953 if (pack->fd == -1) {
954 err = got_error_from_errno("dup");
955 goto done;
957 if (lseek(pack->fd, 0, SEEK_SET) == -1) {
958 err = got_error_from_errno("lseek");
959 goto done;
961 pack->path_packfile = strdup(ipack.path_packfile);
962 if (pack->path_packfile == NULL) {
963 err = got_error_from_errno("strdup");
964 goto done;
967 pack->delta_cache = got_delta_cache_alloc(100,
968 GOT_DELTA_RESULT_SIZE_CACHED_MAX);
969 if (pack->delta_cache == NULL) {
970 err = got_error_from_errno("got_delta_cache_alloc");
971 goto done;
974 #ifndef GOT_PACK_NO_MMAP
975 pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE,
976 pack->fd, 0);
977 if (pack->map == MAP_FAILED)
978 pack->map = NULL; /* fall back to read(2) */
979 #endif
980 done:
981 if (err) {
982 if (imsg.fd != -1)
983 close(imsg.fd);
984 free(pack);
985 } else
986 *packp = pack;
987 imsg_free(&imsg);
988 return err;
991 int
992 main(int argc, char *argv[])
994 const struct got_error *err = NULL;
995 struct imsgbuf ibuf;
996 struct imsg imsg;
997 struct got_packidx *packidx = NULL;
998 struct got_pack *pack = NULL;
999 struct got_object_cache objcache;
1001 //static int attached;
1002 //while (!attached) sleep(1);
1004 signal(SIGINT, catch_sigint);
1006 imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
1008 err = got_object_cache_init(&objcache, GOT_OBJECT_CACHE_TYPE_OBJ);
1009 if (err) {
1010 err = got_error_from_errno("got_object_cache_init");
1011 got_privsep_send_error(&ibuf, err);
1012 return 1;
1015 #ifndef PROFILE
1016 /* revoke access to most system calls */
1017 if (pledge("stdio recvfd", NULL) == -1) {
1018 err = got_error_from_errno("pledge");
1019 got_privsep_send_error(&ibuf, err);
1020 return 1;
1022 #endif
1024 err = receive_packidx(&packidx, &ibuf);
1025 if (err) {
1026 got_privsep_send_error(&ibuf, err);
1027 return 1;
1030 err = receive_pack(&pack, &ibuf);
1031 if (err) {
1032 got_privsep_send_error(&ibuf, err);
1033 return 1;
1036 for (;;) {
1037 imsg.fd = -1;
1039 if (sigint_received) {
1040 err = got_error(GOT_ERR_CANCELLED);
1041 break;
1044 err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
1045 if (err) {
1046 if (err->code == GOT_ERR_PRIVSEP_PIPE)
1047 err = NULL;
1048 break;
1051 if (imsg.hdr.type == GOT_IMSG_STOP)
1052 break;
1054 switch (imsg.hdr.type) {
1055 case GOT_IMSG_PACKED_OBJECT_REQUEST:
1056 err = object_request(&imsg, &ibuf, pack, packidx,
1057 &objcache);
1058 break;
1059 case GOT_IMSG_PACKED_RAW_OBJECT_REQUEST:
1060 err = raw_object_request(&imsg, &ibuf, pack, packidx,
1061 &objcache);
1062 break;
1063 case GOT_IMSG_COMMIT_REQUEST:
1064 err = commit_request(&imsg, &ibuf, pack, packidx,
1065 &objcache);
1066 break;
1067 case GOT_IMSG_TREE_REQUEST:
1068 err = tree_request(&imsg, &ibuf, pack, packidx,
1069 &objcache);
1070 break;
1071 case GOT_IMSG_BLOB_REQUEST:
1072 err = blob_request(&imsg, &ibuf, pack, packidx,
1073 &objcache);
1074 break;
1075 case GOT_IMSG_TAG_REQUEST:
1076 err = tag_request(&imsg, &ibuf, pack, packidx,
1077 &objcache);
1078 break;
1079 case GOT_IMSG_COMMIT_TRAVERSAL_REQUEST:
1080 err = commit_traversal_request(&imsg, &ibuf, pack,
1081 packidx, &objcache);
1082 break;
1083 default:
1084 err = got_error(GOT_ERR_PRIVSEP_MSG);
1085 break;
1088 if (imsg.fd != -1 && close(imsg.fd) == -1 && err == NULL)
1089 err = got_error_from_errno("close");
1090 imsg_free(&imsg);
1091 if (err)
1092 break;
1095 if (packidx)
1096 got_packidx_close(packidx);
1097 if (pack)
1098 got_pack_close(pack);
1099 got_object_cache_close(&objcache);
1100 imsg_clear(&ibuf);
1101 if (err) {
1102 if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) {
1103 fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
1104 got_privsep_send_error(&ibuf, err);
1107 if (close(GOT_IMSG_FD_CHILD) == -1 && err == NULL)
1108 err = got_error_from_errno("close");
1109 return err ? 1 : 0;