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_compat.h"
34 #include "got_error.h"
35 #include "got_object.h"
36 #include "got_repository.h"
37 #include "got_opentemp.h"
40 #include "got_lib_delta.h"
41 #include "got_lib_object.h"
42 #include "got_lib_privsep.h"
43 #include "got_lib_object_cache.h"
44 #include "got_lib_pack.h"
45 #include "got_lib_repository.h"
47 static const struct got_error
*
48 request_packed_object(struct got_object
**obj
, struct got_pack
*pack
, int idx
,
49 struct got_object_id
*id
)
51 const struct got_error
*err
= NULL
;
52 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
54 err
= got_privsep_send_packed_obj_req(ibuf
, idx
, id
);
58 err
= got_privsep_recv_obj(obj
, ibuf
);
62 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
67 /* Create temporary files used during delta application. */
68 static const struct got_error
*
69 pack_child_send_tempfiles(struct imsgbuf
*ibuf
, struct got_pack
*pack
)
71 const struct got_error
*err
;
72 int basefd
= -1, accumfd
= -1;
75 * For performance reasons, the child will keep reusing the
76 * same temporary files during every object request.
77 * Opening and closing new files for every object request is
78 * too expensive during operations such as 'gotadmin pack'.
80 if (pack
->child_has_tempfiles
)
83 basefd
= dup(pack
->basefd
);
85 return got_error_from_errno("dup");
87 accumfd
= dup(pack
->accumfd
);
89 err
= got_error_from_errno("dup");
93 err
= got_privsep_send_tmpfd(ibuf
, basefd
);
97 err
= got_privsep_send_tmpfd(ibuf
, accumfd
);
105 pack
->child_has_tempfiles
= 1;
109 static const struct got_error
*
110 request_packed_object_raw(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
111 int outfd
, struct got_pack
*pack
, int idx
, struct got_object_id
*id
)
113 const struct got_error
*err
= NULL
;
114 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
117 err
= pack_child_send_tempfiles(ibuf
, pack
);
121 outfd_child
= dup(outfd
);
122 if (outfd_child
== -1)
123 return got_error_from_errno("dup");
125 err
= got_privsep_send_packed_raw_obj_req(ibuf
, idx
, id
);
131 err
= got_privsep_send_raw_obj_outfd(ibuf
, outfd_child
);
135 err
= got_privsep_recv_raw_obj(outbuf
, size
, hdrlen
, ibuf
);
142 static const struct got_error
*
143 read_packed_object_privsep(struct got_object
**obj
,
144 struct got_repository
*repo
, struct got_pack
*pack
,
145 struct got_packidx
*packidx
, int idx
, struct got_object_id
*id
)
147 const struct got_error
*err
= NULL
;
149 if (pack
->privsep_child
== NULL
) {
150 err
= got_pack_start_privsep_child(pack
, packidx
);
155 return request_packed_object(obj
, pack
, idx
, id
);
158 static const struct got_error
*
159 read_packed_object_raw_privsep(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
160 int outfd
, struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
161 struct got_object_id
*id
)
163 const struct got_error
*err
= NULL
;
165 if (pack
->privsep_child
== NULL
) {
166 err
= got_pack_start_privsep_child(pack
, packidx
);
171 return request_packed_object_raw(outbuf
, size
, hdrlen
, outfd
, pack
,
175 const struct got_error
*
176 got_object_open_packed(struct got_object
**obj
, struct got_object_id
*id
,
177 struct got_repository
*repo
)
179 const struct got_error
*err
= NULL
;
180 struct got_pack
*pack
= NULL
;
181 struct got_packidx
*packidx
= NULL
;
185 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
189 err
= got_packidx_get_packfile_path(&path_packfile
,
190 packidx
->path_packidx
);
194 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
196 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
201 err
= read_packed_object_privsep(obj
, repo
, pack
, packidx
, idx
, id
);
209 const struct got_error
*
210 got_object_open_from_packfile(struct got_object
**obj
, struct got_object_id
*id
,
211 struct got_pack
*pack
, struct got_packidx
*packidx
, int obj_idx
,
212 struct got_repository
*repo
)
214 return read_packed_object_privsep(obj
, repo
, pack
, packidx
,
218 const struct got_error
*
219 got_object_read_raw_delta(uint64_t *base_size
, uint64_t *result_size
,
220 off_t
*delta_size
, off_t
*delta_compressed_size
, off_t
*delta_offset
,
221 off_t
*delta_out_offset
, struct got_object_id
**base_id
, int delta_cache_fd
,
222 struct got_packidx
*packidx
, int obj_idx
, struct got_object_id
*id
,
223 struct got_repository
*repo
)
225 const struct got_error
*err
= NULL
;
226 struct got_pack
*pack
= NULL
;
232 *delta_compressed_size
= 0;
234 *delta_out_offset
= 0;
236 err
= got_packidx_get_packfile_path(&path_packfile
,
237 packidx
->path_packidx
);
241 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
243 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
248 if (pack
->privsep_child
== NULL
) {
249 err
= got_pack_start_privsep_child(pack
, packidx
);
254 if (!pack
->child_has_delta_outfd
) {
256 outfd_child
= dup(delta_cache_fd
);
257 if (outfd_child
== -1)
258 return got_error_from_errno("dup");
259 err
= got_privsep_send_raw_delta_outfd(
260 pack
->privsep_child
->ibuf
, outfd_child
);
263 pack
->child_has_delta_outfd
= 1;
266 err
= got_privsep_send_raw_delta_req(pack
->privsep_child
->ibuf
,
271 return got_privsep_recv_raw_delta(base_size
, result_size
, delta_size
,
272 delta_compressed_size
, delta_offset
, delta_out_offset
, base_id
,
273 pack
->privsep_child
->ibuf
);
276 static const struct got_error
*
277 request_object(struct got_object
**obj
, struct got_object_id
*id
,
278 struct got_repository
*repo
, int fd
)
280 const struct got_error
*err
= NULL
;
281 struct imsgbuf
*ibuf
;
283 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].ibuf
;
285 err
= got_privsep_send_obj_req(ibuf
, fd
, id
);
289 return got_privsep_recv_obj(obj
, ibuf
);
292 static const struct got_error
*
293 request_raw_object(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
, int outfd
,
294 struct got_object_id
*id
, struct got_repository
*repo
, int infd
)
296 const struct got_error
*err
= NULL
;
297 struct imsgbuf
*ibuf
;
300 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].ibuf
;
302 outfd_child
= dup(outfd
);
303 if (outfd_child
== -1)
304 return got_error_from_errno("dup");
306 err
= got_privsep_send_raw_obj_req(ibuf
, infd
, id
);
310 err
= got_privsep_send_raw_obj_outfd(ibuf
, outfd_child
);
314 return got_privsep_recv_raw_obj(outbuf
, size
, hdrlen
, ibuf
);
317 static const struct got_error
*
318 start_child(struct got_repository
*repo
, int type
)
320 const struct got_error
*err
= NULL
;
323 struct imsgbuf
*ibuf
;
324 const char *prog_path
;
327 case GOT_REPO_PRIVSEP_CHILD_OBJECT
:
328 prog_path
= GOT_PATH_PROG_READ_OBJECT
;
330 case GOT_REPO_PRIVSEP_CHILD_TREE
:
331 prog_path
= GOT_PATH_PROG_READ_TREE
;
333 case GOT_REPO_PRIVSEP_CHILD_COMMIT
:
334 prog_path
= GOT_PATH_PROG_READ_COMMIT
;
336 case GOT_REPO_PRIVSEP_CHILD_BLOB
:
337 prog_path
= GOT_PATH_PROG_READ_BLOB
;
339 case GOT_REPO_PRIVSEP_CHILD_TAG
:
340 prog_path
= GOT_PATH_PROG_READ_TAG
;
343 return got_error(GOT_ERR_OBJ_TYPE
);
346 ibuf
= calloc(1, sizeof(*ibuf
));
348 return got_error_from_errno("calloc");
350 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
351 err
= got_error_from_errno("socketpair");
358 err
= got_error_from_errno("fork");
363 got_privsep_exec_child(imsg_fds
, prog_path
, repo
->path
);
367 if (close(imsg_fds
[1]) == -1) {
368 err
= got_error_from_errno("close");
373 repo
->privsep_children
[type
].imsg_fd
= imsg_fds
[0];
374 repo
->privsep_children
[type
].pid
= pid
;
375 imsg_init(ibuf
, imsg_fds
[0]);
376 repo
->privsep_children
[type
].ibuf
= ibuf
;
381 const struct got_error
*
382 got_object_read_header_privsep(struct got_object
**obj
,
383 struct got_object_id
*id
, struct got_repository
*repo
, int obj_fd
)
385 const struct got_error
*err
;
387 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
!= -1)
388 return request_object(obj
, id
, repo
, obj_fd
);
390 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_OBJECT
);
394 return request_object(obj
, id
, repo
, obj_fd
);
397 static const struct got_error
*
398 read_object_raw_privsep(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
399 int outfd
, struct got_object_id
*id
, struct got_repository
*repo
,
402 const struct got_error
*err
;
404 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
!= -1)
405 return request_raw_object(outbuf
, size
, hdrlen
, outfd
, id
,
408 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_OBJECT
);
412 return request_raw_object(outbuf
, size
, hdrlen
, outfd
, id
, repo
,
416 const struct got_error
*
417 got_object_open(struct got_object
**obj
, struct got_repository
*repo
,
418 struct got_object_id
*id
)
420 const struct got_error
*err
= NULL
;
423 *obj
= got_repo_get_cached_object(repo
, id
);
429 err
= got_object_open_packed(obj
, id
, repo
);
430 if (err
&& err
->code
!= GOT_ERR_NO_OBJ
)
434 return got_repo_cache_object(repo
, id
, *obj
);
437 err
= got_object_open_loose_fd(&fd
, id
, repo
);
439 if (err
->code
== GOT_ERR_ERRNO
&& errno
== ENOENT
)
440 err
= got_error_no_obj(id
);
444 err
= got_object_read_header_privsep(obj
, id
, repo
, fd
);
448 memcpy(&(*obj
)->id
, id
, sizeof(*id
));
451 return got_repo_cache_object(repo
, id
, *obj
);
454 /* *outfd must be initialized to -1 by caller */
455 const struct got_error
*
456 got_object_raw_open(struct got_raw_object
**obj
, int *outfd
,
457 struct got_repository
*repo
, struct got_object_id
*id
)
459 const struct got_error
*err
= NULL
;
460 struct got_packidx
*packidx
= NULL
;
462 uint8_t *outbuf
= NULL
;
465 char *path_packfile
= NULL
;
467 *obj
= got_repo_get_cached_raw_object(repo
, id
);
474 *outfd
= got_opentempfd();
476 return got_error_from_errno("got_opentempfd");
479 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
481 struct got_pack
*pack
= NULL
;
483 err
= got_packidx_get_packfile_path(&path_packfile
,
484 packidx
->path_packidx
);
488 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
490 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
495 err
= read_packed_object_raw_privsep(&outbuf
, &size
, &hdrlen
,
496 *outfd
, pack
, packidx
, idx
, id
);
499 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
502 err
= got_object_open_loose_fd(&fd
, id
, repo
);
505 err
= read_object_raw_privsep(&outbuf
, &size
, &hdrlen
, *outfd
,
511 err
= got_object_raw_alloc(obj
, outbuf
, outfd
,
512 GOT_DELTA_RESULT_SIZE_CACHED_MAX
, hdrlen
, size
);
516 err
= got_repo_cache_raw_object(repo
, id
, *obj
);
521 got_object_raw_close(*obj
);
529 static const struct got_error
*
530 request_packed_commit(struct got_commit_object
**commit
, struct got_pack
*pack
,
531 int pack_idx
, struct got_object_id
*id
)
533 const struct got_error
*err
= NULL
;
535 err
= got_privsep_send_commit_req(pack
->privsep_child
->ibuf
, -1, id
,
540 err
= got_privsep_recv_commit(commit
, pack
->privsep_child
->ibuf
);
544 (*commit
)->flags
|= GOT_COMMIT_FLAG_PACKED
;
548 static const struct got_error
*
549 read_packed_commit_privsep(struct got_commit_object
**commit
,
550 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
551 struct got_object_id
*id
)
553 const struct got_error
*err
= NULL
;
555 if (pack
->privsep_child
)
556 return request_packed_commit(commit
, pack
, idx
, id
);
558 err
= got_pack_start_privsep_child(pack
, packidx
);
562 return request_packed_commit(commit
, pack
, idx
, id
);
565 static const struct got_error
*
566 request_commit(struct got_commit_object
**commit
, struct got_repository
*repo
,
567 int fd
, struct got_object_id
*id
)
569 const struct got_error
*err
= NULL
;
570 struct imsgbuf
*ibuf
;
572 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].ibuf
;
574 err
= got_privsep_send_commit_req(ibuf
, fd
, id
, -1);
578 return got_privsep_recv_commit(commit
, ibuf
);
581 static const struct got_error
*
582 read_commit_privsep(struct got_commit_object
**commit
, int obj_fd
,
583 struct got_object_id
*id
, struct got_repository
*repo
)
585 const struct got_error
*err
;
587 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].imsg_fd
!= -1)
588 return request_commit(commit
, repo
, obj_fd
, id
);
590 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_COMMIT
);
594 return request_commit(commit
, repo
, obj_fd
, id
);
597 static const struct got_error
*
598 open_commit(struct got_commit_object
**commit
,
599 struct got_repository
*repo
, struct got_object_id
*id
, int check_cache
)
601 const struct got_error
*err
= NULL
;
602 struct got_packidx
*packidx
= NULL
;
604 char *path_packfile
= NULL
;
607 *commit
= got_repo_get_cached_commit(repo
, id
);
608 if (*commit
!= NULL
) {
615 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
617 struct got_pack
*pack
= NULL
;
619 err
= got_packidx_get_packfile_path(&path_packfile
,
620 packidx
->path_packidx
);
624 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
626 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
631 err
= read_packed_commit_privsep(commit
, pack
,
633 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
636 err
= got_object_open_loose_fd(&fd
, id
, repo
);
639 err
= read_commit_privsep(commit
, fd
, id
, repo
);
644 err
= got_repo_cache_commit(repo
, id
, *commit
);
651 const struct got_error
*
652 got_object_open_as_commit(struct got_commit_object
**commit
,
653 struct got_repository
*repo
, struct got_object_id
*id
)
655 *commit
= got_repo_get_cached_commit(repo
, id
);
656 if (*commit
!= NULL
) {
661 return open_commit(commit
, repo
, id
, 0);
664 const struct got_error
*
665 got_object_commit_open(struct got_commit_object
**commit
,
666 struct got_repository
*repo
, struct got_object
*obj
)
668 return open_commit(commit
, repo
, got_object_get_id(obj
), 1);
671 static const struct got_error
*
672 request_packed_tree(struct got_tree_object
**tree
, struct got_pack
*pack
,
673 int pack_idx
, struct got_object_id
*id
)
675 const struct got_error
*err
= NULL
;
677 err
= got_privsep_send_tree_req(pack
->privsep_child
->ibuf
, -1, id
,
682 return got_privsep_recv_tree(tree
, pack
->privsep_child
->ibuf
);
685 static const struct got_error
*
686 read_packed_tree_privsep(struct got_tree_object
**tree
,
687 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
688 struct got_object_id
*id
)
690 const struct got_error
*err
= NULL
;
692 if (pack
->privsep_child
)
693 return request_packed_tree(tree
, pack
, idx
, id
);
695 err
= got_pack_start_privsep_child(pack
, packidx
);
699 return request_packed_tree(tree
, pack
, idx
, id
);
702 static const struct got_error
*
703 request_tree(struct got_tree_object
**tree
, struct got_repository
*repo
,
704 int fd
, struct got_object_id
*id
)
706 const struct got_error
*err
= NULL
;
707 struct imsgbuf
*ibuf
;
709 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].ibuf
;
711 err
= got_privsep_send_tree_req(ibuf
, fd
, id
, -1);
715 return got_privsep_recv_tree(tree
, ibuf
);
718 static const struct got_error
*
719 read_tree_privsep(struct got_tree_object
**tree
, int obj_fd
,
720 struct got_object_id
*id
, struct got_repository
*repo
)
722 const struct got_error
*err
;
724 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].imsg_fd
!= -1)
725 return request_tree(tree
, repo
, obj_fd
, id
);
727 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_TREE
);
731 return request_tree(tree
, repo
, obj_fd
, id
);
734 static const struct got_error
*
735 open_tree(struct got_tree_object
**tree
, struct got_repository
*repo
,
736 struct got_object_id
*id
, int check_cache
)
738 const struct got_error
*err
= NULL
;
739 struct got_packidx
*packidx
= NULL
;
741 char *path_packfile
= NULL
;
744 *tree
= got_repo_get_cached_tree(repo
, id
);
752 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
754 struct got_pack
*pack
= NULL
;
756 err
= got_packidx_get_packfile_path(&path_packfile
,
757 packidx
->path_packidx
);
761 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
763 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
768 err
= read_packed_tree_privsep(tree
, pack
,
770 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
773 err
= got_object_open_loose_fd(&fd
, id
, repo
);
776 err
= read_tree_privsep(tree
, fd
, id
, repo
);
781 err
= got_repo_cache_tree(repo
, id
, *tree
);
788 const struct got_error
*
789 got_object_open_as_tree(struct got_tree_object
**tree
,
790 struct got_repository
*repo
, struct got_object_id
*id
)
792 *tree
= got_repo_get_cached_tree(repo
, id
);
798 return open_tree(tree
, repo
, id
, 0);
801 const struct got_error
*
802 got_object_tree_open(struct got_tree_object
**tree
,
803 struct got_repository
*repo
, struct got_object
*obj
)
805 return open_tree(tree
, repo
, got_object_get_id(obj
), 1);
808 static const struct got_error
*
809 request_packed_blob(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
, int outfd
,
810 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
811 struct got_object_id
*id
)
813 const struct got_error
*err
= NULL
;
814 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
817 err
= pack_child_send_tempfiles(ibuf
, pack
);
821 outfd_child
= dup(outfd
);
822 if (outfd_child
== -1)
823 return got_error_from_errno("dup");
825 err
= got_privsep_send_blob_req(pack
->privsep_child
->ibuf
, -1, id
, idx
);
829 err
= got_privsep_send_blob_outfd(pack
->privsep_child
->ibuf
,
835 err
= got_privsep_recv_blob(outbuf
, size
, hdrlen
,
836 pack
->privsep_child
->ibuf
);
840 if (lseek(outfd
, SEEK_SET
, 0) == -1)
841 err
= got_error_from_errno("lseek");
846 static const struct got_error
*
847 read_packed_blob_privsep(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
,
848 int outfd
, struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
849 struct got_object_id
*id
)
851 const struct got_error
*err
= NULL
;
853 if (pack
->privsep_child
== NULL
) {
854 err
= got_pack_start_privsep_child(pack
, packidx
);
859 return request_packed_blob(outbuf
, size
, hdrlen
, outfd
, pack
, packidx
,
863 static const struct got_error
*
864 request_blob(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
, int outfd
,
865 int infd
, struct got_object_id
*id
, struct imsgbuf
*ibuf
)
867 const struct got_error
*err
= NULL
;
870 outfd_child
= dup(outfd
);
871 if (outfd_child
== -1)
872 return got_error_from_errno("dup");
874 err
= got_privsep_send_blob_req(ibuf
, infd
, id
, -1);
878 err
= got_privsep_send_blob_outfd(ibuf
, outfd_child
);
882 err
= got_privsep_recv_blob(outbuf
, size
, hdrlen
, ibuf
);
886 if (lseek(outfd
, SEEK_SET
, 0) == -1)
887 return got_error_from_errno("lseek");
892 static const struct got_error
*
893 read_blob_privsep(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
,
894 int outfd
, int infd
, struct got_object_id
*id
, struct got_repository
*repo
)
896 const struct got_error
*err
;
897 struct imsgbuf
*ibuf
;
899 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].imsg_fd
!= -1) {
900 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].ibuf
;
901 return request_blob(outbuf
, size
, hdrlen
, outfd
, infd
, id
,
905 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_BLOB
);
909 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].ibuf
;
910 return request_blob(outbuf
, size
, hdrlen
, outfd
, infd
, id
, ibuf
);
913 static const struct got_error
*
914 open_blob(struct got_blob_object
**blob
, struct got_repository
*repo
,
915 struct got_object_id
*id
, size_t blocksize
, int outfd
)
917 const struct got_error
*err
= NULL
;
918 struct got_packidx
*packidx
= NULL
;
920 char *path_packfile
= NULL
;
925 *blob
= calloc(1, sizeof(**blob
));
927 return got_error_from_errno("calloc");
929 (*blob
)->read_buf
= malloc(blocksize
);
930 if ((*blob
)->read_buf
== NULL
) {
931 err
= got_error_from_errno("malloc");
935 if (ftruncate(outfd
, 0L) == -1) {
936 err
= got_error_from_errno("ftruncate");
939 if (lseek(outfd
, SEEK_SET
, 0) == -1) {
940 err
= got_error_from_errno("lseek");
944 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
946 struct got_pack
*pack
= NULL
;
948 err
= got_packidx_get_packfile_path(&path_packfile
,
949 packidx
->path_packidx
);
953 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
955 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
960 err
= read_packed_blob_privsep(&outbuf
, &size
, &hdrlen
, outfd
,
961 pack
, packidx
, idx
, id
);
962 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
965 err
= got_object_open_loose_fd(&infd
, id
, repo
);
968 err
= read_blob_privsep(&outbuf
, &size
, &hdrlen
, outfd
, infd
,
975 err
= got_error(GOT_ERR_BAD_OBJ_HDR
);
980 (*blob
)->f
= fmemopen(outbuf
, size
, "rb");
981 if ((*blob
)->f
== NULL
) {
982 err
= got_error_from_errno("fmemopen");
986 (*blob
)->data
= outbuf
;
988 if (fstat(outfd
, &sb
) == -1) {
989 err
= got_error_from_errno("fstat");
993 if (sb
.st_size
!= size
) {
994 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1000 err
= got_error_from_errno("dup");
1004 (*blob
)->f
= fdopen(dfd
, "rb");
1005 if ((*blob
)->f
== NULL
) {
1006 err
= got_error_from_errno("fdopen");
1013 (*blob
)->hdrlen
= hdrlen
;
1014 (*blob
)->blocksize
= blocksize
;
1015 memcpy(&(*blob
)->id
, id
, sizeof(*id
));
1018 free(path_packfile
);
1021 got_object_blob_close(*blob
);
1028 const struct got_error
*
1029 got_object_open_as_blob(struct got_blob_object
**blob
,
1030 struct got_repository
*repo
, struct got_object_id
*id
, size_t blocksize
,
1033 return open_blob(blob
, repo
, id
, blocksize
, outfd
);
1036 const struct got_error
*
1037 got_object_blob_open(struct got_blob_object
**blob
,
1038 struct got_repository
*repo
, struct got_object
*obj
, size_t blocksize
,
1041 return open_blob(blob
, repo
, got_object_get_id(obj
), blocksize
, outfd
);
1044 static const struct got_error
*
1045 request_packed_tag(struct got_tag_object
**tag
, struct got_pack
*pack
,
1046 int pack_idx
, struct got_object_id
*id
)
1048 const struct got_error
*err
= NULL
;
1050 err
= got_privsep_send_tag_req(pack
->privsep_child
->ibuf
, -1, id
,
1055 return got_privsep_recv_tag(tag
, pack
->privsep_child
->ibuf
);
1058 static const struct got_error
*
1059 read_packed_tag_privsep(struct got_tag_object
**tag
,
1060 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
1061 struct got_object_id
*id
)
1063 const struct got_error
*err
= NULL
;
1065 if (pack
->privsep_child
)
1066 return request_packed_tag(tag
, pack
, idx
, id
);
1068 err
= got_pack_start_privsep_child(pack
, packidx
);
1072 return request_packed_tag(tag
, pack
, idx
, id
);
1075 static const struct got_error
*
1076 request_tag(struct got_tag_object
**tag
, struct got_repository
*repo
,
1077 int fd
, struct got_object_id
*id
)
1079 const struct got_error
*err
= NULL
;
1080 struct imsgbuf
*ibuf
;
1082 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].ibuf
;
1084 err
= got_privsep_send_tag_req(ibuf
, fd
, id
, -1);
1088 return got_privsep_recv_tag(tag
, ibuf
);
1091 static const struct got_error
*
1092 read_tag_privsep(struct got_tag_object
**tag
, int obj_fd
,
1093 struct got_object_id
*id
, struct got_repository
*repo
)
1095 const struct got_error
*err
;
1097 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].imsg_fd
!= -1)
1098 return request_tag(tag
, repo
, obj_fd
, id
);
1100 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_TAG
);
1104 return request_tag(tag
, repo
, obj_fd
, id
);
1107 static const struct got_error
*
1108 open_tag(struct got_tag_object
**tag
, struct got_repository
*repo
,
1109 struct got_object_id
*id
, int check_cache
)
1111 const struct got_error
*err
= NULL
;
1112 struct got_packidx
*packidx
= NULL
;
1114 char *path_packfile
= NULL
;
1115 struct got_object
*obj
= NULL
;
1116 int obj_type
= GOT_OBJ_TYPE_ANY
;
1119 *tag
= got_repo_get_cached_tag(repo
, id
);
1127 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
1129 struct got_pack
*pack
= NULL
;
1131 err
= got_packidx_get_packfile_path(&path_packfile
,
1132 packidx
->path_packidx
);
1136 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1138 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
1144 /* Beware of "lightweight" tags: Check object type first. */
1145 err
= read_packed_object_privsep(&obj
, repo
, pack
, packidx
,
1149 obj_type
= obj
->type
;
1150 got_object_close(obj
);
1151 if (obj_type
!= GOT_OBJ_TYPE_TAG
) {
1152 err
= got_error(GOT_ERR_OBJ_TYPE
);
1155 err
= read_packed_tag_privsep(tag
, pack
, packidx
, idx
, id
);
1156 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
1159 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1162 err
= got_object_read_header_privsep(&obj
, id
, repo
, fd
);
1165 obj_type
= obj
->type
;
1166 got_object_close(obj
);
1167 if (obj_type
!= GOT_OBJ_TYPE_TAG
)
1168 return got_error(GOT_ERR_OBJ_TYPE
);
1170 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1173 err
= read_tag_privsep(tag
, fd
, id
, repo
);
1178 err
= got_repo_cache_tag(repo
, id
, *tag
);
1181 free(path_packfile
);
1185 const struct got_error
*
1186 got_object_open_as_tag(struct got_tag_object
**tag
,
1187 struct got_repository
*repo
, struct got_object_id
*id
)
1189 *tag
= got_repo_get_cached_tag(repo
, id
);
1195 return open_tag(tag
, repo
, id
, 0);
1198 const struct got_error
*
1199 got_object_tag_open(struct got_tag_object
**tag
,
1200 struct got_repository
*repo
, struct got_object
*obj
)
1202 return open_tag(tag
, repo
, got_object_get_id(obj
), 1);
1205 const struct got_error
*
1206 got_traverse_packed_commits(struct got_object_id_queue
*traversed_commits
,
1207 struct got_object_id
*commit_id
, const char *path
,
1208 struct got_repository
*repo
)
1210 const struct got_error
*err
= NULL
;
1211 struct got_pack
*pack
= NULL
;
1212 struct got_packidx
*packidx
= NULL
;
1213 char *path_packfile
= NULL
;
1214 struct got_commit_object
*changed_commit
= NULL
;
1215 struct got_object_id
*changed_commit_id
= NULL
;
1218 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, commit_id
);
1220 if (err
->code
!= GOT_ERR_NO_OBJ
)
1225 err
= got_packidx_get_packfile_path(&path_packfile
,
1226 packidx
->path_packidx
);
1230 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1232 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
1237 if (pack
->privsep_child
== NULL
) {
1238 err
= got_pack_start_privsep_child(pack
, packidx
);
1243 err
= got_privsep_send_commit_traversal_request(
1244 pack
->privsep_child
->ibuf
, commit_id
, idx
, path
);
1248 err
= got_privsep_recv_traversed_commits(&changed_commit
,
1249 &changed_commit_id
, traversed_commits
, pack
->privsep_child
->ibuf
);
1253 if (changed_commit
) {
1255 * Cache the commit in which the path was changed.
1256 * This commit might be opened again soon.
1258 changed_commit
->refcnt
++;
1259 err
= got_repo_cache_commit(repo
, changed_commit_id
,
1261 got_object_commit_close(changed_commit
);
1264 free(path_packfile
);
1265 free(changed_commit_id
);
1269 const struct got_error
*
1270 got_object_enumerate(int *found_all_objects
,
1271 got_object_enumerate_commit_cb cb_commit
,
1272 got_object_enumerate_tree_cb cb_tree
, void *cb_arg
,
1273 struct got_object_id
**ours
, int nours
,
1274 struct got_object_id
**theirs
, int ntheirs
,
1275 struct got_packidx
*packidx
, struct got_repository
*repo
)
1277 const struct got_error
*err
= NULL
;
1278 struct got_pack
*pack
;
1279 char *path_packfile
= NULL
;
1281 err
= got_packidx_get_packfile_path(&path_packfile
,
1282 packidx
->path_packidx
);
1286 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1288 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
1293 if (pack
->privsep_child
== NULL
) {
1294 err
= got_pack_start_privsep_child(pack
, packidx
);
1299 err
= got_privsep_send_object_enumeration_request(
1300 pack
->privsep_child
->ibuf
);
1304 err
= got_privsep_send_object_idlist(pack
->privsep_child
->ibuf
,
1308 err
= got_privsep_send_object_idlist_done(pack
->privsep_child
->ibuf
);
1312 err
= got_privsep_send_object_idlist(pack
->privsep_child
->ibuf
,
1316 err
= got_privsep_send_object_idlist_done(pack
->privsep_child
->ibuf
);
1320 err
= got_privsep_recv_enumerated_objects(found_all_objects
,
1321 pack
->privsep_child
->ibuf
, cb_commit
, cb_tree
, cb_arg
, repo
);
1323 free(path_packfile
);