2 * Copyright (c) 2019 Ori Bernstein <ori@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>
35 #include "got_compat.h"
37 #include "got_error.h"
38 #include "got_object.h"
40 #include "got_version.h"
41 #include "got_fetch.h"
42 #include "got_reference.h"
44 #include "got_lib_sha1.h"
45 #include "got_lib_delta.h"
46 #include "got_lib_object.h"
47 #include "got_lib_object_parse.h"
48 #include "got_lib_privsep.h"
49 #include "got_lib_pack.h"
50 #include "got_lib_pkt.h"
51 #include "got_lib_gitproto.h"
54 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
57 struct got_object
*indexed
;
60 static const struct got_capability got_capabilities
[] = {
61 { GOT_CAPA_AGENT
, "got/" GOT_VERSION_STR
},
62 { GOT_CAPA_OFS_DELTA
, NULL
},
63 { GOT_CAPA_SIDE_BAND_64K
, NULL
},
67 match_remote_ref(struct got_pathlist_head
*have_refs
,
68 struct got_object_id
*my_id
, char *refname
)
70 struct got_pathlist_entry
*pe
;
72 /* XXX zero-hash signifies we don't have this ref;
73 * we should use a flag instead */
74 memset(my_id
, 0, sizeof(*my_id
));
76 TAILQ_FOREACH(pe
, have_refs
, entry
) {
77 struct got_object_id
*id
= pe
->data
;
78 if (strcmp(pe
->path
, refname
) == 0) {
79 memcpy(my_id
, id
, sizeof(*my_id
));
86 match_branch(const char *branch
, const char *wanted_branch
)
88 if (strncmp(branch
, "refs/heads/", 11) != 0)
91 if (strncmp(wanted_branch
, "refs/heads/", 11) == 0)
94 return (strcmp(branch
+ 11, wanted_branch
) == 0);
98 match_wanted_ref(const char *refname
, const char *wanted_ref
)
100 if (strncmp(refname
, "refs/", 5) != 0)
105 * Prevent fetching of references that won't make any
106 * sense outside of the remote repository's context.
108 if (strncmp(refname
, "got/", 4) == 0)
110 if (strncmp(refname
, "remotes/", 8) == 0)
113 if (strncmp(wanted_ref
, "refs/", 5) == 0)
116 /* Allow prefix match. */
117 if (got_path_is_child(refname
, wanted_ref
, strlen(wanted_ref
)))
120 /* Allow exact match. */
121 return (strcmp(refname
, wanted_ref
) == 0);
124 static const struct got_error
*
125 send_fetch_server_progress(struct imsgbuf
*ibuf
, const char *msg
, size_t msglen
)
127 if (msglen
> MAX_IMSGSIZE
- IMSG_HEADER_SIZE
)
128 return got_error(GOT_ERR_NO_SPACE
);
133 if (imsg_compose(ibuf
, GOT_IMSG_FETCH_SERVER_PROGRESS
, 0, 0, -1,
135 return got_error_from_errno(
136 "imsg_compose FETCH_SERVER_PROGRESS");
138 return got_privsep_flush_imsg(ibuf
);
141 static const struct got_error
*
142 send_fetch_download_progress(struct imsgbuf
*ibuf
, off_t bytes
)
144 if (imsg_compose(ibuf
, GOT_IMSG_FETCH_DOWNLOAD_PROGRESS
, 0, 0, -1,
145 &bytes
, sizeof(bytes
)) == -1)
146 return got_error_from_errno(
147 "imsg_compose FETCH_DOWNLOAD_PROGRESS");
149 return got_privsep_flush_imsg(ibuf
);
152 static const struct got_error
*
153 send_fetch_done(struct imsgbuf
*ibuf
, uint8_t *pack_sha1
)
155 if (imsg_compose(ibuf
, GOT_IMSG_FETCH_DONE
, 0, 0, -1,
156 pack_sha1
, SHA1_DIGEST_LENGTH
) == -1)
157 return got_error_from_errno("imsg_compose FETCH");
158 return got_privsep_flush_imsg(ibuf
);
161 static const struct got_error
*
162 fetch_progress(struct imsgbuf
*ibuf
, const char *buf
, size_t len
)
170 * Truncate messages which exceed the maximum imsg payload size.
171 * Server may send up to 64k.
173 if (len
> MAX_IMSGSIZE
- IMSG_HEADER_SIZE
)
174 len
= MAX_IMSGSIZE
- IMSG_HEADER_SIZE
;
176 /* Only allow printable ASCII. */
177 for (i
= 0; i
< len
; i
++) {
178 if (isprint((unsigned char)buf
[i
]) ||
179 isspace((unsigned char)buf
[i
]))
181 return got_error_msg(GOT_ERR_BAD_PACKET
,
182 "non-printable progress message received from server");
185 return send_fetch_server_progress(ibuf
, buf
, len
);
188 static const struct got_error
*
189 fetch_error(const char *buf
, size_t len
)
191 static char msg
[1024];
194 for (i
= 0; i
< len
&& i
< sizeof(msg
) - 1; i
++) {
195 if (!isprint(buf
[i
]))
196 return got_error_msg(GOT_ERR_BAD_PACKET
,
197 "non-printable error message received from server");
201 return got_error_msg(GOT_ERR_FETCH_FAILED
, msg
);
204 static const struct got_error
*
205 send_fetch_symrefs(struct imsgbuf
*ibuf
, struct got_pathlist_head
*symrefs
)
207 const struct got_error
*err
= NULL
;
209 size_t len
, nsymrefs
= 0;
210 struct got_pathlist_entry
*pe
;
212 len
= sizeof(struct got_imsg_fetch_symrefs
);
213 TAILQ_FOREACH(pe
, symrefs
, entry
) {
214 const char *target
= pe
->data
;
215 len
+= sizeof(struct got_imsg_fetch_symref
) +
216 pe
->path_len
+ strlen(target
);
220 if (len
>= MAX_IMSGSIZE
- IMSG_HEADER_SIZE
)
221 return got_error(GOT_ERR_NO_SPACE
);
223 wbuf
= imsg_create(ibuf
, GOT_IMSG_FETCH_SYMREFS
, 0, 0, len
);
225 return got_error_from_errno("imsg_create FETCH_SYMREFS");
227 /* Keep in sync with struct got_imsg_fetch_symrefs definition! */
228 if (imsg_add(wbuf
, &nsymrefs
, sizeof(nsymrefs
)) == -1) {
229 err
= got_error_from_errno("imsg_add FETCH_SYMREFS");
234 TAILQ_FOREACH(pe
, symrefs
, entry
) {
235 const char *name
= pe
->path
;
236 size_t name_len
= pe
->path_len
;
237 const char *target
= pe
->data
;
238 size_t target_len
= strlen(target
);
240 /* Keep in sync with struct got_imsg_fetch_symref definition! */
241 if (imsg_add(wbuf
, &name_len
, sizeof(name_len
)) == -1) {
242 err
= got_error_from_errno("imsg_add FETCH_SYMREFS");
246 if (imsg_add(wbuf
, &target_len
, sizeof(target_len
)) == -1) {
247 err
= got_error_from_errno("imsg_add FETCH_SYMREFS");
251 if (imsg_add(wbuf
, name
, name_len
) == -1) {
252 err
= got_error_from_errno("imsg_add FETCH_SYMREFS");
256 if (imsg_add(wbuf
, target
, target_len
) == -1) {
257 err
= got_error_from_errno("imsg_add FETCH_SYMREFS");
264 imsg_close(ibuf
, wbuf
);
265 return got_privsep_flush_imsg(ibuf
);
268 static const struct got_error
*
269 send_fetch_ref(struct imsgbuf
*ibuf
, struct got_object_id
*refid
,
272 const struct got_error
*err
= NULL
;
274 size_t len
, reflen
= strlen(refname
);
276 len
= sizeof(struct got_imsg_fetch_ref
) + reflen
;
277 if (len
>= MAX_IMSGSIZE
- IMSG_HEADER_SIZE
)
278 return got_error(GOT_ERR_NO_SPACE
);
280 wbuf
= imsg_create(ibuf
, GOT_IMSG_FETCH_REF
, 0, 0, len
);
282 return got_error_from_errno("imsg_create FETCH_REF");
284 /* Keep in sync with struct got_imsg_fetch_ref definition! */
285 if (imsg_add(wbuf
, refid
->sha1
, SHA1_DIGEST_LENGTH
) == -1) {
286 err
= got_error_from_errno("imsg_add FETCH_REF");
290 if (imsg_add(wbuf
, refname
, reflen
) == -1) {
291 err
= got_error_from_errno("imsg_add FETCH_REF");
297 imsg_close(ibuf
, wbuf
);
298 return got_privsep_flush_imsg(ibuf
);
301 static const struct got_error
*
302 fetch_pack(int fd
, int packfd
, uint8_t *pack_sha1
,
303 struct got_pathlist_head
*have_refs
, int fetch_all_branches
,
304 struct got_pathlist_head
*wanted_branches
,
305 struct got_pathlist_head
*wanted_refs
, int list_refs_only
,
306 struct imsgbuf
*ibuf
)
308 const struct got_error
*err
= NULL
;
309 char buf
[GOT_PKT_MAX
];
310 char hashstr
[SHA1_DIGEST_STRING_LENGTH
];
311 struct got_object_id
*have
, *want
;
312 int is_firstpkt
= 1, nref
= 0, refsz
= 16;
313 int i
, n
, nwant
= 0, nhave
= 0, acked
= 0;
314 off_t packsz
= 0, last_reported_packsz
= 0;
315 char *id_str
= NULL
, *refname
= NULL
;
316 char *server_capabilities
= NULL
, *my_capabilities
= NULL
;
317 const char *default_branch
= NULL
;
318 struct got_pathlist_head symrefs
;
319 struct got_pathlist_entry
*pe
;
320 int sent_my_capabilites
= 0, have_sidebands
= 0;
321 int found_branch
= 0;
323 uint8_t sha1_buf
[SHA1_DIGEST_LENGTH
];
324 size_t sha1_buf_len
= 0;
327 TAILQ_INIT(&symrefs
);
330 have
= malloc(refsz
* sizeof(have
[0]));
332 return got_error_from_errno("malloc");
333 want
= malloc(refsz
* sizeof(want
[0]));
335 err
= got_error_from_errno("malloc");
339 err
= got_pkt_readpkt(&n
, fd
, buf
, sizeof(buf
), chattygot
);
344 if (n
>= 4 && strncmp(buf
, "ERR ", 4) == 0) {
345 err
= fetch_error(&buf
[4], n
- 4);
348 err
= got_gitproto_parse_refline(&id_str
, &refname
,
349 &server_capabilities
, buf
, n
);
353 if (chattygot
&& server_capabilities
[0] != '\0')
354 fprintf(stderr
, "%s: server capabilities: %s\n",
355 getprogname(), server_capabilities
);
356 err
= got_gitproto_match_capabilities(&my_capabilities
,
357 &symrefs
, server_capabilities
,
358 got_capabilities
, nitems(got_capabilities
));
362 fprintf(stderr
, "%s: my capabilities:%s\n",
363 getprogname(), my_capabilities
!= NULL
?
364 my_capabilities
: "");
365 err
= send_fetch_symrefs(ibuf
, &symrefs
);
369 if (!fetch_all_branches
) {
370 TAILQ_FOREACH(pe
, &symrefs
, entry
) {
371 const char *name
= pe
->path
;
372 const char *symref_target
= pe
->data
;
373 if (strcmp(name
, GOT_REF_HEAD
) != 0)
375 default_branch
= symref_target
;
381 if (strstr(refname
, "^{}")) {
383 fprintf(stderr
, "%s: ignoring %s\n",
384 getprogname(), refname
);
389 if (strncmp(refname
, "refs/heads/", 11) == 0) {
390 if (fetch_all_branches
|| list_refs_only
) {
392 } else if (!TAILQ_EMPTY(wanted_branches
)) {
393 TAILQ_FOREACH(pe
, wanted_branches
, entry
) {
394 if (match_branch(refname
, pe
->path
))
401 getprogname(), refname
);
406 } else if (default_branch
!= NULL
) {
407 if (!match_branch(refname
, default_branch
)) {
411 getprogname(), refname
);
417 } else if (strncmp(refname
, "refs/tags/", 10) != 0) {
418 if (!TAILQ_EMPTY(wanted_refs
)) {
419 TAILQ_FOREACH(pe
, wanted_refs
, entry
) {
420 if (match_wanted_ref(refname
, pe
->path
))
427 getprogname(), refname
);
432 } else if (!list_refs_only
) {
434 fprintf(stderr
, "%s: ignoring %s\n",
435 getprogname(), refname
);
441 if (refsz
== nref
+ 1) {
443 have
= reallocarray(have
, refsz
, sizeof(have
[0]));
445 err
= got_error_from_errno("reallocarray");
448 want
= reallocarray(want
, refsz
, sizeof(want
[0]));
450 err
= got_error_from_errno("reallocarray");
454 if (!got_parse_sha1_digest(want
[nref
].sha1
, id_str
)) {
455 err
= got_error(GOT_ERR_BAD_OBJ_ID_STR
);
458 match_remote_ref(have_refs
, &have
[nref
], refname
);
459 err
= send_fetch_ref(ibuf
, &want
[nref
], refname
);
464 fprintf(stderr
, "%s: %s will be fetched\n",
465 getprogname(), refname
);
468 err
= got_object_id_str(&theirs
, &want
[nref
]);
471 err
= got_object_id_str(&mine
, &have
[nref
]);
476 fprintf(stderr
, "%s: remote: %s\n%s: local: %s\n",
477 getprogname(), theirs
, getprogname(), mine
);
487 /* Abort if we haven't found any branch to fetch. */
489 err
= got_error(GOT_ERR_FETCH_NO_BRANCH
);
493 for (i
= 0; i
< nref
; i
++) {
494 if (got_object_id_cmp(&have
[i
], &want
[i
]) == 0)
496 got_sha1_digest_to_str(want
[i
].sha1
, hashstr
, sizeof(hashstr
));
497 n
= snprintf(buf
, sizeof(buf
), "want %s%s\n", hashstr
,
498 sent_my_capabilites
|| my_capabilities
== NULL
?
499 "" : my_capabilities
);
500 if (n
>= sizeof(buf
)) {
501 err
= got_error(GOT_ERR_NO_SPACE
);
504 err
= got_pkt_writepkt(fd
, buf
, n
, chattygot
);
507 sent_my_capabilites
= 1;
510 err
= got_pkt_flushpkt(fd
, chattygot
);
517 TAILQ_FOREACH(pe
, have_refs
, entry
) {
518 struct got_object_id
*id
= pe
->data
;
519 got_sha1_digest_to_str(id
->sha1
, hashstr
, sizeof(hashstr
));
520 n
= snprintf(buf
, sizeof(buf
), "have %s\n", hashstr
);
521 if (n
>= sizeof(buf
)) {
522 err
= got_error(GOT_ERR_NO_SPACE
);
525 err
= got_pkt_writepkt(fd
, buf
, n
, chattygot
);
531 while (nhave
> 0 && !acked
) {
532 struct got_object_id common_id
;
534 /* The server should ACK the object IDs we need. */
535 err
= got_pkt_readpkt(&n
, fd
, buf
, sizeof(buf
), chattygot
);
538 if (n
>= 4 && strncmp(buf
, "ERR ", 4) == 0) {
539 err
= fetch_error(&buf
[4], n
- 4);
542 if (n
>= 4 && strncmp(buf
, "NAK\n", 4) == 0) {
543 /* Server has not located our objects yet. */
546 if (n
< 4 + SHA1_DIGEST_STRING_LENGTH
||
547 strncmp(buf
, "ACK ", 4) != 0) {
548 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
549 "unexpected message from server");
552 if (!got_parse_sha1_digest(common_id
.sha1
, buf
+ 4)) {
553 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
554 "bad object ID in ACK packet from server");
560 n
= snprintf(buf
, sizeof(buf
), "done\n");
561 err
= got_pkt_writepkt(fd
, buf
, n
, chattygot
);
566 err
= got_pkt_readpkt(&n
, fd
, buf
, sizeof(buf
), chattygot
);
569 if (n
!= 4 || strncmp(buf
, "NAK\n", n
) != 0) {
570 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
571 "unexpected message from server");
577 fprintf(stderr
, "%s: fetching...\n", getprogname());
579 if (my_capabilities
!= NULL
&&
580 strstr(my_capabilities
, GOT_CAPA_SIDE_BAND_64K
) != NULL
)
587 if (have_sidebands
) {
588 err
= got_pkt_readhdr(&datalen
, fd
, chattygot
);
594 /* Read sideband channel ID (one byte). */
595 r
= read(fd
, buf
, 1);
597 err
= got_error_from_errno("read");
601 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
605 if (datalen
> sizeof(buf
) - 5) {
606 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
607 "bad packet length");
610 datalen
--; /* sideband ID has been read */
611 if (buf
[0] == GOT_SIDEBAND_PACKFILE_DATA
) {
612 /* Read packfile data. */
613 err
= got_pkt_readn(&r
, fd
, buf
, datalen
);
617 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
621 } else if (buf
[0] == GOT_SIDEBAND_PROGRESS_INFO
) {
622 err
= got_pkt_readn(&r
, fd
, buf
, datalen
);
626 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
630 err
= fetch_progress(ibuf
, buf
, r
);
634 } else if (buf
[0] == GOT_SIDEBAND_ERROR_INFO
) {
635 err
= got_pkt_readn(&r
, fd
, buf
, datalen
);
639 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
643 err
= fetch_error(buf
, r
);
645 } else if (buf
[0] == 'A') {
646 err
= got_pkt_readn(&r
, fd
, buf
, datalen
);
650 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
655 * Git server responds with ACK after 'done'
656 * even though multi_ack is disabled?!?
659 if (strncmp(buf
, "CK ", 3) == 0)
660 continue; /* ignore */
661 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
662 "unexpected message from server");
665 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
666 "unknown side-band received from server");
670 /* No sideband channel. Every byte is packfile data. */
671 err
= got_pkt_readn(&r
, fd
, buf
, sizeof buf
);
679 * An expected SHA1 checksum sits at the end of the pack file.
680 * Since we don't know the file size ahead of time we have to
681 * keep SHA1_DIGEST_LENGTH bytes buffered and avoid mixing
682 * those bytes into our SHA1 checksum computation until we
683 * know for sure that additional pack file data bytes follow.
685 * We can assume r > 0 since otherwise the loop would exit.
687 if (r
< SHA1_DIGEST_LENGTH
) {
688 if (sha1_buf_len
< SHA1_DIGEST_LENGTH
) {
690 * If there's enough buffered + read data to
691 * fill up the buffer then shift a sufficient
692 * amount of bytes out at the front to make
693 * room, mixing those bytes into the checksum.
695 while (sha1_buf_len
> 0 &&
696 sha1_buf_len
+ r
> SHA1_DIGEST_LENGTH
) {
697 SHA1Update(&sha1_ctx
, sha1_buf
, 1);
698 memmove(sha1_buf
, sha1_buf
+ 1, 1);
702 /* Buffer potential checksum bytes. */
703 memcpy(sha1_buf
+ sha1_buf_len
, buf
, r
);
707 * Mix in previously buffered bytes which
708 * are not part of the checksum after all.
710 SHA1Update(&sha1_ctx
, sha1_buf
, r
);
712 /* Update potential checksum buffer. */
713 memmove(sha1_buf
, sha1_buf
+ r
,
715 memcpy(sha1_buf
+ sha1_buf_len
- r
, buf
, r
);
718 /* Mix in any previously buffered bytes. */
719 SHA1Update(&sha1_ctx
, sha1_buf
, sha1_buf_len
);
721 /* Mix in bytes read minus potential checksum bytes. */
722 SHA1Update(&sha1_ctx
, buf
, r
- SHA1_DIGEST_LENGTH
);
724 /* Buffer potential checksum bytes. */
725 memcpy(sha1_buf
, buf
+ r
- SHA1_DIGEST_LENGTH
,
727 sha1_buf_len
= SHA1_DIGEST_LENGTH
;
730 /* Write packfile data to temporary pack file. */
731 w
= write(packfd
, buf
, r
);
733 err
= got_error_from_errno("write");
737 err
= got_error(GOT_ERR_IO
);
742 /* Don't send too many progress privsep messages. */
743 if (packsz
> last_reported_packsz
+ 1024) {
744 err
= send_fetch_download_progress(ibuf
, packsz
);
747 last_reported_packsz
= packsz
;
750 err
= send_fetch_download_progress(ibuf
, packsz
);
754 SHA1Final(pack_sha1
, &sha1_ctx
);
755 if (sha1_buf_len
!= SHA1_DIGEST_LENGTH
||
756 memcmp(pack_sha1
, sha1_buf
, sha1_buf_len
) != 0) {
757 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
,
758 "pack file checksum mismatch");
761 TAILQ_FOREACH(pe
, &symrefs
, entry
) {
762 free((void *)pe
->path
);
765 got_pathlist_free(&symrefs
);
770 free(server_capabilities
);
776 main(int argc
, char **argv
)
778 const struct got_error
*err
= NULL
;
779 int fetchfd
, packfd
= -1;
780 uint8_t pack_sha1
[SHA1_DIGEST_LENGTH
];
783 struct got_pathlist_head have_refs
;
784 struct got_pathlist_head wanted_branches
;
785 struct got_pathlist_head wanted_refs
;
786 struct got_pathlist_entry
*pe
;
787 struct got_imsg_fetch_request fetch_req
;
788 struct got_imsg_fetch_have_ref href
;
789 struct got_imsg_fetch_wanted_branch wbranch
;
790 struct got_imsg_fetch_wanted_ref wref
;
798 TAILQ_INIT(&have_refs
);
799 TAILQ_INIT(&wanted_branches
);
800 TAILQ_INIT(&wanted_refs
);
802 imsg_init(&ibuf
, GOT_IMSG_FD_CHILD
);
804 /* revoke access to most system calls */
805 if (pledge("stdio recvfd", NULL
) == -1) {
806 err
= got_error_from_errno("pledge");
807 got_privsep_send_error(&ibuf
, err
);
811 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
813 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
817 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
819 if (imsg
.hdr
.type
!= GOT_IMSG_FETCH_REQUEST
) {
820 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
823 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
824 if (datalen
< sizeof(fetch_req
)) {
825 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
828 memcpy(&fetch_req
, imsg
.data
, sizeof(fetch_req
));
832 if (fetch_req
.verbosity
> 0)
833 chattygot
+= fetch_req
.verbosity
;
835 for (i
= 0; i
< fetch_req
.n_have_refs
; i
++) {
836 struct got_object_id
*id
;
839 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
841 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
845 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
847 if (imsg
.hdr
.type
!= GOT_IMSG_FETCH_HAVE_REF
) {
848 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
851 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
852 if (datalen
< sizeof(href
)) {
853 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
856 memcpy(&href
, imsg
.data
, sizeof(href
));
857 if (datalen
- sizeof(href
) < href
.name_len
) {
858 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
861 refname
= malloc(href
.name_len
+ 1);
862 if (refname
== NULL
) {
863 err
= got_error_from_errno("malloc");
866 memcpy(refname
, imsg
.data
+ sizeof(href
), href
.name_len
);
867 refname
[href
.name_len
] = '\0';
869 id
= malloc(sizeof(*id
));
872 err
= got_error_from_errno("malloc");
875 memcpy(id
->sha1
, href
.id
, SHA1_DIGEST_LENGTH
);
876 err
= got_pathlist_append(&have_refs
, refname
, id
);
886 for (i
= 0; i
< fetch_req
.n_wanted_branches
; i
++) {
889 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
891 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
895 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
897 if (imsg
.hdr
.type
!= GOT_IMSG_FETCH_WANTED_BRANCH
) {
898 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
901 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
902 if (datalen
< sizeof(wbranch
)) {
903 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
906 memcpy(&wbranch
, imsg
.data
, sizeof(wbranch
));
907 if (datalen
- sizeof(wbranch
) < wbranch
.name_len
) {
908 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
911 refname
= malloc(wbranch
.name_len
+ 1);
912 if (refname
== NULL
) {
913 err
= got_error_from_errno("malloc");
916 memcpy(refname
, imsg
.data
+ sizeof(wbranch
), wbranch
.name_len
);
917 refname
[wbranch
.name_len
] = '\0';
919 err
= got_pathlist_append(&wanted_branches
, refname
, NULL
);
928 for (i
= 0; i
< fetch_req
.n_wanted_refs
; i
++) {
931 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
933 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
937 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
939 if (imsg
.hdr
.type
!= GOT_IMSG_FETCH_WANTED_REF
) {
940 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
943 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
944 if (datalen
< sizeof(wref
)) {
945 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
948 memcpy(&wref
, imsg
.data
, sizeof(wref
));
949 if (datalen
- sizeof(wref
) < wref
.name_len
) {
950 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
953 refname
= malloc(wref
.name_len
+ 1);
954 if (refname
== NULL
) {
955 err
= got_error_from_errno("malloc");
958 memcpy(refname
, imsg
.data
+ sizeof(wref
), wref
.name_len
);
959 refname
[wref
.name_len
] = '\0';
961 err
= got_pathlist_append(&wanted_refs
, refname
, NULL
);
970 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
972 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
976 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
978 if (imsg
.hdr
.type
!= GOT_IMSG_FETCH_OUTFD
) {
979 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
982 if (imsg
.hdr
.len
- IMSG_HEADER_SIZE
!= 0) {
983 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
988 err
= fetch_pack(fetchfd
, packfd
, pack_sha1
, &have_refs
,
989 fetch_req
.fetch_all_branches
, &wanted_branches
,
990 &wanted_refs
, fetch_req
.list_refs_only
, &ibuf
);
992 TAILQ_FOREACH(pe
, &have_refs
, entry
) {
993 free((char *)pe
->path
);
996 got_pathlist_free(&have_refs
);
997 TAILQ_FOREACH(pe
, &wanted_branches
, entry
)
998 free((char *)pe
->path
);
999 got_pathlist_free(&wanted_branches
);
1000 if (fetchfd
!= -1 && close(fetchfd
) == -1 && err
== NULL
)
1001 err
= got_error_from_errno("close");
1002 if (packfd
!= -1 && close(packfd
) == -1 && err
== NULL
)
1003 err
= got_error_from_errno("close");
1005 got_privsep_send_error(&ibuf
, err
);
1007 err
= send_fetch_done(&ibuf
, pack_sha1
);
1009 fprintf(stderr
, "%s: %s\n", getprogname(), err
->msg
);
1010 got_privsep_send_error(&ibuf
, err
);