2 * Copyright (c) 2018, 2019, 2022 Stefan Sperling <stsp@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <sys/queue.h>
19 #include <sys/types.h>
22 #include <sys/socket.h>
35 #include "got_error.h"
36 #include "got_object.h"
37 #include "got_repository.h"
38 #include "got_opentemp.h"
41 #include "got_lib_delta.h"
42 #include "got_lib_object.h"
43 #include "got_lib_privsep.h"
44 #include "got_lib_object_cache.h"
45 #include "got_lib_pack.h"
46 #include "got_lib_repository.h"
48 static const struct got_error *
49 request_packed_object(struct got_object **obj, struct got_pack *pack, int idx,
50 struct got_object_id *id)
52 const struct got_error *err = NULL;
53 struct imsgbuf *ibuf = pack->privsep_child->ibuf;
55 err = got_privsep_send_packed_obj_req(ibuf, idx, id);
59 err = got_privsep_recv_obj(obj, ibuf);
63 memcpy(&(*obj)->id, id, sizeof((*obj)->id));
68 /* Create temporary files used during delta application. */
69 static const struct got_error *
70 pack_child_send_tempfiles(struct imsgbuf *ibuf, struct got_pack *pack)
72 const struct got_error *err;
73 int basefd = -1, accumfd = -1;
76 * For performance reasons, the child will keep reusing the
77 * same temporary files during every object request.
78 * Opening and closing new files for every object request is
79 * too expensive during operations such as 'gotadmin pack'.
81 if (pack->child_has_tempfiles)
84 basefd = dup(pack->basefd);
86 return got_error_from_errno("dup");
88 accumfd = dup(pack->accumfd);
90 err = got_error_from_errno("dup");
94 err = got_privsep_send_tmpfd(ibuf, basefd);
98 err = got_privsep_send_tmpfd(ibuf, accumfd);
106 pack->child_has_tempfiles = 1;
110 static const struct got_error *
111 request_packed_object_raw(uint8_t **outbuf, off_t *size, size_t *hdrlen,
112 int outfd, struct got_pack *pack, int idx, struct got_object_id *id)
114 const struct got_error *err = NULL;
115 struct imsgbuf *ibuf = pack->privsep_child->ibuf;
118 err = pack_child_send_tempfiles(ibuf, pack);
122 outfd_child = dup(outfd);
123 if (outfd_child == -1)
124 return got_error_from_errno("dup");
126 err = got_privsep_send_packed_raw_obj_req(ibuf, idx, id);
132 err = got_privsep_send_raw_obj_outfd(ibuf, outfd_child);
136 err = got_privsep_recv_raw_obj(outbuf, size, hdrlen, ibuf);
143 static const struct got_error *
144 read_packed_object_privsep(struct got_object **obj,
145 struct got_repository *repo, struct got_pack *pack,
146 struct got_packidx *packidx, int idx, struct got_object_id *id)
148 const struct got_error *err = NULL;
150 if (pack->privsep_child == NULL) {
151 err = got_pack_start_privsep_child(pack, packidx);
156 return request_packed_object(obj, pack, idx, id);
159 static const struct got_error *
160 read_packed_object_raw_privsep(uint8_t **outbuf, off_t *size, size_t *hdrlen,
161 int outfd, struct got_pack *pack, struct got_packidx *packidx, int idx,
162 struct got_object_id *id)
164 const struct got_error *err = NULL;
166 if (pack->privsep_child == NULL) {
167 err = got_pack_start_privsep_child(pack, packidx);
172 return request_packed_object_raw(outbuf, size, hdrlen, outfd, pack,
176 const struct got_error *
177 got_object_open_packed(struct got_object **obj, struct got_object_id *id,
178 struct got_repository *repo)
180 const struct got_error *err = NULL;
181 struct got_pack *pack = NULL;
182 struct got_packidx *packidx = NULL;
186 err = got_repo_search_packidx(&packidx, &idx, repo, id);
190 err = got_packidx_get_packfile_path(&path_packfile,
191 packidx->path_packidx);
195 pack = got_repo_get_cached_pack(repo, path_packfile);
197 err = got_repo_cache_pack(&pack, repo, path_packfile, packidx);
202 err = read_packed_object_privsep(obj, repo, pack, packidx, idx, id);
210 const struct got_error *
211 got_object_open_from_packfile(struct got_object **obj, struct got_object_id *id,
212 struct got_pack *pack, struct got_packidx *packidx, int obj_idx,
213 struct got_repository *repo)
215 return read_packed_object_privsep(obj, repo, pack, packidx,
219 const struct got_error *
220 got_object_read_raw_delta(uint64_t *base_size, uint64_t *result_size,
221 off_t *delta_size, off_t *delta_compressed_size, off_t *delta_offset,
222 off_t *delta_out_offset, struct got_object_id **base_id, int delta_cache_fd,
223 struct got_packidx *packidx, int obj_idx, struct got_object_id *id,
224 struct got_repository *repo)
226 const struct got_error *err = NULL;
227 struct got_pack *pack = NULL;
233 *delta_compressed_size = 0;
235 *delta_out_offset = 0;
237 err = got_packidx_get_packfile_path(&path_packfile,
238 packidx->path_packidx);
242 pack = got_repo_get_cached_pack(repo, path_packfile);
244 err = got_repo_cache_pack(&pack, repo, path_packfile, packidx);
249 if (pack->privsep_child == NULL) {
250 err = got_pack_start_privsep_child(pack, packidx);
255 if (!pack->child_has_delta_outfd) {
257 outfd_child = dup(delta_cache_fd);
258 if (outfd_child == -1)
259 return got_error_from_errno("dup");
260 err = got_privsep_send_raw_delta_outfd(
261 pack->privsep_child->ibuf, outfd_child);
264 pack->child_has_delta_outfd = 1;
267 err = got_privsep_send_raw_delta_req(pack->privsep_child->ibuf,
272 return got_privsep_recv_raw_delta(base_size, result_size, delta_size,
273 delta_compressed_size, delta_offset, delta_out_offset, base_id,
274 pack->privsep_child->ibuf);
277 static const struct got_error *
278 request_object(struct got_object **obj, struct got_object_id *id,
279 struct got_repository *repo, int fd)
281 const struct got_error *err = NULL;
282 struct imsgbuf *ibuf;
284 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf;
286 err = got_privsep_send_obj_req(ibuf, fd, id);
290 return got_privsep_recv_obj(obj, ibuf);
293 static const struct got_error *
294 request_raw_object(uint8_t **outbuf, off_t *size, size_t *hdrlen, int outfd,
295 struct got_object_id *id, struct got_repository *repo, int infd)
297 const struct got_error *err = NULL;
298 struct imsgbuf *ibuf;
301 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf;
303 outfd_child = dup(outfd);
304 if (outfd_child == -1)
305 return got_error_from_errno("dup");
307 err = got_privsep_send_raw_obj_req(ibuf, infd, id);
311 err = got_privsep_send_raw_obj_outfd(ibuf, outfd_child);
315 return got_privsep_recv_raw_obj(outbuf, size, hdrlen, ibuf);
318 static const struct got_error *
319 start_child(struct got_repository *repo, int type)
321 const struct got_error *err = NULL;
324 struct imsgbuf *ibuf;
325 const char *prog_path;
328 case GOT_REPO_PRIVSEP_CHILD_OBJECT:
329 prog_path = GOT_PATH_PROG_READ_OBJECT;
331 case GOT_REPO_PRIVSEP_CHILD_TREE:
332 prog_path = GOT_PATH_PROG_READ_TREE;
334 case GOT_REPO_PRIVSEP_CHILD_COMMIT:
335 prog_path = GOT_PATH_PROG_READ_COMMIT;
337 case GOT_REPO_PRIVSEP_CHILD_BLOB:
338 prog_path = GOT_PATH_PROG_READ_BLOB;
340 case GOT_REPO_PRIVSEP_CHILD_TAG:
341 prog_path = GOT_PATH_PROG_READ_TAG;
344 return got_error(GOT_ERR_OBJ_TYPE);
347 ibuf = calloc(1, sizeof(*ibuf));
349 return got_error_from_errno("calloc");
351 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) {
352 err = got_error_from_errno("socketpair");
359 err = got_error_from_errno("fork");
364 got_privsep_exec_child(imsg_fds, prog_path, repo->path);
368 if (close(imsg_fds[1]) == -1) {
369 err = got_error_from_errno("close");
374 repo->privsep_children[type].imsg_fd = imsg_fds[0];
375 repo->privsep_children[type].pid = pid;
376 imsg_init(ibuf, imsg_fds[0]);
377 repo->privsep_children[type].ibuf = ibuf;
382 const struct got_error *
383 got_object_read_header_privsep(struct got_object **obj,
384 struct got_object_id *id, struct got_repository *repo, int obj_fd)
386 const struct got_error *err;
388 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1)
389 return request_object(obj, id, repo, obj_fd);
391 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_OBJECT);
395 return request_object(obj, id, repo, obj_fd);
398 static const struct got_error *
399 read_object_raw_privsep(uint8_t **outbuf, off_t *size, size_t *hdrlen,
400 int outfd, struct got_object_id *id, struct got_repository *repo,
403 const struct got_error *err;
405 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1)
406 return request_raw_object(outbuf, size, hdrlen, outfd, id,
409 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_OBJECT);
413 return request_raw_object(outbuf, size, hdrlen, outfd, id, repo,
417 const struct got_error *
418 got_object_open(struct got_object **obj, struct got_repository *repo,
419 struct got_object_id *id)
421 const struct got_error *err = NULL;
424 *obj = got_repo_get_cached_object(repo, id);
430 err = got_object_open_packed(obj, id, repo);
431 if (err && err->code != GOT_ERR_NO_OBJ)
435 return got_repo_cache_object(repo, id, *obj);
438 err = got_object_open_loose_fd(&fd, id, repo);
440 if (err->code == GOT_ERR_ERRNO && errno == ENOENT)
441 err = got_error_no_obj(id);
445 err = got_object_read_header_privsep(obj, id, repo, fd);
449 memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
452 return got_repo_cache_object(repo, id, *obj);
455 /* *outfd must be initialized to -1 by caller */
456 const struct got_error *
457 got_object_raw_open(struct got_raw_object **obj, int *outfd,
458 struct got_repository *repo, struct got_object_id *id)
460 const struct got_error *err = NULL;
461 struct got_packidx *packidx = NULL;
463 uint8_t *outbuf = NULL;
466 char *path_packfile = NULL;
468 *obj = got_repo_get_cached_raw_object(repo, id);
475 *outfd = got_opentempfd();
477 return got_error_from_errno("got_opentempfd");
480 err = got_repo_search_packidx(&packidx, &idx, repo, id);
482 struct got_pack *pack = NULL;
484 err = got_packidx_get_packfile_path(&path_packfile,
485 packidx->path_packidx);
489 pack = got_repo_get_cached_pack(repo, path_packfile);
491 err = got_repo_cache_pack(&pack, repo, path_packfile,
496 err = read_packed_object_raw_privsep(&outbuf, &size, &hdrlen,
497 *outfd, pack, packidx, idx, id);
500 } else if (err->code == GOT_ERR_NO_OBJ) {
503 err = got_object_open_loose_fd(&fd, id, repo);
506 err = read_object_raw_privsep(&outbuf, &size, &hdrlen, *outfd,
512 err = got_object_raw_alloc(obj, outbuf, outfd,
513 GOT_DELTA_RESULT_SIZE_CACHED_MAX, hdrlen, size);
517 err = got_repo_cache_raw_object(repo, id, *obj);
522 got_object_raw_close(*obj);
530 static const struct got_error *
531 request_packed_commit(struct got_commit_object **commit, struct got_pack *pack,
532 int pack_idx, struct got_object_id *id)
534 const struct got_error *err = NULL;
536 err = got_privsep_send_commit_req(pack->privsep_child->ibuf, -1, id,
541 err = got_privsep_recv_commit(commit, pack->privsep_child->ibuf);
545 (*commit)->flags |= GOT_COMMIT_FLAG_PACKED;
549 static const struct got_error *
550 read_packed_commit_privsep(struct got_commit_object **commit,
551 struct got_pack *pack, struct got_packidx *packidx, int idx,
552 struct got_object_id *id)
554 const struct got_error *err = NULL;
556 if (pack->privsep_child)
557 return request_packed_commit(commit, pack, idx, id);
559 err = got_pack_start_privsep_child(pack, packidx);
563 return request_packed_commit(commit, pack, idx, id);
566 static const struct got_error *
567 request_commit(struct got_commit_object **commit, struct got_repository *repo,
568 int fd, struct got_object_id *id)
570 const struct got_error *err = NULL;
571 struct imsgbuf *ibuf;
573 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].ibuf;
575 err = got_privsep_send_commit_req(ibuf, fd, id, -1);
579 return got_privsep_recv_commit(commit, ibuf);
582 static const struct got_error *
583 read_commit_privsep(struct got_commit_object **commit, int obj_fd,
584 struct got_object_id *id, struct got_repository *repo)
586 const struct got_error *err;
588 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd != -1)
589 return request_commit(commit, repo, obj_fd, id);
591 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_COMMIT);
595 return request_commit(commit, repo, obj_fd, id);
598 static const struct got_error *
599 open_commit(struct got_commit_object **commit,
600 struct got_repository *repo, struct got_object_id *id, int check_cache)
602 const struct got_error *err = NULL;
603 struct got_packidx *packidx = NULL;
605 char *path_packfile = NULL;
608 *commit = got_repo_get_cached_commit(repo, id);
609 if (*commit != NULL) {
616 err = got_repo_search_packidx(&packidx, &idx, repo, id);
618 struct got_pack *pack = NULL;
620 err = got_packidx_get_packfile_path(&path_packfile,
621 packidx->path_packidx);
625 pack = got_repo_get_cached_pack(repo, path_packfile);
627 err = got_repo_cache_pack(&pack, repo, path_packfile,
632 err = read_packed_commit_privsep(commit, pack,
634 } else if (err->code == GOT_ERR_NO_OBJ) {
637 err = got_object_open_loose_fd(&fd, id, repo);
640 err = read_commit_privsep(commit, fd, id, repo);
645 err = got_repo_cache_commit(repo, id, *commit);
652 const struct got_error *
653 got_object_open_as_commit(struct got_commit_object **commit,
654 struct got_repository *repo, struct got_object_id *id)
656 *commit = got_repo_get_cached_commit(repo, id);
657 if (*commit != NULL) {
662 return open_commit(commit, repo, id, 0);
665 const struct got_error *
666 got_object_commit_open(struct got_commit_object **commit,
667 struct got_repository *repo, struct got_object *obj)
669 return open_commit(commit, repo, got_object_get_id(obj), 1);
672 static const struct got_error *
673 request_packed_tree(struct got_tree_object **tree, struct got_pack *pack,
674 int pack_idx, struct got_object_id *id)
676 const struct got_error *err = NULL;
678 err = got_privsep_send_tree_req(pack->privsep_child->ibuf, -1, id,
683 return got_privsep_recv_tree(tree, pack->privsep_child->ibuf);
686 static const struct got_error *
687 read_packed_tree_privsep(struct got_tree_object **tree,
688 struct got_pack *pack, struct got_packidx *packidx, int idx,
689 struct got_object_id *id)
691 const struct got_error *err = NULL;
693 if (pack->privsep_child)
694 return request_packed_tree(tree, pack, idx, id);
696 err = got_pack_start_privsep_child(pack, packidx);
700 return request_packed_tree(tree, pack, idx, id);
703 static const struct got_error *
704 request_tree(struct got_tree_object **tree, struct got_repository *repo,
705 int fd, struct got_object_id *id)
707 const struct got_error *err = NULL;
708 struct imsgbuf *ibuf;
710 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].ibuf;
712 err = got_privsep_send_tree_req(ibuf, fd, id, -1);
716 return got_privsep_recv_tree(tree, ibuf);
719 static const struct got_error *
720 read_tree_privsep(struct got_tree_object **tree, int obj_fd,
721 struct got_object_id *id, struct got_repository *repo)
723 const struct got_error *err;
725 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd != -1)
726 return request_tree(tree, repo, obj_fd, id);
728 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_TREE);
732 return request_tree(tree, repo, obj_fd, id);
735 static const struct got_error *
736 open_tree(struct got_tree_object **tree, struct got_repository *repo,
737 struct got_object_id *id, int check_cache)
739 const struct got_error *err = NULL;
740 struct got_packidx *packidx = NULL;
742 char *path_packfile = NULL;
745 *tree = got_repo_get_cached_tree(repo, id);
753 err = got_repo_search_packidx(&packidx, &idx, repo, id);
755 struct got_pack *pack = NULL;
757 err = got_packidx_get_packfile_path(&path_packfile,
758 packidx->path_packidx);
762 pack = got_repo_get_cached_pack(repo, path_packfile);
764 err = got_repo_cache_pack(&pack, repo, path_packfile,
769 err = read_packed_tree_privsep(tree, pack,
771 } else if (err->code == GOT_ERR_NO_OBJ) {
774 err = got_object_open_loose_fd(&fd, id, repo);
777 err = read_tree_privsep(tree, fd, id, repo);
782 err = got_repo_cache_tree(repo, id, *tree);
789 const struct got_error *
790 got_object_open_as_tree(struct got_tree_object **tree,
791 struct got_repository *repo, struct got_object_id *id)
793 *tree = got_repo_get_cached_tree(repo, id);
799 return open_tree(tree, repo, id, 0);
802 const struct got_error *
803 got_object_tree_open(struct got_tree_object **tree,
804 struct got_repository *repo, struct got_object *obj)
806 return open_tree(tree, repo, got_object_get_id(obj), 1);
809 static const struct got_error *
810 request_packed_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen, int outfd,
811 struct got_pack *pack, struct got_packidx *packidx, int idx,
812 struct got_object_id *id)
814 const struct got_error *err = NULL;
815 struct imsgbuf *ibuf = pack->privsep_child->ibuf;
818 err = pack_child_send_tempfiles(ibuf, pack);
822 outfd_child = dup(outfd);
823 if (outfd_child == -1)
824 return got_error_from_errno("dup");
826 err = got_privsep_send_blob_req(pack->privsep_child->ibuf, -1, id, idx);
830 err = got_privsep_send_blob_outfd(pack->privsep_child->ibuf,
836 err = got_privsep_recv_blob(outbuf, size, hdrlen,
837 pack->privsep_child->ibuf);
841 if (lseek(outfd, SEEK_SET, 0) == -1)
842 err = got_error_from_errno("lseek");
847 static const struct got_error *
848 read_packed_blob_privsep(uint8_t **outbuf, size_t *size, size_t *hdrlen,
849 int outfd, struct got_pack *pack, struct got_packidx *packidx, int idx,
850 struct got_object_id *id)
852 const struct got_error *err = NULL;
854 if (pack->privsep_child == NULL) {
855 err = got_pack_start_privsep_child(pack, packidx);
860 return request_packed_blob(outbuf, size, hdrlen, outfd, pack, packidx,
864 static const struct got_error *
865 request_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen, int outfd,
866 int infd, struct got_object_id *id, struct imsgbuf *ibuf)
868 const struct got_error *err = NULL;
871 outfd_child = dup(outfd);
872 if (outfd_child == -1)
873 return got_error_from_errno("dup");
875 err = got_privsep_send_blob_req(ibuf, infd, id, -1);
879 err = got_privsep_send_blob_outfd(ibuf, outfd_child);
883 err = got_privsep_recv_blob(outbuf, size, hdrlen, ibuf);
887 if (lseek(outfd, SEEK_SET, 0) == -1)
888 return got_error_from_errno("lseek");
893 static const struct got_error *
894 read_blob_privsep(uint8_t **outbuf, size_t *size, size_t *hdrlen,
895 int outfd, int infd, struct got_object_id *id, struct got_repository *repo)
897 const struct got_error *err;
898 struct imsgbuf *ibuf;
900 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd != -1) {
901 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf;
902 return request_blob(outbuf, size, hdrlen, outfd, infd, id,
906 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_BLOB);
910 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf;
911 return request_blob(outbuf, size, hdrlen, outfd, infd, id, ibuf);
914 static const struct got_error *
915 open_blob(struct got_blob_object **blob, struct got_repository *repo,
916 struct got_object_id *id, size_t blocksize, int outfd)
918 const struct got_error *err = NULL;
919 struct got_packidx *packidx = NULL;
921 char *path_packfile = NULL;
926 *blob = calloc(1, sizeof(**blob));
928 return got_error_from_errno("calloc");
930 (*blob)->read_buf = malloc(blocksize);
931 if ((*blob)->read_buf == NULL) {
932 err = got_error_from_errno("malloc");
936 if (ftruncate(outfd, 0L) == -1) {
937 err = got_error_from_errno("ftruncate");
940 if (lseek(outfd, SEEK_SET, 0) == -1) {
941 err = got_error_from_errno("lseek");
945 err = got_repo_search_packidx(&packidx, &idx, repo, id);
947 struct got_pack *pack = NULL;
949 err = got_packidx_get_packfile_path(&path_packfile,
950 packidx->path_packidx);
954 pack = got_repo_get_cached_pack(repo, path_packfile);
956 err = got_repo_cache_pack(&pack, repo, path_packfile,
961 err = read_packed_blob_privsep(&outbuf, &size, &hdrlen, outfd,
962 pack, packidx, idx, id);
963 } else if (err->code == GOT_ERR_NO_OBJ) {
966 err = got_object_open_loose_fd(&infd, id, repo);
969 err = read_blob_privsep(&outbuf, &size, &hdrlen, outfd, infd,
976 err = got_error(GOT_ERR_BAD_OBJ_HDR);
981 (*blob)->f = fmemopen(outbuf, size, "rb");
982 if ((*blob)->f == NULL) {
983 err = got_error_from_errno("fmemopen");
987 (*blob)->data = outbuf;
989 if (fstat(outfd, &sb) == -1) {
990 err = got_error_from_errno("fstat");
994 if (sb.st_size != size) {
995 err = got_error(GOT_ERR_PRIVSEP_LEN);
1001 err = got_error_from_errno("dup");
1005 (*blob)->f = fdopen(dfd, "rb");
1006 if ((*blob)->f == NULL) {
1007 err = got_error_from_errno("fdopen");
1014 (*blob)->hdrlen = hdrlen;
1015 (*blob)->blocksize = blocksize;
1016 memcpy(&(*blob)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
1019 free(path_packfile);
1022 got_object_blob_close(*blob);
1029 const struct got_error *
1030 got_object_open_as_blob(struct got_blob_object **blob,
1031 struct got_repository *repo, struct got_object_id *id, size_t blocksize,
1034 return open_blob(blob, repo, id, blocksize, outfd);
1037 const struct got_error *
1038 got_object_blob_open(struct got_blob_object **blob,
1039 struct got_repository *repo, struct got_object *obj, size_t blocksize,
1042 return open_blob(blob, repo, got_object_get_id(obj), blocksize, outfd);
1045 static const struct got_error *
1046 request_packed_tag(struct got_tag_object **tag, struct got_pack *pack,
1047 int pack_idx, struct got_object_id *id)
1049 const struct got_error *err = NULL;
1051 err = got_privsep_send_tag_req(pack->privsep_child->ibuf, -1, id,
1056 return got_privsep_recv_tag(tag, pack->privsep_child->ibuf);
1059 static const struct got_error *
1060 read_packed_tag_privsep(struct got_tag_object **tag,
1061 struct got_pack *pack, struct got_packidx *packidx, int idx,
1062 struct got_object_id *id)
1064 const struct got_error *err = NULL;
1066 if (pack->privsep_child)
1067 return request_packed_tag(tag, pack, idx, id);
1069 err = got_pack_start_privsep_child(pack, packidx);
1073 return request_packed_tag(tag, pack, idx, id);
1076 static const struct got_error *
1077 request_tag(struct got_tag_object **tag, struct got_repository *repo,
1078 int fd, struct got_object_id *id)
1080 const struct got_error *err = NULL;
1081 struct imsgbuf *ibuf;
1083 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].ibuf;
1085 err = got_privsep_send_tag_req(ibuf, fd, id, -1);
1089 return got_privsep_recv_tag(tag, ibuf);
1092 static const struct got_error *
1093 read_tag_privsep(struct got_tag_object **tag, int obj_fd,
1094 struct got_object_id *id, struct got_repository *repo)
1096 const struct got_error *err;
1098 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].imsg_fd != -1)
1099 return request_tag(tag, repo, obj_fd, id);
1101 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_TAG);
1105 return request_tag(tag, repo, obj_fd, id);
1108 static const struct got_error *
1109 open_tag(struct got_tag_object **tag, struct got_repository *repo,
1110 struct got_object_id *id, int check_cache)
1112 const struct got_error *err = NULL;
1113 struct got_packidx *packidx = NULL;
1115 char *path_packfile = NULL;
1116 struct got_object *obj = NULL;
1117 int obj_type = GOT_OBJ_TYPE_ANY;
1120 *tag = got_repo_get_cached_tag(repo, id);
1128 err = got_repo_search_packidx(&packidx, &idx, repo, id);
1130 struct got_pack *pack = NULL;
1132 err = got_packidx_get_packfile_path(&path_packfile,
1133 packidx->path_packidx);
1137 pack = got_repo_get_cached_pack(repo, path_packfile);
1139 err = got_repo_cache_pack(&pack, repo, path_packfile,
1145 /* Beware of "lightweight" tags: Check object type first. */
1146 err = read_packed_object_privsep(&obj, repo, pack, packidx,
1150 obj_type = obj->type;
1151 got_object_close(obj);
1152 if (obj_type != GOT_OBJ_TYPE_TAG) {
1153 err = got_error(GOT_ERR_OBJ_TYPE);
1156 err = read_packed_tag_privsep(tag, pack, packidx, idx, id);
1157 } else if (err->code == GOT_ERR_NO_OBJ) {
1160 err = got_object_open_loose_fd(&fd, id, repo);
1163 err = got_object_read_header_privsep(&obj, id, repo, fd);
1166 obj_type = obj->type;
1167 got_object_close(obj);
1168 if (obj_type != GOT_OBJ_TYPE_TAG)
1169 return got_error(GOT_ERR_OBJ_TYPE);
1171 err = got_object_open_loose_fd(&fd, id, repo);
1174 err = read_tag_privsep(tag, fd, id, repo);
1179 err = got_repo_cache_tag(repo, id, *tag);
1182 free(path_packfile);
1186 const struct got_error *
1187 got_object_open_as_tag(struct got_tag_object **tag,
1188 struct got_repository *repo, struct got_object_id *id)
1190 *tag = got_repo_get_cached_tag(repo, id);
1196 return open_tag(tag, repo, id, 0);
1199 const struct got_error *
1200 got_object_tag_open(struct got_tag_object **tag,
1201 struct got_repository *repo, struct got_object *obj)
1203 return open_tag(tag, repo, got_object_get_id(obj), 1);
1206 const struct got_error *
1207 got_traverse_packed_commits(struct got_object_id_queue *traversed_commits,
1208 struct got_object_id *commit_id, const char *path,
1209 struct got_repository *repo)
1211 const struct got_error *err = NULL;
1212 struct got_pack *pack = NULL;
1213 struct got_packidx *packidx = NULL;
1214 char *path_packfile = NULL;
1215 struct got_commit_object *changed_commit = NULL;
1216 struct got_object_id *changed_commit_id = NULL;
1219 err = got_repo_search_packidx(&packidx, &idx, repo, commit_id);
1221 if (err->code != GOT_ERR_NO_OBJ)
1226 err = got_packidx_get_packfile_path(&path_packfile,
1227 packidx->path_packidx);
1231 pack = got_repo_get_cached_pack(repo, path_packfile);
1233 err = got_repo_cache_pack(&pack, repo, path_packfile, packidx);
1238 if (pack->privsep_child == NULL) {
1239 err = got_pack_start_privsep_child(pack, packidx);
1244 err = got_privsep_send_commit_traversal_request(
1245 pack->privsep_child->ibuf, commit_id, idx, path);
1249 err = got_privsep_recv_traversed_commits(&changed_commit,
1250 &changed_commit_id, traversed_commits, pack->privsep_child->ibuf);
1254 if (changed_commit) {
1256 * Cache the commit in which the path was changed.
1257 * This commit might be opened again soon.
1259 changed_commit->refcnt++;
1260 err = got_repo_cache_commit(repo, changed_commit_id,
1262 got_object_commit_close(changed_commit);
1265 free(path_packfile);
1266 free(changed_commit_id);
1270 const struct got_error *
1271 got_object_enumerate(int *found_all_objects,
1272 got_object_enumerate_commit_cb cb_commit,
1273 got_object_enumerate_tree_cb cb_tree, void *cb_arg,
1274 struct got_object_id **ours, int nours,
1275 struct got_object_id **theirs, int ntheirs,
1276 struct got_packidx *packidx, struct got_repository *repo)
1278 const struct got_error *err = NULL;
1279 struct got_pack *pack;
1280 char *path_packfile = NULL;
1282 err = got_packidx_get_packfile_path(&path_packfile,
1283 packidx->path_packidx);
1287 pack = got_repo_get_cached_pack(repo, path_packfile);
1289 err = got_repo_cache_pack(&pack, repo, path_packfile, packidx);
1294 if (pack->privsep_child == NULL) {
1295 err = got_pack_start_privsep_child(pack, packidx);
1300 err = got_privsep_send_object_enumeration_request(
1301 pack->privsep_child->ibuf);
1305 err = got_privsep_send_object_idlist(pack->privsep_child->ibuf,
1309 err = got_privsep_send_object_idlist_done(pack->privsep_child->ibuf);
1313 err = got_privsep_send_object_idlist(pack->privsep_child->ibuf,
1317 err = got_privsep_send_object_idlist_done(pack->privsep_child->ibuf);
1321 err = got_privsep_recv_enumerated_objects(found_all_objects,
1322 pack->privsep_child->ibuf, cb_commit, cb_tree, cb_arg, repo);
1324 free(path_packfile);