2 * Copyright (c) 2018 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.
17 #include <sys/types.h>
19 #include <sys/queue.h>
21 #include <sys/socket.h>
23 #include <sys/syslimits.h>
38 #include "got_error.h"
39 #include "got_object.h"
40 #include "got_repository.h"
41 #include "got_opentemp.h"
43 #include "got_lib_sha1.h"
44 #include "got_lib_delta.h"
45 #include "got_lib_path.h"
46 #include "got_lib_inflate.h"
47 #include "got_lib_object.h"
48 #include "got_lib_privsep.h"
49 #include "got_lib_object_idcache.h"
50 #include "got_lib_object_cache.h"
51 #include "got_lib_object_parse.h"
52 #include "got_lib_pack.h"
53 #include "got_lib_repository.h"
56 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
59 struct got_object_id *
60 got_object_id_dup(struct got_object_id *id1)
62 struct got_object_id *id2;
64 id2 = malloc(sizeof(*id2));
67 memcpy(id2, id1, sizeof(*id2));
71 struct got_object_id *
72 got_object_get_id(struct got_object *obj)
77 const struct got_error *
78 got_object_get_id_str(char **outbuf, struct got_object *obj)
80 return got_object_id_str(outbuf, &obj->id);
83 const struct got_error *
84 got_object_get_type(int *type, struct got_repository *repo,
85 struct got_object_id *id)
87 const struct got_error *err = NULL;
88 struct got_object *obj;
90 err = got_object_open(&obj, repo, id);
95 case GOT_OBJ_TYPE_COMMIT:
96 case GOT_OBJ_TYPE_TREE:
97 case GOT_OBJ_TYPE_BLOB:
98 case GOT_OBJ_TYPE_TAG:
102 err = got_error(GOT_ERR_OBJ_TYPE);
106 got_object_close(obj);
110 static const struct got_error *
111 object_path(char **path, struct got_object_id *id, struct got_repository *repo)
113 const struct got_error *err = NULL;
115 char *path_objects = got_repo_get_path_objects(repo);
119 if (path_objects == NULL)
120 return got_error_from_errno();
122 err = got_object_id_str(&hex, id);
126 if (asprintf(path, "%s/%.2x/%s", path_objects,
127 id->sha1[0], hex + 2) == -1)
128 err = got_error_from_errno();
136 static const struct got_error *
137 open_loose_object(int *fd, struct got_object *obj, struct got_repository *repo)
139 const struct got_error *err = NULL;
142 err = object_path(&path, &obj->id, repo);
145 *fd = open(path, O_RDONLY | O_NOFOLLOW, GOT_DEFAULT_FILE_MODE);
147 err = got_error_from_errno();
155 static const struct got_error *
156 get_packfile_path(char **path_packfile, struct got_packidx *packidx)
160 /* Packfile path contains ".pack" instead of ".idx", so add one byte. */
161 size = strlen(packidx->path_packidx) + 2;
162 if (size < GOT_PACKFILE_NAMELEN + 1)
163 return got_error(GOT_ERR_BAD_PATH);
165 *path_packfile = malloc(size);
166 if (*path_packfile == NULL)
167 return got_error_from_errno();
169 /* Copy up to and excluding ".idx". */
170 if (strlcpy(*path_packfile, packidx->path_packidx,
171 size - strlen(GOT_PACKIDX_SUFFIX) - 1) >= size)
172 return got_error(GOT_ERR_NO_SPACE);
174 if (strlcat(*path_packfile, GOT_PACKFILE_SUFFIX, size) >= size)
175 return got_error(GOT_ERR_NO_SPACE);
180 static const struct got_error *
181 open_packed_object(struct got_object **obj, struct got_object_id *id,
182 struct got_repository *repo)
184 const struct got_error *err = NULL;
185 struct got_pack *pack = NULL;
186 struct got_packidx *packidx = NULL;
190 err = got_repo_search_packidx(&packidx, &idx, repo, id);
194 err = get_packfile_path(&path_packfile, packidx);
198 pack = got_repo_get_cached_pack(repo, path_packfile);
200 err = got_repo_cache_pack(&pack, repo, path_packfile, packidx);
205 err = got_object_packed_read_privsep(obj, repo, pack, packidx, idx, id);
209 err = got_repo_cache_pack(NULL, repo, (*obj)->path_packfile, packidx);
215 const struct got_error *
216 got_object_open(struct got_object **obj, struct got_repository *repo,
217 struct got_object_id *id)
219 const struct got_error *err = NULL;
223 *obj = got_repo_get_cached_object(repo, id);
229 err = open_packed_object(obj, id, repo);
230 if (err && err->code != GOT_ERR_NO_OBJ)
234 return got_repo_cache_object(repo, id, *obj);
237 err = object_path(&path, id, repo);
241 fd = open(path, O_RDONLY | O_NOFOLLOW, GOT_DEFAULT_FILE_MODE);
244 err = got_error_no_obj(id);
246 err = got_error_from_errno();
249 err = got_object_read_header_privsep(obj, repo, fd);
252 memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
256 err = got_repo_cache_object(repo, id, *obj);
265 const struct got_error *
266 got_object_open_by_id_str(struct got_object **obj, struct got_repository *repo,
269 struct got_object_id id;
271 if (!got_parse_sha1_digest(id.sha1, id_str))
272 return got_error(GOT_ERR_BAD_OBJ_ID_STR);
274 return got_object_open(obj, repo, &id);
277 const struct got_error *
278 got_object_resolve_id_str(struct got_object_id **id,
279 struct got_repository *repo, const char *id_str)
281 const struct got_error *err = NULL;
282 struct got_object *obj;
284 err = got_object_open_by_id_str(&obj, repo, id_str);
288 *id = got_object_id_dup(got_object_get_id(obj));
289 got_object_close(obj);
291 return got_error_from_errno();
296 static const struct got_error *
297 open_commit(struct got_commit_object **commit,
298 struct got_repository *repo, struct got_object *obj, int check_cache)
300 const struct got_error *err = NULL;
303 *commit = got_repo_get_cached_commit(repo, &obj->id);
304 if (*commit != NULL) {
311 if (obj->type != GOT_OBJ_TYPE_COMMIT)
312 return got_error(GOT_ERR_OBJ_TYPE);
314 if (obj->flags & GOT_OBJ_FLAG_PACKED) {
315 struct got_pack *pack;
316 pack = got_repo_get_cached_pack(repo, obj->path_packfile);
318 err = got_repo_cache_pack(&pack, repo,
319 obj->path_packfile, NULL);
323 err = got_object_read_packed_commit_privsep(commit, obj, pack);
326 err = open_loose_object(&fd, obj, repo);
329 err = got_object_read_commit_privsep(commit, obj, fd, repo);
335 err = got_repo_cache_commit(repo, &obj->id, *commit);
341 const struct got_error *
342 got_object_open_as_commit(struct got_commit_object **commit,
343 struct got_repository *repo, struct got_object_id *id)
345 const struct got_error *err;
346 struct got_object *obj;
348 *commit = got_repo_get_cached_commit(repo, id);
349 if (*commit != NULL) {
354 err = got_object_open(&obj, repo, id);
357 if (obj->type != GOT_OBJ_TYPE_COMMIT) {
358 err = got_error(GOT_ERR_OBJ_TYPE);
362 err = open_commit(commit, repo, obj, 0);
364 got_object_close(obj);
368 const struct got_error *
369 got_object_commit_open(struct got_commit_object **commit,
370 struct got_repository *repo, struct got_object *obj)
372 return open_commit(commit, repo, obj, 1);
375 const struct got_error *
376 got_object_qid_alloc(struct got_object_qid **qid, struct got_object_id *id)
378 const struct got_error *err = NULL;
380 *qid = calloc(1, sizeof(**qid));
382 return got_error_from_errno();
384 (*qid)->id = got_object_id_dup(id);
385 if ((*qid)->id == NULL) {
386 err = got_error_from_errno();
387 got_object_qid_free(*qid);
395 static const struct got_error *
396 open_tree(struct got_tree_object **tree,
397 struct got_repository *repo, struct got_object *obj, int check_cache)
399 const struct got_error *err = NULL;
402 *tree = got_repo_get_cached_tree(repo, &obj->id);
410 if (obj->type != GOT_OBJ_TYPE_TREE)
411 return got_error(GOT_ERR_OBJ_TYPE);
413 if (obj->flags & GOT_OBJ_FLAG_PACKED) {
414 struct got_pack *pack;
415 pack = got_repo_get_cached_pack(repo, obj->path_packfile);
417 err = got_repo_cache_pack(&pack, repo,
418 obj->path_packfile, NULL);
422 err = got_object_read_packed_tree_privsep(tree, obj, pack);
425 err = open_loose_object(&fd, obj, repo);
428 err = got_object_read_tree_privsep(tree, obj, fd, repo);
434 err = got_repo_cache_tree(repo, &obj->id, *tree);
440 const struct got_error *
441 got_object_open_as_tree(struct got_tree_object **tree,
442 struct got_repository *repo, struct got_object_id *id)
444 const struct got_error *err;
445 struct got_object *obj;
447 *tree = got_repo_get_cached_tree(repo, id);
453 err = got_object_open(&obj, repo, id);
456 if (obj->type != GOT_OBJ_TYPE_TREE) {
457 err = got_error(GOT_ERR_OBJ_TYPE);
461 err = open_tree(tree, repo, obj, 0);
463 got_object_close(obj);
467 const struct got_error *
468 got_object_tree_open(struct got_tree_object **tree,
469 struct got_repository *repo, struct got_object *obj)
471 return open_tree(tree, repo, obj, 1);
474 const struct got_tree_entries *
475 got_object_tree_get_entries(struct got_tree_object *tree)
477 return &tree->entries;
480 static const struct got_error *
481 read_packed_blob_privsep(size_t *size, int outfd, struct got_object *obj,
482 struct got_pack *pack)
484 const struct got_error *err = NULL;
486 int basefd, accumfd; /* temporary files for delta application */
488 basefd = got_opentempfd();
490 return got_error_from_errno();
491 accumfd = got_opentempfd();
493 return got_error_from_errno();
495 outfd_child = dup(outfd);
496 if (outfd_child == -1)
497 return got_error_from_errno();
499 err = got_privsep_send_obj_req(pack->privsep_child->ibuf, -1, obj);
503 err = got_privsep_send_blob_outfd(pack->privsep_child->ibuf,
509 err = got_privsep_send_tmpfd(pack->privsep_child->ibuf,
518 err = got_privsep_send_tmpfd(pack->privsep_child->ibuf,
526 err = got_privsep_recv_blob(size, pack->privsep_child->ibuf);
530 if (lseek(outfd, SEEK_SET, 0) == -1)
531 err = got_error_from_errno();
536 const struct got_error *
537 got_object_blob_open(struct got_blob_object **blob,
538 struct got_repository *repo, struct got_object *obj, size_t blocksize)
540 const struct got_error *err = NULL;
545 if (obj->type != GOT_OBJ_TYPE_BLOB)
546 return got_error(GOT_ERR_OBJ_TYPE);
548 if (blocksize < obj->hdrlen)
549 return got_error(GOT_ERR_NO_SPACE);
551 *blob = calloc(1, sizeof(**blob));
553 return got_error_from_errno();
555 outfd = got_opentempfd();
557 return got_error_from_errno();
559 (*blob)->read_buf = malloc(blocksize);
560 if ((*blob)->read_buf == NULL) {
561 err = got_error_from_errno();
564 if (obj->flags & GOT_OBJ_FLAG_PACKED) {
565 struct got_pack *pack;
566 pack = got_repo_get_cached_pack(repo, obj->path_packfile);
568 err = got_repo_cache_pack(&pack, repo,
569 obj->path_packfile, NULL);
573 err = read_packed_blob_privsep(&size, outfd, obj, pack);
580 err = open_loose_object(&infd, obj, repo);
584 err = got_object_read_blob_privsep(&size, outfd, infd, repo);
589 if (size != obj->hdrlen + obj->size) {
590 err = got_error(GOT_ERR_PRIVSEP_LEN);
595 if (fstat(outfd, &sb) == -1) {
596 err = got_error_from_errno();
600 if (sb.st_size != obj->hdrlen + obj->size) {
601 err = got_error(GOT_ERR_PRIVSEP_LEN);
605 (*blob)->f = fdopen(outfd, "rb");
606 if ((*blob)->f == NULL) {
607 err = got_error_from_errno();
612 (*blob)->hdrlen = obj->hdrlen;
613 (*blob)->blocksize = blocksize;
614 memcpy(&(*blob)->id.sha1, obj->id.sha1, SHA1_DIGEST_LENGTH);
621 free((*blob)->read_buf);
624 } else if (outfd != -1)
630 const struct got_error *
631 got_object_open_as_blob(struct got_blob_object **blob,
632 struct got_repository *repo, struct got_object_id *id,
635 const struct got_error *err;
636 struct got_object *obj;
640 err = got_object_open(&obj, repo, id);
643 if (obj->type != GOT_OBJ_TYPE_BLOB) {
644 err = got_error(GOT_ERR_OBJ_TYPE);
648 err = got_object_blob_open(blob, repo, obj, blocksize);
650 got_object_close(obj);
655 got_object_blob_close(struct got_blob_object *blob)
657 free(blob->read_buf);
663 got_object_blob_id_str(struct got_blob_object *blob, char *buf, size_t size)
665 return got_sha1_digest_to_str(blob->id.sha1, buf, size);
669 got_object_blob_get_hdrlen(struct got_blob_object *blob)
675 got_object_blob_get_read_buf(struct got_blob_object *blob)
677 return blob->read_buf;
680 const struct got_error *
681 got_object_blob_read_block(size_t *outlenp, struct got_blob_object *blob)
685 n = fread(blob->read_buf, 1, blob->blocksize, blob->f);
686 if (n == 0 && ferror(blob->f))
687 return got_ferror(blob->f, GOT_ERR_IO);
692 const struct got_error *
693 got_object_blob_dump_to_file(size_t *total_len, int *nlines,
694 FILE *outfile, struct got_blob_object *blob)
696 const struct got_error *err = NULL;
706 hdrlen = got_object_blob_get_hdrlen(blob);
708 err = got_object_blob_read_block(&len, blob);
715 buf = got_object_blob_get_read_buf(blob);
717 for (i = 0; i < len; i++) {
722 /* Skip blob object header first time around. */
723 fwrite(buf + hdrlen, len - hdrlen, 1, outfile);
733 static const struct got_error *
734 open_tag(struct got_tag_object **tag,
735 struct got_repository *repo, struct got_object *obj, int check_cache)
737 const struct got_error *err = NULL;
740 *tag = got_repo_get_cached_tag(repo, &obj->id);
748 if (obj->type != GOT_OBJ_TYPE_TAG)
749 return got_error(GOT_ERR_OBJ_TYPE);
751 if (obj->flags & GOT_OBJ_FLAG_PACKED) {
752 struct got_pack *pack;
753 pack = got_repo_get_cached_pack(repo, obj->path_packfile);
755 err = got_repo_cache_pack(&pack, repo,
756 obj->path_packfile, NULL);
760 err = got_object_read_packed_tag_privsep(tag, obj, pack);
763 err = open_loose_object(&fd, obj, repo);
766 err = got_object_read_tag_privsep(tag, obj, fd, repo);
772 err = got_repo_cache_tag(repo, &obj->id, *tag);
778 const struct got_error *
779 got_object_open_as_tag(struct got_tag_object **tag,
780 struct got_repository *repo, struct got_object_id *id)
782 const struct got_error *err;
783 struct got_object *obj;
785 *tag = got_repo_get_cached_tag(repo, id);
791 err = got_object_open(&obj, repo, id);
794 if (obj->type != GOT_OBJ_TYPE_COMMIT) {
795 err = got_error(GOT_ERR_OBJ_TYPE);
799 err = open_tag(tag, repo, obj, 0);
801 got_object_close(obj);
805 const struct got_error *
806 got_object_tag_open(struct got_tag_object **tag,
807 struct got_repository *repo, struct got_object *obj)
809 return open_tag(tag, repo, obj, 1);
812 static struct got_tree_entry *
813 find_entry_by_name(struct got_tree_object *tree, const char *name, size_t len)
815 struct got_tree_entry *te;
817 /* Note that tree entries are sorted in strncmp() order. */
818 SIMPLEQ_FOREACH(te, &tree->entries.head, entry) {
819 int cmp = strncmp(te->name, name, len);
824 if (te->name[len] == '\0')
830 const struct got_error *
831 got_object_id_by_path(struct got_object_id **id, struct got_repository *repo,
832 struct got_object_id *commit_id, const char *path)
834 const struct got_error *err = NULL;
835 struct got_commit_object *commit = NULL;
836 struct got_tree_object *tree = NULL;
837 struct got_tree_entry *te = NULL;
843 /* We are expecting an absolute in-repository path. */
845 return got_error(GOT_ERR_NOT_ABSPATH);
847 err = got_object_open_as_commit(&commit, repo, commit_id);
851 /* Handle opening of root of commit's tree. */
852 if (path[1] == '\0') {
853 *id = got_object_id_dup(commit->tree_id);
855 err = got_error_from_errno();
859 err = got_object_open_as_tree(&tree, repo, commit->tree_id);
864 s++; /* skip leading '/' */
868 struct got_tree_object *next_tree;
877 te = find_entry_by_name(tree, seg, seglen);
879 err = got_error(GOT_ERR_NO_TREE_ENTRY);
890 err = got_object_open_as_tree(&next_tree, repo,
895 got_object_tree_close(tree);
901 *id = got_object_id_dup(te->id);
903 return got_error_from_errno();
905 err = got_error(GOT_ERR_NO_TREE_ENTRY);
908 got_object_commit_close(commit);
910 got_object_tree_close(tree);
914 const struct got_error *
915 got_object_tree_path_changed(int *changed,
916 struct got_tree_object *tree01, struct got_tree_object *tree02,
917 const char *path, struct got_repository *repo)
919 const struct got_error *err = NULL;
920 struct got_tree_object *tree1 = NULL, *tree2 = NULL;
921 struct got_tree_entry *te1 = NULL, *te2 = NULL;
927 /* We are expecting an absolute in-repository path. */
929 return got_error(GOT_ERR_NOT_ABSPATH);
931 /* We not do support comparing the root path. */
933 return got_error(GOT_ERR_BAD_PATH);
938 s++; /* skip leading '/' */
942 struct got_tree_object *next_tree1, *next_tree2;
951 te1 = find_entry_by_name(tree1, seg, seglen);
953 err = got_error(GOT_ERR_NO_OBJ);
957 te2 = find_entry_by_name(tree2, seg, seglen);
963 if (te1->mode != te2->mode) {
968 if (got_object_id_cmp(te1->id, te2->id) == 0) {
973 if (*s == '\0') { /* final path element */
982 err = got_object_open_as_tree(&next_tree1, repo,
988 got_object_tree_close(tree1);
991 err = got_object_open_as_tree(&next_tree2, repo,
997 got_object_tree_close(tree2);
1002 if (tree1 && tree1 != tree01)
1003 got_object_tree_close(tree1);
1004 if (tree2 && tree2 != tree02)
1005 got_object_tree_close(tree2);
1010 exec_privsep_child(int imsg_fds[2], const char *path, const char *repo_path)
1014 if (dup2(imsg_fds[1], GOT_IMSG_FD_CHILD) == -1) {
1015 fprintf(stderr, "%s: %s\n", getprogname(),
1019 if (closefrom(GOT_IMSG_FD_CHILD + 1) == -1) {
1020 fprintf(stderr, "%s: %s\n", getprogname(),
1025 if (execl(path, path, repo_path, (char *)NULL) == -1) {
1026 fprintf(stderr, "%s: %s: %s\n", getprogname(), path,
1032 static const struct got_error *
1033 request_object(struct got_object **obj, struct got_repository *repo, int fd)
1035 const struct got_error *err = NULL;
1036 struct imsgbuf *ibuf;
1038 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf;
1040 err = got_privsep_send_obj_req(ibuf, fd, NULL);
1044 return got_privsep_recv_obj(obj, ibuf);
1047 const struct got_error *
1048 got_object_read_header_privsep(struct got_object **obj,
1049 struct got_repository *repo, int obj_fd)
1053 struct imsgbuf *ibuf;
1055 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1)
1056 return request_object(obj, repo, obj_fd);
1058 ibuf = calloc(1, sizeof(*ibuf));
1060 return got_error_from_errno();
1062 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
1063 return got_error_from_errno();
1067 return got_error_from_errno();
1068 else if (pid == 0) {
1069 exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_OBJECT,
1075 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd =
1077 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].pid = pid;
1078 imsg_init(ibuf, imsg_fds[0]);
1079 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf = ibuf;
1081 return request_object(obj, repo, obj_fd);
1084 static const struct got_error *
1085 request_packed_object(struct got_object **obj, struct got_pack *pack, int idx,
1086 struct got_object_id *id)
1088 const struct got_error *err = NULL;
1089 struct imsgbuf *ibuf = pack->privsep_child->ibuf;
1091 err = got_privsep_send_packed_obj_req(ibuf, idx, id);
1095 err = got_privsep_recv_obj(obj, ibuf);
1099 (*obj)->path_packfile = strdup(pack->path_packfile);
1100 if ((*obj)->path_packfile == NULL) {
1101 err = got_error_from_errno();
1104 memcpy(&(*obj)->id, id, sizeof((*obj)->id));
1109 const struct got_error *
1110 got_object_packed_read_privsep(struct got_object **obj,
1111 struct got_repository *repo, struct got_pack *pack,
1112 struct got_packidx *packidx, int idx, struct got_object_id *id)
1114 const struct got_error *err = NULL;
1117 struct imsgbuf *ibuf;
1119 if (pack->privsep_child)
1120 return request_packed_object(obj, pack, idx, id);
1122 ibuf = calloc(1, sizeof(*ibuf));
1124 return got_error_from_errno();
1126 pack->privsep_child = calloc(1, sizeof(*pack->privsep_child));
1127 if (pack->privsep_child == NULL) {
1128 err = got_error_from_errno();
1133 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) {
1134 err = got_error_from_errno();
1140 err = got_error_from_errno();
1142 } else if (pid == 0) {
1143 exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_PACK,
1144 pack->path_packfile);
1149 pack->privsep_child->imsg_fd = imsg_fds[0];
1150 pack->privsep_child->pid = pid;
1151 imsg_init(ibuf, imsg_fds[0]);
1152 pack->privsep_child->ibuf = ibuf;
1154 err = got_privsep_init_pack_child(ibuf, pack, packidx);
1156 const struct got_error *child_err;
1157 err = got_privsep_send_stop(pack->privsep_child->imsg_fd);
1158 child_err = got_privsep_wait_for_child(
1159 pack->privsep_child->pid);
1160 if (child_err && err == NULL)
1163 free(pack->privsep_child);
1164 pack->privsep_child = NULL;
1171 free(pack->privsep_child);
1172 pack->privsep_child = NULL;
1174 err = request_packed_object(obj, pack, idx, id);
1178 static const struct got_error *
1179 request_commit(struct got_commit_object **commit, struct got_repository *repo,
1180 struct got_object *obj, int fd)
1182 const struct got_error *err = NULL;
1183 struct imsgbuf *ibuf;
1185 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].ibuf;
1187 err = got_privsep_send_obj_req(ibuf, fd, obj);
1191 return got_privsep_recv_commit(commit, ibuf);
1194 const struct got_error *
1195 got_object_read_packed_commit_privsep(struct got_commit_object **commit,
1196 struct got_object *obj, struct got_pack *pack)
1198 const struct got_error *err = NULL;
1200 err = got_privsep_send_obj_req(pack->privsep_child->ibuf, -1, obj);
1204 return got_privsep_recv_commit(commit, pack->privsep_child->ibuf);
1207 const struct got_error *
1208 got_object_read_commit_privsep(struct got_commit_object **commit,
1209 struct got_object *obj, int obj_fd, struct got_repository *repo)
1213 struct imsgbuf *ibuf;
1215 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd != -1)
1216 return request_commit(commit, repo, obj, obj_fd);
1218 ibuf = calloc(1, sizeof(*ibuf));
1220 return got_error_from_errno();
1222 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
1223 return got_error_from_errno();
1227 return got_error_from_errno();
1228 else if (pid == 0) {
1229 exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_COMMIT,
1235 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd =
1237 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].pid = pid;
1238 imsg_init(ibuf, imsg_fds[0]);
1239 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].ibuf = ibuf;
1241 return request_commit(commit, repo, obj, obj_fd);
1244 static const struct got_error *
1245 request_tree(struct got_tree_object **tree, struct got_repository *repo,
1246 struct got_object *obj, int fd)
1248 const struct got_error *err = NULL;
1249 struct imsgbuf *ibuf;
1251 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].ibuf;
1253 err = got_privsep_send_obj_req(ibuf, fd, obj);
1257 return got_privsep_recv_tree(tree, ibuf);
1260 const struct got_error *
1261 got_object_read_tree_privsep(struct got_tree_object **tree,
1262 struct got_object *obj, int obj_fd, struct got_repository *repo)
1266 struct imsgbuf *ibuf;
1268 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd != -1)
1269 return request_tree(tree, repo, obj, obj_fd);
1271 ibuf = calloc(1, sizeof(*ibuf));
1273 return got_error_from_errno();
1275 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
1276 return got_error_from_errno();
1280 return got_error_from_errno();
1281 else if (pid == 0) {
1282 exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_TREE,
1289 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd =
1291 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].pid = pid;
1292 imsg_init(ibuf, imsg_fds[0]);
1293 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].ibuf = ibuf;
1296 return request_tree(tree, repo, obj, obj_fd);
1299 const struct got_error *
1300 got_object_read_packed_tree_privsep(struct got_tree_object **tree,
1301 struct got_object *obj, struct got_pack *pack)
1303 const struct got_error *err = NULL;
1305 err = got_privsep_send_obj_req(pack->privsep_child->ibuf, -1, obj);
1309 return got_privsep_recv_tree(tree, pack->privsep_child->ibuf);
1312 static const struct got_error *
1313 request_blob(size_t *size, int outfd, int infd, struct imsgbuf *ibuf)
1315 const struct got_error *err = NULL;
1318 outfd_child = dup(outfd);
1319 if (outfd_child == -1)
1320 return got_error_from_errno();
1322 err = got_privsep_send_blob_req(ibuf, infd);
1326 err = got_privsep_send_blob_outfd(ibuf, outfd_child);
1332 err = got_privsep_recv_blob(size, ibuf);
1336 if (lseek(outfd, SEEK_SET, 0) == -1)
1337 return got_error_from_errno();
1342 const struct got_error *
1343 got_object_read_blob_privsep(size_t *size, int outfd, int infd,
1344 struct got_repository *repo)
1348 struct imsgbuf *ibuf;
1350 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd != -1) {
1351 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf;
1352 return request_blob(size, outfd, infd, ibuf);
1355 ibuf = calloc(1, sizeof(*ibuf));
1357 return got_error_from_errno();
1359 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
1360 return got_error_from_errno();
1364 return got_error_from_errno();
1365 else if (pid == 0) {
1366 exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_BLOB,
1372 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd =
1374 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].pid = pid;
1375 imsg_init(ibuf, imsg_fds[0]);
1376 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf = ibuf;
1378 return request_blob(size, outfd, infd, ibuf);
1381 static const struct got_error *
1382 request_tag(struct got_tag_object **tag, struct got_repository *repo,
1383 struct got_object *obj, int fd)
1385 const struct got_error *err = NULL;
1386 struct imsgbuf *ibuf;
1388 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].ibuf;
1390 err = got_privsep_send_obj_req(ibuf, fd, obj);
1394 return got_privsep_recv_tag(tag, ibuf);
1397 const struct got_error *
1398 got_object_read_packed_tag_privsep(struct got_tag_object **tag,
1399 struct got_object *obj, struct got_pack *pack)
1401 const struct got_error *err = NULL;
1403 err = got_privsep_send_obj_req(pack->privsep_child->ibuf, -1, obj);
1407 return got_privsep_recv_tag(tag, pack->privsep_child->ibuf);
1410 const struct got_error *
1411 got_object_read_tag_privsep(struct got_tag_object **tag,
1412 struct got_object *obj, int obj_fd, struct got_repository *repo)
1416 struct imsgbuf *ibuf;
1418 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].imsg_fd != -1)
1419 return request_tag(tag, repo, obj, obj_fd);
1421 ibuf = calloc(1, sizeof(*ibuf));
1423 return got_error_from_errno();
1425 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
1426 return got_error_from_errno();
1430 return got_error_from_errno();
1431 else if (pid == 0) {
1432 exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_TAG,
1438 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].imsg_fd =
1440 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].pid = pid;
1441 imsg_init(ibuf, imsg_fds[0]);
1442 repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].ibuf = ibuf;
1444 return request_tag(tag, repo, obj, obj_fd);