commit b61ceafcc71b10ab2295bf09b9ddb34a07666f73 from: Stefan Sperling via: Thomas Adam date: Thu Oct 13 19:35:13 2022 UTC move functions which open objects into new file object_open_privsep.c For the future, this will make it possible to provide alternative implementations of functions now stored in object_open_privsep.c. This will probably be needed by future gotd(8) which runs inside a chroot(2) environment and without the "exec" pledge(2) promise, making it impossible to run libexec helpers on the fly. Details of this design are not yet settled, but moving functions into a separate compilation unit won't hurt in any case. commit - c639c9205a410cf7f3535d3ae7f17d2483f2bdfa commit + b61ceafcc71b10ab2295bf09b9ddb34a07666f73 blob - fc6eb096a39e9f187ac3455284648c233358aaf0 blob + 9cde7b165444414f71261f8f2c60b8e8172cbea5 --- Makefile.am +++ Makefile.am @@ -59,6 +59,7 @@ regress-delta: $(top_srcdir)/lib/path.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/sha1.c \ + $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/regress/delta/delta_test.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/delta/delta_test @@ -72,6 +73,7 @@ regress-deltify: $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/sha1.c \ $(top_srcdir)/lib/murmurhash2.c \ + $(top_srcdir)/lib/object_open_privsep.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/deltify/deltify_test @@ -90,6 +92,7 @@ regress-fetch: $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/lockfile.c \ $(top_srcdir)/lib/object_cache.c \ + $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/pack.c \ $(top_srcdir)/lib/inflate.c \ $(top_srcdir)/lib/deflate.c \ @@ -97,6 +100,7 @@ regress-fetch: $(top_srcdir)/lib/delta_cache.c \ $(top_srcdir)/lib/object_idset.c \ $(top_srcdir)/lib/object_create.c \ + $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/fetch.c \ $(top_srcdir)/lib/gotconfig.c \ $(top_srcdir)/lib/dial.c \ @@ -128,5 +132,6 @@ regress-path: $(top_srcdir)/lib/error.c \ $(top_srcdir)/lib/sha1.c \ $(top_srcdir)/lib/path.c \ + $(top_srcdir)/lib/object_open_privsep.c \ -L$(top_builddir)/compat -lopenbsd-compat $(LIBS) && \ $(top_builddir)/regress/path/path_test blob - 2cfcb9975bf6d254fc3274e5ac625e34a64a60db blob + d2ed6174b7b559747661a63aa31f4e54628c99d6 --- got/Makefile.am +++ got/Makefile.am @@ -14,6 +14,7 @@ got_SOURCES = got.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_idset.c \ + $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/patch.c \ blob - 082d306add812b4b36ff4a52d04ea2c4e5706499 blob + 4c2e510946744eb3108d37d94116401e7b8f37c1 --- gotadmin/Makefile.am +++ gotadmin/Makefile.am @@ -15,6 +15,7 @@ gotadmin_SOURCES = gotadmin.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ + $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ blob - 948b9b8fc5270878f0eb2aa61a579197663e4827 blob + dc0086e6c8467903bee24745d317a83ca20c538a --- gotweb/Makefile +++ gotweb/Makefile @@ -15,7 +15,7 @@ SRCS = gotweb.c parse.y blame.c commit_graph.c delta. diff_main.c diff_atomize_text.c diff_myers.c diff_output.c \ diff_output_plain.c diff_output_unidiff.c \ diff_output_edscript.c diff_patience.c \ - bloom.c murmurhash2.c sigs.c date.c + bloom.c murmurhash2.c sigs.c date.c object_open_privsep.c MAN = ${PROG}.conf.5 ${PROG}.8 CPPFLAGS += -I${.CURDIR}/../include -I${.CURDIR}/../lib -I${.CURDIR} \ blob - d2ae13f7dcd10bf3773b331dca85370d6b5d7802 blob + 0815870f33f1ad8613553f86364320c7053fb0f0 --- gotwebd/Makefile.am +++ gotwebd/Makefile.am @@ -40,6 +40,7 @@ gotwebd_SOURCES = config.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_create.c \ $(top_srcdir)/lib/object_idset.c \ + $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/pack.c \ blob - 053eb0ba5b9cf91bc1ea8f179cf16d57da981f43 blob + 5817d7e63b2ede78e8dceb809b4c2faff58ea9f6 --- lib/object.c +++ lib/object.c @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include @@ -27,13 +25,12 @@ #include #include #include -#include +#include #include #include -#include #include #include -#include +#include #include "got_compat.h" @@ -147,517 +144,9 @@ got_object_open_loose_fd(int *fd, struct got_object_id done: free(path); return err; -} - -static const struct got_error * -request_packed_object(struct got_object **obj, struct got_pack *pack, int idx, - struct got_object_id *id) -{ - const struct got_error *err = NULL; - struct imsgbuf *ibuf = pack->privsep_child->ibuf; - - err = got_privsep_send_packed_obj_req(ibuf, idx, id); - if (err) - return err; - - err = got_privsep_recv_obj(obj, ibuf); - if (err) - return err; - - memcpy(&(*obj)->id, id, sizeof((*obj)->id)); - - return NULL; -} - -/* Create temporary files used during delta application. */ -static const struct got_error * -pack_child_send_tempfiles(struct imsgbuf *ibuf, struct got_pack *pack) -{ - const struct got_error *err; - int basefd = -1, accumfd = -1; - - /* - * For performance reasons, the child will keep reusing the - * same temporary files during every object request. - * Opening and closing new files for every object request is - * too expensive during operations such as 'gotadmin pack'. - */ - if (pack->child_has_tempfiles) - return NULL; - - basefd = dup(pack->basefd); - if (basefd == -1) - return got_error_from_errno("dup"); - - accumfd = dup(pack->accumfd); - if (accumfd == -1) { - err = got_error_from_errno("dup"); - goto done; - } - - err = got_privsep_send_tmpfd(ibuf, basefd); - if (err) - goto done; - - err = got_privsep_send_tmpfd(ibuf, accumfd); -done: - if (err) { - if (basefd != -1) - close(basefd); - if (accumfd != -1) - close(accumfd); - } else - pack->child_has_tempfiles = 1; - return NULL; -} - -static const struct got_error * -request_packed_object_raw(uint8_t **outbuf, off_t *size, size_t *hdrlen, - int outfd, struct got_pack *pack, int idx, struct got_object_id *id) -{ - const struct got_error *err = NULL; - struct imsgbuf *ibuf = pack->privsep_child->ibuf; - int outfd_child; - - err = pack_child_send_tempfiles(ibuf, pack); - if (err) - return err; - - outfd_child = dup(outfd); - if (outfd_child == -1) - return got_error_from_errno("dup"); - - err = got_privsep_send_packed_raw_obj_req(ibuf, idx, id); - if (err) { - close(outfd_child); - return err; - } - - err = got_privsep_send_raw_obj_outfd(ibuf, outfd_child); - if (err) - return err; - - err = got_privsep_recv_raw_obj(outbuf, size, hdrlen, ibuf); - if (err) - return err; - - return NULL; -} - -static const struct got_error * -read_packed_object_privsep(struct got_object **obj, - struct got_repository *repo, struct got_pack *pack, - struct got_packidx *packidx, int idx, struct got_object_id *id) -{ - const struct got_error *err = NULL; - - if (pack->privsep_child == NULL) { - err = got_pack_start_privsep_child(pack, packidx); - if (err) - return err; - } - - return request_packed_object(obj, pack, idx, id); -} - -static const struct got_error * -read_packed_object_raw_privsep(uint8_t **outbuf, off_t *size, size_t *hdrlen, - int outfd, struct got_pack *pack, struct got_packidx *packidx, int idx, - struct got_object_id *id) -{ - const struct got_error *err = NULL; - - if (pack->privsep_child == NULL) { - err = got_pack_start_privsep_child(pack, packidx); - if (err) - return err; - } - - return request_packed_object_raw(outbuf, size, hdrlen, outfd, pack, - idx, id); -} - -const struct got_error * -got_object_open_packed(struct got_object **obj, struct got_object_id *id, - struct got_repository *repo) -{ - const struct got_error *err = NULL; - struct got_pack *pack = NULL; - struct got_packidx *packidx = NULL; - int idx; - char *path_packfile; - - err = got_repo_search_packidx(&packidx, &idx, repo, id); - if (err) - return err; - - err = got_packidx_get_packfile_path(&path_packfile, - packidx->path_packidx); - if (err) - return err; - - pack = got_repo_get_cached_pack(repo, path_packfile); - if (pack == NULL) { - err = got_repo_cache_pack(&pack, repo, path_packfile, packidx); - if (err) - goto done; - } - - err = read_packed_object_privsep(obj, repo, pack, packidx, idx, id); - if (err) - goto done; -done: - free(path_packfile); - return err; -} - -const struct got_error * -got_object_open_from_packfile(struct got_object **obj, struct got_object_id *id, - struct got_pack *pack, struct got_packidx *packidx, int obj_idx, - struct got_repository *repo) -{ - return read_packed_object_privsep(obj, repo, pack, packidx, - obj_idx, id); -} - -const struct got_error * -got_object_read_raw_delta(uint64_t *base_size, uint64_t *result_size, - off_t *delta_size, off_t *delta_compressed_size, off_t *delta_offset, - off_t *delta_out_offset, struct got_object_id **base_id, int delta_cache_fd, - struct got_packidx *packidx, int obj_idx, struct got_object_id *id, - struct got_repository *repo) -{ - const struct got_error *err = NULL; - struct got_pack *pack = NULL; - char *path_packfile; - - *base_size = 0; - *result_size = 0; - *delta_size = 0; - *delta_compressed_size = 0; - *delta_offset = 0; - *delta_out_offset = 0; - - err = got_packidx_get_packfile_path(&path_packfile, - packidx->path_packidx); - if (err) - return err; - - pack = got_repo_get_cached_pack(repo, path_packfile); - if (pack == NULL) { - err = got_repo_cache_pack(&pack, repo, path_packfile, packidx); - if (err) - return err; - } - - if (pack->privsep_child == NULL) { - err = got_pack_start_privsep_child(pack, packidx); - if (err) - return err; - } - - if (!pack->child_has_delta_outfd) { - int outfd_child; - outfd_child = dup(delta_cache_fd); - if (outfd_child == -1) - return got_error_from_errno("dup"); - err = got_privsep_send_raw_delta_outfd( - pack->privsep_child->ibuf, outfd_child); - if (err) - return err; - pack->child_has_delta_outfd = 1; - } - - err = got_privsep_send_raw_delta_req(pack->privsep_child->ibuf, - obj_idx, id); - if (err) - return err; - - return got_privsep_recv_raw_delta(base_size, result_size, delta_size, - delta_compressed_size, delta_offset, delta_out_offset, base_id, - pack->privsep_child->ibuf); } -static const struct got_error * -request_object(struct got_object **obj, struct got_object_id *id, - struct got_repository *repo, int fd) -{ - const struct got_error *err = NULL; - struct imsgbuf *ibuf; - - ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf; - - err = got_privsep_send_obj_req(ibuf, fd, id); - if (err) - return err; - - return got_privsep_recv_obj(obj, ibuf); -} - -static const struct got_error * -request_raw_object(uint8_t **outbuf, off_t *size, size_t *hdrlen, int outfd, - struct got_object_id *id, struct got_repository *repo, int infd) -{ - const struct got_error *err = NULL; - struct imsgbuf *ibuf; - int outfd_child; - - ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf; - - outfd_child = dup(outfd); - if (outfd_child == -1) - return got_error_from_errno("dup"); - - err = got_privsep_send_raw_obj_req(ibuf, infd, id); - if (err) - return err; - - err = got_privsep_send_raw_obj_outfd(ibuf, outfd_child); - if (err) - return err; - - return got_privsep_recv_raw_obj(outbuf, size, hdrlen, ibuf); -} - -static const struct got_error * -start_read_object_child(struct got_repository *repo) -{ - const struct got_error *err = NULL; - int imsg_fds[2]; - pid_t pid; - struct imsgbuf *ibuf; - - ibuf = calloc(1, sizeof(*ibuf)); - if (ibuf == NULL) - return got_error_from_errno("calloc"); - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { - err = got_error_from_errno("socketpair"); - free(ibuf); - return err; - } - - pid = fork(); - if (pid == -1) { - err = got_error_from_errno("fork"); - free(ibuf); - return err; - } - else if (pid == 0) { - got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_OBJECT, - repo->path); - /* not reached */ - } - - if (close(imsg_fds[1]) == -1) { - err = got_error_from_errno("close"); - free(ibuf); - return err; - } - - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd = - imsg_fds[0]; - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].pid = pid; - imsg_init(ibuf, imsg_fds[0]); - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf = ibuf; - - return NULL; -} - const struct got_error * -got_object_read_header_privsep(struct got_object **obj, - struct got_object_id *id, struct got_repository *repo, int obj_fd) -{ - const struct got_error *err; - - if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1) - return request_object(obj, id, repo, obj_fd); - - err = start_read_object_child(repo); - if (err) { - close(obj_fd); - return err; - } - - return request_object(obj, id, repo, obj_fd); -} - -static const struct got_error * -read_object_raw_privsep(uint8_t **outbuf, off_t *size, size_t *hdrlen, - int outfd, struct got_object_id *id, struct got_repository *repo, - int obj_fd) -{ - const struct got_error *err; - - if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1) - return request_raw_object(outbuf, size, hdrlen, outfd, id, - repo, obj_fd); - - err = start_read_object_child(repo); - if (err) - return err; - - return request_raw_object(outbuf, size, hdrlen, outfd, id, repo, - obj_fd); -} - -const struct got_error * -got_object_open(struct got_object **obj, struct got_repository *repo, - struct got_object_id *id) -{ - const struct got_error *err = NULL; - int fd; - - *obj = got_repo_get_cached_object(repo, id); - if (*obj != NULL) { - (*obj)->refcnt++; - return NULL; - } - - err = got_object_open_packed(obj, id, repo); - if (err && err->code != GOT_ERR_NO_OBJ) - return err; - if (*obj) { - (*obj)->refcnt++; - return got_repo_cache_object(repo, id, *obj); - } - - err = got_object_open_loose_fd(&fd, id, repo); - if (err) { - if (err->code == GOT_ERR_ERRNO && errno == ENOENT) - err = got_error_no_obj(id); - return err; - } - - err = got_object_read_header_privsep(obj, id, repo, fd); - if (err) - return err; - - memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH); - - (*obj)->refcnt++; - return got_repo_cache_object(repo, id, *obj); -} - -/* *outfd must be initialized to -1 by caller */ -const struct got_error * -got_object_raw_open(struct got_raw_object **obj, int *outfd, - struct got_repository *repo, struct got_object_id *id) -{ - const struct got_error *err = NULL; - struct got_packidx *packidx = NULL; - int idx; - uint8_t *outbuf = NULL; - off_t size = 0; - size_t hdrlen = 0; - char *path_packfile = NULL; - - *obj = got_repo_get_cached_raw_object(repo, id); - if (*obj != NULL) { - (*obj)->refcnt++; - return NULL; - } - - if (*outfd == -1) { - *outfd = got_opentempfd(); - if (*outfd == -1) - return got_error_from_errno("got_opentempfd"); - } - - err = got_repo_search_packidx(&packidx, &idx, repo, id); - if (err == NULL) { - struct got_pack *pack = NULL; - - err = got_packidx_get_packfile_path(&path_packfile, - packidx->path_packidx); - if (err) - goto done; - - pack = got_repo_get_cached_pack(repo, path_packfile); - if (pack == NULL) { - err = got_repo_cache_pack(&pack, repo, path_packfile, - packidx); - if (err) - goto done; - } - err = read_packed_object_raw_privsep(&outbuf, &size, &hdrlen, - *outfd, pack, packidx, idx, id); - if (err) - goto done; - } else if (err->code == GOT_ERR_NO_OBJ) { - int fd; - - err = got_object_open_loose_fd(&fd, id, repo); - if (err) - goto done; - err = read_object_raw_privsep(&outbuf, &size, &hdrlen, *outfd, - id, repo, fd); - if (err) - goto done; - } - - *obj = calloc(1, sizeof(**obj)); - if (*obj == NULL) { - err = got_error_from_errno("calloc"); - goto done; - } - (*obj)->fd = -1; - - if (outbuf) { - (*obj)->data = outbuf; - } else { - struct stat sb; - if (fstat(*outfd, &sb) == -1) { - err = got_error_from_errno("fstat"); - goto done; - } - - if (sb.st_size != hdrlen + size) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } -#ifndef GOT_PACK_NO_MMAP - if (hdrlen + size > 0) { - (*obj)->data = mmap(NULL, hdrlen + size, PROT_READ, - MAP_PRIVATE, *outfd, 0); - if ((*obj)->data == MAP_FAILED) { - if (errno != ENOMEM) { - err = got_error_from_errno("mmap"); - goto done; - } - (*obj)->data = NULL; - } else { - (*obj)->fd = *outfd; - *outfd = -1; - } - } -#endif - if (*outfd != -1) { - (*obj)->f = fdopen(*outfd, "r"); - if ((*obj)->f == NULL) { - err = got_error_from_errno("fdopen"); - goto done; - } - *outfd = -1; - } - } - (*obj)->hdrlen = hdrlen; - (*obj)->size = size; - err = got_repo_cache_raw_object(repo, id, *obj); -done: - free(path_packfile); - if (err) { - if (*obj) { - got_object_raw_close(*obj); - *obj = NULL; - } - free(outbuf); - } else - (*obj)->refcnt++; - return err; -} - -const struct got_error * got_object_open_by_id_str(struct got_object **obj, struct got_repository *repo, const char *id_str) { @@ -688,182 +177,7 @@ got_object_resolve_id_str(struct got_object_id **id, return NULL; } -static const struct got_error * -request_packed_commit(struct got_commit_object **commit, struct got_pack *pack, - int pack_idx, struct got_object_id *id) -{ - const struct got_error *err = NULL; - - err = got_privsep_send_commit_req(pack->privsep_child->ibuf, -1, id, - pack_idx); - if (err) - return err; - - err = got_privsep_recv_commit(commit, pack->privsep_child->ibuf); - if (err) - return err; - - (*commit)->flags |= GOT_COMMIT_FLAG_PACKED; - return NULL; -} - -static const struct got_error * -read_packed_commit_privsep(struct got_commit_object **commit, - struct got_pack *pack, struct got_packidx *packidx, int idx, - struct got_object_id *id) -{ - const struct got_error *err = NULL; - - if (pack->privsep_child) - return request_packed_commit(commit, pack, idx, id); - - err = got_pack_start_privsep_child(pack, packidx); - if (err) - return err; - - return request_packed_commit(commit, pack, idx, id); -} - -static const struct got_error * -request_commit(struct got_commit_object **commit, struct got_repository *repo, - int fd, struct got_object_id *id) -{ - const struct got_error *err = NULL; - struct imsgbuf *ibuf; - - ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].ibuf; - - err = got_privsep_send_commit_req(ibuf, fd, id, -1); - if (err) - return err; - - return got_privsep_recv_commit(commit, ibuf); -} - -static const struct got_error * -read_commit_privsep(struct got_commit_object **commit, int obj_fd, - struct got_object_id *id, struct got_repository *repo) -{ - const struct got_error *err; - int imsg_fds[2]; - pid_t pid; - struct imsgbuf *ibuf; - - if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd != -1) - return request_commit(commit, repo, obj_fd, id); - - ibuf = calloc(1, sizeof(*ibuf)); - if (ibuf == NULL) - return got_error_from_errno("calloc"); - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { - err = got_error_from_errno("socketpair"); - free(ibuf); - return err; - } - - pid = fork(); - if (pid == -1) { - err = got_error_from_errno("fork"); - free(ibuf); - return err; - } - else if (pid == 0) { - got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_COMMIT, - repo->path); - /* not reached */ - } - - if (close(imsg_fds[1]) == -1) { - err = got_error_from_errno("close"); - free(ibuf); - return err; - } - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd = - imsg_fds[0]; - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].pid = pid; - imsg_init(ibuf, imsg_fds[0]); - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].ibuf = ibuf; - - return request_commit(commit, repo, obj_fd, id); -} - - -static const struct got_error * -open_commit(struct got_commit_object **commit, - struct got_repository *repo, struct got_object_id *id, int check_cache) -{ - const struct got_error *err = NULL; - struct got_packidx *packidx = NULL; - int idx; - char *path_packfile = NULL; - - if (check_cache) { - *commit = got_repo_get_cached_commit(repo, id); - if (*commit != NULL) { - (*commit)->refcnt++; - return NULL; - } - } else - *commit = NULL; - - err = got_repo_search_packidx(&packidx, &idx, repo, id); - if (err == NULL) { - struct got_pack *pack = NULL; - - err = got_packidx_get_packfile_path(&path_packfile, - packidx->path_packidx); - if (err) - return err; - - pack = got_repo_get_cached_pack(repo, path_packfile); - if (pack == NULL) { - err = got_repo_cache_pack(&pack, repo, path_packfile, - packidx); - if (err) - goto done; - } - err = read_packed_commit_privsep(commit, pack, - packidx, idx, id); - } else if (err->code == GOT_ERR_NO_OBJ) { - int fd; - - err = got_object_open_loose_fd(&fd, id, repo); - if (err) - return err; - err = read_commit_privsep(commit, fd, id, repo); - } - - if (err == NULL) { - (*commit)->refcnt++; - err = got_repo_cache_commit(repo, id, *commit); - } -done: - free(path_packfile); - return err; -} - const struct got_error * -got_object_open_as_commit(struct got_commit_object **commit, - struct got_repository *repo, struct got_object_id *id) -{ - *commit = got_repo_get_cached_commit(repo, id); - if (*commit != NULL) { - (*commit)->refcnt++; - return NULL; - } - - return open_commit(commit, repo, id, 0); -} - -const struct got_error * -got_object_commit_open(struct got_commit_object **commit, - struct got_repository *repo, struct got_object *obj) -{ - return open_commit(commit, repo, got_object_get_id(obj), 1); -} - -const struct got_error * got_object_qid_alloc(struct got_object_qid **qid, struct got_object_id *id) { *qid = calloc(1, sizeof(**qid)); @@ -896,178 +210,8 @@ got_object_id_queue_copy(const struct got_object_id_qu } return NULL; -} - -static const struct got_error * -request_packed_tree(struct got_tree_object **tree, struct got_pack *pack, - int pack_idx, struct got_object_id *id) -{ - const struct got_error *err = NULL; - - err = got_privsep_send_tree_req(pack->privsep_child->ibuf, -1, id, - pack_idx); - if (err) - return err; - - return got_privsep_recv_tree(tree, pack->privsep_child->ibuf); -} - -static const struct got_error * -read_packed_tree_privsep(struct got_tree_object **tree, - struct got_pack *pack, struct got_packidx *packidx, int idx, - struct got_object_id *id) -{ - const struct got_error *err = NULL; - - if (pack->privsep_child) - return request_packed_tree(tree, pack, idx, id); - - err = got_pack_start_privsep_child(pack, packidx); - if (err) - return err; - - return request_packed_tree(tree, pack, idx, id); -} - -static const struct got_error * -request_tree(struct got_tree_object **tree, struct got_repository *repo, - int fd, struct got_object_id *id) -{ - const struct got_error *err = NULL; - struct imsgbuf *ibuf; - - ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].ibuf; - - err = got_privsep_send_tree_req(ibuf, fd, id, -1); - if (err) - return err; - - return got_privsep_recv_tree(tree, ibuf); } -static const struct got_error * -read_tree_privsep(struct got_tree_object **tree, int obj_fd, - struct got_object_id *id, struct got_repository *repo) -{ - const struct got_error *err; - int imsg_fds[2]; - pid_t pid; - struct imsgbuf *ibuf; - - if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd != -1) - return request_tree(tree, repo, obj_fd, id); - - ibuf = calloc(1, sizeof(*ibuf)); - if (ibuf == NULL) - return got_error_from_errno("calloc"); - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { - err = got_error_from_errno("socketpair"); - free(ibuf); - return err; - } - - pid = fork(); - if (pid == -1) { - err = got_error_from_errno("fork"); - free(ibuf); - return err; - } - else if (pid == 0) { - got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_TREE, - repo->path); - /* not reached */ - } - - if (close(imsg_fds[1]) == -1) { - err = got_error_from_errno("close"); - free(ibuf); - return err; - } - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd = - imsg_fds[0]; - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].pid = pid; - imsg_init(ibuf, imsg_fds[0]); - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].ibuf = ibuf; - - - return request_tree(tree, repo, obj_fd, id); -} - -static const struct got_error * -open_tree(struct got_tree_object **tree, struct got_repository *repo, - struct got_object_id *id, int check_cache) -{ - const struct got_error *err = NULL; - struct got_packidx *packidx = NULL; - int idx; - char *path_packfile = NULL; - - if (check_cache) { - *tree = got_repo_get_cached_tree(repo, id); - if (*tree != NULL) { - (*tree)->refcnt++; - return NULL; - } - } else - *tree = NULL; - - err = got_repo_search_packidx(&packidx, &idx, repo, id); - if (err == NULL) { - struct got_pack *pack = NULL; - - err = got_packidx_get_packfile_path(&path_packfile, - packidx->path_packidx); - if (err) - return err; - - pack = got_repo_get_cached_pack(repo, path_packfile); - if (pack == NULL) { - err = got_repo_cache_pack(&pack, repo, path_packfile, - packidx); - if (err) - goto done; - } - err = read_packed_tree_privsep(tree, pack, - packidx, idx, id); - } else if (err->code == GOT_ERR_NO_OBJ) { - int fd; - - err = got_object_open_loose_fd(&fd, id, repo); - if (err) - return err; - err = read_tree_privsep(tree, fd, id, repo); - } - - if (err == NULL) { - (*tree)->refcnt++; - err = got_repo_cache_tree(repo, id, *tree); - } -done: - free(path_packfile); - return err; -} - -const struct got_error * -got_object_open_as_tree(struct got_tree_object **tree, - struct got_repository *repo, struct got_object_id *id) -{ - *tree = got_repo_get_cached_tree(repo, id); - if (*tree != NULL) { - (*tree)->refcnt++; - return NULL; - } - - return open_tree(tree, repo, id, 0); -} - -const struct got_error * -got_object_tree_open(struct got_tree_object **tree, - struct got_repository *repo, struct got_object *obj) -{ - return open_tree(tree, repo, got_object_get_id(obj), 1); -} - int got_object_tree_get_nentries(struct got_tree_object *tree) { @@ -1208,275 +352,9 @@ got_tree_entry_get_prev(struct got_tree_object *tree, struct got_tree_entry *te) { return got_object_tree_get_entry(tree, te->idx - 1); -} - -static const struct got_error * -request_packed_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen, int outfd, - struct got_pack *pack, struct got_packidx *packidx, int idx, - struct got_object_id *id) -{ - const struct got_error *err = NULL; - struct imsgbuf *ibuf = pack->privsep_child->ibuf; - int outfd_child; - - err = pack_child_send_tempfiles(ibuf, pack); - if (err) - return err; - - outfd_child = dup(outfd); - if (outfd_child == -1) - return got_error_from_errno("dup"); - - err = got_privsep_send_blob_req(pack->privsep_child->ibuf, -1, id, idx); - if (err) - return err; - - err = got_privsep_send_blob_outfd(pack->privsep_child->ibuf, - outfd_child); - if (err) { - return err; - } - - err = got_privsep_recv_blob(outbuf, size, hdrlen, - pack->privsep_child->ibuf); - if (err) - return err; - - if (lseek(outfd, SEEK_SET, 0) == -1) - err = got_error_from_errno("lseek"); - - return err; -} - -static const struct got_error * -read_packed_blob_privsep(uint8_t **outbuf, size_t *size, size_t *hdrlen, - int outfd, struct got_pack *pack, struct got_packidx *packidx, int idx, - struct got_object_id *id) -{ - const struct got_error *err = NULL; - - if (pack->privsep_child == NULL) { - err = got_pack_start_privsep_child(pack, packidx); - if (err) - return err; - } - - return request_packed_blob(outbuf, size, hdrlen, outfd, pack, packidx, - idx, id); -} - -static const struct got_error * -request_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen, int outfd, - int infd, struct got_object_id *id, struct imsgbuf *ibuf) -{ - const struct got_error *err = NULL; - int outfd_child; - - outfd_child = dup(outfd); - if (outfd_child == -1) - return got_error_from_errno("dup"); - - err = got_privsep_send_blob_req(ibuf, infd, id, -1); - if (err) - return err; - - err = got_privsep_send_blob_outfd(ibuf, outfd_child); - if (err) - return err; - - err = got_privsep_recv_blob(outbuf, size, hdrlen, ibuf); - if (err) - return err; - - if (lseek(outfd, SEEK_SET, 0) == -1) - return got_error_from_errno("lseek"); - - return err; -} - -static const struct got_error * -read_blob_privsep(uint8_t **outbuf, size_t *size, size_t *hdrlen, - int outfd, int infd, struct got_object_id *id, struct got_repository *repo) -{ - const struct got_error *err; - int imsg_fds[2]; - pid_t pid; - struct imsgbuf *ibuf; - - if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd != -1) { - ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf; - return request_blob(outbuf, size, hdrlen, outfd, infd, id, - ibuf); - } - - ibuf = calloc(1, sizeof(*ibuf)); - if (ibuf == NULL) - return got_error_from_errno("calloc"); - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { - err = got_error_from_errno("socketpair"); - free(ibuf); - return err; - } - - pid = fork(); - if (pid == -1) { - err = got_error_from_errno("fork"); - free(ibuf); - return err; - } - else if (pid == 0) { - got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_BLOB, - repo->path); - /* not reached */ - } - - if (close(imsg_fds[1]) == -1) { - err = got_error_from_errno("close"); - free(ibuf); - return err; - } - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd = - imsg_fds[0]; - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].pid = pid; - imsg_init(ibuf, imsg_fds[0]); - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf = ibuf; - - return request_blob(outbuf, size, hdrlen, outfd, infd, id, ibuf); -} - -static const struct got_error * -open_blob(struct got_blob_object **blob, struct got_repository *repo, - struct got_object_id *id, size_t blocksize, int outfd) -{ - const struct got_error *err = NULL; - struct got_packidx *packidx = NULL; - int idx, dfd = -1; - char *path_packfile = NULL; - uint8_t *outbuf; - size_t size, hdrlen; - struct stat sb; - - *blob = calloc(1, sizeof(**blob)); - if (*blob == NULL) - return got_error_from_errno("calloc"); - - (*blob)->read_buf = malloc(blocksize); - if ((*blob)->read_buf == NULL) { - err = got_error_from_errno("malloc"); - goto done; - } - - if (ftruncate(outfd, 0L) == -1) { - err = got_error_from_errno("ftruncate"); - goto done; - } - if (lseek(outfd, SEEK_SET, 0) == -1) { - err = got_error_from_errno("lseek"); - goto done; - } - - err = got_repo_search_packidx(&packidx, &idx, repo, id); - if (err == NULL) { - struct got_pack *pack = NULL; - - err = got_packidx_get_packfile_path(&path_packfile, - packidx->path_packidx); - if (err) - goto done; - - pack = got_repo_get_cached_pack(repo, path_packfile); - if (pack == NULL) { - err = got_repo_cache_pack(&pack, repo, path_packfile, - packidx); - if (err) - goto done; - } - err = read_packed_blob_privsep(&outbuf, &size, &hdrlen, outfd, - pack, packidx, idx, id); - } else if (err->code == GOT_ERR_NO_OBJ) { - int infd; - - err = got_object_open_loose_fd(&infd, id, repo); - if (err) - goto done; - err = read_blob_privsep(&outbuf, &size, &hdrlen, outfd, infd, - id, repo); - } - if (err) - goto done; - - if (hdrlen > size) { - err = got_error(GOT_ERR_BAD_OBJ_HDR); - goto done; - } - - if (outbuf) { - (*blob)->f = fmemopen(outbuf, size, "rb"); - if ((*blob)->f == NULL) { - err = got_error_from_errno("fmemopen"); - free(outbuf); - goto done; - } - (*blob)->data = outbuf; - } else { - if (fstat(outfd, &sb) == -1) { - err = got_error_from_errno("fstat"); - goto done; - } - - if (sb.st_size != size) { - err = got_error(GOT_ERR_PRIVSEP_LEN); - goto done; - } - - dfd = dup(outfd); - if (dfd == -1) { - err = got_error_from_errno("dup"); - goto done; - } - - (*blob)->f = fdopen(dfd, "rb"); - if ((*blob)->f == NULL) { - err = got_error_from_errno("fdopen"); - close(dfd); - dfd = -1; - goto done; - } - } - - (*blob)->hdrlen = hdrlen; - (*blob)->blocksize = blocksize; - memcpy(&(*blob)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH); - -done: - free(path_packfile); - if (err) { - if (*blob) { - got_object_blob_close(*blob); - *blob = NULL; - } - } - return err; } const struct got_error * -got_object_open_as_blob(struct got_blob_object **blob, - struct got_repository *repo, struct got_object_id *id, size_t blocksize, - int outfd) -{ - return open_blob(blob, repo, id, blocksize, outfd); -} - -const struct got_error * -got_object_blob_open(struct got_blob_object **blob, - struct got_repository *repo, struct got_object *obj, size_t blocksize, - int outfd) -{ - return open_blob(blob, repo, got_object_get_id(obj), blocksize, outfd); -} - -const struct got_error * got_object_blob_close(struct got_blob_object *blob) { const struct got_error *err = NULL; @@ -1615,199 +493,6 @@ got_object_blob_dump_to_file(off_t *filesize, int *nli return NULL; } -static const struct got_error * -request_packed_tag(struct got_tag_object **tag, struct got_pack *pack, - int pack_idx, struct got_object_id *id) -{ - const struct got_error *err = NULL; - - err = got_privsep_send_tag_req(pack->privsep_child->ibuf, -1, id, - pack_idx); - if (err) - return err; - - return got_privsep_recv_tag(tag, pack->privsep_child->ibuf); -} - -static const struct got_error * -read_packed_tag_privsep(struct got_tag_object **tag, - struct got_pack *pack, struct got_packidx *packidx, int idx, - struct got_object_id *id) -{ - const struct got_error *err = NULL; - - if (pack->privsep_child) - return request_packed_tag(tag, pack, idx, id); - - err = got_pack_start_privsep_child(pack, packidx); - if (err) - return err; - - return request_packed_tag(tag, pack, idx, id); -} - -static const struct got_error * -request_tag(struct got_tag_object **tag, struct got_repository *repo, - int fd, struct got_object_id *id) -{ - const struct got_error *err = NULL; - struct imsgbuf *ibuf; - - ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].ibuf; - - err = got_privsep_send_tag_req(ibuf, fd, id, -1); - if (err) - return err; - - return got_privsep_recv_tag(tag, ibuf); -} - -static const struct got_error * -read_tag_privsep(struct got_tag_object **tag, int obj_fd, - struct got_object_id *id, struct got_repository *repo) -{ - const struct got_error *err; - int imsg_fds[2]; - pid_t pid; - struct imsgbuf *ibuf; - - if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].imsg_fd != -1) - return request_tag(tag, repo, obj_fd, id); - - ibuf = calloc(1, sizeof(*ibuf)); - if (ibuf == NULL) - return got_error_from_errno("calloc"); - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { - err = got_error_from_errno("socketpair"); - free(ibuf); - return err; - } - - pid = fork(); - if (pid == -1) { - err = got_error_from_errno("fork"); - free(ibuf); - return err; - } - else if (pid == 0) { - got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_TAG, - repo->path); - /* not reached */ - } - - if (close(imsg_fds[1]) == -1) { - err = got_error_from_errno("close"); - free(ibuf); - return err; - } - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].imsg_fd = - imsg_fds[0]; - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].pid = pid; - imsg_init(ibuf, imsg_fds[0]); - repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].ibuf = ibuf; - - return request_tag(tag, repo, obj_fd, id); -} - -static const struct got_error * -open_tag(struct got_tag_object **tag, struct got_repository *repo, - struct got_object_id *id, int check_cache) -{ - const struct got_error *err = NULL; - struct got_packidx *packidx = NULL; - int idx; - char *path_packfile = NULL; - struct got_object *obj = NULL; - int obj_type = GOT_OBJ_TYPE_ANY; - - if (check_cache) { - *tag = got_repo_get_cached_tag(repo, id); - if (*tag != NULL) { - (*tag)->refcnt++; - return NULL; - } - } else - *tag = NULL; - - err = got_repo_search_packidx(&packidx, &idx, repo, id); - if (err == NULL) { - struct got_pack *pack = NULL; - - err = got_packidx_get_packfile_path(&path_packfile, - packidx->path_packidx); - if (err) - return err; - - pack = got_repo_get_cached_pack(repo, path_packfile); - if (pack == NULL) { - err = got_repo_cache_pack(&pack, repo, path_packfile, - packidx); - if (err) - goto done; - } - - /* Beware of "lightweight" tags: Check object type first. */ - err = read_packed_object_privsep(&obj, repo, pack, packidx, - idx, id); - if (err) - goto done; - obj_type = obj->type; - got_object_close(obj); - if (obj_type != GOT_OBJ_TYPE_TAG) { - err = got_error(GOT_ERR_OBJ_TYPE); - goto done; - } - err = read_packed_tag_privsep(tag, pack, packidx, idx, id); - } else if (err->code == GOT_ERR_NO_OBJ) { - int fd; - - err = got_object_open_loose_fd(&fd, id, repo); - if (err) - return err; - err = got_object_read_header_privsep(&obj, id, repo, fd); - if (err) - return err; - obj_type = obj->type; - got_object_close(obj); - if (obj_type != GOT_OBJ_TYPE_TAG) - return got_error(GOT_ERR_OBJ_TYPE); - - err = got_object_open_loose_fd(&fd, id, repo); - if (err) - return err; - err = read_tag_privsep(tag, fd, id, repo); - } - - if (err == NULL) { - (*tag)->refcnt++; - err = got_repo_cache_tag(repo, id, *tag); - } -done: - free(path_packfile); - return err; -} - -const struct got_error * -got_object_open_as_tag(struct got_tag_object **tag, - struct got_repository *repo, struct got_object_id *id) -{ - *tag = got_repo_get_cached_tag(repo, id); - if (*tag != NULL) { - (*tag)->refcnt++; - return NULL; - } - - return open_tag(tag, repo, id, 0); -} - -const struct got_error * -got_object_tag_open(struct got_tag_object **tag, - struct got_repository *repo, struct got_object *obj) -{ - return open_tag(tag, repo, got_object_get_id(obj), 1); -} - const char * got_object_tag_get_name(struct got_tag_object *tag) { @@ -1941,6 +626,7 @@ done: got_object_tree_close(subtree); return err; } + const struct got_error * got_object_id_by_path(struct got_object_id **id, struct got_repository *repo, struct got_commit_object *commit, const char *path) @@ -2230,129 +916,7 @@ got_object_resolve_symlinks(char **link_target, const return err; } - -const struct got_error * -got_traverse_packed_commits(struct got_object_id_queue *traversed_commits, - struct got_object_id *commit_id, const char *path, - struct got_repository *repo) -{ - const struct got_error *err = NULL; - struct got_pack *pack = NULL; - struct got_packidx *packidx = NULL; - char *path_packfile = NULL; - struct got_commit_object *changed_commit = NULL; - struct got_object_id *changed_commit_id = NULL; - int idx; - err = got_repo_search_packidx(&packidx, &idx, repo, commit_id); - if (err) { - if (err->code != GOT_ERR_NO_OBJ) - return err; - return NULL; - } - - err = got_packidx_get_packfile_path(&path_packfile, - packidx->path_packidx); - if (err) - return err; - - pack = got_repo_get_cached_pack(repo, path_packfile); - if (pack == NULL) { - err = got_repo_cache_pack(&pack, repo, path_packfile, packidx); - if (err) - goto done; - } - - if (pack->privsep_child == NULL) { - err = got_pack_start_privsep_child(pack, packidx); - if (err) - goto done; - } - - err = got_privsep_send_commit_traversal_request( - pack->privsep_child->ibuf, commit_id, idx, path); - if (err) - goto done; - - err = got_privsep_recv_traversed_commits(&changed_commit, - &changed_commit_id, traversed_commits, pack->privsep_child->ibuf); - if (err) - goto done; - - if (changed_commit) { - /* - * Cache the commit in which the path was changed. - * This commit might be opened again soon. - */ - changed_commit->refcnt++; - err = got_repo_cache_commit(repo, changed_commit_id, - changed_commit); - got_object_commit_close(changed_commit); - } -done: - free(path_packfile); - free(changed_commit_id); - return err; -} - -const struct got_error * -got_object_enumerate(int *found_all_objects, - got_object_enumerate_commit_cb cb_commit, - got_object_enumerate_tree_cb cb_tree, void *cb_arg, - struct got_object_id **ours, int nours, - struct got_object_id **theirs, int ntheirs, - struct got_packidx *packidx, struct got_repository *repo) -{ - const struct got_error *err = NULL; - struct got_pack *pack; - char *path_packfile = NULL; - - err = got_packidx_get_packfile_path(&path_packfile, - packidx->path_packidx); - if (err) - return err; - - pack = got_repo_get_cached_pack(repo, path_packfile); - if (pack == NULL) { - err = got_repo_cache_pack(&pack, repo, path_packfile, packidx); - if (err) - goto done; - } - - if (pack->privsep_child == NULL) { - err = got_pack_start_privsep_child(pack, packidx); - if (err) - goto done; - } - - err = got_privsep_send_object_enumeration_request( - pack->privsep_child->ibuf); - if (err) - goto done; - - err = got_privsep_send_object_idlist(pack->privsep_child->ibuf, - ours, nours); - if (err) - goto done; - err = got_privsep_send_object_idlist_done(pack->privsep_child->ibuf); - if (err) - goto done; - - err = got_privsep_send_object_idlist(pack->privsep_child->ibuf, - theirs, ntheirs); - if (err) - goto done; - err = got_privsep_send_object_idlist_done(pack->privsep_child->ibuf); - if (err) - goto done; - - err = got_privsep_recv_enumerated_objects(found_all_objects, - pack->privsep_child->ibuf, cb_commit, cb_tree, cb_arg, repo); -done: - free(path_packfile); - return err; -} - void got_object_commit_retain(struct got_commit_object *commit) { blob - /dev/null blob + 306778c910ea41abc42a6c935b33661ebea9403f (mode 644) --- /dev/null +++ lib/object_open_privsep.c @@ -0,0 +1,1478 @@ +/* + * Copyright (c) 2018, 2019, 2022 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "got_error.h" +#include "got_object.h" +#include "got_repository.h" +#include "got_opentemp.h" +#include "got_path.h" + +#include "got_lib_delta.h" +#include "got_lib_object.h" +#include "got_lib_privsep.h" +#include "got_lib_object_cache.h" +#include "got_lib_pack.h" +#include "got_lib_repository.h" + +static const struct got_error * +request_packed_object(struct got_object **obj, struct got_pack *pack, int idx, + struct got_object_id *id) +{ + const struct got_error *err = NULL; + struct imsgbuf *ibuf = pack->privsep_child->ibuf; + + err = got_privsep_send_packed_obj_req(ibuf, idx, id); + if (err) + return err; + + err = got_privsep_recv_obj(obj, ibuf); + if (err) + return err; + + memcpy(&(*obj)->id, id, sizeof((*obj)->id)); + + return NULL; +} + +/* Create temporary files used during delta application. */ +static const struct got_error * +pack_child_send_tempfiles(struct imsgbuf *ibuf, struct got_pack *pack) +{ + const struct got_error *err; + int basefd = -1, accumfd = -1; + + /* + * For performance reasons, the child will keep reusing the + * same temporary files during every object request. + * Opening and closing new files for every object request is + * too expensive during operations such as 'gotadmin pack'. + */ + if (pack->child_has_tempfiles) + return NULL; + + basefd = dup(pack->basefd); + if (basefd == -1) + return got_error_from_errno("dup"); + + accumfd = dup(pack->accumfd); + if (accumfd == -1) { + err = got_error_from_errno("dup"); + goto done; + } + + err = got_privsep_send_tmpfd(ibuf, basefd); + if (err) + goto done; + + err = got_privsep_send_tmpfd(ibuf, accumfd); +done: + if (err) { + if (basefd != -1) + close(basefd); + if (accumfd != -1) + close(accumfd); + } else + pack->child_has_tempfiles = 1; + return NULL; +} + +static const struct got_error * +request_packed_object_raw(uint8_t **outbuf, off_t *size, size_t *hdrlen, + int outfd, struct got_pack *pack, int idx, struct got_object_id *id) +{ + const struct got_error *err = NULL; + struct imsgbuf *ibuf = pack->privsep_child->ibuf; + int outfd_child; + + err = pack_child_send_tempfiles(ibuf, pack); + if (err) + return err; + + outfd_child = dup(outfd); + if (outfd_child == -1) + return got_error_from_errno("dup"); + + err = got_privsep_send_packed_raw_obj_req(ibuf, idx, id); + if (err) { + close(outfd_child); + return err; + } + + err = got_privsep_send_raw_obj_outfd(ibuf, outfd_child); + if (err) + return err; + + err = got_privsep_recv_raw_obj(outbuf, size, hdrlen, ibuf); + if (err) + return err; + + return NULL; +} + +static const struct got_error * +read_packed_object_privsep(struct got_object **obj, + struct got_repository *repo, struct got_pack *pack, + struct got_packidx *packidx, int idx, struct got_object_id *id) +{ + const struct got_error *err = NULL; + + if (pack->privsep_child == NULL) { + err = got_pack_start_privsep_child(pack, packidx); + if (err) + return err; + } + + return request_packed_object(obj, pack, idx, id); +} + +static const struct got_error * +read_packed_object_raw_privsep(uint8_t **outbuf, off_t *size, size_t *hdrlen, + int outfd, struct got_pack *pack, struct got_packidx *packidx, int idx, + struct got_object_id *id) +{ + const struct got_error *err = NULL; + + if (pack->privsep_child == NULL) { + err = got_pack_start_privsep_child(pack, packidx); + if (err) + return err; + } + + return request_packed_object_raw(outbuf, size, hdrlen, outfd, pack, + idx, id); +} + +const struct got_error * +got_object_open_packed(struct got_object **obj, struct got_object_id *id, + struct got_repository *repo) +{ + const struct got_error *err = NULL; + struct got_pack *pack = NULL; + struct got_packidx *packidx = NULL; + int idx; + char *path_packfile; + + err = got_repo_search_packidx(&packidx, &idx, repo, id); + if (err) + return err; + + err = got_packidx_get_packfile_path(&path_packfile, + packidx->path_packidx); + if (err) + return err; + + pack = got_repo_get_cached_pack(repo, path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, path_packfile, packidx); + if (err) + goto done; + } + + err = read_packed_object_privsep(obj, repo, pack, packidx, idx, id); + if (err) + goto done; +done: + free(path_packfile); + return err; +} + +const struct got_error * +got_object_open_from_packfile(struct got_object **obj, struct got_object_id *id, + struct got_pack *pack, struct got_packidx *packidx, int obj_idx, + struct got_repository *repo) +{ + return read_packed_object_privsep(obj, repo, pack, packidx, + obj_idx, id); +} + +const struct got_error * +got_object_read_raw_delta(uint64_t *base_size, uint64_t *result_size, + off_t *delta_size, off_t *delta_compressed_size, off_t *delta_offset, + off_t *delta_out_offset, struct got_object_id **base_id, int delta_cache_fd, + struct got_packidx *packidx, int obj_idx, struct got_object_id *id, + struct got_repository *repo) +{ + const struct got_error *err = NULL; + struct got_pack *pack = NULL; + char *path_packfile; + + *base_size = 0; + *result_size = 0; + *delta_size = 0; + *delta_compressed_size = 0; + *delta_offset = 0; + *delta_out_offset = 0; + + err = got_packidx_get_packfile_path(&path_packfile, + packidx->path_packidx); + if (err) + return err; + + pack = got_repo_get_cached_pack(repo, path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, path_packfile, packidx); + if (err) + return err; + } + + if (pack->privsep_child == NULL) { + err = got_pack_start_privsep_child(pack, packidx); + if (err) + return err; + } + + if (!pack->child_has_delta_outfd) { + int outfd_child; + outfd_child = dup(delta_cache_fd); + if (outfd_child == -1) + return got_error_from_errno("dup"); + err = got_privsep_send_raw_delta_outfd( + pack->privsep_child->ibuf, outfd_child); + if (err) + return err; + pack->child_has_delta_outfd = 1; + } + + err = got_privsep_send_raw_delta_req(pack->privsep_child->ibuf, + obj_idx, id); + if (err) + return err; + + return got_privsep_recv_raw_delta(base_size, result_size, delta_size, + delta_compressed_size, delta_offset, delta_out_offset, base_id, + pack->privsep_child->ibuf); +} + +static const struct got_error * +request_object(struct got_object **obj, struct got_object_id *id, + struct got_repository *repo, int fd) +{ + const struct got_error *err = NULL; + struct imsgbuf *ibuf; + + ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf; + + err = got_privsep_send_obj_req(ibuf, fd, id); + if (err) + return err; + + return got_privsep_recv_obj(obj, ibuf); +} + +static const struct got_error * +request_raw_object(uint8_t **outbuf, off_t *size, size_t *hdrlen, int outfd, + struct got_object_id *id, struct got_repository *repo, int infd) +{ + const struct got_error *err = NULL; + struct imsgbuf *ibuf; + int outfd_child; + + ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf; + + outfd_child = dup(outfd); + if (outfd_child == -1) + return got_error_from_errno("dup"); + + err = got_privsep_send_raw_obj_req(ibuf, infd, id); + if (err) + return err; + + err = got_privsep_send_raw_obj_outfd(ibuf, outfd_child); + if (err) + return err; + + return got_privsep_recv_raw_obj(outbuf, size, hdrlen, ibuf); +} + +static const struct got_error * +start_read_object_child(struct got_repository *repo) +{ + const struct got_error *err = NULL; + int imsg_fds[2]; + pid_t pid; + struct imsgbuf *ibuf; + + ibuf = calloc(1, sizeof(*ibuf)); + if (ibuf == NULL) + return got_error_from_errno("calloc"); + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { + err = got_error_from_errno("socketpair"); + free(ibuf); + return err; + } + + pid = fork(); + if (pid == -1) { + err = got_error_from_errno("fork"); + free(ibuf); + return err; + } + else if (pid == 0) { + got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_OBJECT, + repo->path); + /* not reached */ + } + + if (close(imsg_fds[1]) == -1) { + err = got_error_from_errno("close"); + free(ibuf); + return err; + } + + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd = + imsg_fds[0]; + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].pid = pid; + imsg_init(ibuf, imsg_fds[0]); + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf = ibuf; + + return NULL; +} + +const struct got_error * +got_object_read_header_privsep(struct got_object **obj, + struct got_object_id *id, struct got_repository *repo, int obj_fd) +{ + const struct got_error *err; + + if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1) + return request_object(obj, id, repo, obj_fd); + + err = start_read_object_child(repo); + if (err) { + close(obj_fd); + return err; + } + + return request_object(obj, id, repo, obj_fd); +} + +static const struct got_error * +read_object_raw_privsep(uint8_t **outbuf, off_t *size, size_t *hdrlen, + int outfd, struct got_object_id *id, struct got_repository *repo, + int obj_fd) +{ + const struct got_error *err; + + if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1) + return request_raw_object(outbuf, size, hdrlen, outfd, id, + repo, obj_fd); + + err = start_read_object_child(repo); + if (err) + return err; + + return request_raw_object(outbuf, size, hdrlen, outfd, id, repo, + obj_fd); +} + +const struct got_error * +got_object_open(struct got_object **obj, struct got_repository *repo, + struct got_object_id *id) +{ + const struct got_error *err = NULL; + int fd; + + *obj = got_repo_get_cached_object(repo, id); + if (*obj != NULL) { + (*obj)->refcnt++; + return NULL; + } + + err = got_object_open_packed(obj, id, repo); + if (err && err->code != GOT_ERR_NO_OBJ) + return err; + if (*obj) { + (*obj)->refcnt++; + return got_repo_cache_object(repo, id, *obj); + } + + err = got_object_open_loose_fd(&fd, id, repo); + if (err) { + if (err->code == GOT_ERR_ERRNO && errno == ENOENT) + err = got_error_no_obj(id); + return err; + } + + err = got_object_read_header_privsep(obj, id, repo, fd); + if (err) + return err; + + memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH); + + (*obj)->refcnt++; + return got_repo_cache_object(repo, id, *obj); +} + +/* *outfd must be initialized to -1 by caller */ +const struct got_error * +got_object_raw_open(struct got_raw_object **obj, int *outfd, + struct got_repository *repo, struct got_object_id *id) +{ + const struct got_error *err = NULL; + struct got_packidx *packidx = NULL; + int idx; + uint8_t *outbuf = NULL; + off_t size = 0; + size_t hdrlen = 0; + char *path_packfile = NULL; + + *obj = got_repo_get_cached_raw_object(repo, id); + if (*obj != NULL) { + (*obj)->refcnt++; + return NULL; + } + + if (*outfd == -1) { + *outfd = got_opentempfd(); + if (*outfd == -1) + return got_error_from_errno("got_opentempfd"); + } + + err = got_repo_search_packidx(&packidx, &idx, repo, id); + if (err == NULL) { + struct got_pack *pack = NULL; + + err = got_packidx_get_packfile_path(&path_packfile, + packidx->path_packidx); + if (err) + goto done; + + pack = got_repo_get_cached_pack(repo, path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, path_packfile, + packidx); + if (err) + goto done; + } + err = read_packed_object_raw_privsep(&outbuf, &size, &hdrlen, + *outfd, pack, packidx, idx, id); + if (err) + goto done; + } else if (err->code == GOT_ERR_NO_OBJ) { + int fd; + + err = got_object_open_loose_fd(&fd, id, repo); + if (err) + goto done; + err = read_object_raw_privsep(&outbuf, &size, &hdrlen, *outfd, + id, repo, fd); + if (err) + goto done; + } + + *obj = calloc(1, sizeof(**obj)); + if (*obj == NULL) { + err = got_error_from_errno("calloc"); + goto done; + } + (*obj)->fd = -1; + + if (outbuf) { + (*obj)->data = outbuf; + } else { + struct stat sb; + if (fstat(*outfd, &sb) == -1) { + err = got_error_from_errno("fstat"); + goto done; + } + + if (sb.st_size != hdrlen + size) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } +#ifndef GOT_PACK_NO_MMAP + if (hdrlen + size > 0) { + (*obj)->data = mmap(NULL, hdrlen + size, PROT_READ, + MAP_PRIVATE, *outfd, 0); + if ((*obj)->data == MAP_FAILED) { + if (errno != ENOMEM) { + err = got_error_from_errno("mmap"); + goto done; + } + (*obj)->data = NULL; + } else { + (*obj)->fd = *outfd; + *outfd = -1; + } + } +#endif + if (*outfd != -1) { + (*obj)->f = fdopen(*outfd, "r"); + if ((*obj)->f == NULL) { + err = got_error_from_errno("fdopen"); + goto done; + } + *outfd = -1; + } + } + (*obj)->hdrlen = hdrlen; + (*obj)->size = size; + err = got_repo_cache_raw_object(repo, id, *obj); +done: + free(path_packfile); + if (err) { + if (*obj) { + got_object_raw_close(*obj); + *obj = NULL; + } + free(outbuf); + } else + (*obj)->refcnt++; + return err; +} + +static const struct got_error * +request_packed_commit(struct got_commit_object **commit, struct got_pack *pack, + int pack_idx, struct got_object_id *id) +{ + const struct got_error *err = NULL; + + err = got_privsep_send_commit_req(pack->privsep_child->ibuf, -1, id, + pack_idx); + if (err) + return err; + + err = got_privsep_recv_commit(commit, pack->privsep_child->ibuf); + if (err) + return err; + + (*commit)->flags |= GOT_COMMIT_FLAG_PACKED; + return NULL; +} + +static const struct got_error * +read_packed_commit_privsep(struct got_commit_object **commit, + struct got_pack *pack, struct got_packidx *packidx, int idx, + struct got_object_id *id) +{ + const struct got_error *err = NULL; + + if (pack->privsep_child) + return request_packed_commit(commit, pack, idx, id); + + err = got_pack_start_privsep_child(pack, packidx); + if (err) + return err; + + return request_packed_commit(commit, pack, idx, id); +} + +static const struct got_error * +request_commit(struct got_commit_object **commit, struct got_repository *repo, + int fd, struct got_object_id *id) +{ + const struct got_error *err = NULL; + struct imsgbuf *ibuf; + + ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].ibuf; + + err = got_privsep_send_commit_req(ibuf, fd, id, -1); + if (err) + return err; + + return got_privsep_recv_commit(commit, ibuf); +} + +static const struct got_error * +read_commit_privsep(struct got_commit_object **commit, int obj_fd, + struct got_object_id *id, struct got_repository *repo) +{ + const struct got_error *err; + int imsg_fds[2]; + pid_t pid; + struct imsgbuf *ibuf; + + if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd != -1) + return request_commit(commit, repo, obj_fd, id); + + ibuf = calloc(1, sizeof(*ibuf)); + if (ibuf == NULL) + return got_error_from_errno("calloc"); + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { + err = got_error_from_errno("socketpair"); + free(ibuf); + return err; + } + + pid = fork(); + if (pid == -1) { + err = got_error_from_errno("fork"); + free(ibuf); + return err; + } + else if (pid == 0) { + got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_COMMIT, + repo->path); + /* not reached */ + } + + if (close(imsg_fds[1]) == -1) { + err = got_error_from_errno("close"); + free(ibuf); + return err; + } + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd = + imsg_fds[0]; + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].pid = pid; + imsg_init(ibuf, imsg_fds[0]); + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].ibuf = ibuf; + + return request_commit(commit, repo, obj_fd, id); +} + +static const struct got_error * +open_commit(struct got_commit_object **commit, + struct got_repository *repo, struct got_object_id *id, int check_cache) +{ + const struct got_error *err = NULL; + struct got_packidx *packidx = NULL; + int idx; + char *path_packfile = NULL; + + if (check_cache) { + *commit = got_repo_get_cached_commit(repo, id); + if (*commit != NULL) { + (*commit)->refcnt++; + return NULL; + } + } else + *commit = NULL; + + err = got_repo_search_packidx(&packidx, &idx, repo, id); + if (err == NULL) { + struct got_pack *pack = NULL; + + err = got_packidx_get_packfile_path(&path_packfile, + packidx->path_packidx); + if (err) + return err; + + pack = got_repo_get_cached_pack(repo, path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, path_packfile, + packidx); + if (err) + goto done; + } + err = read_packed_commit_privsep(commit, pack, + packidx, idx, id); + } else if (err->code == GOT_ERR_NO_OBJ) { + int fd; + + err = got_object_open_loose_fd(&fd, id, repo); + if (err) + return err; + err = read_commit_privsep(commit, fd, id, repo); + } + + if (err == NULL) { + (*commit)->refcnt++; + err = got_repo_cache_commit(repo, id, *commit); + } +done: + free(path_packfile); + return err; +} + +const struct got_error * +got_object_open_as_commit(struct got_commit_object **commit, + struct got_repository *repo, struct got_object_id *id) +{ + *commit = got_repo_get_cached_commit(repo, id); + if (*commit != NULL) { + (*commit)->refcnt++; + return NULL; + } + + return open_commit(commit, repo, id, 0); +} + +const struct got_error * +got_object_commit_open(struct got_commit_object **commit, + struct got_repository *repo, struct got_object *obj) +{ + return open_commit(commit, repo, got_object_get_id(obj), 1); +} + +static const struct got_error * +request_packed_tree(struct got_tree_object **tree, struct got_pack *pack, + int pack_idx, struct got_object_id *id) +{ + const struct got_error *err = NULL; + + err = got_privsep_send_tree_req(pack->privsep_child->ibuf, -1, id, + pack_idx); + if (err) + return err; + + return got_privsep_recv_tree(tree, pack->privsep_child->ibuf); +} + +static const struct got_error * +read_packed_tree_privsep(struct got_tree_object **tree, + struct got_pack *pack, struct got_packidx *packidx, int idx, + struct got_object_id *id) +{ + const struct got_error *err = NULL; + + if (pack->privsep_child) + return request_packed_tree(tree, pack, idx, id); + + err = got_pack_start_privsep_child(pack, packidx); + if (err) + return err; + + return request_packed_tree(tree, pack, idx, id); +} + +static const struct got_error * +request_tree(struct got_tree_object **tree, struct got_repository *repo, + int fd, struct got_object_id *id) +{ + const struct got_error *err = NULL; + struct imsgbuf *ibuf; + + ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].ibuf; + + err = got_privsep_send_tree_req(ibuf, fd, id, -1); + if (err) + return err; + + return got_privsep_recv_tree(tree, ibuf); +} + +static const struct got_error * +read_tree_privsep(struct got_tree_object **tree, int obj_fd, + struct got_object_id *id, struct got_repository *repo) +{ + const struct got_error *err; + int imsg_fds[2]; + pid_t pid; + struct imsgbuf *ibuf; + + if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd != -1) + return request_tree(tree, repo, obj_fd, id); + + ibuf = calloc(1, sizeof(*ibuf)); + if (ibuf == NULL) + return got_error_from_errno("calloc"); + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { + err = got_error_from_errno("socketpair"); + free(ibuf); + return err; + } + + pid = fork(); + if (pid == -1) { + err = got_error_from_errno("fork"); + free(ibuf); + return err; + } else if (pid == 0) { + got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_TREE, + repo->path); + /* not reached */ + } + + if (close(imsg_fds[1]) == -1) { + err = got_error_from_errno("close"); + free(ibuf); + return err; + } + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd = + imsg_fds[0]; + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].pid = pid; + imsg_init(ibuf, imsg_fds[0]); + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].ibuf = ibuf; + + + return request_tree(tree, repo, obj_fd, id); +} + +static const struct got_error * +open_tree(struct got_tree_object **tree, struct got_repository *repo, + struct got_object_id *id, int check_cache) +{ + const struct got_error *err = NULL; + struct got_packidx *packidx = NULL; + int idx; + char *path_packfile = NULL; + + if (check_cache) { + *tree = got_repo_get_cached_tree(repo, id); + if (*tree != NULL) { + (*tree)->refcnt++; + return NULL; + } + } else + *tree = NULL; + + err = got_repo_search_packidx(&packidx, &idx, repo, id); + if (err == NULL) { + struct got_pack *pack = NULL; + + err = got_packidx_get_packfile_path(&path_packfile, + packidx->path_packidx); + if (err) + return err; + + pack = got_repo_get_cached_pack(repo, path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, path_packfile, + packidx); + if (err) + goto done; + } + err = read_packed_tree_privsep(tree, pack, + packidx, idx, id); + } else if (err->code == GOT_ERR_NO_OBJ) { + int fd; + + err = got_object_open_loose_fd(&fd, id, repo); + if (err) + return err; + err = read_tree_privsep(tree, fd, id, repo); + } + + if (err == NULL) { + (*tree)->refcnt++; + err = got_repo_cache_tree(repo, id, *tree); + } +done: + free(path_packfile); + return err; +} + +const struct got_error * +got_object_open_as_tree(struct got_tree_object **tree, + struct got_repository *repo, struct got_object_id *id) +{ + *tree = got_repo_get_cached_tree(repo, id); + if (*tree != NULL) { + (*tree)->refcnt++; + return NULL; + } + + return open_tree(tree, repo, id, 0); +} + +const struct got_error * +got_object_tree_open(struct got_tree_object **tree, + struct got_repository *repo, struct got_object *obj) +{ + return open_tree(tree, repo, got_object_get_id(obj), 1); +} + +static const struct got_error * +request_packed_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen, int outfd, + struct got_pack *pack, struct got_packidx *packidx, int idx, + struct got_object_id *id) +{ + const struct got_error *err = NULL; + struct imsgbuf *ibuf = pack->privsep_child->ibuf; + int outfd_child; + + err = pack_child_send_tempfiles(ibuf, pack); + if (err) + return err; + + outfd_child = dup(outfd); + if (outfd_child == -1) + return got_error_from_errno("dup"); + + err = got_privsep_send_blob_req(pack->privsep_child->ibuf, -1, id, idx); + if (err) + return err; + + err = got_privsep_send_blob_outfd(pack->privsep_child->ibuf, + outfd_child); + if (err) { + return err; + } + + err = got_privsep_recv_blob(outbuf, size, hdrlen, + pack->privsep_child->ibuf); + if (err) + return err; + + if (lseek(outfd, SEEK_SET, 0) == -1) + err = got_error_from_errno("lseek"); + + return err; +} + +static const struct got_error * +read_packed_blob_privsep(uint8_t **outbuf, size_t *size, size_t *hdrlen, + int outfd, struct got_pack *pack, struct got_packidx *packidx, int idx, + struct got_object_id *id) +{ + const struct got_error *err = NULL; + + if (pack->privsep_child == NULL) { + err = got_pack_start_privsep_child(pack, packidx); + if (err) + return err; + } + + return request_packed_blob(outbuf, size, hdrlen, outfd, pack, packidx, + idx, id); +} + +static const struct got_error * +request_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen, int outfd, + int infd, struct got_object_id *id, struct imsgbuf *ibuf) +{ + const struct got_error *err = NULL; + int outfd_child; + + outfd_child = dup(outfd); + if (outfd_child == -1) + return got_error_from_errno("dup"); + + err = got_privsep_send_blob_req(ibuf, infd, id, -1); + if (err) + return err; + + err = got_privsep_send_blob_outfd(ibuf, outfd_child); + if (err) + return err; + + err = got_privsep_recv_blob(outbuf, size, hdrlen, ibuf); + if (err) + return err; + + if (lseek(outfd, SEEK_SET, 0) == -1) + return got_error_from_errno("lseek"); + + return err; +} + +static const struct got_error * +read_blob_privsep(uint8_t **outbuf, size_t *size, size_t *hdrlen, + int outfd, int infd, struct got_object_id *id, struct got_repository *repo) +{ + const struct got_error *err; + int imsg_fds[2]; + pid_t pid; + struct imsgbuf *ibuf; + + if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd != -1) { + ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf; + return request_blob(outbuf, size, hdrlen, outfd, infd, id, + ibuf); + } + + ibuf = calloc(1, sizeof(*ibuf)); + if (ibuf == NULL) + return got_error_from_errno("calloc"); + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { + err = got_error_from_errno("socketpair"); + free(ibuf); + return err; + } + + pid = fork(); + if (pid == -1) { + err = got_error_from_errno("fork"); + free(ibuf); + return err; + } + else if (pid == 0) { + got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_BLOB, + repo->path); + /* not reached */ + } + + if (close(imsg_fds[1]) == -1) { + err = got_error_from_errno("close"); + free(ibuf); + return err; + } + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd = + imsg_fds[0]; + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].pid = pid; + imsg_init(ibuf, imsg_fds[0]); + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf = ibuf; + + return request_blob(outbuf, size, hdrlen, outfd, infd, id, ibuf); +} + +static const struct got_error * +open_blob(struct got_blob_object **blob, struct got_repository *repo, + struct got_object_id *id, size_t blocksize, int outfd) +{ + const struct got_error *err = NULL; + struct got_packidx *packidx = NULL; + int idx, dfd = -1; + char *path_packfile = NULL; + uint8_t *outbuf; + size_t size, hdrlen; + struct stat sb; + + *blob = calloc(1, sizeof(**blob)); + if (*blob == NULL) + return got_error_from_errno("calloc"); + + (*blob)->read_buf = malloc(blocksize); + if ((*blob)->read_buf == NULL) { + err = got_error_from_errno("malloc"); + goto done; + } + + if (ftruncate(outfd, 0L) == -1) { + err = got_error_from_errno("ftruncate"); + goto done; + } + if (lseek(outfd, SEEK_SET, 0) == -1) { + err = got_error_from_errno("lseek"); + goto done; + } + + err = got_repo_search_packidx(&packidx, &idx, repo, id); + if (err == NULL) { + struct got_pack *pack = NULL; + + err = got_packidx_get_packfile_path(&path_packfile, + packidx->path_packidx); + if (err) + goto done; + + pack = got_repo_get_cached_pack(repo, path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, path_packfile, + packidx); + if (err) + goto done; + } + err = read_packed_blob_privsep(&outbuf, &size, &hdrlen, outfd, + pack, packidx, idx, id); + } else if (err->code == GOT_ERR_NO_OBJ) { + int infd; + + err = got_object_open_loose_fd(&infd, id, repo); + if (err) + goto done; + err = read_blob_privsep(&outbuf, &size, &hdrlen, outfd, infd, + id, repo); + } + if (err) + goto done; + + if (hdrlen > size) { + err = got_error(GOT_ERR_BAD_OBJ_HDR); + goto done; + } + + if (outbuf) { + (*blob)->f = fmemopen(outbuf, size, "rb"); + if ((*blob)->f == NULL) { + err = got_error_from_errno("fmemopen"); + free(outbuf); + goto done; + } + (*blob)->data = outbuf; + } else { + if (fstat(outfd, &sb) == -1) { + err = got_error_from_errno("fstat"); + goto done; + } + + if (sb.st_size != size) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + goto done; + } + + dfd = dup(outfd); + if (dfd == -1) { + err = got_error_from_errno("dup"); + goto done; + } + + (*blob)->f = fdopen(dfd, "rb"); + if ((*blob)->f == NULL) { + err = got_error_from_errno("fdopen"); + close(dfd); + dfd = -1; + goto done; + } + } + + (*blob)->hdrlen = hdrlen; + (*blob)->blocksize = blocksize; + memcpy(&(*blob)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH); + +done: + free(path_packfile); + if (err) { + if (*blob) { + got_object_blob_close(*blob); + *blob = NULL; + } + } + return err; +} + +const struct got_error * +got_object_open_as_blob(struct got_blob_object **blob, + struct got_repository *repo, struct got_object_id *id, size_t blocksize, + int outfd) +{ + return open_blob(blob, repo, id, blocksize, outfd); +} + +const struct got_error * +got_object_blob_open(struct got_blob_object **blob, + struct got_repository *repo, struct got_object *obj, size_t blocksize, + int outfd) +{ + return open_blob(blob, repo, got_object_get_id(obj), blocksize, outfd); +} + +static const struct got_error * +request_packed_tag(struct got_tag_object **tag, struct got_pack *pack, + int pack_idx, struct got_object_id *id) +{ + const struct got_error *err = NULL; + + err = got_privsep_send_tag_req(pack->privsep_child->ibuf, -1, id, + pack_idx); + if (err) + return err; + + return got_privsep_recv_tag(tag, pack->privsep_child->ibuf); +} + +static const struct got_error * +read_packed_tag_privsep(struct got_tag_object **tag, + struct got_pack *pack, struct got_packidx *packidx, int idx, + struct got_object_id *id) +{ + const struct got_error *err = NULL; + + if (pack->privsep_child) + return request_packed_tag(tag, pack, idx, id); + + err = got_pack_start_privsep_child(pack, packidx); + if (err) + return err; + + return request_packed_tag(tag, pack, idx, id); +} + +static const struct got_error * +request_tag(struct got_tag_object **tag, struct got_repository *repo, + int fd, struct got_object_id *id) +{ + const struct got_error *err = NULL; + struct imsgbuf *ibuf; + + ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].ibuf; + + err = got_privsep_send_tag_req(ibuf, fd, id, -1); + if (err) + return err; + + return got_privsep_recv_tag(tag, ibuf); +} + +static const struct got_error * +read_tag_privsep(struct got_tag_object **tag, int obj_fd, + struct got_object_id *id, struct got_repository *repo) +{ + const struct got_error *err; + int imsg_fds[2]; + pid_t pid; + struct imsgbuf *ibuf; + + if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].imsg_fd != -1) + return request_tag(tag, repo, obj_fd, id); + + ibuf = calloc(1, sizeof(*ibuf)); + if (ibuf == NULL) + return got_error_from_errno("calloc"); + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { + err = got_error_from_errno("socketpair"); + free(ibuf); + return err; + } + + pid = fork(); + if (pid == -1) { + err = got_error_from_errno("fork"); + free(ibuf); + return err; + } + else if (pid == 0) { + got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_TAG, + repo->path); + /* not reached */ + } + + if (close(imsg_fds[1]) == -1) { + err = got_error_from_errno("close"); + free(ibuf); + return err; + } + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].imsg_fd = + imsg_fds[0]; + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].pid = pid; + imsg_init(ibuf, imsg_fds[0]); + repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].ibuf = ibuf; + + return request_tag(tag, repo, obj_fd, id); +} + +static const struct got_error * +open_tag(struct got_tag_object **tag, struct got_repository *repo, + struct got_object_id *id, int check_cache) +{ + const struct got_error *err = NULL; + struct got_packidx *packidx = NULL; + int idx; + char *path_packfile = NULL; + struct got_object *obj = NULL; + int obj_type = GOT_OBJ_TYPE_ANY; + + if (check_cache) { + *tag = got_repo_get_cached_tag(repo, id); + if (*tag != NULL) { + (*tag)->refcnt++; + return NULL; + } + } else + *tag = NULL; + + err = got_repo_search_packidx(&packidx, &idx, repo, id); + if (err == NULL) { + struct got_pack *pack = NULL; + + err = got_packidx_get_packfile_path(&path_packfile, + packidx->path_packidx); + if (err) + return err; + + pack = got_repo_get_cached_pack(repo, path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, path_packfile, + packidx); + if (err) + goto done; + } + + /* Beware of "lightweight" tags: Check object type first. */ + err = read_packed_object_privsep(&obj, repo, pack, packidx, + idx, id); + if (err) + goto done; + obj_type = obj->type; + got_object_close(obj); + if (obj_type != GOT_OBJ_TYPE_TAG) { + err = got_error(GOT_ERR_OBJ_TYPE); + goto done; + } + err = read_packed_tag_privsep(tag, pack, packidx, idx, id); + } else if (err->code == GOT_ERR_NO_OBJ) { + int fd; + + err = got_object_open_loose_fd(&fd, id, repo); + if (err) + return err; + err = got_object_read_header_privsep(&obj, id, repo, fd); + if (err) + return err; + obj_type = obj->type; + got_object_close(obj); + if (obj_type != GOT_OBJ_TYPE_TAG) + return got_error(GOT_ERR_OBJ_TYPE); + + err = got_object_open_loose_fd(&fd, id, repo); + if (err) + return err; + err = read_tag_privsep(tag, fd, id, repo); + } + + if (err == NULL) { + (*tag)->refcnt++; + err = got_repo_cache_tag(repo, id, *tag); + } +done: + free(path_packfile); + return err; +} + +const struct got_error * +got_object_open_as_tag(struct got_tag_object **tag, + struct got_repository *repo, struct got_object_id *id) +{ + *tag = got_repo_get_cached_tag(repo, id); + if (*tag != NULL) { + (*tag)->refcnt++; + return NULL; + } + + return open_tag(tag, repo, id, 0); +} + +const struct got_error * +got_object_tag_open(struct got_tag_object **tag, + struct got_repository *repo, struct got_object *obj) +{ + return open_tag(tag, repo, got_object_get_id(obj), 1); +} + +const struct got_error * +got_traverse_packed_commits(struct got_object_id_queue *traversed_commits, + struct got_object_id *commit_id, const char *path, + struct got_repository *repo) +{ + const struct got_error *err = NULL; + struct got_pack *pack = NULL; + struct got_packidx *packidx = NULL; + char *path_packfile = NULL; + struct got_commit_object *changed_commit = NULL; + struct got_object_id *changed_commit_id = NULL; + int idx; + + err = got_repo_search_packidx(&packidx, &idx, repo, commit_id); + if (err) { + if (err->code != GOT_ERR_NO_OBJ) + return err; + return NULL; + } + + err = got_packidx_get_packfile_path(&path_packfile, + packidx->path_packidx); + if (err) + return err; + + pack = got_repo_get_cached_pack(repo, path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, path_packfile, packidx); + if (err) + goto done; + } + + if (pack->privsep_child == NULL) { + err = got_pack_start_privsep_child(pack, packidx); + if (err) + goto done; + } + + err = got_privsep_send_commit_traversal_request( + pack->privsep_child->ibuf, commit_id, idx, path); + if (err) + goto done; + + err = got_privsep_recv_traversed_commits(&changed_commit, + &changed_commit_id, traversed_commits, pack->privsep_child->ibuf); + if (err) + goto done; + + if (changed_commit) { + /* + * Cache the commit in which the path was changed. + * This commit might be opened again soon. + */ + changed_commit->refcnt++; + err = got_repo_cache_commit(repo, changed_commit_id, + changed_commit); + got_object_commit_close(changed_commit); + } +done: + free(path_packfile); + free(changed_commit_id); + return err; +} + +const struct got_error * +got_object_enumerate(int *found_all_objects, + got_object_enumerate_commit_cb cb_commit, + got_object_enumerate_tree_cb cb_tree, void *cb_arg, + struct got_object_id **ours, int nours, + struct got_object_id **theirs, int ntheirs, + struct got_packidx *packidx, struct got_repository *repo) +{ + const struct got_error *err = NULL; + struct got_pack *pack; + char *path_packfile = NULL; + + err = got_packidx_get_packfile_path(&path_packfile, + packidx->path_packidx); + if (err) + return err; + + pack = got_repo_get_cached_pack(repo, path_packfile); + if (pack == NULL) { + err = got_repo_cache_pack(&pack, repo, path_packfile, packidx); + if (err) + goto done; + } + + if (pack->privsep_child == NULL) { + err = got_pack_start_privsep_child(pack, packidx); + if (err) + goto done; + } + + err = got_privsep_send_object_enumeration_request( + pack->privsep_child->ibuf); + if (err) + goto done; + + err = got_privsep_send_object_idlist(pack->privsep_child->ibuf, + ours, nours); + if (err) + goto done; + err = got_privsep_send_object_idlist_done(pack->privsep_child->ibuf); + if (err) + goto done; + + err = got_privsep_send_object_idlist(pack->privsep_child->ibuf, + theirs, ntheirs); + if (err) + goto done; + err = got_privsep_send_object_idlist_done(pack->privsep_child->ibuf); + if (err) + goto done; + + err = got_privsep_recv_enumerated_objects(found_all_objects, + pack->privsep_child->ibuf, cb_commit, cb_tree, cb_arg, repo); +done: + free(path_packfile); + return err; +} blob - f835a2398bf16bf81771722cceeaea81aaa9423b blob + 010d5c58dd7c45337472d5f5bb7045b080150f3d --- regress/fetch/Makefile +++ regress/fetch/Makefile @@ -5,7 +5,7 @@ SRCS = error.c privsep.c reference.c sha1.c object.c o opentemp.c repository.c lockfile.c object_cache.c pack.c inflate.c \ deflate.c delta.c delta_cache.c object_idset.c object_create.c \ fetch.c gotconfig.c dial.c fetch_test.c bloom.c murmurhash2.c sigs.c \ - buf.c date.c + buf.c date.c object_open_privsep.c CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib LDADD = -lutil -lz -lm blob - 633edbc33bcfb15eb4bfc91ad86feadfb1315f3d blob + d29f3726176bcecc862c887cc1f0264ad91a958f --- tog/Makefile.am +++ tog/Makefile.am @@ -13,6 +13,7 @@ tog_SOURCES = tog.c \ $(top_srcdir)/lib/object.c \ $(top_srcdir)/lib/object_cache.c \ $(top_srcdir)/lib/object_idset.c \ + $(top_srcdir)/lib/object_open_privsep.c \ $(top_srcdir)/lib/object_parse.c \ $(top_srcdir)/lib/opentemp.c \ $(top_srcdir)/lib/path.c \