Commit Diff


commit - 0e51642e8ca7b6c1024426347999853df4cc21e7
commit + 8e359fa0dccf91ec3b06edc1ea17404f42a62862
blob - 1b45b53a4efff9977dcd3c2e2e33c499adc94533
blob + ebdd46b32765e3a469912c789d2e66380474b9bb
--- got/Makefile
+++ got/Makefile
@@ -13,7 +13,8 @@ SRCS=		got.c blame.c commit_graph.c delta.c diff.c \
 		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
@@ -9,7 +9,7 @@ SRCS=		gotadmin.c \
 		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
@@ -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 - 01296896441d21b985a59ffc870ef3d3b03f4a31
blob + de3dcacc20ae8cf7d1e63df9fbfa5430784ab2bb
--- gotwebd/Makefile
+++ gotwebd/Makefile
@@ -17,7 +17,8 @@ SRCS +=		blame.c commit_graph.c delta.c diff.c \
 		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
@@ -19,8 +19,6 @@
 #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>
@@ -28,15 +26,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 <imsg.h>
-#include <time.h>
 
 #include "got_error.h"
 #include "got_object.h"
@@ -147,514 +142,6 @@ 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;
 }
 
@@ -689,182 +176,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));
@@ -897,178 +209,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)
 {
@@ -1211,273 +353,7 @@ got_tree_entry_get_prev(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;
@@ -1616,199 +492,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)
 {
@@ -1942,6 +625,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)
@@ -2231,129 +915,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 - 7379d7e77fb9e190eb44211cdf722939696a6cbe
blob + aa13e23859c0a05101c4f431cd0675719f48a8e2
--- tog/Makefile
+++ tog/Makefile
@@ -12,7 +12,8 @@ SRCS=		tog.c blame.c commit_graph.c delta.c diff.c \
 		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