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 imsg_init(ibuf
, imsg_fds
[0]);
382 repo
->privsep_children
[type
].ibuf
= ibuf
;
387 const struct got_error
*
388 got_object_read_header_privsep(struct got_object
**obj
,
389 struct got_object_id
*id
, struct got_repository
*repo
, int obj_fd
)
391 const struct got_error
*err
;
393 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
!= -1)
394 return request_object(obj
, id
, repo
, obj_fd
);
396 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_OBJECT
);
400 return request_object(obj
, id
, repo
, obj_fd
);
403 static const struct got_error
*
404 read_object_raw_privsep(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
405 int outfd
, struct got_object_id
*id
, struct got_repository
*repo
,
408 const struct got_error
*err
;
410 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
!= -1)
411 return request_raw_object(outbuf
, size
, hdrlen
, outfd
, id
,
414 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_OBJECT
);
418 return request_raw_object(outbuf
, size
, hdrlen
, outfd
, id
, repo
,
422 const struct got_error
*
423 got_object_open(struct got_object
**obj
, struct got_repository
*repo
,
424 struct got_object_id
*id
)
426 const struct got_error
*err
= NULL
;
429 *obj
= got_repo_get_cached_object(repo
, id
);
435 err
= got_object_open_packed(obj
, id
, repo
);
436 if (err
&& err
->code
!= GOT_ERR_NO_OBJ
)
440 return got_repo_cache_object(repo
, id
, *obj
);
443 err
= got_object_open_loose_fd(&fd
, id
, repo
);
447 err
= got_object_read_header_privsep(obj
, id
, repo
, fd
);
451 memcpy(&(*obj
)->id
, id
, sizeof(*id
));
454 return got_repo_cache_object(repo
, id
, *obj
);
457 /* *outfd must be initialized to -1 by caller */
458 const struct got_error
*
459 got_object_raw_open(struct got_raw_object
**obj
, int *outfd
,
460 struct got_repository
*repo
, struct got_object_id
*id
)
462 const struct got_error
*err
= NULL
;
463 struct got_packidx
*packidx
= NULL
;
465 uint8_t *outbuf
= NULL
;
468 char *path_packfile
= NULL
;
470 *obj
= got_repo_get_cached_raw_object(repo
, id
);
477 *outfd
= got_opentempfd();
479 return got_error_from_errno("got_opentempfd");
482 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
484 struct got_pack
*pack
= NULL
;
486 err
= got_packidx_get_packfile_path(&path_packfile
,
487 packidx
->path_packidx
);
491 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
493 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
498 err
= read_packed_object_raw_privsep(&outbuf
, &size
, &hdrlen
,
499 *outfd
, pack
, packidx
, idx
, id
);
502 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
505 err
= got_object_open_loose_fd(&fd
, id
, repo
);
508 err
= read_object_raw_privsep(&outbuf
, &size
, &hdrlen
, *outfd
,
514 err
= got_object_raw_alloc(obj
, outbuf
, outfd
,
515 GOT_DELTA_RESULT_SIZE_CACHED_MAX
, hdrlen
, size
);
519 err
= got_repo_cache_raw_object(repo
, id
, *obj
);
524 got_object_raw_close(*obj
);
532 static const struct got_error
*
533 request_packed_commit(struct got_commit_object
**commit
, struct got_pack
*pack
,
534 int pack_idx
, struct got_object_id
*id
)
536 const struct got_error
*err
= NULL
;
538 err
= got_privsep_send_commit_req(pack
->privsep_child
->ibuf
, -1, id
,
543 err
= got_privsep_recv_commit(commit
, pack
->privsep_child
->ibuf
);
547 (*commit
)->flags
|= GOT_COMMIT_FLAG_PACKED
;
551 static const struct got_error
*
552 read_packed_commit_privsep(struct got_commit_object
**commit
,
553 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
554 struct got_object_id
*id
)
556 const struct got_error
*err
= NULL
;
558 if (pack
->privsep_child
)
559 return request_packed_commit(commit
, pack
, idx
, id
);
561 err
= got_pack_start_privsep_child(pack
, packidx
);
565 return request_packed_commit(commit
, pack
, idx
, id
);
568 static const struct got_error
*
569 request_commit(struct got_commit_object
**commit
, struct got_repository
*repo
,
570 int fd
, struct got_object_id
*id
)
572 const struct got_error
*err
= NULL
;
573 struct imsgbuf
*ibuf
;
575 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].ibuf
;
577 err
= got_privsep_send_commit_req(ibuf
, fd
, id
, -1);
581 return got_privsep_recv_commit(commit
, ibuf
);
584 static const struct got_error
*
585 read_commit_privsep(struct got_commit_object
**commit
, int obj_fd
,
586 struct got_object_id
*id
, struct got_repository
*repo
)
588 const struct got_error
*err
;
590 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].imsg_fd
!= -1)
591 return request_commit(commit
, repo
, obj_fd
, id
);
593 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_COMMIT
);
597 return request_commit(commit
, repo
, obj_fd
, id
);
600 static const struct got_error
*
601 open_commit(struct got_commit_object
**commit
,
602 struct got_repository
*repo
, struct got_object_id
*id
, int check_cache
)
604 const struct got_error
*err
= NULL
;
605 struct got_packidx
*packidx
= NULL
;
607 char *path_packfile
= NULL
;
610 *commit
= got_repo_get_cached_commit(repo
, id
);
611 if (*commit
!= NULL
) {
618 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
620 struct got_pack
*pack
= NULL
;
622 err
= got_packidx_get_packfile_path(&path_packfile
,
623 packidx
->path_packidx
);
627 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
629 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
634 err
= read_packed_commit_privsep(commit
, pack
,
636 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
639 err
= got_object_open_loose_fd(&fd
, id
, repo
);
642 err
= read_commit_privsep(commit
, fd
, id
, repo
);
647 err
= got_repo_cache_commit(repo
, id
, *commit
);
654 const struct got_error
*
655 got_object_open_as_commit(struct got_commit_object
**commit
,
656 struct got_repository
*repo
, struct got_object_id
*id
)
658 *commit
= got_repo_get_cached_commit(repo
, id
);
659 if (*commit
!= NULL
) {
664 return open_commit(commit
, repo
, id
, 0);
667 const struct got_error
*
668 got_object_commit_open(struct got_commit_object
**commit
,
669 struct got_repository
*repo
, struct got_object
*obj
)
671 return open_commit(commit
, repo
, got_object_get_id(obj
), 1);
674 static const struct got_error
*
675 request_packed_tree(struct got_tree_object
**tree
, struct got_pack
*pack
,
676 int pack_idx
, struct got_object_id
*id
)
678 const struct got_error
*err
= NULL
;
680 err
= got_privsep_send_tree_req(pack
->privsep_child
->ibuf
, -1, id
,
685 return got_privsep_recv_tree(tree
, pack
->privsep_child
->ibuf
);
688 static const struct got_error
*
689 read_packed_tree_privsep(struct got_tree_object
**tree
,
690 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
691 struct got_object_id
*id
)
693 const struct got_error
*err
= NULL
;
695 if (pack
->privsep_child
)
696 return request_packed_tree(tree
, pack
, idx
, id
);
698 err
= got_pack_start_privsep_child(pack
, packidx
);
702 return request_packed_tree(tree
, pack
, idx
, id
);
705 static const struct got_error
*
706 request_tree(struct got_tree_object
**tree
, struct got_repository
*repo
,
707 int fd
, struct got_object_id
*id
)
709 const struct got_error
*err
= NULL
;
710 struct imsgbuf
*ibuf
;
712 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].ibuf
;
714 err
= got_privsep_send_tree_req(ibuf
, fd
, id
, -1);
718 return got_privsep_recv_tree(tree
, ibuf
);
721 static const struct got_error
*
722 read_tree_privsep(struct got_tree_object
**tree
, int obj_fd
,
723 struct got_object_id
*id
, struct got_repository
*repo
)
725 const struct got_error
*err
;
727 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].imsg_fd
!= -1)
728 return request_tree(tree
, repo
, obj_fd
, id
);
730 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_TREE
);
734 return request_tree(tree
, repo
, obj_fd
, id
);
737 static const struct got_error
*
738 open_tree(struct got_tree_object
**tree
, struct got_repository
*repo
,
739 struct got_object_id
*id
, int check_cache
)
741 const struct got_error
*err
= NULL
;
742 struct got_packidx
*packidx
= NULL
;
744 char *path_packfile
= NULL
;
747 *tree
= got_repo_get_cached_tree(repo
, id
);
755 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
757 struct got_pack
*pack
= NULL
;
759 err
= got_packidx_get_packfile_path(&path_packfile
,
760 packidx
->path_packidx
);
764 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
766 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
771 err
= read_packed_tree_privsep(tree
, pack
,
773 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
776 err
= got_object_open_loose_fd(&fd
, id
, repo
);
779 err
= read_tree_privsep(tree
, fd
, id
, repo
);
784 err
= got_repo_cache_tree(repo
, id
, *tree
);
791 const struct got_error
*
792 got_object_open_as_tree(struct got_tree_object
**tree
,
793 struct got_repository
*repo
, struct got_object_id
*id
)
795 *tree
= got_repo_get_cached_tree(repo
, id
);
801 return open_tree(tree
, repo
, id
, 0);
804 const struct got_error
*
805 got_object_tree_open(struct got_tree_object
**tree
,
806 struct got_repository
*repo
, struct got_object
*obj
)
808 return open_tree(tree
, repo
, got_object_get_id(obj
), 1);
811 static const struct got_error
*
812 request_packed_blob(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
, int outfd
,
813 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
814 struct got_object_id
*id
)
816 const struct got_error
*err
= NULL
;
817 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
820 err
= pack_child_send_tempfiles(ibuf
, pack
);
824 outfd_child
= dup(outfd
);
825 if (outfd_child
== -1)
826 return got_error_from_errno("dup");
828 err
= got_privsep_send_blob_req(pack
->privsep_child
->ibuf
, -1, id
, idx
);
832 err
= got_privsep_send_blob_outfd(pack
->privsep_child
->ibuf
,
838 err
= got_privsep_recv_blob(outbuf
, size
, hdrlen
,
839 pack
->privsep_child
->ibuf
);
843 if (lseek(outfd
, SEEK_SET
, 0) == -1)
844 err
= got_error_from_errno("lseek");
849 static const struct got_error
*
850 read_packed_blob_privsep(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
,
851 int outfd
, struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
852 struct got_object_id
*id
)
854 const struct got_error
*err
= NULL
;
856 if (pack
->privsep_child
== NULL
) {
857 err
= got_pack_start_privsep_child(pack
, packidx
);
862 return request_packed_blob(outbuf
, size
, hdrlen
, outfd
, pack
, packidx
,
866 static const struct got_error
*
867 request_blob(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
, int outfd
,
868 int infd
, struct got_object_id
*id
, struct imsgbuf
*ibuf
)
870 const struct got_error
*err
= NULL
;
873 outfd_child
= dup(outfd
);
874 if (outfd_child
== -1)
875 return got_error_from_errno("dup");
877 err
= got_privsep_send_blob_req(ibuf
, infd
, id
, -1);
881 err
= got_privsep_send_blob_outfd(ibuf
, outfd_child
);
885 err
= got_privsep_recv_blob(outbuf
, size
, hdrlen
, ibuf
);
889 if (lseek(outfd
, SEEK_SET
, 0) == -1)
890 return got_error_from_errno("lseek");
895 static const struct got_error
*
896 read_blob_privsep(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
,
897 int outfd
, int infd
, struct got_object_id
*id
, struct got_repository
*repo
)
899 const struct got_error
*err
;
900 struct imsgbuf
*ibuf
;
902 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].imsg_fd
!= -1) {
903 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].ibuf
;
904 return request_blob(outbuf
, size
, hdrlen
, outfd
, infd
, id
,
908 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_BLOB
);
912 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].ibuf
;
913 return request_blob(outbuf
, size
, hdrlen
, outfd
, infd
, id
, ibuf
);
916 static const struct got_error
*
917 open_blob(struct got_blob_object
**blob
, struct got_repository
*repo
,
918 struct got_object_id
*id
, size_t blocksize
, int outfd
)
920 const struct got_error
*err
= NULL
;
921 struct got_packidx
*packidx
= NULL
;
923 char *path_packfile
= NULL
;
928 *blob
= calloc(1, sizeof(**blob
));
930 return got_error_from_errno("calloc");
932 (*blob
)->read_buf
= malloc(blocksize
);
933 if ((*blob
)->read_buf
== NULL
) {
934 err
= got_error_from_errno("malloc");
938 if (ftruncate(outfd
, 0L) == -1) {
939 err
= got_error_from_errno("ftruncate");
942 if (lseek(outfd
, SEEK_SET
, 0) == -1) {
943 err
= got_error_from_errno("lseek");
947 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
949 struct got_pack
*pack
= NULL
;
951 err
= got_packidx_get_packfile_path(&path_packfile
,
952 packidx
->path_packidx
);
956 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
958 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
963 err
= read_packed_blob_privsep(&outbuf
, &size
, &hdrlen
, outfd
,
964 pack
, packidx
, idx
, id
);
965 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
968 err
= got_object_open_loose_fd(&infd
, id
, repo
);
971 err
= read_blob_privsep(&outbuf
, &size
, &hdrlen
, outfd
, infd
,
978 err
= got_error(GOT_ERR_BAD_OBJ_HDR
);
982 if (outbuf
&& size
> 0) {
983 (*blob
)->f
= fmemopen(outbuf
, size
, "rb");
984 if ((*blob
)->f
== NULL
) {
985 err
= got_error_from_errno("fmemopen");
989 (*blob
)->data
= outbuf
;
991 if (fstat(outfd
, &sb
) == -1) {
992 err
= got_error_from_errno("fstat");
996 if (sb
.st_size
!= size
) {
997 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1003 err
= got_error_from_errno("dup");
1007 (*blob
)->f
= fdopen(dfd
, "rb");
1008 if ((*blob
)->f
== NULL
) {
1009 err
= got_error_from_errno("fdopen");
1016 (*blob
)->hdrlen
= hdrlen
;
1017 (*blob
)->blocksize
= blocksize
;
1018 memcpy(&(*blob
)->id
, id
, sizeof(*id
));
1021 free(path_packfile
);
1024 got_object_blob_close(*blob
);
1031 const struct got_error
*
1032 got_object_open_as_blob(struct got_blob_object
**blob
,
1033 struct got_repository
*repo
, struct got_object_id
*id
, size_t blocksize
,
1036 return open_blob(blob
, repo
, id
, blocksize
, outfd
);
1039 const struct got_error
*
1040 got_object_blob_open(struct got_blob_object
**blob
,
1041 struct got_repository
*repo
, struct got_object
*obj
, size_t blocksize
,
1044 return open_blob(blob
, repo
, got_object_get_id(obj
), blocksize
, outfd
);
1047 static const struct got_error
*
1048 request_packed_tag(struct got_tag_object
**tag
, struct got_pack
*pack
,
1049 int pack_idx
, struct got_object_id
*id
)
1051 const struct got_error
*err
= NULL
;
1053 err
= got_privsep_send_tag_req(pack
->privsep_child
->ibuf
, -1, id
,
1058 return got_privsep_recv_tag(tag
, pack
->privsep_child
->ibuf
);
1061 static const struct got_error
*
1062 read_packed_tag_privsep(struct got_tag_object
**tag
,
1063 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
1064 struct got_object_id
*id
)
1066 const struct got_error
*err
= NULL
;
1068 if (pack
->privsep_child
)
1069 return request_packed_tag(tag
, pack
, idx
, id
);
1071 err
= got_pack_start_privsep_child(pack
, packidx
);
1075 return request_packed_tag(tag
, pack
, idx
, id
);
1078 static const struct got_error
*
1079 request_tag(struct got_tag_object
**tag
, struct got_repository
*repo
,
1080 int fd
, struct got_object_id
*id
)
1082 const struct got_error
*err
= NULL
;
1083 struct imsgbuf
*ibuf
;
1085 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].ibuf
;
1087 err
= got_privsep_send_tag_req(ibuf
, fd
, id
, -1);
1091 return got_privsep_recv_tag(tag
, ibuf
);
1094 static const struct got_error
*
1095 read_tag_privsep(struct got_tag_object
**tag
, int obj_fd
,
1096 struct got_object_id
*id
, struct got_repository
*repo
)
1098 const struct got_error
*err
;
1100 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].imsg_fd
!= -1)
1101 return request_tag(tag
, repo
, obj_fd
, id
);
1103 err
= start_child(repo
, GOT_REPO_PRIVSEP_CHILD_TAG
);
1107 return request_tag(tag
, repo
, obj_fd
, id
);
1110 static const struct got_error
*
1111 open_tag(struct got_tag_object
**tag
, struct got_repository
*repo
,
1112 struct got_object_id
*id
, int check_cache
)
1114 const struct got_error
*err
= NULL
;
1115 struct got_packidx
*packidx
= NULL
;
1117 char *path_packfile
= NULL
;
1118 struct got_object
*obj
= NULL
;
1119 int obj_type
= GOT_OBJ_TYPE_ANY
;
1122 *tag
= got_repo_get_cached_tag(repo
, id
);
1130 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
1132 struct got_pack
*pack
= NULL
;
1134 err
= got_packidx_get_packfile_path(&path_packfile
,
1135 packidx
->path_packidx
);
1139 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1141 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
1147 /* Beware of "lightweight" tags: Check object type first. */
1148 err
= read_packed_object_privsep(&obj
, repo
, pack
, packidx
,
1152 obj_type
= obj
->type
;
1153 got_object_close(obj
);
1154 if (obj_type
!= GOT_OBJ_TYPE_TAG
) {
1155 err
= got_error(GOT_ERR_OBJ_TYPE
);
1158 err
= read_packed_tag_privsep(tag
, pack
, packidx
, idx
, id
);
1159 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
1162 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1165 err
= got_object_read_header_privsep(&obj
, id
, repo
, fd
);
1168 obj_type
= obj
->type
;
1169 got_object_close(obj
);
1170 if (obj_type
!= GOT_OBJ_TYPE_TAG
)
1171 return got_error(GOT_ERR_OBJ_TYPE
);
1173 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1176 err
= read_tag_privsep(tag
, fd
, id
, repo
);
1181 err
= got_repo_cache_tag(repo
, id
, *tag
);
1184 free(path_packfile
);
1188 const struct got_error
*
1189 got_object_open_as_tag(struct got_tag_object
**tag
,
1190 struct got_repository
*repo
, struct got_object_id
*id
)
1192 *tag
= got_repo_get_cached_tag(repo
, id
);
1198 return open_tag(tag
, repo
, id
, 0);
1201 const struct got_error
*
1202 got_object_tag_open(struct got_tag_object
**tag
,
1203 struct got_repository
*repo
, struct got_object
*obj
)
1205 return open_tag(tag
, repo
, got_object_get_id(obj
), 1);
1208 const struct got_error
*
1209 got_traverse_packed_commits(struct got_object_id_queue
*traversed_commits
,
1210 struct got_object_id
*commit_id
, const char *path
,
1211 struct got_repository
*repo
)
1213 const struct got_error
*err
= NULL
;
1214 struct got_pack
*pack
= NULL
;
1215 struct got_packidx
*packidx
= NULL
;
1216 char *path_packfile
= NULL
;
1217 struct got_commit_object
*changed_commit
= NULL
;
1218 struct got_object_qid
*changed_commit_qid
= NULL
;
1221 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, commit_id
);
1223 if (err
->code
!= GOT_ERR_NO_OBJ
)
1228 err
= got_packidx_get_packfile_path(&path_packfile
,
1229 packidx
->path_packidx
);
1233 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1235 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
1240 if (pack
->privsep_child
== NULL
) {
1241 err
= got_pack_start_privsep_child(pack
, packidx
);
1246 err
= got_privsep_send_commit_traversal_request(
1247 pack
->privsep_child
->ibuf
, commit_id
, idx
, path
);
1251 err
= got_privsep_recv_traversed_commits(&changed_commit
,
1252 traversed_commits
, pack
->privsep_child
->ibuf
);
1256 if (changed_commit
) {
1258 * Cache the commit in which the path was changed.
1259 * This commit might be opened again soon.
1261 changed_commit
->refcnt
++;
1262 changed_commit_qid
= STAILQ_LAST(traversed_commits
, got_object_qid
, entry
);
1263 err
= got_repo_cache_commit(repo
, &changed_commit_qid
->id
,
1265 got_object_commit_close(changed_commit
);
1268 free(path_packfile
);
1272 const struct got_error
*
1273 got_object_enumerate(int *found_all_objects
,
1274 got_object_enumerate_commit_cb cb_commit
,
1275 got_object_enumerate_tree_cb cb_tree
, void *cb_arg
,
1276 struct got_object_id
**ours
, int nours
,
1277 struct got_object_id
**theirs
, int ntheirs
,
1278 struct got_packidx
*packidx
, struct got_repository
*repo
)
1280 const struct got_error
*err
= NULL
;
1281 struct got_pack
*pack
;
1282 char *path_packfile
= NULL
;
1284 err
= got_packidx_get_packfile_path(&path_packfile
,
1285 packidx
->path_packidx
);
1289 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1291 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
1296 if (pack
->privsep_child
== NULL
) {
1297 err
= got_pack_start_privsep_child(pack
, packidx
);
1302 err
= got_privsep_send_object_enumeration_request(
1303 pack
->privsep_child
->ibuf
);
1307 err
= got_privsep_send_object_idlist(pack
->privsep_child
->ibuf
,
1311 err
= got_privsep_send_object_idlist_done(pack
->privsep_child
->ibuf
);
1315 err
= got_privsep_send_object_idlist(pack
->privsep_child
->ibuf
,
1319 err
= got_privsep_send_object_idlist_done(pack
->privsep_child
->ibuf
);
1323 err
= got_privsep_recv_enumerated_objects(found_all_objects
,
1324 pack
->privsep_child
->ibuf
, cb_commit
, cb_tree
, cb_arg
, repo
);
1326 free(path_packfile
);