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.
17 #include "got_compat.h"
20 #include <sys/queue.h>
21 #include <sys/types.h>
23 #include <sys/socket.h>
36 #include "got_error.h"
37 #include "got_object.h"
38 #include "got_repository.h"
39 #include "got_opentemp.h"
42 #include "got_lib_delta.h"
43 #include "got_lib_object.h"
44 #include "got_lib_hash.h"
45 #include "got_lib_privsep.h"
46 #include "got_lib_object_cache.h"
47 #include "got_lib_pack.h"
48 #include "got_lib_repository.h"
50 static const struct got_error
*
51 request_packed_object(struct got_object
**obj
, struct got_pack
*pack
, int idx
,
52 struct got_object_id
*id
)
54 const struct got_error
*err
= NULL
;
55 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
57 err
= got_privsep_send_packed_obj_req(ibuf
, idx
, id
);
61 err
= got_privsep_recv_obj(obj
, ibuf
);
65 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
70 /* Create temporary files used during delta application. */
71 static const struct got_error
*
72 pack_child_send_tempfiles(struct imsgbuf
*ibuf
, struct got_pack
*pack
)
74 const struct got_error
*err
;
75 int basefd
= -1, accumfd
= -1;
78 * For performance reasons, the child will keep reusing the
79 * same temporary files during every object request.
80 * Opening and closing new files for every object request is
81 * too expensive during operations such as 'gotadmin pack'.
83 if (pack
->child_has_tempfiles
)
86 basefd
= dup(pack
->basefd
);
88 return got_error_from_errno("dup");
90 accumfd
= dup(pack
->accumfd
);
92 err
= got_error_from_errno("dup");
96 err
= got_privsep_send_tmpfd(ibuf
, basefd
);
100 err
= got_privsep_send_tmpfd(ibuf
, accumfd
);
108 pack
->child_has_tempfiles
= 1;
112 static const struct got_error
*
113 request_packed_object_raw(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
114 int outfd
, struct got_pack
*pack
, int idx
, struct got_object_id
*id
)
116 const struct got_error
*err
= NULL
;
117 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
120 err
= pack_child_send_tempfiles(ibuf
, pack
);
124 outfd_child
= dup(outfd
);
125 if (outfd_child
== -1)
126 return got_error_from_errno("dup");
128 err
= got_privsep_send_packed_raw_obj_req(ibuf
, idx
, id
);
134 err
= got_privsep_send_raw_obj_outfd(ibuf
, outfd_child
);
138 err
= got_privsep_recv_raw_obj(outbuf
, size
, hdrlen
, ibuf
);
145 static const struct got_error
*
146 read_packed_object_privsep(struct got_object
**obj
,
147 struct got_repository
*repo
, struct got_pack
*pack
,
148 struct got_packidx
*packidx
, int idx
, struct got_object_id
*id
)
150 const struct got_error
*err
= NULL
;
152 if (pack
->privsep_child
== NULL
) {
153 err
= got_pack_start_privsep_child(pack
, packidx
);
158 return request_packed_object(obj
, pack
, idx
, id
);
161 static const struct got_error
*
162 read_packed_object_raw_privsep(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
163 int outfd
, struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
164 struct got_object_id
*id
)
166 const struct got_error
*err
= NULL
;
168 if (pack
->privsep_child
== NULL
) {
169 err
= got_pack_start_privsep_child(pack
, packidx
);
174 return request_packed_object_raw(outbuf
, size
, hdrlen
, outfd
, pack
,
178 const struct got_error
*
179 got_object_open_packed(struct got_object
**obj
, struct got_object_id
*id
,
180 struct got_repository
*repo
)
182 const struct got_error
*err
= NULL
;
183 struct got_pack
*pack
= NULL
;
184 struct got_packidx
*packidx
= NULL
;
188 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
192 err
= got_packidx_get_packfile_path(&path_packfile
,
193 packidx
->path_packidx
);
197 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
199 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
204 err
= read_packed_object_privsep(obj
, repo
, pack
, packidx
, idx
, id
);
212 const struct got_error
*
213 got_object_open_from_packfile(struct got_object
**obj
, struct got_object_id
*id
,
214 struct got_pack
*pack
, struct got_packidx
*packidx
, int obj_idx
,
215 struct got_repository
*repo
)
217 return read_packed_object_privsep(obj
, repo
, pack
, packidx
,
221 const struct got_error
*
222 got_object_read_raw_delta(uint64_t *base_size
, uint64_t *result_size
,
223 off_t
*delta_size
, off_t
*delta_compressed_size
, off_t
*delta_offset
,
224 off_t
*delta_out_offset
, struct got_object_id
**base_id
, int delta_cache_fd
,
225 struct got_packidx
*packidx
, int obj_idx
, struct got_object_id
*id
,
226 struct got_repository
*repo
)
228 const struct got_error
*err
= NULL
;
229 struct got_pack
*pack
= NULL
;
235 *delta_compressed_size
= 0;
237 *delta_out_offset
= 0;
239 err
= got_packidx_get_packfile_path(&path_packfile
,
240 packidx
->path_packidx
);
244 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
246 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
251 if (pack
->privsep_child
== NULL
) {
252 err
= got_pack_start_privsep_child(pack
, packidx
);
257 if (!pack
->child_has_delta_outfd
) {
259 outfd_child
= dup(delta_cache_fd
);
260 if (outfd_child
== -1)
261 return got_error_from_errno("dup");
262 err
= got_privsep_send_raw_delta_outfd(
263 pack
->privsep_child
->ibuf
, outfd_child
);
266 pack
->child_has_delta_outfd
= 1;
269 err
= got_privsep_send_raw_delta_req(pack
->privsep_child
->ibuf
,
274 return got_privsep_recv_raw_delta(base_size
, result_size
, delta_size
,
275 delta_compressed_size
, delta_offset
, delta_out_offset
, base_id
,
276 pack
->privsep_child
->ibuf
);
279 static const struct got_error
*
280 request_object(struct got_object
**obj
, struct got_object_id
*id
,
281 struct got_repository
*repo
, int fd
)
283 const struct got_error
*err
= NULL
;
284 struct imsgbuf
*ibuf
;
286 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].ibuf
;
288 err
= got_privsep_send_obj_req(ibuf
, fd
, id
);
292 return got_privsep_recv_obj(obj
, ibuf
);
295 static const struct got_error
*
296 request_raw_object(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
, int outfd
,
297 struct got_object_id
*id
, struct got_repository
*repo
, int infd
)
299 const struct got_error
*err
= NULL
;
300 struct imsgbuf
*ibuf
;
303 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].ibuf
;
305 outfd_child
= dup(outfd
);
306 if (outfd_child
== -1)
307 return got_error_from_errno("dup");
309 err
= got_privsep_send_raw_obj_req(ibuf
, infd
, id
);
313 err
= got_privsep_send_raw_obj_outfd(ibuf
, outfd_child
);
317 return got_privsep_recv_raw_obj(outbuf
, size
, hdrlen
, ibuf
);
320 static const struct got_error
*
321 start_child(struct got_repository
*repo
, int type
)
323 const struct got_error
*err
= NULL
;
326 struct imsgbuf
*ibuf
;
327 const char *prog_path
;
330 case GOT_REPO_PRIVSEP_CHILD_OBJECT
:
331 prog_path
= GOT_PATH_PROG_READ_OBJECT
;
333 case GOT_REPO_PRIVSEP_CHILD_TREE
:
334 prog_path
= GOT_PATH_PROG_READ_TREE
;
336 case GOT_REPO_PRIVSEP_CHILD_COMMIT
:
337 prog_path
= GOT_PATH_PROG_READ_COMMIT
;
339 case GOT_REPO_PRIVSEP_CHILD_BLOB
:
340 prog_path
= GOT_PATH_PROG_READ_BLOB
;
342 case GOT_REPO_PRIVSEP_CHILD_TAG
:
343 prog_path
= GOT_PATH_PROG_READ_TAG
;
346 return got_error(GOT_ERR_OBJ_TYPE
);
349 ibuf
= calloc(1, sizeof(*ibuf
));
351 return got_error_from_errno("calloc");
353 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
354 err
= got_error_from_errno("socketpair");
361 err
= got_error_from_errno("fork");
368 got_privsep_exec_child(imsg_fds
, prog_path
, repo
->path
);
372 if (close(imsg_fds
[1]) == -1) {
373 err
= got_error_from_errno("close");
379 repo
->privsep_children
[type
].imsg_fd
= imsg_fds
[0];
380 repo
->privsep_children
[type
].pid
= pid
;
381 if (imsgbuf_init(ibuf
, imsg_fds
[0]) == -1) {
382 err
= got_error_from_errno("imsgbuf_init");
387 imsgbuf_allow_fdpass(ibuf
);
389 repo
->privsep_children
[type
].ibuf
= ibuf
;
394 const struct got_error
*
395 got_object_read_header_privsep(struct got_object
**obj
,
396 struct got_object_id
*id
, struct got_repository
*repo
, int obj_fd
)
398 const struct got_error
*err
;
400 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
!= -1)
401 return request_object(obj
, id
, repo
, obj_fd
);
403 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_OBJECT
);
407 return request_object(obj
, id
, repo
, obj_fd
);
410 static const struct got_error
*
411 read_object_raw_privsep(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
412 int outfd
, struct got_object_id
*id
, struct got_repository
*repo
,
415 const struct got_error
*err
;
417 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
!= -1)
418 return request_raw_object(outbuf
, size
, hdrlen
, outfd
, id
,
421 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_OBJECT
);
425 return request_raw_object(outbuf
, size
, hdrlen
, outfd
, id
, repo
,
429 const struct got_error
*
430 got_object_open(struct got_object
**obj
, struct got_repository
*repo
,
431 struct got_object_id
*id
)
433 const struct got_error
*err
= NULL
;
436 *obj
= got_repo_get_cached_object(repo
, id
);
442 err
= got_object_open_packed(obj
, id
, repo
);
443 if (err
&& err
->code
!= GOT_ERR_NO_OBJ
)
447 return got_repo_cache_object(repo
, id
, *obj
);
450 err
= got_object_open_loose_fd(&fd
, id
, repo
);
454 err
= got_object_read_header_privsep(obj
, id
, repo
, fd
);
458 memcpy(&(*obj
)->id
, id
, sizeof(*id
));
461 return got_repo_cache_object(repo
, id
, *obj
);
464 /* *outfd must be initialized to -1 by caller */
465 const struct got_error
*
466 got_object_raw_open(struct got_raw_object
**obj
, int *outfd
,
467 struct got_repository
*repo
, struct got_object_id
*id
)
469 const struct got_error
*err
= NULL
;
470 struct got_packidx
*packidx
= NULL
;
472 uint8_t *outbuf
= NULL
;
475 char *path_packfile
= NULL
;
477 *obj
= got_repo_get_cached_raw_object(repo
, id
);
484 *outfd
= got_opentempfd();
486 return got_error_from_errno("got_opentempfd");
489 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
491 struct got_pack
*pack
= NULL
;
493 err
= got_packidx_get_packfile_path(&path_packfile
,
494 packidx
->path_packidx
);
498 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
500 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
505 err
= read_packed_object_raw_privsep(&outbuf
, &size
, &hdrlen
,
506 *outfd
, pack
, packidx
, idx
, id
);
509 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
512 err
= got_object_open_loose_fd(&fd
, id
, repo
);
515 err
= read_object_raw_privsep(&outbuf
, &size
, &hdrlen
, *outfd
,
521 err
= got_object_raw_alloc(obj
, outbuf
, outfd
,
522 GOT_DELTA_RESULT_SIZE_CACHED_MAX
, hdrlen
, size
);
526 err
= got_repo_cache_raw_object(repo
, id
, *obj
);
531 got_object_raw_close(*obj
);
539 static const struct got_error
*
540 request_packed_commit(struct got_commit_object
**commit
, struct got_pack
*pack
,
541 int pack_idx
, struct got_object_id
*id
)
543 const struct got_error
*err
= NULL
;
545 err
= got_privsep_send_commit_req(pack
->privsep_child
->ibuf
, -1, id
,
550 err
= got_privsep_recv_commit(commit
, pack
->privsep_child
->ibuf
);
554 (*commit
)->flags
|= GOT_COMMIT_FLAG_PACKED
;
558 static const struct got_error
*
559 read_packed_commit_privsep(struct got_commit_object
**commit
,
560 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
561 struct got_object_id
*id
)
563 const struct got_error
*err
= NULL
;
565 if (pack
->privsep_child
)
566 return request_packed_commit(commit
, pack
, idx
, id
);
568 err
= got_pack_start_privsep_child(pack
, packidx
);
572 return request_packed_commit(commit
, pack
, idx
, id
);
575 static const struct got_error
*
576 request_commit(struct got_commit_object
**commit
, struct got_repository
*repo
,
577 int fd
, struct got_object_id
*id
)
579 const struct got_error
*err
= NULL
;
580 struct imsgbuf
*ibuf
;
582 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].ibuf
;
584 err
= got_privsep_send_commit_req(ibuf
, fd
, id
, -1);
588 return got_privsep_recv_commit(commit
, ibuf
);
591 static const struct got_error
*
592 read_commit_privsep(struct got_commit_object
**commit
, int obj_fd
,
593 struct got_object_id
*id
, struct got_repository
*repo
)
595 const struct got_error
*err
;
597 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].imsg_fd
!= -1)
598 return request_commit(commit
, repo
, obj_fd
, id
);
600 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_COMMIT
);
604 return request_commit(commit
, repo
, obj_fd
, id
);
607 static const struct got_error
*
608 open_commit(struct got_commit_object
**commit
,
609 struct got_repository
*repo
, struct got_object_id
*id
, int check_cache
)
611 const struct got_error
*err
= NULL
;
612 struct got_packidx
*packidx
= NULL
;
614 char *path_packfile
= NULL
;
617 *commit
= got_repo_get_cached_commit(repo
, id
);
618 if (*commit
!= NULL
) {
625 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
627 struct got_pack
*pack
= NULL
;
629 err
= got_packidx_get_packfile_path(&path_packfile
,
630 packidx
->path_packidx
);
634 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
636 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
641 err
= read_packed_commit_privsep(commit
, pack
,
643 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
646 err
= got_object_open_loose_fd(&fd
, id
, repo
);
649 err
= read_commit_privsep(commit
, fd
, id
, repo
);
654 err
= got_repo_cache_commit(repo
, id
, *commit
);
661 const struct got_error
*
662 got_object_open_as_commit(struct got_commit_object
**commit
,
663 struct got_repository
*repo
, struct got_object_id
*id
)
665 *commit
= got_repo_get_cached_commit(repo
, id
);
666 if (*commit
!= NULL
) {
671 return open_commit(commit
, repo
, id
, 0);
674 const struct got_error
*
675 got_object_commit_open(struct got_commit_object
**commit
,
676 struct got_repository
*repo
, struct got_object
*obj
)
678 return open_commit(commit
, repo
, got_object_get_id(obj
), 1);
681 static const struct got_error
*
682 request_packed_tree(struct got_tree_object
**tree
, struct got_pack
*pack
,
683 int pack_idx
, struct got_object_id
*id
)
685 const struct got_error
*err
= NULL
;
687 err
= got_privsep_send_tree_req(pack
->privsep_child
->ibuf
, -1, id
,
692 return got_privsep_recv_tree(tree
, pack
->privsep_child
->ibuf
);
695 static const struct got_error
*
696 read_packed_tree_privsep(struct got_tree_object
**tree
,
697 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
698 struct got_object_id
*id
)
700 const struct got_error
*err
= NULL
;
702 if (pack
->privsep_child
)
703 return request_packed_tree(tree
, pack
, idx
, id
);
705 err
= got_pack_start_privsep_child(pack
, packidx
);
709 return request_packed_tree(tree
, pack
, idx
, id
);
712 static const struct got_error
*
713 request_tree(struct got_tree_object
**tree
, struct got_repository
*repo
,
714 int fd
, struct got_object_id
*id
)
716 const struct got_error
*err
= NULL
;
717 struct imsgbuf
*ibuf
;
719 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].ibuf
;
721 err
= got_privsep_send_tree_req(ibuf
, fd
, id
, -1);
725 return got_privsep_recv_tree(tree
, ibuf
);
728 static const struct got_error
*
729 read_tree_privsep(struct got_tree_object
**tree
, int obj_fd
,
730 struct got_object_id
*id
, struct got_repository
*repo
)
732 const struct got_error
*err
;
734 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].imsg_fd
!= -1)
735 return request_tree(tree
, repo
, obj_fd
, id
);
737 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_TREE
);
741 return request_tree(tree
, repo
, obj_fd
, id
);
744 static const struct got_error
*
745 open_tree(struct got_tree_object
**tree
, struct got_repository
*repo
,
746 struct got_object_id
*id
, int check_cache
)
748 const struct got_error
*err
= NULL
;
749 struct got_packidx
*packidx
= NULL
;
751 char *path_packfile
= NULL
;
754 *tree
= got_repo_get_cached_tree(repo
, id
);
762 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
764 struct got_pack
*pack
= NULL
;
766 err
= got_packidx_get_packfile_path(&path_packfile
,
767 packidx
->path_packidx
);
771 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
773 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
778 err
= read_packed_tree_privsep(tree
, pack
,
780 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
783 err
= got_object_open_loose_fd(&fd
, id
, repo
);
786 err
= read_tree_privsep(tree
, fd
, id
, repo
);
791 err
= got_repo_cache_tree(repo
, id
, *tree
);
798 const struct got_error
*
799 got_object_open_as_tree(struct got_tree_object
**tree
,
800 struct got_repository
*repo
, struct got_object_id
*id
)
802 *tree
= got_repo_get_cached_tree(repo
, id
);
808 return open_tree(tree
, repo
, id
, 0);
811 const struct got_error
*
812 got_object_tree_open(struct got_tree_object
**tree
,
813 struct got_repository
*repo
, struct got_object
*obj
)
815 return open_tree(tree
, repo
, got_object_get_id(obj
), 1);
818 static const struct got_error
*
819 request_packed_blob(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
, int outfd
,
820 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
821 struct got_object_id
*id
)
823 const struct got_error
*err
= NULL
;
824 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
827 err
= pack_child_send_tempfiles(ibuf
, pack
);
831 outfd_child
= dup(outfd
);
832 if (outfd_child
== -1)
833 return got_error_from_errno("dup");
835 err
= got_privsep_send_blob_req(pack
->privsep_child
->ibuf
, -1, id
, idx
);
839 err
= got_privsep_send_blob_outfd(pack
->privsep_child
->ibuf
,
845 err
= got_privsep_recv_blob(outbuf
, size
, hdrlen
,
846 pack
->privsep_child
->ibuf
);
850 if (lseek(outfd
, SEEK_SET
, 0) == -1)
851 err
= got_error_from_errno("lseek");
856 static const struct got_error
*
857 read_packed_blob_privsep(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
,
858 int outfd
, struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
859 struct got_object_id
*id
)
861 const struct got_error
*err
= NULL
;
863 if (pack
->privsep_child
== NULL
) {
864 err
= got_pack_start_privsep_child(pack
, packidx
);
869 return request_packed_blob(outbuf
, size
, hdrlen
, outfd
, pack
, packidx
,
873 static const struct got_error
*
874 request_blob(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
, int outfd
,
875 int infd
, struct got_object_id
*id
, struct imsgbuf
*ibuf
)
877 const struct got_error
*err
= NULL
;
880 outfd_child
= dup(outfd
);
881 if (outfd_child
== -1)
882 return got_error_from_errno("dup");
884 err
= got_privsep_send_blob_req(ibuf
, infd
, id
, -1);
888 err
= got_privsep_send_blob_outfd(ibuf
, outfd_child
);
892 err
= got_privsep_recv_blob(outbuf
, size
, hdrlen
, ibuf
);
896 if (lseek(outfd
, SEEK_SET
, 0) == -1)
897 return got_error_from_errno("lseek");
902 static const struct got_error
*
903 read_blob_privsep(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
,
904 int outfd
, int infd
, struct got_object_id
*id
, struct got_repository
*repo
)
906 const struct got_error
*err
;
907 struct imsgbuf
*ibuf
;
909 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].imsg_fd
!= -1) {
910 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].ibuf
;
911 return request_blob(outbuf
, size
, hdrlen
, outfd
, infd
, id
,
915 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_BLOB
);
919 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].ibuf
;
920 return request_blob(outbuf
, size
, hdrlen
, outfd
, infd
, id
, ibuf
);
923 static const struct got_error
*
924 open_blob(struct got_blob_object
**blob
, struct got_repository
*repo
,
925 struct got_object_id
*id
, size_t blocksize
, int outfd
)
927 const struct got_error
*err
= NULL
;
928 struct got_packidx
*packidx
= NULL
;
930 char *path_packfile
= NULL
;
935 *blob
= calloc(1, sizeof(**blob
));
937 return got_error_from_errno("calloc");
939 (*blob
)->read_buf
= malloc(blocksize
);
940 if ((*blob
)->read_buf
== NULL
) {
941 err
= got_error_from_errno("malloc");
945 if (ftruncate(outfd
, 0L) == -1) {
946 err
= got_error_from_errno("ftruncate");
949 if (lseek(outfd
, SEEK_SET
, 0) == -1) {
950 err
= got_error_from_errno("lseek");
954 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
956 struct got_pack
*pack
= NULL
;
958 err
= got_packidx_get_packfile_path(&path_packfile
,
959 packidx
->path_packidx
);
963 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
965 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
970 err
= read_packed_blob_privsep(&outbuf
, &size
, &hdrlen
, outfd
,
971 pack
, packidx
, idx
, id
);
972 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
975 err
= got_object_open_loose_fd(&infd
, id
, repo
);
978 err
= read_blob_privsep(&outbuf
, &size
, &hdrlen
, outfd
, infd
,
985 err
= got_error(GOT_ERR_BAD_OBJ_HDR
);
989 if (outbuf
&& size
> 0) {
990 (*blob
)->f
= fmemopen(outbuf
, size
, "rb");
991 if ((*blob
)->f
== NULL
) {
992 err
= got_error_from_errno("fmemopen");
996 (*blob
)->data
= outbuf
;
998 if (fstat(outfd
, &sb
) == -1) {
999 err
= got_error_from_errno("fstat");
1003 if (sb
.st_size
!= size
) {
1004 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1010 err
= got_error_from_errno("dup");
1014 (*blob
)->f
= fdopen(dfd
, "rb");
1015 if ((*blob
)->f
== NULL
) {
1016 err
= got_error_from_errno("fdopen");
1023 (*blob
)->hdrlen
= hdrlen
;
1024 (*blob
)->blocksize
= blocksize
;
1025 memcpy(&(*blob
)->id
, id
, sizeof(*id
));
1028 free(path_packfile
);
1031 got_object_blob_close(*blob
);
1038 const struct got_error
*
1039 got_object_open_as_blob(struct got_blob_object
**blob
,
1040 struct got_repository
*repo
, struct got_object_id
*id
, size_t blocksize
,
1043 return open_blob(blob
, repo
, id
, blocksize
, outfd
);
1046 const struct got_error
*
1047 got_object_blob_open(struct got_blob_object
**blob
,
1048 struct got_repository
*repo
, struct got_object
*obj
, size_t blocksize
,
1051 return open_blob(blob
, repo
, got_object_get_id(obj
), blocksize
, outfd
);
1054 static const struct got_error
*
1055 request_packed_tag(struct got_tag_object
**tag
, struct got_pack
*pack
,
1056 int pack_idx
, struct got_object_id
*id
)
1058 const struct got_error
*err
= NULL
;
1060 err
= got_privsep_send_tag_req(pack
->privsep_child
->ibuf
, -1, id
,
1065 return got_privsep_recv_tag(tag
, pack
->privsep_child
->ibuf
);
1068 static const struct got_error
*
1069 read_packed_tag_privsep(struct got_tag_object
**tag
,
1070 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
1071 struct got_object_id
*id
)
1073 const struct got_error
*err
= NULL
;
1075 if (pack
->privsep_child
)
1076 return request_packed_tag(tag
, pack
, idx
, id
);
1078 err
= got_pack_start_privsep_child(pack
, packidx
);
1082 return request_packed_tag(tag
, pack
, idx
, id
);
1085 static const struct got_error
*
1086 request_tag(struct got_tag_object
**tag
, struct got_repository
*repo
,
1087 int fd
, struct got_object_id
*id
)
1089 const struct got_error
*err
= NULL
;
1090 struct imsgbuf
*ibuf
;
1092 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].ibuf
;
1094 err
= got_privsep_send_tag_req(ibuf
, fd
, id
, -1);
1098 return got_privsep_recv_tag(tag
, ibuf
);
1101 static const struct got_error
*
1102 read_tag_privsep(struct got_tag_object
**tag
, int obj_fd
,
1103 struct got_object_id
*id
, struct got_repository
*repo
)
1105 const struct got_error
*err
;
1107 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].imsg_fd
!= -1)
1108 return request_tag(tag
, repo
, obj_fd
, id
);
1110 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_TAG
);
1114 return request_tag(tag
, repo
, obj_fd
, id
);
1117 static const struct got_error
*
1118 open_tag(struct got_tag_object
**tag
, struct got_repository
*repo
,
1119 struct got_object_id
*id
, int check_cache
)
1121 const struct got_error
*err
= NULL
;
1122 struct got_packidx
*packidx
= NULL
;
1124 char *path_packfile
= NULL
;
1125 struct got_object
*obj
= NULL
;
1126 int obj_type
= GOT_OBJ_TYPE_ANY
;
1129 *tag
= got_repo_get_cached_tag(repo
, id
);
1137 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
1139 struct got_pack
*pack
= NULL
;
1141 err
= got_packidx_get_packfile_path(&path_packfile
,
1142 packidx
->path_packidx
);
1146 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1148 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
1154 /* Beware of "lightweight" tags: Check object type first. */
1155 err
= read_packed_object_privsep(&obj
, repo
, pack
, packidx
,
1159 obj_type
= obj
->type
;
1160 got_object_close(obj
);
1161 if (obj_type
!= GOT_OBJ_TYPE_TAG
) {
1162 err
= got_error(GOT_ERR_OBJ_TYPE
);
1165 err
= read_packed_tag_privsep(tag
, pack
, packidx
, idx
, id
);
1166 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
1169 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1172 err
= got_object_read_header_privsep(&obj
, id
, repo
, fd
);
1175 obj_type
= obj
->type
;
1176 got_object_close(obj
);
1177 if (obj_type
!= GOT_OBJ_TYPE_TAG
)
1178 return got_error(GOT_ERR_OBJ_TYPE
);
1180 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1183 err
= read_tag_privsep(tag
, fd
, id
, repo
);
1188 err
= got_repo_cache_tag(repo
, id
, *tag
);
1191 free(path_packfile
);
1195 const struct got_error
*
1196 got_object_open_as_tag(struct got_tag_object
**tag
,
1197 struct got_repository
*repo
, struct got_object_id
*id
)
1199 *tag
= got_repo_get_cached_tag(repo
, id
);
1205 return open_tag(tag
, repo
, id
, 0);
1208 const struct got_error
*
1209 got_object_tag_open(struct got_tag_object
**tag
,
1210 struct got_repository
*repo
, struct got_object
*obj
)
1212 return open_tag(tag
, repo
, got_object_get_id(obj
), 1);
1215 const struct got_error
*
1216 got_traverse_packed_commits(struct got_object_id_queue
*traversed_commits
,
1217 struct got_object_id
*commit_id
, const char *path
,
1218 struct got_repository
*repo
)
1220 const struct got_error
*err
= NULL
;
1221 struct got_pack
*pack
= NULL
;
1222 struct got_packidx
*packidx
= NULL
;
1223 char *path_packfile
= NULL
;
1224 struct got_commit_object
*changed_commit
= NULL
;
1225 struct got_object_qid
*changed_commit_qid
= NULL
;
1228 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, commit_id
);
1230 if (err
->code
!= GOT_ERR_NO_OBJ
)
1235 err
= got_packidx_get_packfile_path(&path_packfile
,
1236 packidx
->path_packidx
);
1240 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1242 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
1247 if (pack
->privsep_child
== NULL
) {
1248 err
= got_pack_start_privsep_child(pack
, packidx
);
1253 err
= got_privsep_send_commit_traversal_request(
1254 pack
->privsep_child
->ibuf
, commit_id
, idx
, path
);
1258 err
= got_privsep_recv_traversed_commits(&changed_commit
,
1259 traversed_commits
, pack
->privsep_child
->ibuf
);
1263 if (changed_commit
) {
1265 * Cache the commit in which the path was changed.
1266 * This commit might be opened again soon.
1268 changed_commit
->refcnt
++;
1269 changed_commit_qid
= STAILQ_LAST(traversed_commits
, got_object_qid
, entry
);
1270 err
= got_repo_cache_commit(repo
, &changed_commit_qid
->id
,
1272 got_object_commit_close(changed_commit
);
1275 free(path_packfile
);
1279 const struct got_error
*
1280 got_object_enumerate(int *found_all_objects
,
1281 got_object_enumerate_commit_cb cb_commit
,
1282 got_object_enumerate_tree_cb cb_tree
, void *cb_arg
,
1283 struct got_object_id
**ours
, int nours
,
1284 struct got_object_id
**theirs
, int ntheirs
,
1285 struct got_packidx
*packidx
, struct got_repository
*repo
)
1287 const struct got_error
*err
= NULL
;
1288 struct got_pack
*pack
;
1289 char *path_packfile
= NULL
;
1291 err
= got_packidx_get_packfile_path(&path_packfile
,
1292 packidx
->path_packidx
);
1296 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1298 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
1303 if (pack
->privsep_child
== NULL
) {
1304 err
= got_pack_start_privsep_child(pack
, packidx
);
1309 err
= got_privsep_send_object_enumeration_request(
1310 pack
->privsep_child
->ibuf
);
1314 err
= got_privsep_send_object_idlist(pack
->privsep_child
->ibuf
,
1318 err
= got_privsep_send_object_idlist_done(pack
->privsep_child
->ibuf
);
1322 err
= got_privsep_send_object_idlist(pack
->privsep_child
->ibuf
,
1326 err
= got_privsep_send_object_idlist_done(pack
->privsep_child
->ibuf
);
1330 err
= got_privsep_recv_enumerated_objects(found_all_objects
,
1331 pack
->privsep_child
->ibuf
, cb_commit
, cb_tree
, cb_arg
, repo
);
1333 free(path_packfile
);