Commit Diff


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 <sys/stat.h>
 #include <sys/queue.h>
 #include <sys/uio.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
 #include <sys/mman.h>
 
 #include <errno.h>
@@ -27,13 +25,12 @@
 #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 <time.h>
+#include <imsg.h>
 
 #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 <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
@@ -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 \