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>
20 #include <sys/socket.h>
22 #include <sys/resource.h>
37 #include "got_compat.h"
39 #include "got_error.h"
40 #include "got_object.h"
41 #include "got_repository.h"
42 #include "got_opentemp.h"
45 #include "got_lib_sha1.h"
46 #include "got_lib_delta.h"
47 #include "got_lib_inflate.h"
48 #include "got_lib_object.h"
49 #include "got_lib_privsep.h"
50 #include "got_lib_object_idcache.h"
51 #include "got_lib_object_cache.h"
52 #include "got_lib_object_parse.h"
53 #include "got_lib_pack.h"
54 #include "got_lib_repository.h"
57 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
60 struct got_object_id
*
61 got_object_get_id(struct got_object
*obj
)
66 const struct got_error
*
67 got_object_get_id_str(char **outbuf
, struct got_object
*obj
)
69 return got_object_id_str(outbuf
, &obj
->id
);
72 const struct got_error
*
73 got_object_get_type(int *type
, struct got_repository
*repo
,
74 struct got_object_id
*id
)
76 const struct got_error
*err
= NULL
;
77 struct got_object
*obj
;
79 err
= got_object_open(&obj
, repo
, id
);
84 case GOT_OBJ_TYPE_COMMIT
:
85 case GOT_OBJ_TYPE_TREE
:
86 case GOT_OBJ_TYPE_BLOB
:
87 case GOT_OBJ_TYPE_TAG
:
91 err
= got_error(GOT_ERR_OBJ_TYPE
);
95 got_object_close(obj
);
99 const struct got_error
*
100 got_object_get_path(char **path
, struct got_object_id
*id
,
101 struct got_repository
*repo
)
103 const struct got_error
*err
= NULL
;
109 path_objects
= got_repo_get_path_objects(repo
);
110 if (path_objects
== NULL
)
111 return got_error_from_errno("got_repo_get_path_objects");
113 err
= got_object_id_str(&hex
, id
);
117 if (asprintf(path
, "%s/%.2x/%s", path_objects
,
118 id
->sha1
[0], hex
+ 2) == -1)
119 err
= got_error_from_errno("asprintf");
127 const struct got_error
*
128 got_object_open_loose_fd(int *fd
, struct got_object_id
*id
,
129 struct got_repository
*repo
)
131 const struct got_error
*err
= NULL
;
134 err
= got_object_get_path(&path
, id
, repo
);
137 *fd
= open(path
, O_RDONLY
| O_NOFOLLOW
);
139 err
= got_error_from_errno2("open", path
);
147 static const struct got_error
*
148 request_packed_object(struct got_object
**obj
, struct got_pack
*pack
, int idx
,
149 struct got_object_id
*id
)
151 const struct got_error
*err
= NULL
;
152 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
154 err
= got_privsep_send_packed_obj_req(ibuf
, idx
, id
);
158 err
= got_privsep_recv_obj(obj
, ibuf
);
162 memcpy(&(*obj
)->id
, id
, sizeof((*obj
)->id
));
167 static const struct got_error
*
168 request_packed_object_raw(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
169 int outfd
, struct got_pack
*pack
, int idx
, struct got_object_id
*id
)
171 const struct got_error
*err
= NULL
;
172 struct imsgbuf
*ibuf
= pack
->privsep_child
->ibuf
;
174 int basefd
, accumfd
; /* temporary files for delta application */
176 basefd
= got_opentempfd();
178 return got_error_from_errno("got_opentempfd");
180 accumfd
= got_opentempfd();
183 return got_error_from_errno("got_opentempfd");
186 outfd_child
= dup(outfd
);
187 if (outfd_child
== -1) {
188 err
= got_error_from_errno("dup");
194 err
= got_privsep_send_packed_raw_obj_req(ibuf
, idx
, id
);
202 err
= got_privsep_send_raw_obj_outfd(ibuf
, outfd_child
);
210 err
= got_privsep_send_tmpfd(pack
->privsep_child
->ibuf
,
217 err
= got_privsep_send_tmpfd(pack
->privsep_child
->ibuf
,
222 err
= got_privsep_recv_raw_obj(outbuf
, size
, hdrlen
, ibuf
);
230 set_max_datasize(void)
234 if (getrlimit(RLIMIT_DATA
, &rl
) != 0)
237 rl
.rlim_cur
= rl
.rlim_max
;
238 setrlimit(RLIMIT_DATA
, &rl
);
241 static const struct got_error
*
242 start_pack_privsep_child(struct got_pack
*pack
, struct got_packidx
*packidx
)
244 const struct got_error
*err
= NULL
;
247 struct imsgbuf
*ibuf
;
249 ibuf
= calloc(1, sizeof(*ibuf
));
251 return got_error_from_errno("calloc");
253 pack
->privsep_child
= calloc(1, sizeof(*pack
->privsep_child
));
254 if (pack
->privsep_child
== NULL
) {
255 err
= got_error_from_errno("calloc");
260 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
261 err
= got_error_from_errno("socketpair");
267 err
= got_error_from_errno("fork");
269 } else if (pid
== 0) {
271 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_PACK
,
272 pack
->path_packfile
);
276 if (close(imsg_fds
[1]) == -1)
277 return got_error_from_errno("close");
278 pack
->privsep_child
->imsg_fd
= imsg_fds
[0];
279 pack
->privsep_child
->pid
= pid
;
280 imsg_init(ibuf
, imsg_fds
[0]);
281 pack
->privsep_child
->ibuf
= ibuf
;
283 err
= got_privsep_init_pack_child(ibuf
, pack
, packidx
);
285 const struct got_error
*child_err
;
286 err
= got_privsep_send_stop(pack
->privsep_child
->imsg_fd
);
287 child_err
= got_privsep_wait_for_child(
288 pack
->privsep_child
->pid
);
289 if (child_err
&& err
== NULL
)
295 free(pack
->privsep_child
);
296 pack
->privsep_child
= NULL
;
301 static const struct got_error
*
302 read_packed_object_privsep(struct got_object
**obj
,
303 struct got_repository
*repo
, struct got_pack
*pack
,
304 struct got_packidx
*packidx
, int idx
, struct got_object_id
*id
)
306 const struct got_error
*err
= NULL
;
308 if (pack
->privsep_child
== NULL
) {
309 err
= start_pack_privsep_child(pack
, packidx
);
314 return request_packed_object(obj
, pack
, idx
, id
);
317 static const struct got_error
*
318 read_packed_object_raw_privsep(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
319 int outfd
, struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
320 struct got_object_id
*id
)
322 const struct got_error
*err
= NULL
;
324 if (pack
->privsep_child
== NULL
) {
325 err
= start_pack_privsep_child(pack
, packidx
);
330 return request_packed_object_raw(outbuf
, size
, hdrlen
, outfd
, pack
,
334 const struct got_error
*
335 got_object_open_packed(struct got_object
**obj
, struct got_object_id
*id
,
336 struct got_repository
*repo
)
338 const struct got_error
*err
= NULL
;
339 struct got_pack
*pack
= NULL
;
340 struct got_packidx
*packidx
= NULL
;
344 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
348 err
= got_packidx_get_packfile_path(&path_packfile
,
349 packidx
->path_packidx
);
353 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
355 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
360 err
= read_packed_object_privsep(obj
, repo
, pack
, packidx
, idx
, id
);
368 static const struct got_error
*
369 request_object(struct got_object
**obj
, struct got_object_id
*id
,
370 struct got_repository
*repo
, int fd
)
372 const struct got_error
*err
= NULL
;
373 struct imsgbuf
*ibuf
;
375 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].ibuf
;
377 err
= got_privsep_send_obj_req(ibuf
, fd
, id
);
381 return got_privsep_recv_obj(obj
, ibuf
);
384 static const struct got_error
*
385 request_raw_object(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
, int outfd
,
386 struct got_object_id
*id
, struct got_repository
*repo
, int infd
)
388 const struct got_error
*err
= NULL
;
389 struct imsgbuf
*ibuf
;
392 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].ibuf
;
394 outfd_child
= dup(outfd
);
395 if (outfd_child
== -1)
396 return got_error_from_errno("dup");
398 err
= got_privsep_send_raw_obj_req(ibuf
, infd
, id
);
402 err
= got_privsep_send_raw_obj_outfd(ibuf
, outfd_child
);
406 return got_privsep_recv_raw_obj(outbuf
, size
, hdrlen
, ibuf
);
409 static const struct got_error
*
410 start_read_object_child(struct got_repository
*repo
)
412 const struct got_error
*err
= NULL
;
415 struct imsgbuf
*ibuf
;
417 ibuf
= calloc(1, sizeof(*ibuf
));
419 return got_error_from_errno("calloc");
421 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
422 err
= got_error_from_errno("socketpair");
429 err
= got_error_from_errno("fork");
434 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_OBJECT
,
439 if (close(imsg_fds
[1]) == -1) {
440 err
= got_error_from_errno("close");
445 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
=
447 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].pid
= pid
;
448 imsg_init(ibuf
, imsg_fds
[0]);
449 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].ibuf
= ibuf
;
454 const struct got_error
*
455 got_object_read_header_privsep(struct got_object
**obj
,
456 struct got_object_id
*id
, struct got_repository
*repo
, int obj_fd
)
458 const struct got_error
*err
;
460 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
!= -1)
461 return request_object(obj
, id
, repo
, obj_fd
);
463 err
= start_read_object_child(repo
);
469 return request_object(obj
, id
, repo
, obj_fd
);
472 static const struct got_error
*
473 read_object_raw_privsep(uint8_t **outbuf
, off_t
*size
, size_t *hdrlen
,
474 int outfd
, struct got_object_id
*id
, struct got_repository
*repo
,
477 const struct got_error
*err
;
479 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_OBJECT
].imsg_fd
!= -1)
480 return request_raw_object(outbuf
, size
, hdrlen
, outfd
, id
,
483 err
= start_read_object_child(repo
);
487 return request_raw_object(outbuf
, size
, hdrlen
, outfd
, id
, repo
,
491 const struct got_error
*
492 got_object_open(struct got_object
**obj
, struct got_repository
*repo
,
493 struct got_object_id
*id
)
495 const struct got_error
*err
= NULL
;
498 *obj
= got_repo_get_cached_object(repo
, id
);
504 err
= got_object_open_packed(obj
, id
, repo
);
505 if (err
&& err
->code
!= GOT_ERR_NO_OBJ
)
509 return got_repo_cache_object(repo
, id
, *obj
);
512 err
= got_object_open_loose_fd(&fd
, id
, repo
);
514 if (err
->code
== GOT_ERR_ERRNO
&& errno
== ENOENT
)
515 err
= got_error_no_obj(id
);
519 err
= got_object_read_header_privsep(obj
, id
, repo
, fd
);
523 memcpy((*obj
)->id
.sha1
, id
->sha1
, SHA1_DIGEST_LENGTH
);
526 return got_repo_cache_object(repo
, id
, *obj
);
529 const struct got_error
*
530 got_object_raw_open(struct got_raw_object
**obj
, struct got_repository
*repo
,
531 struct got_object_id
*id
, size_t blocksize
)
533 const struct got_error
*err
= NULL
;
534 struct got_packidx
*packidx
= NULL
;
536 uint8_t *outbuf
= NULL
;
540 char *path_packfile
= NULL
;
544 outfd
= got_opentempfd();
546 return got_error_from_errno("got_opentempfd");
548 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
550 struct got_pack
*pack
= NULL
;
552 err
= got_packidx_get_packfile_path(&path_packfile
,
553 packidx
->path_packidx
);
557 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
559 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
564 err
= read_packed_object_raw_privsep(&outbuf
, &size
, &hdrlen
,
565 outfd
, pack
, packidx
, idx
, id
);
566 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
569 err
= got_object_open_loose_fd(&fd
, id
, repo
);
572 err
= read_object_raw_privsep(&outbuf
, &size
, &hdrlen
, outfd
,
576 *obj
= calloc(1, sizeof(**obj
));
578 err
= got_error_from_errno("calloc");
582 (*obj
)->read_buf
= malloc(blocksize
);
583 if ((*obj
)->read_buf
== NULL
) {
584 err
= got_error_from_errno("malloc");
589 if (close(outfd
) == -1) {
590 err
= got_error_from_errno("close");
594 (*obj
)->f
= fmemopen(outbuf
, hdrlen
+ size
, "r");
595 if ((*obj
)->f
== NULL
) {
596 err
= got_error_from_errno("fdopen");
599 (*obj
)->data
= outbuf
;
602 if (fstat(outfd
, &sb
) == -1) {
603 err
= got_error_from_errno("fstat");
607 if (sb
.st_size
!= hdrlen
+ size
) {
608 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
612 (*obj
)->f
= fdopen(outfd
, "r");
613 if ((*obj
)->f
== NULL
) {
614 err
= got_error_from_errno("fdopen");
620 (*obj
)->hdrlen
= hdrlen
;
622 (*obj
)->blocksize
= blocksize
;
627 got_object_raw_close(*obj
);
638 got_object_raw_rewind(struct got_raw_object
*obj
)
645 got_object_raw_get_hdrlen(struct got_raw_object
*obj
)
651 got_object_raw_get_read_buf(struct got_raw_object
*obj
)
653 return obj
->read_buf
;
656 const struct got_error
*
657 got_object_raw_read_block(size_t *outlenp
, struct got_raw_object
*obj
)
661 n
= fread(obj
->read_buf
, 1, obj
->blocksize
, obj
->f
);
662 if (n
== 0 && ferror(obj
->f
))
663 return got_ferror(obj
->f
, GOT_ERR_IO
);
668 const struct got_error
*
669 got_object_raw_close(struct got_raw_object
*obj
)
671 const struct got_error
*err
= NULL
;
674 if (obj
->f
!= NULL
&& fclose(obj
->f
) == EOF
&& err
== NULL
)
675 err
= got_error_from_errno("fclose");
681 const struct got_error
*
682 got_object_open_by_id_str(struct got_object
**obj
, struct got_repository
*repo
,
685 struct got_object_id id
;
687 if (!got_parse_sha1_digest(id
.sha1
, id_str
))
688 return got_error_path(id_str
, GOT_ERR_BAD_OBJ_ID_STR
);
690 return got_object_open(obj
, repo
, &id
);
693 const struct got_error
*
694 got_object_resolve_id_str(struct got_object_id
**id
,
695 struct got_repository
*repo
, const char *id_str
)
697 const struct got_error
*err
= NULL
;
698 struct got_object
*obj
;
700 err
= got_object_open_by_id_str(&obj
, repo
, id_str
);
704 *id
= got_object_id_dup(got_object_get_id(obj
));
705 got_object_close(obj
);
707 return got_error_from_errno("got_object_id_dup");
712 static const struct got_error
*
713 request_packed_commit(struct got_commit_object
**commit
, struct got_pack
*pack
,
714 int pack_idx
, struct got_object_id
*id
)
716 const struct got_error
*err
= NULL
;
718 err
= got_privsep_send_commit_req(pack
->privsep_child
->ibuf
, -1, id
,
723 err
= got_privsep_recv_commit(commit
, pack
->privsep_child
->ibuf
);
727 (*commit
)->flags
|= GOT_COMMIT_FLAG_PACKED
;
731 static const struct got_error
*
732 read_packed_commit_privsep(struct got_commit_object
**commit
,
733 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
734 struct got_object_id
*id
)
736 const struct got_error
*err
= NULL
;
738 if (pack
->privsep_child
)
739 return request_packed_commit(commit
, pack
, idx
, id
);
741 err
= start_pack_privsep_child(pack
, packidx
);
745 return request_packed_commit(commit
, pack
, idx
, id
);
748 static const struct got_error
*
749 request_commit(struct got_commit_object
**commit
, struct got_repository
*repo
,
750 int fd
, struct got_object_id
*id
)
752 const struct got_error
*err
= NULL
;
753 struct imsgbuf
*ibuf
;
755 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].ibuf
;
757 err
= got_privsep_send_commit_req(ibuf
, fd
, id
, -1);
761 return got_privsep_recv_commit(commit
, ibuf
);
764 static const struct got_error
*
765 read_commit_privsep(struct got_commit_object
**commit
, int obj_fd
,
766 struct got_object_id
*id
, struct got_repository
*repo
)
768 const struct got_error
*err
;
771 struct imsgbuf
*ibuf
;
773 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].imsg_fd
!= -1)
774 return request_commit(commit
, repo
, obj_fd
, id
);
776 ibuf
= calloc(1, sizeof(*ibuf
));
778 return got_error_from_errno("calloc");
780 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
781 err
= got_error_from_errno("socketpair");
788 err
= got_error_from_errno("fork");
793 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_COMMIT
,
798 if (close(imsg_fds
[1]) == -1) {
799 err
= got_error_from_errno("close");
803 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].imsg_fd
=
805 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].pid
= pid
;
806 imsg_init(ibuf
, imsg_fds
[0]);
807 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_COMMIT
].ibuf
= ibuf
;
809 return request_commit(commit
, repo
, obj_fd
, id
);
813 static const struct got_error
*
814 open_commit(struct got_commit_object
**commit
,
815 struct got_repository
*repo
, struct got_object_id
*id
, int check_cache
)
817 const struct got_error
*err
= NULL
;
818 struct got_packidx
*packidx
= NULL
;
820 char *path_packfile
= NULL
;
823 *commit
= got_repo_get_cached_commit(repo
, id
);
824 if (*commit
!= NULL
) {
831 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
833 struct got_pack
*pack
= NULL
;
835 err
= got_packidx_get_packfile_path(&path_packfile
,
836 packidx
->path_packidx
);
840 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
842 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
847 err
= read_packed_commit_privsep(commit
, pack
,
849 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
852 err
= got_object_open_loose_fd(&fd
, id
, repo
);
855 err
= read_commit_privsep(commit
, fd
, id
, repo
);
860 err
= got_repo_cache_commit(repo
, id
, *commit
);
867 const struct got_error
*
868 got_object_open_as_commit(struct got_commit_object
**commit
,
869 struct got_repository
*repo
, struct got_object_id
*id
)
871 *commit
= got_repo_get_cached_commit(repo
, id
);
872 if (*commit
!= NULL
) {
877 return open_commit(commit
, repo
, id
, 0);
880 const struct got_error
*
881 got_object_commit_open(struct got_commit_object
**commit
,
882 struct got_repository
*repo
, struct got_object
*obj
)
884 return open_commit(commit
, repo
, got_object_get_id(obj
), 1);
887 const struct got_error
*
888 got_object_qid_alloc(struct got_object_qid
**qid
, struct got_object_id
*id
)
890 const struct got_error
*err
= NULL
;
892 *qid
= calloc(1, sizeof(**qid
));
894 return got_error_from_errno("calloc");
896 (*qid
)->id
= got_object_id_dup(id
);
897 if ((*qid
)->id
== NULL
) {
898 err
= got_error_from_errno("got_object_id_dup");
899 got_object_qid_free(*qid
);
907 const struct got_error
*
908 got_object_id_queue_copy(const struct got_object_id_queue
*src
,
909 struct got_object_id_queue
*dest
)
911 const struct got_error
*err
;
912 struct got_object_qid
*qid
;
914 STAILQ_FOREACH(qid
, src
, entry
) {
915 struct got_object_qid
*new;
917 * Deep-copy the object ID only. Let the caller deal
918 * with setting up the new->data pointer if needed.
920 err
= got_object_qid_alloc(&new, qid
->id
);
922 got_object_id_queue_free(dest
);
925 STAILQ_INSERT_TAIL(dest
, new, entry
);
931 static const struct got_error
*
932 request_packed_tree(struct got_tree_object
**tree
, struct got_pack
*pack
,
933 int pack_idx
, struct got_object_id
*id
)
935 const struct got_error
*err
= NULL
;
937 err
= got_privsep_send_tree_req(pack
->privsep_child
->ibuf
, -1, id
,
942 return got_privsep_recv_tree(tree
, pack
->privsep_child
->ibuf
);
945 static const struct got_error
*
946 read_packed_tree_privsep(struct got_tree_object
**tree
,
947 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
948 struct got_object_id
*id
)
950 const struct got_error
*err
= NULL
;
952 if (pack
->privsep_child
)
953 return request_packed_tree(tree
, pack
, idx
, id
);
955 err
= start_pack_privsep_child(pack
, packidx
);
959 return request_packed_tree(tree
, pack
, idx
, id
);
962 static const struct got_error
*
963 request_tree(struct got_tree_object
**tree
, struct got_repository
*repo
,
964 int fd
, struct got_object_id
*id
)
966 const struct got_error
*err
= NULL
;
967 struct imsgbuf
*ibuf
;
969 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].ibuf
;
971 err
= got_privsep_send_tree_req(ibuf
, fd
, id
, -1);
975 return got_privsep_recv_tree(tree
, ibuf
);
978 const struct got_error
*
979 read_tree_privsep(struct got_tree_object
**tree
, int obj_fd
,
980 struct got_object_id
*id
, struct got_repository
*repo
)
982 const struct got_error
*err
;
985 struct imsgbuf
*ibuf
;
987 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].imsg_fd
!= -1)
988 return request_tree(tree
, repo
, obj_fd
, id
);
990 ibuf
= calloc(1, sizeof(*ibuf
));
992 return got_error_from_errno("calloc");
994 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
995 err
= got_error_from_errno("socketpair");
1002 err
= got_error_from_errno("fork");
1006 else if (pid
== 0) {
1007 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_TREE
,
1012 if (close(imsg_fds
[1]) == -1) {
1013 err
= got_error_from_errno("close");
1017 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].imsg_fd
=
1019 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].pid
= pid
;
1020 imsg_init(ibuf
, imsg_fds
[0]);
1021 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TREE
].ibuf
= ibuf
;
1024 return request_tree(tree
, repo
, obj_fd
, id
);
1027 static const struct got_error
*
1028 open_tree(struct got_tree_object
**tree
, struct got_repository
*repo
,
1029 struct got_object_id
*id
, int check_cache
)
1031 const struct got_error
*err
= NULL
;
1032 struct got_packidx
*packidx
= NULL
;
1034 char *path_packfile
= NULL
;
1037 *tree
= got_repo_get_cached_tree(repo
, id
);
1038 if (*tree
!= NULL
) {
1045 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
1047 struct got_pack
*pack
= NULL
;
1049 err
= got_packidx_get_packfile_path(&path_packfile
,
1050 packidx
->path_packidx
);
1054 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1056 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
1061 err
= read_packed_tree_privsep(tree
, pack
,
1063 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
1066 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1069 err
= read_tree_privsep(tree
, fd
, id
, repo
);
1074 err
= got_repo_cache_tree(repo
, id
, *tree
);
1077 free(path_packfile
);
1081 const struct got_error
*
1082 got_object_open_as_tree(struct got_tree_object
**tree
,
1083 struct got_repository
*repo
, struct got_object_id
*id
)
1085 *tree
= got_repo_get_cached_tree(repo
, id
);
1086 if (*tree
!= NULL
) {
1091 return open_tree(tree
, repo
, id
, 0);
1094 const struct got_error
*
1095 got_object_tree_open(struct got_tree_object
**tree
,
1096 struct got_repository
*repo
, struct got_object
*obj
)
1098 return open_tree(tree
, repo
, got_object_get_id(obj
), 1);
1102 got_object_tree_get_nentries(struct got_tree_object
*tree
)
1104 return tree
->nentries
;
1107 struct got_tree_entry
*
1108 got_object_tree_get_first_entry(struct got_tree_object
*tree
)
1110 return got_object_tree_get_entry(tree
, 0);
1113 struct got_tree_entry
*
1114 got_object_tree_get_last_entry(struct got_tree_object
*tree
)
1116 return got_object_tree_get_entry(tree
, tree
->nentries
- 1);
1119 struct got_tree_entry
*
1120 got_object_tree_get_entry(struct got_tree_object
*tree
, int i
)
1122 if (i
< 0 || i
>= tree
->nentries
)
1124 return &tree
->entries
[i
];
1128 got_tree_entry_get_mode(struct got_tree_entry
*te
)
1134 got_tree_entry_get_name(struct got_tree_entry
*te
)
1136 return &te
->name
[0];
1139 struct got_object_id
*
1140 got_tree_entry_get_id(struct got_tree_entry
*te
)
1145 const struct got_error
*
1146 got_object_blob_read_to_str(char **s
, struct got_blob_object
*blob
)
1148 const struct got_error
*err
= NULL
;
1149 size_t len
, totlen
, hdrlen
, offset
;
1153 hdrlen
= got_object_blob_get_hdrlen(blob
);
1159 err
= got_object_blob_read_block(&len
, blob
);
1166 totlen
+= len
- hdrlen
;
1167 p
= realloc(*s
, totlen
+ 1);
1169 err
= got_error_from_errno("realloc");
1175 /* Skip blob object header first time around. */
1177 got_object_blob_get_read_buf(blob
) + hdrlen
, len
- hdrlen
);
1182 (*s
)[totlen
] = '\0';
1186 const struct got_error
*
1187 got_tree_entry_get_symlink_target(char **link_target
, struct got_tree_entry
*te
,
1188 struct got_repository
*repo
)
1190 const struct got_error
*err
= NULL
;
1191 struct got_blob_object
*blob
= NULL
;
1193 *link_target
= NULL
;
1195 if (!got_object_tree_entry_is_symlink(te
))
1196 return got_error(GOT_ERR_TREE_ENTRY_TYPE
);
1198 err
= got_object_open_as_blob(&blob
, repo
,
1199 got_tree_entry_get_id(te
), PATH_MAX
);
1203 err
= got_object_blob_read_to_str(link_target
, blob
);
1204 got_object_blob_close(blob
);
1207 *link_target
= NULL
;
1213 got_tree_entry_get_index(struct got_tree_entry
*te
)
1218 struct got_tree_entry
*
1219 got_tree_entry_get_next(struct got_tree_object
*tree
,
1220 struct got_tree_entry
*te
)
1222 return got_object_tree_get_entry(tree
, te
->idx
+ 1);
1225 struct got_tree_entry
*
1226 got_tree_entry_get_prev(struct got_tree_object
*tree
,
1227 struct got_tree_entry
*te
)
1229 return got_object_tree_get_entry(tree
, te
->idx
- 1);
1232 static const struct got_error
*
1233 request_packed_blob(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
, int outfd
,
1234 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
1235 struct got_object_id
*id
)
1237 const struct got_error
*err
= NULL
;
1239 int basefd
, accumfd
; /* temporary files for delta application */
1241 basefd
= got_opentempfd();
1243 return got_error_from_errno("got_opentempfd");
1244 accumfd
= got_opentempfd();
1246 return got_error_from_errno("got_opentempfd");
1248 outfd_child
= dup(outfd
);
1249 if (outfd_child
== -1)
1250 return got_error_from_errno("dup");
1252 err
= got_privsep_send_blob_req(pack
->privsep_child
->ibuf
, -1, id
, idx
);
1256 err
= got_privsep_send_blob_outfd(pack
->privsep_child
->ibuf
,
1264 err
= got_privsep_send_tmpfd(pack
->privsep_child
->ibuf
,
1271 err
= got_privsep_send_tmpfd(pack
->privsep_child
->ibuf
,
1276 err
= got_privsep_recv_blob(outbuf
, size
, hdrlen
,
1277 pack
->privsep_child
->ibuf
);
1281 if (lseek(outfd
, SEEK_SET
, 0) == -1)
1282 err
= got_error_from_errno("lseek");
1287 static const struct got_error
*
1288 read_packed_blob_privsep(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
,
1289 int outfd
, struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
1290 struct got_object_id
*id
)
1292 const struct got_error
*err
= NULL
;
1294 if (pack
->privsep_child
== NULL
) {
1295 err
= start_pack_privsep_child(pack
, packidx
);
1300 return request_packed_blob(outbuf
, size
, hdrlen
, outfd
, pack
, packidx
,
1304 static const struct got_error
*
1305 request_blob(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
, int outfd
,
1306 int infd
, struct got_object_id
*id
, struct imsgbuf
*ibuf
)
1308 const struct got_error
*err
= NULL
;
1311 outfd_child
= dup(outfd
);
1312 if (outfd_child
== -1)
1313 return got_error_from_errno("dup");
1315 err
= got_privsep_send_blob_req(ibuf
, infd
, id
, -1);
1319 err
= got_privsep_send_blob_outfd(ibuf
, outfd_child
);
1323 err
= got_privsep_recv_blob(outbuf
, size
, hdrlen
, ibuf
);
1327 if (lseek(outfd
, SEEK_SET
, 0) == -1)
1328 return got_error_from_errno("lseek");
1333 static const struct got_error
*
1334 read_blob_privsep(uint8_t **outbuf
, size_t *size
, size_t *hdrlen
,
1335 int outfd
, int infd
, struct got_object_id
*id
, struct got_repository
*repo
)
1337 const struct got_error
*err
;
1340 struct imsgbuf
*ibuf
;
1342 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].imsg_fd
!= -1) {
1343 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].ibuf
;
1344 return request_blob(outbuf
, size
, hdrlen
, outfd
, infd
, id
,
1348 ibuf
= calloc(1, sizeof(*ibuf
));
1350 return got_error_from_errno("calloc");
1352 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
1353 err
= got_error_from_errno("socketpair");
1360 err
= got_error_from_errno("fork");
1364 else if (pid
== 0) {
1365 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_BLOB
,
1370 if (close(imsg_fds
[1]) == -1) {
1371 err
= got_error_from_errno("close");
1375 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].imsg_fd
=
1377 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].pid
= pid
;
1378 imsg_init(ibuf
, imsg_fds
[0]);
1379 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_BLOB
].ibuf
= ibuf
;
1381 return request_blob(outbuf
, size
, hdrlen
, outfd
, infd
, id
, ibuf
);
1384 static const struct got_error
*
1385 open_blob(struct got_blob_object
**blob
, struct got_repository
*repo
,
1386 struct got_object_id
*id
, size_t blocksize
)
1388 const struct got_error
*err
= NULL
;
1389 struct got_packidx
*packidx
= NULL
;
1391 char *path_packfile
= NULL
;
1394 size_t size
, hdrlen
;
1397 *blob
= calloc(1, sizeof(**blob
));
1399 return got_error_from_errno("calloc");
1401 outfd
= got_opentempfd();
1403 return got_error_from_errno("got_opentempfd");
1405 (*blob
)->read_buf
= malloc(blocksize
);
1406 if ((*blob
)->read_buf
== NULL
) {
1407 err
= got_error_from_errno("malloc");
1411 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
1413 struct got_pack
*pack
= NULL
;
1415 err
= got_packidx_get_packfile_path(&path_packfile
,
1416 packidx
->path_packidx
);
1420 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1422 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
1427 err
= read_packed_blob_privsep(&outbuf
, &size
, &hdrlen
, outfd
,
1428 pack
, packidx
, idx
, id
);
1429 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
1432 err
= got_object_open_loose_fd(&infd
, id
, repo
);
1435 err
= read_blob_privsep(&outbuf
, &size
, &hdrlen
, outfd
, infd
,
1441 if (hdrlen
> size
) {
1442 err
= got_error(GOT_ERR_BAD_OBJ_HDR
);
1447 if (close(outfd
) == -1 && err
== NULL
)
1448 err
= got_error_from_errno("close");
1450 (*blob
)->f
= fmemopen(outbuf
, size
, "rb");
1451 if ((*blob
)->f
== NULL
) {
1452 err
= got_error_from_errno("fmemopen");
1456 (*blob
)->data
= outbuf
;
1458 if (fstat(outfd
, &sb
) == -1) {
1459 err
= got_error_from_errno("fstat");
1463 if (sb
.st_size
!= size
) {
1464 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1468 (*blob
)->f
= fdopen(outfd
, "rb");
1469 if ((*blob
)->f
== NULL
) {
1470 err
= got_error_from_errno("fdopen");
1477 (*blob
)->hdrlen
= hdrlen
;
1478 (*blob
)->blocksize
= blocksize
;
1479 memcpy(&(*blob
)->id
.sha1
, id
->sha1
, SHA1_DIGEST_LENGTH
);
1482 free(path_packfile
);
1485 got_object_blob_close(*blob
);
1487 } else if (outfd
!= -1)
1493 const struct got_error
*
1494 got_object_open_as_blob(struct got_blob_object
**blob
,
1495 struct got_repository
*repo
, struct got_object_id
*id
,
1498 return open_blob(blob
, repo
, id
, blocksize
);
1501 const struct got_error
*
1502 got_object_blob_open(struct got_blob_object
**blob
,
1503 struct got_repository
*repo
, struct got_object
*obj
, size_t blocksize
)
1505 return open_blob(blob
, repo
, got_object_get_id(obj
), blocksize
);
1508 const struct got_error
*
1509 got_object_blob_close(struct got_blob_object
*blob
)
1511 const struct got_error
*err
= NULL
;
1512 free(blob
->read_buf
);
1513 if (blob
->f
&& fclose(blob
->f
) == EOF
)
1514 err
= got_error_from_errno("fclose");
1521 got_object_blob_rewind(struct got_blob_object
*blob
)
1528 got_object_blob_id_str(struct got_blob_object
*blob
, char *buf
, size_t size
)
1530 return got_sha1_digest_to_str(blob
->id
.sha1
, buf
, size
);
1534 got_object_blob_get_hdrlen(struct got_blob_object
*blob
)
1536 return blob
->hdrlen
;
1540 got_object_blob_get_read_buf(struct got_blob_object
*blob
)
1542 return blob
->read_buf
;
1545 const struct got_error
*
1546 got_object_blob_read_block(size_t *outlenp
, struct got_blob_object
*blob
)
1550 n
= fread(blob
->read_buf
, 1, blob
->blocksize
, blob
->f
);
1551 if (n
== 0 && ferror(blob
->f
))
1552 return got_ferror(blob
->f
, GOT_ERR_IO
);
1557 const struct got_error
*
1558 got_object_blob_dump_to_file(off_t
*filesize
, int *nlines
,
1559 off_t
**line_offsets
, FILE *outfile
, struct got_blob_object
*blob
)
1561 const struct got_error
*err
= NULL
;
1562 size_t n
, len
, hdrlen
;
1565 const int alloc_chunksz
= 512;
1567 off_t off
= 0, total_len
= 0;
1570 *line_offsets
= NULL
;
1576 hdrlen
= got_object_blob_get_hdrlen(blob
);
1578 err
= got_object_blob_read_block(&len
, blob
);
1583 buf
= got_object_blob_get_read_buf(blob
);
1586 if (line_offsets
&& *line_offsets
== NULL
) {
1587 /* Have some data but perhaps no '\n'. */
1589 nalloc
= alloc_chunksz
;
1590 *line_offsets
= calloc(nalloc
,
1591 sizeof(**line_offsets
));
1592 if (*line_offsets
== NULL
)
1593 return got_error_from_errno("calloc");
1595 /* Skip forward over end of first line. */
1602 /* Scan '\n' offsets in remaining chunk of data. */
1604 if (buf
[i
] != '\n') {
1609 if (line_offsets
&& nalloc
< *nlines
) {
1610 size_t n
= *nlines
+ alloc_chunksz
;
1611 off_t
*o
= recallocarray(*line_offsets
,
1612 nalloc
, n
, sizeof(**line_offsets
));
1614 free(*line_offsets
);
1615 *line_offsets
= NULL
;
1616 return got_error_from_errno(
1623 off
= total_len
+ i
- hdrlen
+ 1;
1624 (*line_offsets
)[*nlines
- 1] = off
;
1629 /* Skip blob object header first time around. */
1630 n
= fwrite(buf
+ hdrlen
, 1, len
- hdrlen
, outfile
);
1631 if (n
!= len
- hdrlen
)
1632 return got_ferror(outfile
, GOT_ERR_IO
);
1633 total_len
+= len
- hdrlen
;
1637 if (fflush(outfile
) != 0)
1638 return got_error_from_errno("fflush");
1642 *filesize
= total_len
;
1647 static const struct got_error
*
1648 request_packed_tag(struct got_tag_object
**tag
, struct got_pack
*pack
,
1649 int pack_idx
, struct got_object_id
*id
)
1651 const struct got_error
*err
= NULL
;
1653 err
= got_privsep_send_tag_req(pack
->privsep_child
->ibuf
, -1, id
,
1658 return got_privsep_recv_tag(tag
, pack
->privsep_child
->ibuf
);
1661 static const struct got_error
*
1662 read_packed_tag_privsep(struct got_tag_object
**tag
,
1663 struct got_pack
*pack
, struct got_packidx
*packidx
, int idx
,
1664 struct got_object_id
*id
)
1666 const struct got_error
*err
= NULL
;
1668 if (pack
->privsep_child
)
1669 return request_packed_tag(tag
, pack
, idx
, id
);
1671 err
= start_pack_privsep_child(pack
, packidx
);
1675 return request_packed_tag(tag
, pack
, idx
, id
);
1678 static const struct got_error
*
1679 request_tag(struct got_tag_object
**tag
, struct got_repository
*repo
,
1680 int fd
, struct got_object_id
*id
)
1682 const struct got_error
*err
= NULL
;
1683 struct imsgbuf
*ibuf
;
1685 ibuf
= repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].ibuf
;
1687 err
= got_privsep_send_tag_req(ibuf
, fd
, id
, -1);
1691 return got_privsep_recv_tag(tag
, ibuf
);
1694 static const struct got_error
*
1695 read_tag_privsep(struct got_tag_object
**tag
, int obj_fd
,
1696 struct got_object_id
*id
, struct got_repository
*repo
)
1698 const struct got_error
*err
;
1701 struct imsgbuf
*ibuf
;
1703 if (repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].imsg_fd
!= -1)
1704 return request_tag(tag
, repo
, obj_fd
, id
);
1706 ibuf
= calloc(1, sizeof(*ibuf
));
1708 return got_error_from_errno("calloc");
1710 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, imsg_fds
) == -1) {
1711 err
= got_error_from_errno("socketpair");
1718 err
= got_error_from_errno("fork");
1722 else if (pid
== 0) {
1723 got_privsep_exec_child(imsg_fds
, GOT_PATH_PROG_READ_TAG
,
1728 if (close(imsg_fds
[1]) == -1) {
1729 err
= got_error_from_errno("close");
1733 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].imsg_fd
=
1735 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].pid
= pid
;
1736 imsg_init(ibuf
, imsg_fds
[0]);
1737 repo
->privsep_children
[GOT_REPO_PRIVSEP_CHILD_TAG
].ibuf
= ibuf
;
1739 return request_tag(tag
, repo
, obj_fd
, id
);
1742 static const struct got_error
*
1743 open_tag(struct got_tag_object
**tag
, struct got_repository
*repo
,
1744 struct got_object_id
*id
, int check_cache
)
1746 const struct got_error
*err
= NULL
;
1747 struct got_packidx
*packidx
= NULL
;
1749 char *path_packfile
= NULL
;
1750 struct got_object
*obj
= NULL
;
1751 int obj_type
= GOT_OBJ_TYPE_ANY
;
1754 *tag
= got_repo_get_cached_tag(repo
, id
);
1762 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, id
);
1764 struct got_pack
*pack
= NULL
;
1766 err
= got_packidx_get_packfile_path(&path_packfile
,
1767 packidx
->path_packidx
);
1771 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
1773 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
,
1779 /* Beware of "lightweight" tags: Check object type first. */
1780 err
= read_packed_object_privsep(&obj
, repo
, pack
, packidx
,
1784 obj_type
= obj
->type
;
1785 got_object_close(obj
);
1786 if (obj_type
!= GOT_OBJ_TYPE_TAG
) {
1787 err
= got_error(GOT_ERR_OBJ_TYPE
);
1790 err
= read_packed_tag_privsep(tag
, pack
, packidx
, idx
, id
);
1791 } else if (err
->code
== GOT_ERR_NO_OBJ
) {
1794 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1797 err
= got_object_read_header_privsep(&obj
, id
, repo
, fd
);
1800 obj_type
= obj
->type
;
1801 got_object_close(obj
);
1802 if (obj_type
!= GOT_OBJ_TYPE_TAG
)
1803 return got_error(GOT_ERR_OBJ_TYPE
);
1805 err
= got_object_open_loose_fd(&fd
, id
, repo
);
1808 err
= read_tag_privsep(tag
, fd
, id
, repo
);
1813 err
= got_repo_cache_tag(repo
, id
, *tag
);
1816 free(path_packfile
);
1820 const struct got_error
*
1821 got_object_open_as_tag(struct got_tag_object
**tag
,
1822 struct got_repository
*repo
, struct got_object_id
*id
)
1824 *tag
= got_repo_get_cached_tag(repo
, id
);
1830 return open_tag(tag
, repo
, id
, 0);
1833 const struct got_error
*
1834 got_object_tag_open(struct got_tag_object
**tag
,
1835 struct got_repository
*repo
, struct got_object
*obj
)
1837 return open_tag(tag
, repo
, got_object_get_id(obj
), 1);
1841 got_object_tag_get_name(struct got_tag_object
*tag
)
1847 got_object_tag_get_object_type(struct got_tag_object
*tag
)
1849 return tag
->obj_type
;
1852 struct got_object_id
*
1853 got_object_tag_get_object_id(struct got_tag_object
*tag
)
1859 got_object_tag_get_tagger_time(struct got_tag_object
*tag
)
1861 return tag
->tagger_time
;
1865 got_object_tag_get_tagger_gmtoff(struct got_tag_object
*tag
)
1867 return tag
->tagger_gmtoff
;
1871 got_object_tag_get_tagger(struct got_tag_object
*tag
)
1877 got_object_tag_get_message(struct got_tag_object
*tag
)
1882 static struct got_tree_entry
*
1883 find_entry_by_name(struct got_tree_object
*tree
, const char *name
, size_t len
)
1887 /* Note that tree entries are sorted in strncmp() order. */
1888 for (i
= 0; i
< tree
->nentries
; i
++) {
1889 struct got_tree_entry
*te
= &tree
->entries
[i
];
1890 int cmp
= strncmp(te
->name
, name
, len
);
1895 if (te
->name
[len
] == '\0')
1901 struct got_tree_entry
*
1902 got_object_tree_find_entry(struct got_tree_object
*tree
, const char *name
)
1904 return find_entry_by_name(tree
, name
, strlen(name
));
1907 const struct got_error
*
1908 got_object_id_by_path(struct got_object_id
**id
, struct got_repository
*repo
,
1909 struct got_object_id
*commit_id
, const char *path
)
1911 const struct got_error
*err
= NULL
;
1912 struct got_commit_object
*commit
= NULL
;
1913 struct got_tree_object
*tree
= NULL
;
1914 struct got_tree_entry
*te
= NULL
;
1915 const char *seg
, *s
;
1920 err
= got_object_open_as_commit(&commit
, repo
, commit_id
);
1924 /* Handle opening of root of commit's tree. */
1925 if (got_path_is_root_dir(path
)) {
1926 *id
= got_object_id_dup(commit
->tree_id
);
1928 err
= got_error_from_errno("got_object_id_dup");
1932 err
= got_object_open_as_tree(&tree
, repo
, commit
->tree_id
);
1942 struct got_tree_object
*next_tree
;
1951 te
= find_entry_by_name(tree
, seg
, seglen
);
1953 err
= got_error_path(path
, GOT_ERR_NO_TREE_ENTRY
);
1964 err
= got_object_open_as_tree(&next_tree
, repo
,
1969 got_object_tree_close(tree
);
1975 *id
= got_object_id_dup(&te
->id
);
1977 return got_error_from_errno("got_object_id_dup");
1979 err
= got_error_path(path
, GOT_ERR_NO_TREE_ENTRY
);
1982 got_object_commit_close(commit
);
1984 got_object_tree_close(tree
);
1989 * Normalize file mode bits to avoid false positive tree entry differences
1990 * in case tree entries have unexpected mode bits set.
1993 normalize_mode_for_comparison(mode_t mode
)
1996 * For directories, the only relevant bit is the IFDIR bit.
1997 * This allows us to detect paths changing from a directory
1998 * to a file and vice versa.
2001 return mode
& S_IFDIR
;
2004 * For symlinks, the only relevant bit is the IFLNK bit.
2005 * This allows us to detect paths changing from a symlinks
2006 * to a file or directory and vice versa.
2009 return mode
& S_IFLNK
;
2011 /* For files, the only change we care about is the executable bit. */
2012 return mode
& S_IXUSR
;
2015 const struct got_error
*
2016 got_object_tree_path_changed(int *changed
,
2017 struct got_tree_object
*tree01
, struct got_tree_object
*tree02
,
2018 const char *path
, struct got_repository
*repo
)
2020 const struct got_error
*err
= NULL
;
2021 struct got_tree_object
*tree1
= NULL
, *tree2
= NULL
;
2022 struct got_tree_entry
*te1
= NULL
, *te2
= NULL
;
2023 const char *seg
, *s
;
2028 /* We not do support comparing the root path. */
2029 if (got_path_is_root_dir(path
))
2030 return got_error_path(path
, GOT_ERR_BAD_PATH
);
2040 struct got_tree_object
*next_tree1
, *next_tree2
;
2041 mode_t mode1
, mode2
;
2050 te1
= find_entry_by_name(tree1
, seg
, seglen
);
2052 err
= got_error(GOT_ERR_NO_OBJ
);
2057 te2
= find_entry_by_name(tree2
, seg
, seglen
);
2060 mode1
= normalize_mode_for_comparison(te1
->mode
);
2061 mode2
= normalize_mode_for_comparison(te2
->mode
);
2062 if (mode1
!= mode2
) {
2067 if (got_object_id_cmp(&te1
->id
, &te2
->id
) == 0) {
2073 if (*s
== '\0') { /* final path element */
2082 err
= got_object_open_as_tree(&next_tree1
, repo
,
2087 if (tree1
!= tree01
)
2088 got_object_tree_close(tree1
);
2092 err
= got_object_open_as_tree(&next_tree2
, repo
,
2097 if (tree2
!= tree02
)
2098 got_object_tree_close(tree2
);
2101 if (tree2
!= tree02
)
2102 got_object_tree_close(tree2
);
2108 if (tree1
&& tree1
!= tree01
)
2109 got_object_tree_close(tree1
);
2110 if (tree2
&& tree2
!= tree02
)
2111 got_object_tree_close(tree2
);
2115 const struct got_error
*
2116 got_object_tree_entry_dup(struct got_tree_entry
**new_te
,
2117 struct got_tree_entry
*te
)
2119 const struct got_error
*err
= NULL
;
2121 *new_te
= calloc(1, sizeof(**new_te
));
2122 if (*new_te
== NULL
)
2123 return got_error_from_errno("calloc");
2125 (*new_te
)->mode
= te
->mode
;
2126 memcpy((*new_te
)->name
, te
->name
, sizeof((*new_te
)->name
));
2127 memcpy(&(*new_te
)->id
, &te
->id
, sizeof((*new_te
)->id
));
2132 got_object_tree_entry_is_submodule(struct got_tree_entry
*te
)
2134 return (te
->mode
& S_IFMT
) == (S_IFDIR
| S_IFLNK
);
2138 got_object_tree_entry_is_symlink(struct got_tree_entry
*te
)
2140 /* S_IFDIR check avoids confusing symlinks with submodules. */
2141 return ((te
->mode
& (S_IFDIR
| S_IFLNK
)) == S_IFLNK
);
2144 static const struct got_error
*
2145 resolve_symlink(char **link_target
, const char *path
,
2146 struct got_object_id
*commit_id
, struct got_repository
*repo
)
2148 const struct got_error
*err
= NULL
;
2150 char *name
, *parent_path
= NULL
;
2151 struct got_object_id
*tree_obj_id
= NULL
;
2152 struct got_tree_object
*tree
= NULL
;
2153 struct got_tree_entry
*te
= NULL
;
2155 *link_target
= NULL
;
2157 if (strlcpy(buf
, path
, sizeof(buf
)) >= sizeof(buf
))
2158 return got_error(GOT_ERR_NO_SPACE
);
2160 name
= basename(buf
);
2162 return got_error_from_errno2("basename", path
);
2164 err
= got_path_dirname(&parent_path
, path
);
2168 err
= got_object_id_by_path(&tree_obj_id
, repo
, commit_id
,
2171 if (err
->code
== GOT_ERR_NO_TREE_ENTRY
) {
2172 /* Display the complete path in error message. */
2173 err
= got_error_path(path
, err
->code
);
2178 err
= got_object_open_as_tree(&tree
, repo
, tree_obj_id
);
2182 te
= got_object_tree_find_entry(tree
, name
);
2184 err
= got_error_path(path
, GOT_ERR_NO_TREE_ENTRY
);
2188 if (got_object_tree_entry_is_symlink(te
)) {
2189 err
= got_tree_entry_get_symlink_target(link_target
, te
, repo
);
2192 if (!got_path_is_absolute(*link_target
)) {
2194 if (asprintf(&abspath
, "%s/%s", parent_path
,
2195 *link_target
) == -1) {
2196 err
= got_error_from_errno("asprintf");
2200 *link_target
= malloc(PATH_MAX
);
2201 if (*link_target
== NULL
) {
2202 err
= got_error_from_errno("malloc");
2205 err
= got_canonpath(abspath
, *link_target
, PATH_MAX
);
2214 got_object_tree_close(tree
);
2217 *link_target
= NULL
;
2222 const struct got_error
*
2223 got_object_resolve_symlinks(char **link_target
, const char *path
,
2224 struct got_object_id
*commit_id
, struct got_repository
*repo
)
2226 const struct got_error
*err
= NULL
;
2227 char *next_target
= NULL
;
2228 int max_recursion
= 40; /* matches Git */
2230 *link_target
= NULL
;
2233 err
= resolve_symlink(&next_target
,
2234 *link_target
? *link_target
: path
, commit_id
, repo
);
2239 if (--max_recursion
== 0) {
2240 err
= got_error_path(path
, GOT_ERR_RECURSION
);
2241 *link_target
= NULL
;
2244 *link_target
= next_target
;
2246 } while (next_target
);
2251 const struct got_error
*
2252 got_traverse_packed_commits(struct got_object_id_queue
*traversed_commits
,
2253 struct got_object_id
*commit_id
, const char *path
,
2254 struct got_repository
*repo
)
2256 const struct got_error
*err
= NULL
;
2257 struct got_pack
*pack
= NULL
;
2258 struct got_packidx
*packidx
= NULL
;
2259 char *path_packfile
= NULL
;
2260 struct got_commit_object
*changed_commit
= NULL
;
2261 struct got_object_id
*changed_commit_id
= NULL
;
2264 err
= got_repo_search_packidx(&packidx
, &idx
, repo
, commit_id
);
2266 if (err
->code
!= GOT_ERR_NO_OBJ
)
2271 err
= got_packidx_get_packfile_path(&path_packfile
,
2272 packidx
->path_packidx
);
2276 pack
= got_repo_get_cached_pack(repo
, path_packfile
);
2278 err
= got_repo_cache_pack(&pack
, repo
, path_packfile
, packidx
);
2283 if (pack
->privsep_child
== NULL
) {
2284 err
= start_pack_privsep_child(pack
, packidx
);
2289 err
= got_privsep_send_commit_traversal_request(
2290 pack
->privsep_child
->ibuf
, commit_id
, idx
, path
);
2294 err
= got_privsep_recv_traversed_commits(&changed_commit
,
2295 &changed_commit_id
, traversed_commits
, pack
->privsep_child
->ibuf
);
2299 if (changed_commit
) {
2301 * Cache the commit in which the path was changed.
2302 * This commit might be opened again soon.
2304 changed_commit
->refcnt
++;
2305 err
= got_repo_cache_commit(repo
, changed_commit_id
,
2307 got_object_commit_close(changed_commit
);
2310 free(path_packfile
);
2311 free(changed_commit_id
);