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>
21 #include <sys/socket.h>
33 #include "got_error.h"
34 #include "got_object.h"
35 #include "got_repository.h"
36 #include "got_opentemp.h"
39 #include "got_lib_delta.h"
40 #include "got_lib_object.h"
41 #include "got_lib_privsep.h"
42 #include "got_lib_object_cache.h"
43 #include "got_lib_pack.h"
44 #include "got_lib_repository.h"
46 static const struct got_error *
47 request_packed_object(struct got_object **obj, struct got_pack *pack, int idx,
48 struct got_object_id *id)
50 const struct got_error *err = NULL;
51 struct imsgbuf *ibuf = pack->privsep_child->ibuf;
53 err = got_privsep_send_packed_obj_req(ibuf, idx, id);
57 err = got_privsep_recv_obj(obj, ibuf);
61 memcpy(&(*obj)->id, id, sizeof((*obj)->id));
66 /* Create temporary files used during delta application. */
67 static const struct got_error *
68 pack_child_send_tempfiles(struct imsgbuf *ibuf, struct got_pack *pack)
70 const struct got_error *err;
71 int basefd = -1, accumfd = -1;
74 * For performance reasons, the child will keep reusing the
75 * same temporary files during every object request.
76 * Opening and closing new files for every object request is
77 * too expensive during operations such as 'gotadmin pack'.
79 if (pack->child_has_tempfiles)
82 basefd = dup(pack->basefd);
84 return got_error_from_errno("dup");
86 accumfd = dup(pack->accumfd);
88 err = got_error_from_errno("dup");
92 err = got_privsep_send_tmpfd(ibuf, basefd);
96 err = got_privsep_send_tmpfd(ibuf, accumfd);
104 pack->child_has_tempfiles = 1;
108 static const struct got_error *
109 request_packed_object_raw(uint8_t **outbuf, off_t *size, size_t *hdrlen,
110 int outfd, struct got_pack *pack, int idx, struct got_object_id *id)
112 const struct got_error *err = NULL;
113 struct imsgbuf *ibuf = pack->privsep_child->ibuf;
116 err = pack_child_send_tempfiles(ibuf, pack);
120 outfd_child = dup(outfd);
121 if (outfd_child == -1)
122 return got_error_from_errno("dup");
124 err = got_privsep_send_packed_raw_obj_req(ibuf, idx, id);
130 err = got_privsep_send_raw_obj_outfd(ibuf, outfd_child);
134 err = got_privsep_recv_raw_obj(outbuf, size, hdrlen, ibuf);
141 static const struct got_error *
142 read_packed_object_privsep(struct got_object **obj,
143 struct got_repository *repo, struct got_pack *pack,
144 struct got_packidx *packidx, int idx, struct got_object_id *id)
146 const struct got_error *err = NULL;
148 if (pack->privsep_child == NULL) {
149 err = got_pack_start_privsep_child(pack, packidx);
154 return request_packed_object(obj, pack, idx, id);
157 static const struct got_error *
158 read_packed_object_raw_privsep(uint8_t **outbuf, off_t *size, size_t *hdrlen,
159 int outfd, struct got_pack *pack, struct got_packidx *packidx, int idx,
160 struct got_object_id *id)
162 const struct got_error *err = NULL;
164 if (pack->privsep_child == NULL) {
165 err = got_pack_start_privsep_child(pack, packidx);
170 return request_packed_object_raw(outbuf, size, hdrlen, outfd, pack,
174 const struct got_error *
175 got_object_open_packed(struct got_object **obj, struct got_object_id *id,
176 struct got_repository *repo)
178 const struct got_error *err = NULL;
179 struct got_pack *pack = NULL;
180 struct got_packidx *packidx = NULL;
184 err = got_repo_search_packidx(&packidx, &idx, repo, id);
188 err = got_packidx_get_packfile_path(&path_packfile,
189 packidx->path_packidx);
193 pack = got_repo_get_cached_pack(repo, path_packfile);
195 err = got_repo_cache_pack(&pack, repo, path_packfile, packidx);
200 err = read_packed_object_privsep(obj, repo, pack, packidx, idx, id);
208 const struct got_error *
209 got_object_open_from_packfile(struct got_object **obj, struct got_object_id *id,
210 struct got_pack *pack, struct got_packidx *packidx, int obj_idx,
211 struct got_repository *repo)
213 return read_packed_object_privsep(obj, repo, pack, packidx,
217 const struct got_error *
218 got_object_read_raw_delta(uint64_t *base_size, uint64_t *result_size,
219 off_t *delta_size, off_t *delta_compressed_size, off_t *delta_offset,
220 off_t *delta_out_offset, struct got_object_id **base_id, int delta_cache_fd,
221 struct got_packidx *packidx, int obj_idx, struct got_object_id *id,
222 struct got_repository *repo)
224 const struct got_error *err = NULL;
225 struct got_pack *pack = NULL;
231 *delta_compressed_size = 0;
233 *delta_out_offset = 0;
235 err = got_packidx_get_packfile_path(&path_packfile,
236 packidx->path_packidx);
240 pack = got_repo_get_cached_pack(repo, path_packfile);
242 err = got_repo_cache_pack(&pack, repo, path_packfile, packidx);
247 if (pack->privsep_child == NULL) {
248 err = got_pack_start_privsep_child(pack, packidx);
253 if (!pack->child_has_delta_outfd) {
255 outfd_child = dup(delta_cache_fd);
256 if (outfd_child == -1)
257 return got_error_from_errno("dup");
258 err = got_privsep_send_raw_delta_outfd(
259 pack->privsep_child->ibuf, outfd_child);
262 pack->child_has_delta_outfd = 1;
265 err = got_privsep_send_raw_delta_req(pack->privsep_child->ibuf,
270 return got_privsep_recv_raw_delta(base_size, result_size, delta_size,
271 delta_compressed_size, delta_offset, delta_out_offset, base_id,
272 pack->privsep_child->ibuf);
275 static const struct got_error *
276 request_object(struct got_object **obj, struct got_object_id *id,
277 struct got_repository *repo, int fd)
279 const struct got_error *err = NULL;
280 struct imsgbuf *ibuf;
282 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf;
284 err = got_privsep_send_obj_req(ibuf, fd, id);
288 return got_privsep_recv_obj(obj, ibuf);
291 static const struct got_error *
292 request_raw_object(uint8_t **outbuf, off_t *size, size_t *hdrlen, int outfd,
293 struct got_object_id *id, struct got_repository *repo, int infd)
295 const struct got_error *err = NULL;
296 struct imsgbuf *ibuf;
299 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].ibuf;
301 outfd_child = dup(outfd);
302 if (outfd_child == -1)
303 return got_error_from_errno("dup");
305 err = got_privsep_send_raw_obj_req(ibuf, infd, id);
309 err = got_privsep_send_raw_obj_outfd(ibuf, outfd_child);
313 return got_privsep_recv_raw_obj(outbuf, size, hdrlen, ibuf);
316 static const struct got_error *
317 start_child(struct got_repository *repo, int type)
319 const struct got_error *err = NULL;
322 struct imsgbuf *ibuf;
323 const char *prog_path;
326 case GOT_REPO_PRIVSEP_CHILD_OBJECT:
327 prog_path = GOT_PATH_PROG_READ_OBJECT;
329 case GOT_REPO_PRIVSEP_CHILD_TREE:
330 prog_path = GOT_PATH_PROG_READ_TREE;
332 case GOT_REPO_PRIVSEP_CHILD_COMMIT:
333 prog_path = GOT_PATH_PROG_READ_COMMIT;
335 case GOT_REPO_PRIVSEP_CHILD_BLOB:
336 prog_path = GOT_PATH_PROG_READ_BLOB;
338 case GOT_REPO_PRIVSEP_CHILD_TAG:
339 prog_path = GOT_PATH_PROG_READ_TAG;
342 return got_error(GOT_ERR_OBJ_TYPE);
345 ibuf = calloc(1, sizeof(*ibuf));
347 return got_error_from_errno("calloc");
349 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) {
350 err = got_error_from_errno("socketpair");
357 err = got_error_from_errno("fork");
362 got_privsep_exec_child(imsg_fds, prog_path, repo->path);
366 if (close(imsg_fds[1]) == -1) {
367 err = got_error_from_errno("close");
372 repo->privsep_children[type].imsg_fd = imsg_fds[0];
373 repo->privsep_children[type].pid = pid;
374 imsg_init(ibuf, imsg_fds[0]);
375 repo->privsep_children[type].ibuf = ibuf;
380 const struct got_error *
381 got_object_read_header_privsep(struct got_object **obj,
382 struct got_object_id *id, struct got_repository *repo, int obj_fd)
384 const struct got_error *err;
386 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1)
387 return request_object(obj, id, repo, obj_fd);
389 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_OBJECT);
393 return request_object(obj, id, repo, obj_fd);
396 static const struct got_error *
397 read_object_raw_privsep(uint8_t **outbuf, off_t *size, size_t *hdrlen,
398 int outfd, struct got_object_id *id, struct got_repository *repo,
401 const struct got_error *err;
403 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1)
404 return request_raw_object(outbuf, size, hdrlen, outfd, id,
407 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_OBJECT);
411 return request_raw_object(outbuf, size, hdrlen, outfd, id, repo,
415 const struct got_error *
416 got_object_open(struct got_object **obj, struct got_repository *repo,
417 struct got_object_id *id)
419 const struct got_error *err = NULL;
422 *obj = got_repo_get_cached_object(repo, id);
428 err = got_object_open_packed(obj, id, repo);
429 if (err && err->code != GOT_ERR_NO_OBJ)
433 return got_repo_cache_object(repo, id, *obj);
436 err = got_object_open_loose_fd(&fd, id, repo);
438 if (err->code == GOT_ERR_ERRNO && errno == ENOENT)
439 err = got_error_no_obj(id);
443 err = got_object_read_header_privsep(obj, id, repo, fd);
447 memcpy(&(*obj)->id, id, sizeof(*id));
450 return got_repo_cache_object(repo, id, *obj);
453 /* *outfd must be initialized to -1 by caller */
454 const struct got_error *
455 got_object_raw_open(struct got_raw_object **obj, int *outfd,
456 struct got_repository *repo, struct got_object_id *id)
458 const struct got_error *err = NULL;
459 struct got_packidx *packidx = NULL;
461 uint8_t *outbuf = NULL;
464 char *path_packfile = NULL;
466 *obj = got_repo_get_cached_raw_object(repo, id);
473 *outfd = got_opentempfd();
475 return got_error_from_errno("got_opentempfd");
478 err = got_repo_search_packidx(&packidx, &idx, repo, id);
480 struct got_pack *pack = NULL;
482 err = got_packidx_get_packfile_path(&path_packfile,
483 packidx->path_packidx);
487 pack = got_repo_get_cached_pack(repo, path_packfile);
489 err = got_repo_cache_pack(&pack, repo, path_packfile,
494 err = read_packed_object_raw_privsep(&outbuf, &size, &hdrlen,
495 *outfd, pack, packidx, idx, id);
498 } else if (err->code == GOT_ERR_NO_OBJ) {
501 err = got_object_open_loose_fd(&fd, id, repo);
504 err = read_object_raw_privsep(&outbuf, &size, &hdrlen, *outfd,
510 err = got_object_raw_alloc(obj, outbuf, outfd,
511 GOT_DELTA_RESULT_SIZE_CACHED_MAX, hdrlen, size);
515 err = got_repo_cache_raw_object(repo, id, *obj);
520 got_object_raw_close(*obj);
528 static const struct got_error *
529 request_packed_commit(struct got_commit_object **commit, struct got_pack *pack,
530 int pack_idx, struct got_object_id *id)
532 const struct got_error *err = NULL;
534 err = got_privsep_send_commit_req(pack->privsep_child->ibuf, -1, id,
539 err = got_privsep_recv_commit(commit, pack->privsep_child->ibuf);
543 (*commit)->flags |= GOT_COMMIT_FLAG_PACKED;
547 static const struct got_error *
548 read_packed_commit_privsep(struct got_commit_object **commit,
549 struct got_pack *pack, struct got_packidx *packidx, int idx,
550 struct got_object_id *id)
552 const struct got_error *err = NULL;
554 if (pack->privsep_child)
555 return request_packed_commit(commit, pack, idx, id);
557 err = got_pack_start_privsep_child(pack, packidx);
561 return request_packed_commit(commit, pack, idx, id);
564 static const struct got_error *
565 request_commit(struct got_commit_object **commit, struct got_repository *repo,
566 int fd, struct got_object_id *id)
568 const struct got_error *err = NULL;
569 struct imsgbuf *ibuf;
571 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].ibuf;
573 err = got_privsep_send_commit_req(ibuf, fd, id, -1);
577 return got_privsep_recv_commit(commit, ibuf);
580 static const struct got_error *
581 read_commit_privsep(struct got_commit_object **commit, int obj_fd,
582 struct got_object_id *id, struct got_repository *repo)
584 const struct got_error *err;
586 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd != -1)
587 return request_commit(commit, repo, obj_fd, id);
589 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_COMMIT);
593 return request_commit(commit, repo, obj_fd, id);
596 static const struct got_error *
597 open_commit(struct got_commit_object **commit,
598 struct got_repository *repo, struct got_object_id *id, int check_cache)
600 const struct got_error *err = NULL;
601 struct got_packidx *packidx = NULL;
603 char *path_packfile = NULL;
606 *commit = got_repo_get_cached_commit(repo, id);
607 if (*commit != NULL) {
614 err = got_repo_search_packidx(&packidx, &idx, repo, id);
616 struct got_pack *pack = NULL;
618 err = got_packidx_get_packfile_path(&path_packfile,
619 packidx->path_packidx);
623 pack = got_repo_get_cached_pack(repo, path_packfile);
625 err = got_repo_cache_pack(&pack, repo, path_packfile,
630 err = read_packed_commit_privsep(commit, pack,
632 } else if (err->code == GOT_ERR_NO_OBJ) {
635 err = got_object_open_loose_fd(&fd, id, repo);
638 err = read_commit_privsep(commit, fd, id, repo);
643 err = got_repo_cache_commit(repo, id, *commit);
650 const struct got_error *
651 got_object_open_as_commit(struct got_commit_object **commit,
652 struct got_repository *repo, struct got_object_id *id)
654 *commit = got_repo_get_cached_commit(repo, id);
655 if (*commit != NULL) {
660 return open_commit(commit, repo, id, 0);
663 const struct got_error *
664 got_object_commit_open(struct got_commit_object **commit,
665 struct got_repository *repo, struct got_object *obj)
667 return open_commit(commit, repo, got_object_get_id(obj), 1);
670 static const struct got_error *
671 request_packed_tree(struct got_tree_object **tree, struct got_pack *pack,
672 int pack_idx, struct got_object_id *id)
674 const struct got_error *err = NULL;
676 err = got_privsep_send_tree_req(pack->privsep_child->ibuf, -1, id,
681 return got_privsep_recv_tree(tree, pack->privsep_child->ibuf);
684 static const struct got_error *
685 read_packed_tree_privsep(struct got_tree_object **tree,
686 struct got_pack *pack, struct got_packidx *packidx, int idx,
687 struct got_object_id *id)
689 const struct got_error *err = NULL;
691 if (pack->privsep_child)
692 return request_packed_tree(tree, pack, idx, id);
694 err = got_pack_start_privsep_child(pack, packidx);
698 return request_packed_tree(tree, pack, idx, id);
701 static const struct got_error *
702 request_tree(struct got_tree_object **tree, struct got_repository *repo,
703 int fd, struct got_object_id *id)
705 const struct got_error *err = NULL;
706 struct imsgbuf *ibuf;
708 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].ibuf;
710 err = got_privsep_send_tree_req(ibuf, fd, id, -1);
714 return got_privsep_recv_tree(tree, ibuf);
717 static const struct got_error *
718 read_tree_privsep(struct got_tree_object **tree, int obj_fd,
719 struct got_object_id *id, struct got_repository *repo)
721 const struct got_error *err;
723 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd != -1)
724 return request_tree(tree, repo, obj_fd, id);
726 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_TREE);
730 return request_tree(tree, repo, obj_fd, id);
733 static const struct got_error *
734 open_tree(struct got_tree_object **tree, struct got_repository *repo,
735 struct got_object_id *id, int check_cache)
737 const struct got_error *err = NULL;
738 struct got_packidx *packidx = NULL;
740 char *path_packfile = NULL;
743 *tree = got_repo_get_cached_tree(repo, id);
751 err = got_repo_search_packidx(&packidx, &idx, repo, id);
753 struct got_pack *pack = NULL;
755 err = got_packidx_get_packfile_path(&path_packfile,
756 packidx->path_packidx);
760 pack = got_repo_get_cached_pack(repo, path_packfile);
762 err = got_repo_cache_pack(&pack, repo, path_packfile,
767 err = read_packed_tree_privsep(tree, pack,
769 } else if (err->code == GOT_ERR_NO_OBJ) {
772 err = got_object_open_loose_fd(&fd, id, repo);
775 err = read_tree_privsep(tree, fd, id, repo);
780 err = got_repo_cache_tree(repo, id, *tree);
787 const struct got_error *
788 got_object_open_as_tree(struct got_tree_object **tree,
789 struct got_repository *repo, struct got_object_id *id)
791 *tree = got_repo_get_cached_tree(repo, id);
797 return open_tree(tree, repo, id, 0);
800 const struct got_error *
801 got_object_tree_open(struct got_tree_object **tree,
802 struct got_repository *repo, struct got_object *obj)
804 return open_tree(tree, repo, got_object_get_id(obj), 1);
807 static const struct got_error *
808 request_packed_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen, int outfd,
809 struct got_pack *pack, struct got_packidx *packidx, int idx,
810 struct got_object_id *id)
812 const struct got_error *err = NULL;
813 struct imsgbuf *ibuf = pack->privsep_child->ibuf;
816 err = pack_child_send_tempfiles(ibuf, pack);
820 outfd_child = dup(outfd);
821 if (outfd_child == -1)
822 return got_error_from_errno("dup");
824 err = got_privsep_send_blob_req(pack->privsep_child->ibuf, -1, id, idx);
828 err = got_privsep_send_blob_outfd(pack->privsep_child->ibuf,
834 err = got_privsep_recv_blob(outbuf, size, hdrlen,
835 pack->privsep_child->ibuf);
839 if (lseek(outfd, SEEK_SET, 0) == -1)
840 err = got_error_from_errno("lseek");
845 static const struct got_error *
846 read_packed_blob_privsep(uint8_t **outbuf, size_t *size, size_t *hdrlen,
847 int outfd, struct got_pack *pack, struct got_packidx *packidx, int idx,
848 struct got_object_id *id)
850 const struct got_error *err = NULL;
852 if (pack->privsep_child == NULL) {
853 err = got_pack_start_privsep_child(pack, packidx);
858 return request_packed_blob(outbuf, size, hdrlen, outfd, pack, packidx,
862 static const struct got_error *
863 request_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen, int outfd,
864 int infd, struct got_object_id *id, struct imsgbuf *ibuf)
866 const struct got_error *err = NULL;
869 outfd_child = dup(outfd);
870 if (outfd_child == -1)
871 return got_error_from_errno("dup");
873 err = got_privsep_send_blob_req(ibuf, infd, id, -1);
877 err = got_privsep_send_blob_outfd(ibuf, outfd_child);
881 err = got_privsep_recv_blob(outbuf, size, hdrlen, ibuf);
885 if (lseek(outfd, SEEK_SET, 0) == -1)
886 return got_error_from_errno("lseek");
891 static const struct got_error *
892 read_blob_privsep(uint8_t **outbuf, size_t *size, size_t *hdrlen,
893 int outfd, int infd, struct got_object_id *id, struct got_repository *repo)
895 const struct got_error *err;
896 struct imsgbuf *ibuf;
898 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd != -1) {
899 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf;
900 return request_blob(outbuf, size, hdrlen, outfd, infd, id,
904 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_BLOB);
908 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].ibuf;
909 return request_blob(outbuf, size, hdrlen, outfd, infd, id, ibuf);
912 static const struct got_error *
913 open_blob(struct got_blob_object **blob, struct got_repository *repo,
914 struct got_object_id *id, size_t blocksize, int outfd)
916 const struct got_error *err = NULL;
917 struct got_packidx *packidx = NULL;
919 char *path_packfile = NULL;
924 *blob = calloc(1, sizeof(**blob));
926 return got_error_from_errno("calloc");
928 (*blob)->read_buf = malloc(blocksize);
929 if ((*blob)->read_buf == NULL) {
930 err = got_error_from_errno("malloc");
934 if (ftruncate(outfd, 0L) == -1) {
935 err = got_error_from_errno("ftruncate");
938 if (lseek(outfd, SEEK_SET, 0) == -1) {
939 err = got_error_from_errno("lseek");
943 err = got_repo_search_packidx(&packidx, &idx, repo, id);
945 struct got_pack *pack = NULL;
947 err = got_packidx_get_packfile_path(&path_packfile,
948 packidx->path_packidx);
952 pack = got_repo_get_cached_pack(repo, path_packfile);
954 err = got_repo_cache_pack(&pack, repo, path_packfile,
959 err = read_packed_blob_privsep(&outbuf, &size, &hdrlen, outfd,
960 pack, packidx, idx, id);
961 } else if (err->code == GOT_ERR_NO_OBJ) {
964 err = got_object_open_loose_fd(&infd, id, repo);
967 err = read_blob_privsep(&outbuf, &size, &hdrlen, outfd, infd,
974 err = got_error(GOT_ERR_BAD_OBJ_HDR);
979 (*blob)->f = fmemopen(outbuf, size, "rb");
980 if ((*blob)->f == NULL) {
981 err = got_error_from_errno("fmemopen");
985 (*blob)->data = outbuf;
987 if (fstat(outfd, &sb) == -1) {
988 err = got_error_from_errno("fstat");
992 if (sb.st_size != size) {
993 err = got_error(GOT_ERR_PRIVSEP_LEN);
999 err = got_error_from_errno("dup");
1003 (*blob)->f = fdopen(dfd, "rb");
1004 if ((*blob)->f == NULL) {
1005 err = got_error_from_errno("fdopen");
1012 (*blob)->hdrlen = hdrlen;
1013 (*blob)->blocksize = blocksize;
1014 memcpy(&(*blob)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
1017 free(path_packfile);
1020 got_object_blob_close(*blob);
1027 const struct got_error *
1028 got_object_open_as_blob(struct got_blob_object **blob,
1029 struct got_repository *repo, struct got_object_id *id, size_t blocksize,
1032 return open_blob(blob, repo, id, blocksize, outfd);
1035 const struct got_error *
1036 got_object_blob_open(struct got_blob_object **blob,
1037 struct got_repository *repo, struct got_object *obj, size_t blocksize,
1040 return open_blob(blob, repo, got_object_get_id(obj), blocksize, outfd);
1043 static const struct got_error *
1044 request_packed_tag(struct got_tag_object **tag, struct got_pack *pack,
1045 int pack_idx, struct got_object_id *id)
1047 const struct got_error *err = NULL;
1049 err = got_privsep_send_tag_req(pack->privsep_child->ibuf, -1, id,
1054 return got_privsep_recv_tag(tag, pack->privsep_child->ibuf);
1057 static const struct got_error *
1058 read_packed_tag_privsep(struct got_tag_object **tag,
1059 struct got_pack *pack, struct got_packidx *packidx, int idx,
1060 struct got_object_id *id)
1062 const struct got_error *err = NULL;
1064 if (pack->privsep_child)
1065 return request_packed_tag(tag, pack, idx, id);
1067 err = got_pack_start_privsep_child(pack, packidx);
1071 return request_packed_tag(tag, pack, idx, id);
1074 static const struct got_error *
1075 request_tag(struct got_tag_object **tag, struct got_repository *repo,
1076 int fd, struct got_object_id *id)
1078 const struct got_error *err = NULL;
1079 struct imsgbuf *ibuf;
1081 ibuf = repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].ibuf;
1083 err = got_privsep_send_tag_req(ibuf, fd, id, -1);
1087 return got_privsep_recv_tag(tag, ibuf);
1090 static const struct got_error *
1091 read_tag_privsep(struct got_tag_object **tag, int obj_fd,
1092 struct got_object_id *id, struct got_repository *repo)
1094 const struct got_error *err;
1096 if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TAG].imsg_fd != -1)
1097 return request_tag(tag, repo, obj_fd, id);
1099 err = start_child(repo, GOT_REPO_PRIVSEP_CHILD_TAG);
1103 return request_tag(tag, repo, obj_fd, id);
1106 static const struct got_error *
1107 open_tag(struct got_tag_object **tag, struct got_repository *repo,
1108 struct got_object_id *id, int check_cache)
1110 const struct got_error *err = NULL;
1111 struct got_packidx *packidx = NULL;
1113 char *path_packfile = NULL;
1114 struct got_object *obj = NULL;
1115 int obj_type = GOT_OBJ_TYPE_ANY;
1118 *tag = got_repo_get_cached_tag(repo, id);
1126 err = got_repo_search_packidx(&packidx, &idx, repo, id);
1128 struct got_pack *pack = NULL;
1130 err = got_packidx_get_packfile_path(&path_packfile,
1131 packidx->path_packidx);
1135 pack = got_repo_get_cached_pack(repo, path_packfile);
1137 err = got_repo_cache_pack(&pack, repo, path_packfile,
1143 /* Beware of "lightweight" tags: Check object type first. */
1144 err = read_packed_object_privsep(&obj, repo, pack, packidx,
1148 obj_type = obj->type;
1149 got_object_close(obj);
1150 if (obj_type != GOT_OBJ_TYPE_TAG) {
1151 err = got_error(GOT_ERR_OBJ_TYPE);
1154 err = read_packed_tag_privsep(tag, pack, packidx, idx, id);
1155 } else if (err->code == GOT_ERR_NO_OBJ) {
1158 err = got_object_open_loose_fd(&fd, id, repo);
1161 err = got_object_read_header_privsep(&obj, id, repo, fd);
1164 obj_type = obj->type;
1165 got_object_close(obj);
1166 if (obj_type != GOT_OBJ_TYPE_TAG)
1167 return got_error(GOT_ERR_OBJ_TYPE);
1169 err = got_object_open_loose_fd(&fd, id, repo);
1172 err = read_tag_privsep(tag, fd, id, repo);
1177 err = got_repo_cache_tag(repo, id, *tag);
1180 free(path_packfile);
1184 const struct got_error *
1185 got_object_open_as_tag(struct got_tag_object **tag,
1186 struct got_repository *repo, struct got_object_id *id)
1188 *tag = got_repo_get_cached_tag(repo, id);
1194 return open_tag(tag, repo, id, 0);
1197 const struct got_error *
1198 got_object_tag_open(struct got_tag_object **tag,
1199 struct got_repository *repo, struct got_object *obj)
1201 return open_tag(tag, repo, got_object_get_id(obj), 1);
1204 const struct got_error *
1205 got_traverse_packed_commits(struct got_object_id_queue *traversed_commits,
1206 struct got_object_id *commit_id, const char *path,
1207 struct got_repository *repo)
1209 const struct got_error *err = NULL;
1210 struct got_pack *pack = NULL;
1211 struct got_packidx *packidx = NULL;
1212 char *path_packfile = NULL;
1213 struct got_commit_object *changed_commit = NULL;
1214 struct got_object_id *changed_commit_id = NULL;
1217 err = got_repo_search_packidx(&packidx, &idx, repo, commit_id);
1219 if (err->code != GOT_ERR_NO_OBJ)
1224 err = got_packidx_get_packfile_path(&path_packfile,
1225 packidx->path_packidx);
1229 pack = got_repo_get_cached_pack(repo, path_packfile);
1231 err = got_repo_cache_pack(&pack, repo, path_packfile, packidx);
1236 if (pack->privsep_child == NULL) {
1237 err = got_pack_start_privsep_child(pack, packidx);
1242 err = got_privsep_send_commit_traversal_request(
1243 pack->privsep_child->ibuf, commit_id, idx, path);
1247 err = got_privsep_recv_traversed_commits(&changed_commit,
1248 &changed_commit_id, traversed_commits, pack->privsep_child->ibuf);
1252 if (changed_commit) {
1254 * Cache the commit in which the path was changed.
1255 * This commit might be opened again soon.
1257 changed_commit->refcnt++;
1258 err = got_repo_cache_commit(repo, changed_commit_id,
1260 got_object_commit_close(changed_commit);
1263 free(path_packfile);
1264 free(changed_commit_id);
1268 const struct got_error *
1269 got_object_enumerate(int *found_all_objects,
1270 got_object_enumerate_commit_cb cb_commit,
1271 got_object_enumerate_tree_cb cb_tree, void *cb_arg,
1272 struct got_object_id **ours, int nours,
1273 struct got_object_id **theirs, int ntheirs,
1274 struct got_packidx *packidx, struct got_repository *repo)
1276 const struct got_error *err = NULL;
1277 struct got_pack *pack;
1278 char *path_packfile = NULL;
1280 err = got_packidx_get_packfile_path(&path_packfile,
1281 packidx->path_packidx);
1285 pack = got_repo_get_cached_pack(repo, path_packfile);
1287 err = got_repo_cache_pack(&pack, repo, path_packfile, packidx);
1292 if (pack->privsep_child == NULL) {
1293 err = got_pack_start_privsep_child(pack, packidx);
1298 err = got_privsep_send_object_enumeration_request(
1299 pack->privsep_child->ibuf);
1303 err = got_privsep_send_object_idlist(pack->privsep_child->ibuf,
1307 err = got_privsep_send_object_idlist_done(pack->privsep_child->ibuf);
1311 err = got_privsep_send_object_idlist(pack->privsep_child->ibuf,
1315 err = got_privsep_send_object_idlist_done(pack->privsep_child->ibuf);
1319 err = got_privsep_recv_enumerated_objects(found_all_objects,
1320 pack->privsep_child->ibuf, cb_commit, cb_tree, cb_arg, repo);
1322 free(path_packfile);