2 * Copyright (c) 2018, 2019 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 <sys/types.h>
19 #include <sys/queue.h>
22 #include <sys/socket.h>
24 #include <sys/resource.h>
39 #include "got_compat.h"
41 #include "got_error.h"
42 #include "got_object.h"
43 #include "got_repository.h"
44 #include "got_opentemp.h"
47 #include "got_lib_sha1.h"
48 #include "got_lib_delta.h"
49 #include "got_lib_inflate.h"
50 #include "got_lib_object.h"
51 #include "got_lib_privsep.h"
52 #include "got_lib_object_idcache.h"
53 #include "got_lib_object_cache.h"
54 #include "got_lib_object_parse.h"
55 #include "got_lib_pack.h"
56 #include "got_lib_repository.h"
59 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
62 struct got_object_id
*
63 got_object_get_id(struct got_object
*obj
)
68 const struct got_error
*
69 got_object_get_id_str(char **outbuf
, struct got_object
*obj
)
71 return got_object_id_str(outbuf
, &obj
->id
);
74 const struct got_error
*
75 got_object_get_type(int *type
, struct got_repository
*repo
,
76 struct got_object_id
*id
)
78 const struct got_error
*err
= NULL
;
79 struct got_object
*obj
;
81 err
= got_object_open(&obj
, repo
, id
);
86 case GOT_OBJ_TYPE_COMMIT
:
87 case GOT_OBJ_TYPE_TREE
:
88 case GOT_OBJ_TYPE_BLOB
:
89 case GOT_OBJ_TYPE_TAG
:
93 err
= got_error(GOT_ERR_OBJ_TYPE
);
97 got_object_close(obj
);
101 const struct got_error
*
102 got_object_get_path(char **path
, struct got_object_id
*id
,
103 struct got_repository
*repo
)
105 const struct got_error
*err
= NULL
;
111 path_objects
= got_repo_get_path_objects(repo
);
112 if (path_objects
== NULL
)
113 return got_error_from_errno("got_repo_get_path_objects");
115 err
= got_object_id_str(&hex
, id
);
119 if (asprintf(path
, "%s/%.2x/%s", path_objects
,
120 id
->sha1
[0], hex
+ 2) == -1)
121 err
= got_error_from_errno("asprintf");
129 const struct got_error
*
130 got_object_open_loose_fd(int *fd
, struct got_object_id
*id
,
131 struct got_repository
*repo
)
133 const struct got_error
*err
= NULL
;
136 err
= got_object_get_path(&path
, id
, repo
);
139 *fd
= open(path
, O_RDONLY
| O_NOFOLLOW
);
141 err
= got_error_from_errno2("open", path
);
149 static const struct got_error
*
150 request_packed_object(struct got_object
**obj
, struct got_pack
*pack
, int idx
,
151 struct got_object_id
*id
)
153 const struct got_error
*err
= NULL
;
154 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
156 err
= got_privsep_send_packed_obj_req(ibuf
, idx
, id
);
160 err
= got_privsep_recv_obj(obj
, ibuf
);
164 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
169 static const struct got_error
*
170 request_packed_object_raw(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
171 int outfd
, struct got_pack
*pack
, int idx
, struct got_object_id
*id
)
173 const struct got_error
*err
= NULL
;
174 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
176 int basefd
, accumfd
; /* temporary files for delta application */
178 basefd
= got_opentempfd();
180 return got_error_from_errno("got_opentempfd");
182 accumfd
= got_opentempfd();
185 return got_error_from_errno("got_opentempfd");
188 outfd_child
= dup(outfd
);
189 if (outfd_child
== -1) {
190 err
= got_error_from_errno("dup");
196 err
= got_privsep_send_packed_raw_obj_req(ibuf
, idx
, id
);
204 err
= got_privsep_send_raw_obj_outfd(ibuf
, outfd_child
);
212 err
= got_privsep_send_tmpfd(pack
->privsep_child
->ibuf
,
219 err
= got_privsep_send_tmpfd(pack
->privsep_child
->ibuf
,
224 err
= got_privsep_recv_raw_obj(outbuf
, size
, hdrlen
, ibuf
);
232 set_max_datasize(void)
236 if (getrlimit(RLIMIT_DATA
, &rl
) != 0)
239 rl
.rlim_cur
= rl
.rlim_max
;
240 setrlimit(RLIMIT_DATA
, &rl
);
243 static const struct got_error
*
244 start_pack_privsep_child(struct got_pack
*pack
, struct got_packidx
*packidx
)
246 const struct got_error
*err
= NULL
;
249 struct imsgbuf
*ibuf
;
251 ibuf
= calloc(1, sizeof(*ibuf
));
253 return got_error_from_errno("calloc");
255 pack
->privsep_child
= calloc(1, sizeof(*pack
->privsep_child
));
256 if (pack
->privsep_child
== NULL
) {
257 err
= got_error_from_errno("calloc");
262 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
263 err
= got_error_from_errno("socketpair");
269 err
= got_error_from_errno("fork");
271 } else if (pid
== 0) {
273 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_PACK
,
274 pack
->path_packfile
);
278 if (close(imsg_fds
[1]) == -1)
279 return got_error_from_errno("close");
280 pack
->privsep_child
->imsg_fd
= imsg_fds
[0];
281 pack
->privsep_child
->pid
= pid
;
282 imsg_init(ibuf
, imsg_fds
[0]);
283 pack
->privsep_child
->ibuf
= ibuf
;
285 err
= got_privsep_init_pack_child(ibuf
, pack
, packidx
);
287 const struct got_error
*child_err
;
288 err
= got_privsep_send_stop(pack
->privsep_child
->imsg_fd
);
289 child_err
= got_privsep_wait_for_child(
290 pack
->privsep_child
->pid
);
291 if (child_err
&& err
== NULL
)
297 free(pack
->privsep_child
);
298 pack
->privsep_child
= NULL
;
303 static const struct got_error
*
304 read_packed_object_privsep(struct got_object
**obj
,
305 struct got_repository
*repo
, struct got_pack
*pack
,
306 struct got_packidx
*packidx
, int idx
, struct got_object_id
*id
)
308 const struct got_error
*err
= NULL
;
310 if (pack
->privsep_child
== NULL
) {
311 err
= start_pack_privsep_child(pack
, packidx
);
316 return request_packed_object(obj
, pack
, idx
, id
);
319 static const struct got_error
*
320 read_packed_object_raw_privsep(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
321 int outfd
, struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
322 struct got_object_id
*id
)
324 const struct got_error
*err
= NULL
;
326 if (pack
->privsep_child
== NULL
) {
327 err
= start_pack_privsep_child(pack
, packidx
);
332 return request_packed_object_raw(outbuf
, size
, hdrlen
, outfd
, pack
,
336 const struct got_error
*
337 got_object_open_packed(struct got_object
**obj
, struct got_object_id
*id
,
338 struct got_repository
*repo
)
340 const struct got_error
*err
= NULL
;
341 struct got_pack
*pack
= NULL
;
342 struct got_packidx
*packidx
= NULL
;
346 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
350 err
= got_packidx_get_packfile_path(&path_packfile
,
351 packidx
->path_packidx
);
355 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
357 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
362 err
= read_packed_object_privsep(obj
, repo
, pack
, packidx
, idx
, id
);
370 static const struct got_error
*
371 request_object(struct got_object
**obj
, struct got_object_id
*id
,
372 struct got_repository
*repo
, int fd
)
374 const struct got_error
*err
= NULL
;
375 struct imsgbuf
*ibuf
;
377 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].ibuf
;
379 err
= got_privsep_send_obj_req(ibuf
, fd
, id
);
383 return got_privsep_recv_obj(obj
, ibuf
);
386 static const struct got_error
*
387 request_raw_object(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
, int outfd
,
388 struct got_object_id
*id
, struct got_repository
*repo
, int infd
)
390 const struct got_error
*err
= NULL
;
391 struct imsgbuf
*ibuf
;
394 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].ibuf
;
396 outfd_child
= dup(outfd
);
397 if (outfd_child
== -1)
398 return got_error_from_errno("dup");
400 err
= got_privsep_send_raw_obj_req(ibuf
, infd
, id
);
404 err
= got_privsep_send_raw_obj_outfd(ibuf
, outfd_child
);
408 return got_privsep_recv_raw_obj(outbuf
, size
, hdrlen
, ibuf
);
411 static const struct got_error
*
412 start_read_object_child(struct got_repository
*repo
)
414 const struct got_error
*err
= NULL
;
417 struct imsgbuf
*ibuf
;
419 ibuf
= calloc(1, sizeof(*ibuf
));
421 return got_error_from_errno("calloc");
423 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
424 err
= got_error_from_errno("socketpair");
431 err
= got_error_from_errno("fork");
436 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_OBJECT
,
441 if (close(imsg_fds
[1]) == -1) {
442 err
= got_error_from_errno("close");
447 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
=
449 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].pid
= pid
;
450 imsg_init(ibuf
, imsg_fds
[0]);
451 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].ibuf
= ibuf
;
456 const struct got_error
*
457 got_object_read_header_privsep(struct got_object
**obj
,
458 struct got_object_id
*id
, struct got_repository
*repo
, int obj_fd
)
460 const struct got_error
*err
;
462 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
!= -1)
463 return request_object(obj
, id
, repo
, obj_fd
);
465 err
= start_read_object_child(repo
);
471 return request_object(obj
, id
, repo
, obj_fd
);
474 static const struct got_error
*
475 read_object_raw_privsep(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
476 int outfd
, struct got_object_id
*id
, struct got_repository
*repo
,
479 const struct got_error
*err
;
481 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
!= -1)
482 return request_raw_object(outbuf
, size
, hdrlen
, outfd
, id
,
485 err
= start_read_object_child(repo
);
489 return request_raw_object(outbuf
, size
, hdrlen
, outfd
, id
, repo
,
493 const struct got_error
*
494 got_object_open(struct got_object
**obj
, struct got_repository
*repo
,
495 struct got_object_id
*id
)
497 const struct got_error
*err
= NULL
;
500 *obj
= got_repo_get_cached_object(repo
, id
);
506 err
= got_object_open_packed(obj
, id
, repo
);
507 if (err
&& err
->code
!= GOT_ERR_NO_OBJ
)
511 return got_repo_cache_object(repo
, id
, *obj
);
514 err
= got_object_open_loose_fd(&fd
, id
, repo
);
516 if (err
->code
== GOT_ERR_ERRNO
&& errno
== ENOENT
)
517 err
= got_error_no_obj(id
);
521 err
= got_object_read_header_privsep(obj
, id
, repo
, fd
);
525 memcpy((*obj
)->id
.sha1
, id
->sha1
, SHA1_DIGEST_LENGTH
);
528 return got_repo_cache_object(repo
, id
, *obj
);
531 /* *outfd must be initialized to -1 by caller */
532 const struct got_error
*
533 got_object_raw_open(struct got_raw_object
**obj
, int *outfd
,
534 struct got_repository
*repo
, struct got_object_id
*id
)
536 const struct got_error
*err
= NULL
;
537 struct got_packidx
*packidx
= NULL
;
539 uint8_t *outbuf
= NULL
;
542 char *path_packfile
= NULL
;
544 *obj
= got_repo_get_cached_raw_object(repo
, id
);
551 *outfd
= got_opentempfd();
553 return got_error_from_errno("got_opentempfd");
556 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
558 struct got_pack
*pack
= NULL
;
560 err
= got_packidx_get_packfile_path(&path_packfile
,
561 packidx
->path_packidx
);
565 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
567 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
572 err
= read_packed_object_raw_privsep(&outbuf
, &size
, &hdrlen
,
573 *outfd
, pack
, packidx
, idx
, id
);
576 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
579 err
= got_object_open_loose_fd(&fd
, id
, repo
);
582 err
= read_object_raw_privsep(&outbuf
, &size
, &hdrlen
, *outfd
,
588 *obj
= calloc(1, sizeof(**obj
));
590 err
= got_error_from_errno("calloc");
595 (*obj
)->f
= fmemopen(outbuf
, hdrlen
+ size
, "r");
596 if ((*obj
)->f
== NULL
) {
597 err
= got_error_from_errno("fdopen");
600 (*obj
)->data
= outbuf
;
603 if (fstat(*outfd
, &sb
) == -1) {
604 err
= got_error_from_errno("fstat");
608 if (sb
.st_size
!= hdrlen
+ size
) {
609 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
613 (*obj
)->f
= fdopen(*outfd
, "r");
614 if ((*obj
)->f
== NULL
) {
615 err
= got_error_from_errno("fdopen");
621 (*obj
)->hdrlen
= hdrlen
;
623 err
= got_repo_cache_raw_object(repo
, id
, *obj
);
628 got_object_raw_close(*obj
);
637 const struct got_error
*
638 got_object_open_by_id_str(struct got_object
**obj
, struct got_repository
*repo
,
641 struct got_object_id id
;
643 if (!got_parse_sha1_digest(id
.sha1
, id_str
))
644 return got_error_path(id_str
, GOT_ERR_BAD_OBJ_ID_STR
);
646 return got_object_open(obj
, repo
, &id
);
649 const struct got_error
*
650 got_object_resolve_id_str(struct got_object_id
**id
,
651 struct got_repository
*repo
, const char *id_str
)
653 const struct got_error
*err
= NULL
;
654 struct got_object
*obj
;
656 err
= got_object_open_by_id_str(&obj
, repo
, id_str
);
660 *id
= got_object_id_dup(got_object_get_id(obj
));
661 got_object_close(obj
);
663 return got_error_from_errno("got_object_id_dup");
668 static const struct got_error
*
669 request_packed_commit(struct got_commit_object
**commit
, struct got_pack
*pack
,
670 int pack_idx
, struct got_object_id
*id
)
672 const struct got_error
*err
= NULL
;
674 err
= got_privsep_send_commit_req(pack
->privsep_child
->ibuf
, -1, id
,
679 err
= got_privsep_recv_commit(commit
, pack
->privsep_child
->ibuf
);
683 (*commit
)->flags
|= GOT_COMMIT_FLAG_PACKED
;
687 static const struct got_error
*
688 read_packed_commit_privsep(struct got_commit_object
**commit
,
689 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
690 struct got_object_id
*id
)
692 const struct got_error
*err
= NULL
;
694 if (pack
->privsep_child
)
695 return request_packed_commit(commit
, pack
, idx
, id
);
697 err
= start_pack_privsep_child(pack
, packidx
);
701 return request_packed_commit(commit
, pack
, idx
, id
);
704 static const struct got_error
*
705 request_commit(struct got_commit_object
**commit
, struct got_repository
*repo
,
706 int fd
, struct got_object_id
*id
)
708 const struct got_error
*err
= NULL
;
709 struct imsgbuf
*ibuf
;
711 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].ibuf
;
713 err
= got_privsep_send_commit_req(ibuf
, fd
, id
, -1);
717 return got_privsep_recv_commit(commit
, ibuf
);
720 static const struct got_error
*
721 read_commit_privsep(struct got_commit_object
**commit
, int obj_fd
,
722 struct got_object_id
*id
, struct got_repository
*repo
)
724 const struct got_error
*err
;
727 struct imsgbuf
*ibuf
;
729 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].imsg_fd
!= -1)
730 return request_commit(commit
, repo
, obj_fd
, id
);
732 ibuf
= calloc(1, sizeof(*ibuf
));
734 return got_error_from_errno("calloc");
736 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
737 err
= got_error_from_errno("socketpair");
744 err
= got_error_from_errno("fork");
749 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_COMMIT
,
754 if (close(imsg_fds
[1]) == -1) {
755 err
= got_error_from_errno("close");
759 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].imsg_fd
=
761 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].pid
= pid
;
762 imsg_init(ibuf
, imsg_fds
[0]);
763 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].ibuf
= ibuf
;
765 return request_commit(commit
, repo
, obj_fd
, id
);
769 static const struct got_error
*
770 open_commit(struct got_commit_object
**commit
,
771 struct got_repository
*repo
, struct got_object_id
*id
, int check_cache
)
773 const struct got_error
*err
= NULL
;
774 struct got_packidx
*packidx
= NULL
;
776 char *path_packfile
= NULL
;
779 *commit
= got_repo_get_cached_commit(repo
, id
);
780 if (*commit
!= NULL
) {
787 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
789 struct got_pack
*pack
= NULL
;
791 err
= got_packidx_get_packfile_path(&path_packfile
,
792 packidx
->path_packidx
);
796 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
798 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
803 err
= read_packed_commit_privsep(commit
, pack
,
805 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
808 err
= got_object_open_loose_fd(&fd
, id
, repo
);
811 err
= read_commit_privsep(commit
, fd
, id
, repo
);
816 err
= got_repo_cache_commit(repo
, id
, *commit
);
823 const struct got_error
*
824 got_object_open_as_commit(struct got_commit_object
**commit
,
825 struct got_repository
*repo
, struct got_object_id
*id
)
827 *commit
= got_repo_get_cached_commit(repo
, id
);
828 if (*commit
!= NULL
) {
833 return open_commit(commit
, repo
, id
, 0);
836 const struct got_error
*
837 got_object_commit_open(struct got_commit_object
**commit
,
838 struct got_repository
*repo
, struct got_object
*obj
)
840 return open_commit(commit
, repo
, got_object_get_id(obj
), 1);
843 const struct got_error
*
844 got_object_qid_alloc(struct got_object_qid
**qid
, struct got_object_id
*id
)
846 const struct got_error
*err
= NULL
;
848 *qid
= calloc(1, sizeof(**qid
));
850 return got_error_from_errno("calloc");
852 (*qid
)->id
= got_object_id_dup(id
);
853 if ((*qid
)->id
== NULL
) {
854 err
= got_error_from_errno("got_object_id_dup");
855 got_object_qid_free(*qid
);
863 const struct got_error
*
864 got_object_id_queue_copy(const struct got_object_id_queue
*src
,
865 struct got_object_id_queue
*dest
)
867 const struct got_error
*err
;
868 struct got_object_qid
*qid
;
870 STAILQ_FOREACH(qid
, src
, entry
) {
871 struct got_object_qid
*new;
873 * Deep-copy the object ID only. Let the caller deal
874 * with setting up the new->data pointer if needed.
876 err
= got_object_qid_alloc(&new, qid
->id
);
878 got_object_id_queue_free(dest
);
881 STAILQ_INSERT_TAIL(dest
, new, entry
);
887 static const struct got_error
*
888 request_packed_tree(struct got_tree_object
**tree
, struct got_pack
*pack
,
889 int pack_idx
, struct got_object_id
*id
)
891 const struct got_error
*err
= NULL
;
893 err
= got_privsep_send_tree_req(pack
->privsep_child
->ibuf
, -1, id
,
898 return got_privsep_recv_tree(tree
, pack
->privsep_child
->ibuf
);
901 static const struct got_error
*
902 read_packed_tree_privsep(struct got_tree_object
**tree
,
903 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
904 struct got_object_id
*id
)
906 const struct got_error
*err
= NULL
;
908 if (pack
->privsep_child
)
909 return request_packed_tree(tree
, pack
, idx
, id
);
911 err
= start_pack_privsep_child(pack
, packidx
);
915 return request_packed_tree(tree
, pack
, idx
, id
);
918 static const struct got_error
*
919 request_tree(struct got_tree_object
**tree
, struct got_repository
*repo
,
920 int fd
, struct got_object_id
*id
)
922 const struct got_error
*err
= NULL
;
923 struct imsgbuf
*ibuf
;
925 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].ibuf
;
927 err
= got_privsep_send_tree_req(ibuf
, fd
, id
, -1);
931 return got_privsep_recv_tree(tree
, ibuf
);
934 const struct got_error
*
935 read_tree_privsep(struct got_tree_object
**tree
, int obj_fd
,
936 struct got_object_id
*id
, struct got_repository
*repo
)
938 const struct got_error
*err
;
941 struct imsgbuf
*ibuf
;
943 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].imsg_fd
!= -1)
944 return request_tree(tree
, repo
, obj_fd
, id
);
946 ibuf
= calloc(1, sizeof(*ibuf
));
948 return got_error_from_errno("calloc");
950 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
951 err
= got_error_from_errno("socketpair");
958 err
= got_error_from_errno("fork");
963 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_TREE
,
968 if (close(imsg_fds
[1]) == -1) {
969 err
= got_error_from_errno("close");
973 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].imsg_fd
=
975 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].pid
= pid
;
976 imsg_init(ibuf
, imsg_fds
[0]);
977 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].ibuf
= ibuf
;
980 return request_tree(tree
, repo
, obj_fd
, id
);
983 static const struct got_error
*
984 open_tree(struct got_tree_object
**tree
, struct got_repository
*repo
,
985 struct got_object_id
*id
, int check_cache
)
987 const struct got_error
*err
= NULL
;
988 struct got_packidx
*packidx
= NULL
;
990 char *path_packfile
= NULL
;
993 *tree
= got_repo_get_cached_tree(repo
, id
);
1001 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
1003 struct got_pack
*pack
= NULL
;
1005 err
= got_packidx_get_packfile_path(&path_packfile
,
1006 packidx
->path_packidx
);
1010 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1012 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
1017 err
= read_packed_tree_privsep(tree
, pack
,
1019 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
1022 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1025 err
= read_tree_privsep(tree
, fd
, id
, repo
);
1030 err
= got_repo_cache_tree(repo
, id
, *tree
);
1033 free(path_packfile
);
1037 const struct got_error
*
1038 got_object_open_as_tree(struct got_tree_object
**tree
,
1039 struct got_repository
*repo
, struct got_object_id
*id
)
1041 *tree
= got_repo_get_cached_tree(repo
, id
);
1042 if (*tree
!= NULL
) {
1047 return open_tree(tree
, repo
, id
, 0);
1050 const struct got_error
*
1051 got_object_tree_open(struct got_tree_object
**tree
,
1052 struct got_repository
*repo
, struct got_object
*obj
)
1054 return open_tree(tree
, repo
, got_object_get_id(obj
), 1);
1058 got_object_tree_get_nentries(struct got_tree_object
*tree
)
1060 return tree
->nentries
;
1063 struct got_tree_entry
*
1064 got_object_tree_get_first_entry(struct got_tree_object
*tree
)
1066 return got_object_tree_get_entry(tree
, 0);
1069 struct got_tree_entry
*
1070 got_object_tree_get_last_entry(struct got_tree_object
*tree
)
1072 return got_object_tree_get_entry(tree
, tree
->nentries
- 1);
1075 struct got_tree_entry
*
1076 got_object_tree_get_entry(struct got_tree_object
*tree
, int i
)
1078 if (i
< 0 || i
>= tree
->nentries
)
1080 return &tree
->entries
[i
];
1084 got_tree_entry_get_mode(struct got_tree_entry
*te
)
1090 got_tree_entry_get_name(struct got_tree_entry
*te
)
1092 return &te
->name
[0];
1095 struct got_object_id
*
1096 got_tree_entry_get_id(struct got_tree_entry
*te
)
1101 const struct got_error
*
1102 got_object_blob_read_to_str(char **s
, struct got_blob_object
*blob
)
1104 const struct got_error
*err
= NULL
;
1105 size_t len
, totlen
, hdrlen
, offset
;
1109 hdrlen
= got_object_blob_get_hdrlen(blob
);
1115 err
= got_object_blob_read_block(&len
, blob
);
1122 totlen
+= len
- hdrlen
;
1123 p
= realloc(*s
, totlen
+ 1);
1125 err
= got_error_from_errno("realloc");
1131 /* Skip blob object header first time around. */
1133 got_object_blob_get_read_buf(blob
) + hdrlen
, len
- hdrlen
);
1138 (*s
)[totlen
] = '\0';
1142 const struct got_error
*
1143 got_tree_entry_get_symlink_target(char **link_target
, struct got_tree_entry
*te
,
1144 struct got_repository
*repo
)
1146 const struct got_error
*err
= NULL
;
1147 struct got_blob_object
*blob
= NULL
;
1149 *link_target
= NULL
;
1151 if (!got_object_tree_entry_is_symlink(te
))
1152 return got_error(GOT_ERR_TREE_ENTRY_TYPE
);
1154 err
= got_object_open_as_blob(&blob
, repo
,
1155 got_tree_entry_get_id(te
), PATH_MAX
);
1159 err
= got_object_blob_read_to_str(link_target
, blob
);
1160 got_object_blob_close(blob
);
1163 *link_target
= NULL
;
1169 got_tree_entry_get_index(struct got_tree_entry
*te
)
1174 struct got_tree_entry
*
1175 got_tree_entry_get_next(struct got_tree_object
*tree
,
1176 struct got_tree_entry
*te
)
1178 return got_object_tree_get_entry(tree
, te
->idx
+ 1);
1181 struct got_tree_entry
*
1182 got_tree_entry_get_prev(struct got_tree_object
*tree
,
1183 struct got_tree_entry
*te
)
1185 return got_object_tree_get_entry(tree
, te
->idx
- 1);
1188 static const struct got_error
*
1189 request_packed_blob(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
, int outfd
,
1190 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
1191 struct got_object_id
*id
)
1193 const struct got_error
*err
= NULL
;
1195 int basefd
, accumfd
; /* temporary files for delta application */
1197 basefd
= got_opentempfd();
1199 return got_error_from_errno("got_opentempfd");
1200 accumfd
= got_opentempfd();
1202 return got_error_from_errno("got_opentempfd");
1204 outfd_child
= dup(outfd
);
1205 if (outfd_child
== -1)
1206 return got_error_from_errno("dup");
1208 err
= got_privsep_send_blob_req(pack
->privsep_child
->ibuf
, -1, id
, idx
);
1212 err
= got_privsep_send_blob_outfd(pack
->privsep_child
->ibuf
,
1220 err
= got_privsep_send_tmpfd(pack
->privsep_child
->ibuf
,
1227 err
= got_privsep_send_tmpfd(pack
->privsep_child
->ibuf
,
1232 err
= got_privsep_recv_blob(outbuf
, size
, hdrlen
,
1233 pack
->privsep_child
->ibuf
);
1237 if (lseek(outfd
, SEEK_SET
, 0) == -1)
1238 err
= got_error_from_errno("lseek");
1243 static const struct got_error
*
1244 read_packed_blob_privsep(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
,
1245 int outfd
, struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
1246 struct got_object_id
*id
)
1248 const struct got_error
*err
= NULL
;
1250 if (pack
->privsep_child
== NULL
) {
1251 err
= start_pack_privsep_child(pack
, packidx
);
1256 return request_packed_blob(outbuf
, size
, hdrlen
, outfd
, pack
, packidx
,
1260 static const struct got_error
*
1261 request_blob(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
, int outfd
,
1262 int infd
, struct got_object_id
*id
, struct imsgbuf
*ibuf
)
1264 const struct got_error
*err
= NULL
;
1267 outfd_child
= dup(outfd
);
1268 if (outfd_child
== -1)
1269 return got_error_from_errno("dup");
1271 err
= got_privsep_send_blob_req(ibuf
, infd
, id
, -1);
1275 err
= got_privsep_send_blob_outfd(ibuf
, outfd_child
);
1279 err
= got_privsep_recv_blob(outbuf
, size
, hdrlen
, ibuf
);
1283 if (lseek(outfd
, SEEK_SET
, 0) == -1)
1284 return got_error_from_errno("lseek");
1289 static const struct got_error
*
1290 read_blob_privsep(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
,
1291 int outfd
, int infd
, struct got_object_id
*id
, struct got_repository
*repo
)
1293 const struct got_error
*err
;
1296 struct imsgbuf
*ibuf
;
1298 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].imsg_fd
!= -1) {
1299 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].ibuf
;
1300 return request_blob(outbuf
, size
, hdrlen
, outfd
, infd
, id
,
1304 ibuf
= calloc(1, sizeof(*ibuf
));
1306 return got_error_from_errno("calloc");
1308 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
1309 err
= got_error_from_errno("socketpair");
1316 err
= got_error_from_errno("fork");
1320 else if (pid
== 0) {
1321 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_BLOB
,
1326 if (close(imsg_fds
[1]) == -1) {
1327 err
= got_error_from_errno("close");
1331 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].imsg_fd
=
1333 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].pid
= pid
;
1334 imsg_init(ibuf
, imsg_fds
[0]);
1335 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].ibuf
= ibuf
;
1337 return request_blob(outbuf
, size
, hdrlen
, outfd
, infd
, id
, ibuf
);
1340 static const struct got_error
*
1341 open_blob(struct got_blob_object
**blob
, struct got_repository
*repo
,
1342 struct got_object_id
*id
, size_t blocksize
)
1344 const struct got_error
*err
= NULL
;
1345 struct got_packidx
*packidx
= NULL
;
1347 char *path_packfile
= NULL
;
1350 size_t size
, hdrlen
;
1353 *blob
= calloc(1, sizeof(**blob
));
1355 return got_error_from_errno("calloc");
1357 outfd
= got_opentempfd();
1359 return got_error_from_errno("got_opentempfd");
1361 (*blob
)->read_buf
= malloc(blocksize
);
1362 if ((*blob
)->read_buf
== NULL
) {
1363 err
= got_error_from_errno("malloc");
1367 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
1369 struct got_pack
*pack
= NULL
;
1371 err
= got_packidx_get_packfile_path(&path_packfile
,
1372 packidx
->path_packidx
);
1376 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1378 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
1383 err
= read_packed_blob_privsep(&outbuf
, &size
, &hdrlen
, outfd
,
1384 pack
, packidx
, idx
, id
);
1385 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
1388 err
= got_object_open_loose_fd(&infd
, id
, repo
);
1391 err
= read_blob_privsep(&outbuf
, &size
, &hdrlen
, outfd
, infd
,
1397 if (hdrlen
> size
) {
1398 err
= got_error(GOT_ERR_BAD_OBJ_HDR
);
1403 if (close(outfd
) == -1 && err
== NULL
)
1404 err
= got_error_from_errno("close");
1406 (*blob
)->f
= fmemopen(outbuf
, size
, "rb");
1407 if ((*blob
)->f
== NULL
) {
1408 err
= got_error_from_errno("fmemopen");
1412 (*blob
)->data
= outbuf
;
1414 if (fstat(outfd
, &sb
) == -1) {
1415 err
= got_error_from_errno("fstat");
1419 if (sb
.st_size
!= size
) {
1420 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1424 (*blob
)->f
= fdopen(outfd
, "rb");
1425 if ((*blob
)->f
== NULL
) {
1426 err
= got_error_from_errno("fdopen");
1433 (*blob
)->hdrlen
= hdrlen
;
1434 (*blob
)->blocksize
= blocksize
;
1435 memcpy(&(*blob
)->id
.sha1
, id
->sha1
, SHA1_DIGEST_LENGTH
);
1438 free(path_packfile
);
1441 got_object_blob_close(*blob
);
1443 } else if (outfd
!= -1)
1449 const struct got_error
*
1450 got_object_open_as_blob(struct got_blob_object
**blob
,
1451 struct got_repository
*repo
, struct got_object_id
*id
,
1454 return open_blob(blob
, repo
, id
, blocksize
);
1457 const struct got_error
*
1458 got_object_blob_open(struct got_blob_object
**blob
,
1459 struct got_repository
*repo
, struct got_object
*obj
, size_t blocksize
)
1461 return open_blob(blob
, repo
, got_object_get_id(obj
), blocksize
);
1464 const struct got_error
*
1465 got_object_blob_close(struct got_blob_object
*blob
)
1467 const struct got_error
*err
= NULL
;
1468 free(blob
->read_buf
);
1469 if (blob
->f
&& fclose(blob
->f
) == EOF
)
1470 err
= got_error_from_errno("fclose");
1477 got_object_blob_rewind(struct got_blob_object
*blob
)
1484 got_object_blob_id_str(struct got_blob_object
*blob
, char *buf
, size_t size
)
1486 return got_sha1_digest_to_str(blob
->id
.sha1
, buf
, size
);
1490 got_object_blob_get_hdrlen(struct got_blob_object
*blob
)
1492 return blob
->hdrlen
;
1496 got_object_blob_get_read_buf(struct got_blob_object
*blob
)
1498 return blob
->read_buf
;
1501 const struct got_error
*
1502 got_object_blob_read_block(size_t *outlenp
, struct got_blob_object
*blob
)
1506 n
= fread(blob
->read_buf
, 1, blob
->blocksize
, blob
->f
);
1507 if (n
== 0 && ferror(blob
->f
))
1508 return got_ferror(blob
->f
, GOT_ERR_IO
);
1513 const struct got_error
*
1514 got_object_blob_dump_to_file(off_t
*filesize
, int *nlines
,
1515 off_t
**line_offsets
, FILE *outfile
, struct got_blob_object
*blob
)
1517 const struct got_error
*err
= NULL
;
1518 size_t n
, len
, hdrlen
;
1521 const int alloc_chunksz
= 512;
1523 off_t off
= 0, total_len
= 0;
1526 *line_offsets
= NULL
;
1532 hdrlen
= got_object_blob_get_hdrlen(blob
);
1534 err
= got_object_blob_read_block(&len
, blob
);
1539 buf
= got_object_blob_get_read_buf(blob
);
1542 if (line_offsets
&& *line_offsets
== NULL
) {
1543 /* Have some data but perhaps no '\n'. */
1545 nalloc
= alloc_chunksz
;
1546 *line_offsets
= calloc(nalloc
,
1547 sizeof(**line_offsets
));
1548 if (*line_offsets
== NULL
)
1549 return got_error_from_errno("calloc");
1551 /* Skip forward over end of first line. */
1558 /* Scan '\n' offsets in remaining chunk of data. */
1560 if (buf
[i
] != '\n') {
1565 if (line_offsets
&& nalloc
< *nlines
) {
1566 size_t n
= *nlines
+ alloc_chunksz
;
1567 off_t
*o
= recallocarray(*line_offsets
,
1568 nalloc
, n
, sizeof(**line_offsets
));
1570 free(*line_offsets
);
1571 *line_offsets
= NULL
;
1572 return got_error_from_errno(
1579 off
= total_len
+ i
- hdrlen
+ 1;
1580 (*line_offsets
)[*nlines
- 1] = off
;
1585 /* Skip blob object header first time around. */
1586 n
= fwrite(buf
+ hdrlen
, 1, len
- hdrlen
, outfile
);
1587 if (n
!= len
- hdrlen
)
1588 return got_ferror(outfile
, GOT_ERR_IO
);
1589 total_len
+= len
- hdrlen
;
1593 if (fflush(outfile
) != 0)
1594 return got_error_from_errno("fflush");
1598 *filesize
= total_len
;
1603 static const struct got_error
*
1604 request_packed_tag(struct got_tag_object
**tag
, struct got_pack
*pack
,
1605 int pack_idx
, struct got_object_id
*id
)
1607 const struct got_error
*err
= NULL
;
1609 err
= got_privsep_send_tag_req(pack
->privsep_child
->ibuf
, -1, id
,
1614 return got_privsep_recv_tag(tag
, pack
->privsep_child
->ibuf
);
1617 static const struct got_error
*
1618 read_packed_tag_privsep(struct got_tag_object
**tag
,
1619 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
1620 struct got_object_id
*id
)
1622 const struct got_error
*err
= NULL
;
1624 if (pack
->privsep_child
)
1625 return request_packed_tag(tag
, pack
, idx
, id
);
1627 err
= start_pack_privsep_child(pack
, packidx
);
1631 return request_packed_tag(tag
, pack
, idx
, id
);
1634 static const struct got_error
*
1635 request_tag(struct got_tag_object
**tag
, struct got_repository
*repo
,
1636 int fd
, struct got_object_id
*id
)
1638 const struct got_error
*err
= NULL
;
1639 struct imsgbuf
*ibuf
;
1641 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].ibuf
;
1643 err
= got_privsep_send_tag_req(ibuf
, fd
, id
, -1);
1647 return got_privsep_recv_tag(tag
, ibuf
);
1650 static const struct got_error
*
1651 read_tag_privsep(struct got_tag_object
**tag
, int obj_fd
,
1652 struct got_object_id
*id
, struct got_repository
*repo
)
1654 const struct got_error
*err
;
1657 struct imsgbuf
*ibuf
;
1659 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].imsg_fd
!= -1)
1660 return request_tag(tag
, repo
, obj_fd
, id
);
1662 ibuf
= calloc(1, sizeof(*ibuf
));
1664 return got_error_from_errno("calloc");
1666 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
1667 err
= got_error_from_errno("socketpair");
1674 err
= got_error_from_errno("fork");
1678 else if (pid
== 0) {
1679 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_TAG
,
1684 if (close(imsg_fds
[1]) == -1) {
1685 err
= got_error_from_errno("close");
1689 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].imsg_fd
=
1691 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].pid
= pid
;
1692 imsg_init(ibuf
, imsg_fds
[0]);
1693 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].ibuf
= ibuf
;
1695 return request_tag(tag
, repo
, obj_fd
, id
);
1698 static const struct got_error
*
1699 open_tag(struct got_tag_object
**tag
, struct got_repository
*repo
,
1700 struct got_object_id
*id
, int check_cache
)
1702 const struct got_error
*err
= NULL
;
1703 struct got_packidx
*packidx
= NULL
;
1705 char *path_packfile
= NULL
;
1706 struct got_object
*obj
= NULL
;
1707 int obj_type
= GOT_OBJ_TYPE_ANY
;
1710 *tag
= got_repo_get_cached_tag(repo
, id
);
1718 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
1720 struct got_pack
*pack
= NULL
;
1722 err
= got_packidx_get_packfile_path(&path_packfile
,
1723 packidx
->path_packidx
);
1727 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1729 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
1735 /* Beware of "lightweight" tags: Check object type first. */
1736 err
= read_packed_object_privsep(&obj
, repo
, pack
, packidx
,
1740 obj_type
= obj
->type
;
1741 got_object_close(obj
);
1742 if (obj_type
!= GOT_OBJ_TYPE_TAG
) {
1743 err
= got_error(GOT_ERR_OBJ_TYPE
);
1746 err
= read_packed_tag_privsep(tag
, pack
, packidx
, idx
, id
);
1747 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
1750 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1753 err
= got_object_read_header_privsep(&obj
, id
, repo
, fd
);
1756 obj_type
= obj
->type
;
1757 got_object_close(obj
);
1758 if (obj_type
!= GOT_OBJ_TYPE_TAG
)
1759 return got_error(GOT_ERR_OBJ_TYPE
);
1761 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1764 err
= read_tag_privsep(tag
, fd
, id
, repo
);
1769 err
= got_repo_cache_tag(repo
, id
, *tag
);
1772 free(path_packfile
);
1776 const struct got_error
*
1777 got_object_open_as_tag(struct got_tag_object
**tag
,
1778 struct got_repository
*repo
, struct got_object_id
*id
)
1780 *tag
= got_repo_get_cached_tag(repo
, id
);
1786 return open_tag(tag
, repo
, id
, 0);
1789 const struct got_error
*
1790 got_object_tag_open(struct got_tag_object
**tag
,
1791 struct got_repository
*repo
, struct got_object
*obj
)
1793 return open_tag(tag
, repo
, got_object_get_id(obj
), 1);
1797 got_object_tag_get_name(struct got_tag_object
*tag
)
1803 got_object_tag_get_object_type(struct got_tag_object
*tag
)
1805 return tag
->obj_type
;
1808 struct got_object_id
*
1809 got_object_tag_get_object_id(struct got_tag_object
*tag
)
1815 got_object_tag_get_tagger_time(struct got_tag_object
*tag
)
1817 return tag
->tagger_time
;
1821 got_object_tag_get_tagger_gmtoff(struct got_tag_object
*tag
)
1823 return tag
->tagger_gmtoff
;
1827 got_object_tag_get_tagger(struct got_tag_object
*tag
)
1833 got_object_tag_get_message(struct got_tag_object
*tag
)
1838 static struct got_tree_entry
*
1839 find_entry_by_name(struct got_tree_object
*tree
, const char *name
, size_t len
)
1843 /* Note that tree entries are sorted in strncmp() order. */
1844 for (i
= 0; i
< tree
->nentries
; i
++) {
1845 struct got_tree_entry
*te
= &tree
->entries
[i
];
1846 int cmp
= strncmp(te
->name
, name
, len
);
1851 if (te
->name
[len
] == '\0')
1857 struct got_tree_entry
*
1858 got_object_tree_find_entry(struct got_tree_object
*tree
, const char *name
)
1860 return find_entry_by_name(tree
, name
, strlen(name
));
1863 const struct got_error
*
1864 got_object_tree_find_path(struct got_object_id
**id
, mode_t
*mode
,
1865 struct got_repository
*repo
, struct got_tree_object
*tree
,
1868 const struct got_error
*err
= NULL
;
1869 struct got_tree_object
*subtree
= NULL
;
1870 struct got_tree_entry
*te
= NULL
;
1871 const char *seg
, *s
;
1883 struct got_tree_object
*next_tree
;
1892 te
= find_entry_by_name(subtree
, seg
, seglen
);
1894 err
= got_error_path(path
, GOT_ERR_NO_TREE_ENTRY
);
1905 err
= got_object_open_as_tree(&next_tree
, repo
,
1910 if (subtree
!= tree
)
1911 got_object_tree_close(subtree
);
1912 subtree
= next_tree
;
1917 *id
= got_object_id_dup(&te
->id
);
1919 return got_error_from_errno("got_object_id_dup");
1923 err
= got_error_path(path
, GOT_ERR_NO_TREE_ENTRY
);
1925 if (subtree
&& subtree
!= tree
)
1926 got_object_tree_close(subtree
);
1929 const struct got_error
*
1930 got_object_id_by_path(struct got_object_id
**id
, struct got_repository
*repo
,
1931 struct got_object_id
*commit_id
, const char *path
)
1933 const struct got_error
*err
= NULL
;
1934 struct got_commit_object
*commit
= NULL
;
1935 struct got_tree_object
*tree
= NULL
;
1939 err
= got_object_open_as_commit(&commit
, repo
, commit_id
);
1943 /* Handle opening of root of commit's tree. */
1944 if (got_path_is_root_dir(path
)) {
1945 *id
= got_object_id_dup(commit
->tree_id
);
1947 err
= got_error_from_errno("got_object_id_dup");
1949 err
= got_object_open_as_tree(&tree
, repo
, commit
->tree_id
);
1952 err
= got_object_tree_find_path(id
, NULL
, repo
, tree
, path
);
1956 got_object_commit_close(commit
);
1958 got_object_tree_close(tree
);
1963 * Normalize file mode bits to avoid false positive tree entry differences
1964 * in case tree entries have unexpected mode bits set.
1967 normalize_mode_for_comparison(mode_t mode
)
1970 * For directories, the only relevant bit is the IFDIR bit.
1971 * This allows us to detect paths changing from a directory
1972 * to a file and vice versa.
1975 return mode
& S_IFDIR
;
1978 * For symlinks, the only relevant bit is the IFLNK bit.
1979 * This allows us to detect paths changing from a symlinks
1980 * to a file or directory and vice versa.
1983 return mode
& S_IFLNK
;
1985 /* For files, the only change we care about is the executable bit. */
1986 return mode
& S_IXUSR
;
1989 const struct got_error
*
1990 got_object_tree_path_changed(int *changed
,
1991 struct got_tree_object
*tree01
, struct got_tree_object
*tree02
,
1992 const char *path
, struct got_repository
*repo
)
1994 const struct got_error
*err
= NULL
;
1995 struct got_tree_object
*tree1
= NULL
, *tree2
= NULL
;
1996 struct got_tree_entry
*te1
= NULL
, *te2
= NULL
;
1997 const char *seg
, *s
;
2002 /* We not do support comparing the root path. */
2003 if (got_path_is_root_dir(path
))
2004 return got_error_path(path
, GOT_ERR_BAD_PATH
);
2014 struct got_tree_object
*next_tree1
, *next_tree2
;
2015 mode_t mode1
, mode2
;
2024 te1
= find_entry_by_name(tree1
, seg
, seglen
);
2026 err
= got_error(GOT_ERR_NO_OBJ
);
2031 te2
= find_entry_by_name(tree2
, seg
, seglen
);
2034 mode1
= normalize_mode_for_comparison(te1
->mode
);
2035 mode2
= normalize_mode_for_comparison(te2
->mode
);
2036 if (mode1
!= mode2
) {
2041 if (got_object_id_cmp(&te1
->id
, &te2
->id
) == 0) {
2047 if (*s
== '\0') { /* final path element */
2056 err
= got_object_open_as_tree(&next_tree1
, repo
,
2061 if (tree1
!= tree01
)
2062 got_object_tree_close(tree1
);
2066 err
= got_object_open_as_tree(&next_tree2
, repo
,
2071 if (tree2
!= tree02
)
2072 got_object_tree_close(tree2
);
2075 if (tree2
!= tree02
)
2076 got_object_tree_close(tree2
);
2082 if (tree1
&& tree1
!= tree01
)
2083 got_object_tree_close(tree1
);
2084 if (tree2
&& tree2
!= tree02
)
2085 got_object_tree_close(tree2
);
2089 const struct got_error
*
2090 got_object_tree_entry_dup(struct got_tree_entry
**new_te
,
2091 struct got_tree_entry
*te
)
2093 const struct got_error
*err
= NULL
;
2095 *new_te
= calloc(1, sizeof(**new_te
));
2096 if (*new_te
== NULL
)
2097 return got_error_from_errno("calloc");
2099 (*new_te
)->mode
= te
->mode
;
2100 memcpy((*new_te
)->name
, te
->name
, sizeof((*new_te
)->name
));
2101 memcpy(&(*new_te
)->id
, &te
->id
, sizeof((*new_te
)->id
));
2106 got_object_tree_entry_is_submodule(struct got_tree_entry
*te
)
2108 return (te
->mode
& S_IFMT
) == (S_IFDIR
| S_IFLNK
);
2112 got_object_tree_entry_is_symlink(struct got_tree_entry
*te
)
2114 /* S_IFDIR check avoids confusing symlinks with submodules. */
2115 return ((te
->mode
& (S_IFDIR
| S_IFLNK
)) == S_IFLNK
);
2118 static const struct got_error
*
2119 resolve_symlink(char **link_target
, const char *path
,
2120 struct got_object_id
*commit_id
, struct got_repository
*repo
)
2122 const struct got_error
*err
= NULL
;
2124 char *name
, *parent_path
= NULL
;
2125 struct got_object_id
*tree_obj_id
= NULL
;
2126 struct got_tree_object
*tree
= NULL
;
2127 struct got_tree_entry
*te
= NULL
;
2129 *link_target
= NULL
;
2131 if (strlcpy(buf
, path
, sizeof(buf
)) >= sizeof(buf
))
2132 return got_error(GOT_ERR_NO_SPACE
);
2134 name
= basename(buf
);
2136 return got_error_from_errno2("basename", path
);
2138 err
= got_path_dirname(&parent_path
, path
);
2142 err
= got_object_id_by_path(&tree_obj_id
, repo
, commit_id
,
2145 if (err
->code
== GOT_ERR_NO_TREE_ENTRY
) {
2146 /* Display the complete path in error message. */
2147 err
= got_error_path(path
, err
->code
);
2152 err
= got_object_open_as_tree(&tree
, repo
, tree_obj_id
);
2156 te
= got_object_tree_find_entry(tree
, name
);
2158 err
= got_error_path(path
, GOT_ERR_NO_TREE_ENTRY
);
2162 if (got_object_tree_entry_is_symlink(te
)) {
2163 err
= got_tree_entry_get_symlink_target(link_target
, te
, repo
);
2166 if (!got_path_is_absolute(*link_target
)) {
2168 if (asprintf(&abspath
, "%s/%s", parent_path
,
2169 *link_target
) == -1) {
2170 err
= got_error_from_errno("asprintf");
2174 *link_target
= malloc(PATH_MAX
);
2175 if (*link_target
== NULL
) {
2176 err
= got_error_from_errno("malloc");
2179 err
= got_canonpath(abspath
, *link_target
, PATH_MAX
);
2188 got_object_tree_close(tree
);
2191 *link_target
= NULL
;
2196 const struct got_error
*
2197 got_object_resolve_symlinks(char **link_target
, const char *path
,
2198 struct got_object_id
*commit_id
, struct got_repository
*repo
)
2200 const struct got_error
*err
= NULL
;
2201 char *next_target
= NULL
;
2202 int max_recursion
= 40; /* matches Git */
2204 *link_target
= NULL
;
2207 err
= resolve_symlink(&next_target
,
2208 *link_target
? *link_target
: path
, commit_id
, repo
);
2213 if (--max_recursion
== 0) {
2214 err
= got_error_path(path
, GOT_ERR_RECURSION
);
2215 *link_target
= NULL
;
2218 *link_target
= next_target
;
2220 } while (next_target
);
2225 const struct got_error
*
2226 got_traverse_packed_commits(struct got_object_id_queue
*traversed_commits
,
2227 struct got_object_id
*commit_id
, const char *path
,
2228 struct got_repository
*repo
)
2230 const struct got_error
*err
= NULL
;
2231 struct got_pack
*pack
= NULL
;
2232 struct got_packidx
*packidx
= NULL
;
2233 char *path_packfile
= NULL
;
2234 struct got_commit_object
*changed_commit
= NULL
;
2235 struct got_object_id
*changed_commit_id
= NULL
;
2238 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, commit_id
);
2240 if (err
->code
!= GOT_ERR_NO_OBJ
)
2245 err
= got_packidx_get_packfile_path(&path_packfile
,
2246 packidx
->path_packidx
);
2250 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
2252 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
2257 if (pack
->privsep_child
== NULL
) {
2258 err
= start_pack_privsep_child(pack
, packidx
);
2263 err
= got_privsep_send_commit_traversal_request(
2264 pack
->privsep_child
->ibuf
, commit_id
, idx
, path
);
2268 err
= got_privsep_recv_traversed_commits(&changed_commit
,
2269 &changed_commit_id
, traversed_commits
, pack
->privsep_child
->ibuf
);
2273 if (changed_commit
) {
2275 * Cache the commit in which the path was changed.
2276 * This commit might be opened again soon.
2278 changed_commit
->refcnt
++;
2279 err
= got_repo_cache_commit(repo
, changed_commit_id
,
2281 got_object_commit_close(changed_commit
);
2284 free(path_packfile
);
2285 free(changed_commit_id
);