commit - 0e51642e8ca7b6c1024426347999853df4cc21e7
commit + 8e359fa0dccf91ec3b06edc1ea17404f42a62862
blob - 1b45b53a4efff9977dcd3c2e2e33c499adc94533
blob + ebdd46b32765e3a469912c789d2e66380474b9bb
--- got/Makefile
+++ got/Makefile
diff_myers.c diff_output.c diff_output_plain.c \
diff_output_unidiff.c diff_output_edscript.c \
diff_patience.c send.c deltify.c pack_create.c dial.c \
- bloom.c murmurhash2.c ratelimit.c patch.c sigs.c date.c
+ bloom.c murmurhash2.c ratelimit.c patch.c sigs.c date.c \
+ object_open_privsep.c
MAN = ${PROG}.1 got-worktree.5 git-repository.5 got.conf.5
blob - bf9729a9216142455edfd253fb05cd98c0b4b1f1
blob + 61964eeb24894743d7e03a98d7da55b1ffc4a4af
--- gotadmin/Makefile
+++ gotadmin/Makefile
object_idset.c object_parse.c opentemp.c pack.c pack_create.c \
path.c privsep.c reference.c repository.c repository_admin.c \
worktree_open.c sha1.c bloom.c murmurhash2.c ratelimit.c \
- sigs.c buf.c date.c
+ sigs.c buf.c date.c object_open_privsep.c
MAN = ${PROG}.1
CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib
blob - 948b9b8fc5270878f0eb2aa61a579197663e4827
blob + dc0086e6c8467903bee24745d317a83ca20c538a
--- gotweb/Makefile
+++ gotweb/Makefile
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 - 01296896441d21b985a59ffc870ef3d3b03f4a31
blob + de3dcacc20ae8cf7d1e63df9fbfa5430784ab2bb
--- gotwebd/Makefile
+++ gotwebd/Makefile
gotconfig.c 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 \
- worktree_open.c patch.c sigs.c date.c sockaddr.c
+ worktree_open.c patch.c sigs.c date.c sockaddr.c \
+ object_open_privsep.c
MAN = ${PROG}.conf.5 ${PROG}.8
blob - 51d0400aa260f449e446626d2fe0f2826612a326
blob + ddb9eb27727656a27e3a34e8d1389a4549d8dd8d
--- lib/object.c
+++ lib/object.c
#include <sys/queue.h>
#include <sys/tree.h>
#include <sys/uio.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdint.h>
#include <sha1.h>
#include <unistd.h>
#include <zlib.h>
-#include <ctype.h>
#include <libgen.h>
#include <limits.h>
#include <imsg.h>
-#include <time.h>
#include "got_error.h"
#include "got_object.h"
}
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;
}
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));
}
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)
{
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;
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)
{
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)
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
+/*
+ * Copyright (c) 2018, 2019, 2022 Stefan Sperling <stsp@openbsd.org>
+ *
+ * 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 <sys/mman.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/tree.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <imsg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sha1.h>
+#include <limits.h>
+#include <unistd.h>
+
+#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
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 - 7379d7e77fb9e190eb44211cdf722939696a6cbe
blob + aa13e23859c0a05101c4f431cd0675719f48a8e2
--- tog/Makefile
+++ tog/Makefile
gotconfig.c 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
+ diff_patience.c bloom.c murmurhash2.c sigs.c date.c \
+ object_open_privsep.c
MAN = ${PROG}.1
CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib