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 "got_compat.h"
19 #include <sys/types.h>
20 #include <sys/queue.h>
39 #include "got_error.h"
40 #include "got_object.h"
42 #include "got_version.h"
43 #include "got_fetch.h"
44 #include "got_reference.h"
46 #include "got_lib_hash.h"
47 #include "got_lib_delta.h"
48 #include "got_lib_object.h"
49 #include "got_lib_object_parse.h"
50 #include "got_lib_privsep.h"
51 #include "got_lib_pack.h"
52 #include "got_lib_pkt.h"
53 #include "got_lib_poll.h"
54 #include "got_lib_gitproto.h"
55 #include "got_lib_ratelimit.h"
58 #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
62 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
65 struct got_object
*indexed
;
68 static const struct got_capability got_capabilities
[] = {
69 { GOT_CAPA_AGENT
, "got/" GOT_VERSION_STR
},
70 { GOT_CAPA_OFS_DELTA
, NULL
},
71 { GOT_CAPA_SIDE_BAND_64K
, NULL
},
75 match_remote_ref(struct got_pathlist_head
*have_refs
,
76 struct got_object_id
*my_id
, const char *refname
)
78 struct got_pathlist_entry
*pe
;
80 /* XXX zero-hash signifies we don't have this ref;
81 * we should use a flag instead */
82 memset(my_id
, 0, sizeof(*my_id
));
84 TAILQ_FOREACH(pe
, have_refs
, entry
) {
85 struct got_object_id
*id
= pe
->data
;
86 if (strcmp(pe
->path
, refname
) == 0) {
87 memcpy(my_id
, id
, sizeof(*my_id
));
94 match_branch(const char *branch
, const char *wanted_branch
)
96 if (strncmp(branch
, "refs/heads/", 11) != 0)
99 if (strncmp(wanted_branch
, "refs/heads/", 11) == 0)
102 return (strcmp(branch
+ 11, wanted_branch
) == 0);
106 match_wanted_ref(const char *refname
, const char *wanted_ref
)
108 if (strncmp(refname
, "refs/", 5) != 0)
113 * Prevent fetching of references that won't make any
114 * sense outside of the remote repository's context.
116 if (strncmp(refname
, "got/", 4) == 0)
118 if (strncmp(refname
, "remotes/", 8) == 0)
121 if (strncmp(wanted_ref
, "refs/", 5) == 0)
124 /* Allow prefix match. */
125 if (got_path_is_child(refname
, wanted_ref
, strlen(wanted_ref
)))
128 /* Allow exact match. */
129 return (strcmp(refname
, wanted_ref
) == 0);
132 static const struct got_error
*
133 send_fetch_server_progress(struct imsgbuf
*ibuf
, const char *msg
, size_t msglen
)
135 if (msglen
> MAX_IMSGSIZE
- IMSG_HEADER_SIZE
)
136 return got_error(GOT_ERR_NO_SPACE
);
141 if (imsg_compose(ibuf
, GOT_IMSG_FETCH_SERVER_PROGRESS
, 0, 0, -1,
143 return got_error_from_errno(
144 "imsg_compose FETCH_SERVER_PROGRESS");
146 return got_privsep_flush_imsg(ibuf
);
149 static const struct got_error
*
150 send_fetch_download_progress(struct imsgbuf
*ibuf
, off_t bytes
,
151 struct got_ratelimit
*rl
)
153 const struct got_error
*err
;
157 err
= got_ratelimit_check(&elapsed
, rl
);
162 if (imsg_compose(ibuf
, GOT_IMSG_FETCH_DOWNLOAD_PROGRESS
, 0, 0, -1,
163 &bytes
, sizeof(bytes
)) == -1)
164 return got_error_from_errno(
165 "imsg_compose FETCH_DOWNLOAD_PROGRESS");
167 return got_privsep_flush_imsg(ibuf
);
170 static const struct got_error
*
171 send_fetch_done(struct imsgbuf
*ibuf
, uint8_t *pack_sha1
)
173 if (imsg_compose(ibuf
, GOT_IMSG_FETCH_DONE
, 0, 0, -1,
174 pack_sha1
, SHA1_DIGEST_LENGTH
) == -1)
175 return got_error_from_errno("imsg_compose FETCH");
176 return got_privsep_flush_imsg(ibuf
);
179 static const struct got_error
*
180 fetch_progress(struct imsgbuf
*ibuf
, const char *buf
, size_t len
)
188 * Truncate messages which exceed the maximum imsg payload size.
189 * Server may send up to 64k.
191 if (len
> MAX_IMSGSIZE
- IMSG_HEADER_SIZE
)
192 len
= MAX_IMSGSIZE
- IMSG_HEADER_SIZE
;
194 /* Only allow printable ASCII. */
195 for (i
= 0; i
< len
; i
++) {
196 if (isprint((unsigned char)buf
[i
]) ||
197 isspace((unsigned char)buf
[i
]))
199 return got_error_msg(GOT_ERR_BAD_PACKET
,
200 "non-printable progress message received from server");
203 return send_fetch_server_progress(ibuf
, buf
, len
);
206 static const struct got_error
*
207 fetch_error(const char *buf
, size_t len
)
209 static char msg
[1024];
212 for (i
= 0; i
< len
&& i
< sizeof(msg
) - 1; i
++) {
213 if (!isprint((unsigned char)buf
[i
]))
214 return got_error_msg(GOT_ERR_BAD_PACKET
,
215 "non-printable error message received from server");
219 return got_error_msg(GOT_ERR_FETCH_FAILED
, msg
);
222 static const struct got_error
*
223 send_fetch_symrefs(struct imsgbuf
*ibuf
, struct got_pathlist_head
*symrefs
)
226 size_t len
, nsymrefs
= 0;
227 struct got_pathlist_entry
*pe
;
229 len
= sizeof(struct got_imsg_fetch_symrefs
);
230 TAILQ_FOREACH(pe
, symrefs
, entry
) {
231 const char *target
= pe
->data
;
232 len
+= sizeof(struct got_imsg_fetch_symref
) +
233 pe
->path_len
+ strlen(target
);
237 if (len
>= MAX_IMSGSIZE
- IMSG_HEADER_SIZE
)
238 return got_error(GOT_ERR_NO_SPACE
);
240 wbuf
= imsg_create(ibuf
, GOT_IMSG_FETCH_SYMREFS
, 0, 0, len
);
242 return got_error_from_errno("imsg_create FETCH_SYMREFS");
244 /* Keep in sync with struct got_imsg_fetch_symrefs definition! */
245 if (imsg_add(wbuf
, &nsymrefs
, sizeof(nsymrefs
)) == -1)
246 return got_error_from_errno("imsg_add FETCH_SYMREFS");
248 TAILQ_FOREACH(pe
, symrefs
, entry
) {
249 const char *name
= pe
->path
;
250 size_t name_len
= pe
->path_len
;
251 const char *target
= pe
->data
;
252 size_t target_len
= strlen(target
);
254 /* Keep in sync with struct got_imsg_fetch_symref definition! */
255 if (imsg_add(wbuf
, &name_len
, sizeof(name_len
)) == -1)
256 return got_error_from_errno("imsg_add FETCH_SYMREFS");
257 if (imsg_add(wbuf
, &target_len
, sizeof(target_len
)) == -1)
258 return got_error_from_errno("imsg_add FETCH_SYMREFS");
259 if (imsg_add(wbuf
, name
, name_len
) == -1)
260 return got_error_from_errno("imsg_add FETCH_SYMREFS");
261 if (imsg_add(wbuf
, target
, target_len
) == -1)
262 return got_error_from_errno("imsg_add FETCH_SYMREFS");
265 imsg_close(ibuf
, wbuf
);
266 return got_privsep_flush_imsg(ibuf
);
269 static const struct got_error
*
270 send_fetch_ref(struct imsgbuf
*ibuf
, struct got_object_id
*refid
,
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
, sizeof(*refid
)) == -1)
286 return got_error_from_errno("imsg_add FETCH_REF");
287 if (imsg_add(wbuf
, refname
, reflen
) == -1)
288 return got_error_from_errno("imsg_add FETCH_REF");
290 imsg_close(ibuf
, wbuf
);
291 return got_privsep_flush_imsg(ibuf
);
294 static const struct got_error
*
295 fetch_ref(struct imsgbuf
*ibuf
, struct got_pathlist_head
*have_refs
,
296 struct got_object_id
*have
, struct got_object_id
*want
,
297 const char *refname
, const char *id_str
)
299 const struct got_error
*err
;
300 char *theirs
= NULL
, *mine
= NULL
;
302 if (!got_parse_object_id(want
, id_str
, GOT_HASH_SHA1
)) {
303 err
= got_error(GOT_ERR_BAD_OBJ_ID_STR
);
307 match_remote_ref(have_refs
, have
, refname
);
308 err
= send_fetch_ref(ibuf
, want
, refname
);
313 fprintf(stderr
, "%s: %s will be fetched\n",
314 getprogname(), refname
);
316 err
= got_object_id_str(&theirs
, want
);
319 err
= got_object_id_str(&mine
, have
);
322 fprintf(stderr
, "%s: remote: %s\n%s: local: %s\n",
323 getprogname(), theirs
, getprogname(), mine
);
331 static const struct got_error
*
332 fetch_pack(int fd
, int packfd
, uint8_t *pack_sha1
,
333 struct got_pathlist_head
*have_refs
, int fetch_all_branches
,
334 struct got_pathlist_head
*wanted_branches
,
335 struct got_pathlist_head
*wanted_refs
, int list_refs_only
,
336 const char *worktree_branch
, const char *remote_head
,
337 int no_head
, struct imsgbuf
*ibuf
)
339 const struct got_error
*err
= NULL
;
340 char buf
[GOT_PKT_MAX
];
341 char hashstr
[SHA1_DIGEST_STRING_LENGTH
];
342 struct got_object_id
*have
, *want
;
343 int is_firstpkt
= 1, nref
= 0, refsz
= 16;
344 int i
, n
, nwant
= 0, nhave
= 0, acked
= 0, eof
= 0;
345 off_t packsz
= 0, last_reported_packsz
= 0;
346 char *id_str
= NULL
, *default_id_str
= NULL
, *refname
= NULL
;
347 char *server_capabilities
= NULL
, *my_capabilities
= NULL
;
348 const char *default_branch
= NULL
;
349 struct got_pathlist_head symrefs
;
350 struct got_pathlist_entry
*pe
;
351 int sent_my_capabilites
= 0, have_sidebands
= 0;
352 int found_branch
= 0;
354 uint8_t sha1_buf
[SHA1_DIGEST_LENGTH
];
355 size_t sha1_buf_len
= 0;
357 struct got_ratelimit rl
;
359 TAILQ_INIT(&symrefs
);
360 got_hash_init(&ctx
, GOT_HASH_SHA1
);
361 got_ratelimit_init(&rl
, 0, 500);
363 have
= malloc(refsz
* sizeof(have
[0]));
365 return got_error_from_errno("malloc");
366 want
= malloc(refsz
* sizeof(want
[0]));
368 err
= got_error_from_errno("malloc");
372 err
= got_pkt_readpkt(&n
, fd
, buf
, sizeof(buf
), chattygot
,
378 if (n
>= 4 && strncmp(buf
, "ERR ", 4) == 0) {
379 err
= fetch_error(&buf
[4], n
- 4);
384 err
= got_gitproto_parse_refline(&id_str
, &refname
,
385 &server_capabilities
, buf
, n
);
389 if (refsz
== nref
+ 1) {
390 struct got_object_id
*h
, *w
;
393 h
= reallocarray(have
, refsz
, sizeof(have
[0]));
395 err
= got_error_from_errno("reallocarray");
399 w
= reallocarray(want
, refsz
, sizeof(want
[0]));
401 err
= got_error_from_errno("reallocarray");
408 if (chattygot
&& server_capabilities
[0] != '\0')
409 fprintf(stderr
, "%s: server capabilities: %s\n",
410 getprogname(), server_capabilities
);
411 err
= got_gitproto_match_capabilities(&my_capabilities
,
412 &symrefs
, server_capabilities
,
413 got_capabilities
, nitems(got_capabilities
));
417 fprintf(stderr
, "%s: my capabilities:%s\n",
418 getprogname(), my_capabilities
!= NULL
?
419 my_capabilities
: "");
420 err
= send_fetch_symrefs(ibuf
, &symrefs
);
424 if (!fetch_all_branches
) {
425 TAILQ_FOREACH(pe
, &symrefs
, entry
) {
426 const char *name
= pe
->path
;
427 const char *symref_target
= pe
->data
;
428 if (strcmp(name
, GOT_REF_HEAD
) != 0)
430 default_branch
= symref_target
;
437 if (strstr(refname
, "^{}")) {
439 fprintf(stderr
, "%s: ignoring %s\n",
440 getprogname(), refname
);
444 if (default_branch
&& default_id_str
== NULL
&&
445 strcmp(refname
, default_branch
) == 0) {
446 default_id_str
= strdup(id_str
);
447 if (default_id_str
== NULL
) {
448 err
= got_error_from_errno("strdup");
453 if (list_refs_only
|| strncmp(refname
, "refs/tags/", 10) == 0) {
454 err
= fetch_ref(ibuf
, have_refs
, &have
[nref
],
455 &want
[nref
], refname
, id_str
);
459 } else if (strncmp(refname
, "refs/heads/", 11) == 0) {
460 if (fetch_all_branches
) {
461 err
= fetch_ref(ibuf
, have_refs
, &have
[nref
],
462 &want
[nref
], refname
, id_str
);
469 TAILQ_FOREACH(pe
, wanted_branches
, entry
) {
470 if (match_branch(refname
, pe
->path
))
473 if (pe
!= NULL
|| (worktree_branch
!= NULL
&&
474 match_branch(refname
, worktree_branch
))) {
475 err
= fetch_ref(ibuf
, have_refs
, &have
[nref
],
476 &want
[nref
], refname
, id_str
);
481 } else if (chattygot
) {
482 fprintf(stderr
, "%s: ignoring %s\n",
483 getprogname(), refname
);
486 TAILQ_FOREACH(pe
, wanted_refs
, entry
) {
487 if (match_wanted_ref(refname
, pe
->path
))
491 err
= fetch_ref(ibuf
, have_refs
, &have
[nref
],
492 &want
[nref
], refname
, id_str
);
496 } else if (chattygot
) {
497 fprintf(stderr
, "%s: ignoring %s\n",
498 getprogname(), refname
);
507 * If -b was not used and either none of the requested branches
508 * (got.conf, worktree) were found or the client already has the
509 * remote HEAD symref but its target changed, fetch remote's HEAD.
511 if (!no_head
&& default_branch
&& default_id_str
&&
512 strncmp(default_branch
, "refs/heads/", 11) == 0) {
513 int remote_head_changed
= 0;
516 if (strcmp(remote_head
, default_branch
+ 11) != 0)
517 remote_head_changed
= 1;
520 if (!found_branch
|| remote_head_changed
) {
521 err
= fetch_ref(ibuf
, have_refs
, &have
[nref
],
522 &want
[nref
], default_branch
, default_id_str
);
529 /* Abort if we haven't found anything to fetch. */
531 struct got_pathlist_entry
*pe
;
532 static char msg
[PATH_MAX
+ 33];
534 pe
= TAILQ_FIRST(wanted_branches
);
536 snprintf(msg
, sizeof(msg
),
537 "branch \"%s\" not found on server", pe
->path
);
538 err
= got_error_msg(GOT_ERR_FETCH_NO_BRANCH
, msg
);
542 pe
= TAILQ_FIRST(wanted_refs
);
544 snprintf(msg
, sizeof(msg
),
545 "reference \"%s\" not found on server", pe
->path
);
546 err
= got_error_msg(GOT_ERR_FETCH_NO_BRANCH
, msg
);
550 err
= got_error(GOT_ERR_FETCH_NO_BRANCH
);
554 for (i
= 0; i
< nref
; i
++) {
555 if (got_object_id_cmp(&have
[i
], &want
[i
]) == 0)
557 got_object_id_hex(&want
[i
], hashstr
, sizeof(hashstr
));
558 n
= snprintf(buf
, sizeof(buf
), "want %s%s\n", hashstr
,
559 sent_my_capabilites
|| my_capabilities
== NULL
?
560 "" : my_capabilities
);
561 if (n
< 0 || (size_t)n
>= sizeof(buf
)) {
562 err
= got_error(GOT_ERR_NO_SPACE
);
565 err
= got_pkt_writepkt(fd
, buf
, n
, chattygot
);
568 sent_my_capabilites
= 1;
571 err
= got_pkt_flushpkt(fd
, chattygot
);
578 TAILQ_FOREACH(pe
, have_refs
, entry
) {
579 struct got_object_id
*id
= pe
->data
;
580 got_object_id_hex(id
, hashstr
, sizeof(hashstr
));
581 n
= snprintf(buf
, sizeof(buf
), "have %s\n", hashstr
);
582 if (n
< 0 || (size_t)n
>= sizeof(buf
)) {
583 err
= got_error(GOT_ERR_NO_SPACE
);
586 err
= got_pkt_writepkt(fd
, buf
, n
, chattygot
);
592 n
= strlcpy(buf
, "done\n", sizeof(buf
));
593 err
= got_pkt_writepkt(fd
, buf
, n
, chattygot
);
597 while (nhave
> 0 && !acked
) {
598 struct got_object_id common_id
;
600 /* The server should ACK the object IDs we need. */
601 err
= got_pkt_readpkt(&n
, fd
, buf
, sizeof(buf
), chattygot
,
605 if (n
>= 4 && strncmp(buf
, "ERR ", 4) == 0) {
606 err
= fetch_error(&buf
[4], n
- 4);
609 if (n
>= 4 && strncmp(buf
, "NAK\n", 4) == 0) {
611 * Server could not find a common ancestor.
612 * Perhaps it is an out-of-date mirror, or there
613 * is a repository with unrelated history.
617 if (n
< 4 + SHA1_DIGEST_STRING_LENGTH
||
618 strncmp(buf
, "ACK ", 4) != 0) {
619 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
620 "unexpected message from server");
623 if (!got_parse_object_id(&common_id
, buf
+ 4,
625 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
626 "bad object ID in ACK packet from server");
633 err
= got_pkt_readpkt(&n
, fd
, buf
, sizeof(buf
), chattygot
,
637 if (n
!= 4 || strncmp(buf
, "NAK\n", n
) != 0) {
638 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
639 "unexpected message from server");
645 fprintf(stderr
, "%s: fetching...\n", getprogname());
647 if (my_capabilities
!= NULL
&&
648 strstr(my_capabilities
, GOT_CAPA_SIDE_BAND_64K
) != NULL
)
655 if (have_sidebands
) {
656 err
= got_pkt_readhdr(&datalen
, fd
, chattygot
, INFTIM
);
662 /* Read sideband channel ID (one byte). */
663 r
= read(fd
, buf
, 1);
665 err
= got_error_from_errno("read");
669 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
673 if (datalen
> sizeof(buf
) - 5) {
674 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
675 "bad packet length");
678 datalen
--; /* sideband ID has been read */
679 if (buf
[0] == GOT_SIDEBAND_PACKFILE_DATA
) {
680 /* Read packfile data. */
681 err
= got_pkt_readn(&r
, fd
, buf
, datalen
,
686 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
690 } else if (buf
[0] == GOT_SIDEBAND_PROGRESS_INFO
) {
691 err
= got_pkt_readn(&r
, fd
, buf
, datalen
,
696 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
700 err
= fetch_progress(ibuf
, buf
, r
);
704 } else if (buf
[0] == GOT_SIDEBAND_ERROR_INFO
) {
705 err
= got_pkt_readn(&r
, fd
, buf
, datalen
,
710 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
714 err
= fetch_error(buf
, r
);
716 } else if (buf
[0] == 'A') {
717 err
= got_pkt_readn(&r
, fd
, buf
, datalen
,
722 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
727 * Git server responds with ACK after 'done'
728 * even though multi_ack is disabled?!?
731 if (strncmp(buf
, "CK ", 3) == 0)
732 continue; /* ignore */
733 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
734 "unexpected message from server");
737 err
= got_error_msg(GOT_ERR_BAD_PACKET
,
738 "unknown side-band received from server");
742 /* No sideband channel. Every byte is packfile data. */
744 err
= got_poll_read_full_timeout(fd
, &n
,
745 buf
, sizeof buf
, 1, INFTIM
);
747 if (err
->code
!= GOT_ERR_EOF
)
756 * An expected SHA1 checksum sits at the end of the pack file.
757 * Since we don't know the file size ahead of time we have to
758 * keep SHA1_DIGEST_LENGTH bytes buffered and avoid mixing
759 * those bytes into our SHA1 checksum computation until we
760 * know for sure that additional pack file data bytes follow.
762 if (r
< SHA1_DIGEST_LENGTH
) {
763 if (sha1_buf_len
< SHA1_DIGEST_LENGTH
) {
765 * If there's enough buffered + read data to
766 * fill up the buffer then shift a sufficient
767 * amount of bytes out at the front to make
768 * room, mixing those bytes into the checksum.
770 if (sha1_buf_len
> 0 &&
771 sha1_buf_len
+ r
> SHA1_DIGEST_LENGTH
) {
772 size_t nshift
= MIN(sha1_buf_len
+ r
-
773 SHA1_DIGEST_LENGTH
, sha1_buf_len
);
774 got_hash_update(&ctx
, sha1_buf
,
776 memmove(sha1_buf
, sha1_buf
+ nshift
,
777 sha1_buf_len
- nshift
);
778 sha1_buf_len
-= nshift
;
781 /* Buffer potential checksum bytes. */
782 memcpy(sha1_buf
+ sha1_buf_len
, buf
, r
);
786 * Mix in previously buffered bytes which
787 * are not part of the checksum after all.
789 got_hash_update(&ctx
, sha1_buf
, r
);
791 /* Update potential checksum buffer. */
792 memmove(sha1_buf
, sha1_buf
+ r
,
794 memcpy(sha1_buf
+ sha1_buf_len
- r
, buf
, r
);
797 /* Mix in any previously buffered bytes. */
798 got_hash_update(&ctx
, sha1_buf
, sha1_buf_len
);
800 /* Mix in bytes read minus potential checksum bytes. */
801 got_hash_update(&ctx
, buf
, r
- SHA1_DIGEST_LENGTH
);
803 /* Buffer potential checksum bytes. */
804 memcpy(sha1_buf
, buf
+ r
- SHA1_DIGEST_LENGTH
,
806 sha1_buf_len
= SHA1_DIGEST_LENGTH
;
809 /* Write packfile data to temporary pack file. */
810 w
= write(packfd
, buf
, r
);
812 err
= got_error_from_errno("write");
816 err
= got_error(GOT_ERR_IO
);
821 /* Don't send too many progress privsep messages. */
822 if (packsz
> last_reported_packsz
+ 1024) {
823 err
= send_fetch_download_progress(ibuf
, packsz
, &rl
);
826 last_reported_packsz
= packsz
;
829 err
= send_fetch_download_progress(ibuf
, packsz
, NULL
);
833 got_hash_final(&ctx
, pack_sha1
);
834 if (sha1_buf_len
!= SHA1_DIGEST_LENGTH
||
835 memcmp(pack_sha1
, sha1_buf
, sha1_buf_len
) != 0) {
836 err
= got_error_msg(GOT_ERR_BAD_PACKFILE
,
837 "pack file checksum mismatch");
840 got_pathlist_free(&symrefs
, GOT_PATHLIST_FREE_ALL
);
844 free(default_id_str
);
846 free(server_capabilities
);
852 main(int argc
, char **argv
)
854 const struct got_error
*err
= NULL
;
855 int fetchfd
= -1, packfd
= -1;
856 uint8_t pack_sha1
[SHA1_DIGEST_LENGTH
];
859 struct got_pathlist_head have_refs
;
860 struct got_pathlist_head wanted_branches
;
861 struct got_pathlist_head wanted_refs
;
862 struct got_imsg_fetch_request fetch_req
;
863 struct got_imsg_fetch_have_ref href
;
864 struct got_imsg_fetch_wanted_branch wbranch
;
865 struct got_imsg_fetch_wanted_ref wref
;
867 char *remote_head
= NULL
, *worktree_branch
= NULL
;
874 TAILQ_INIT(&have_refs
);
875 TAILQ_INIT(&wanted_branches
);
876 TAILQ_INIT(&wanted_refs
);
878 imsg_init(&ibuf
, GOT_IMSG_FD_CHILD
);
880 /* revoke access to most system calls */
881 if (pledge("stdio recvfd", NULL
) == -1) {
882 err
= got_error_from_errno("pledge");
883 got_privsep_send_error(&ibuf
, err
);
887 /* revoke fs access */
888 if (landlock_no_fs() == -1) {
889 err
= got_error_from_errno("landlock_no_fs");
890 got_privsep_send_error(&ibuf
, err
);
893 if (cap_enter() == -1) {
894 err
= got_error_from_errno("cap_enter");
895 got_privsep_send_error(&ibuf
, err
);
899 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
901 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
905 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
907 if (imsg
.hdr
.type
!= GOT_IMSG_FETCH_REQUEST
) {
908 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
911 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
912 if (datalen
< sizeof(fetch_req
)) {
913 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
916 memcpy(&fetch_req
, imsg
.data
, sizeof(fetch_req
));
917 fetchfd
= imsg_get_fd(&imsg
);
919 if (datalen
!= sizeof(fetch_req
) +
920 fetch_req
.worktree_branch_len
+ fetch_req
.remote_head_len
) {
921 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
925 if (fetch_req
.worktree_branch_len
!= 0) {
926 worktree_branch
= strndup(imsg
.data
+
927 sizeof(fetch_req
), fetch_req
.worktree_branch_len
);
928 if (worktree_branch
== NULL
) {
929 err
= got_error_from_errno("strndup");
934 if (fetch_req
.remote_head_len
!= 0) {
935 remote_head
= strndup(imsg
.data
+ sizeof(fetch_req
) +
936 fetch_req
.worktree_branch_len
, fetch_req
.remote_head_len
);
937 if (remote_head
== NULL
) {
938 err
= got_error_from_errno("strndup");
945 if (fetch_req
.verbosity
> 0)
946 chattygot
+= fetch_req
.verbosity
;
948 for (i
= 0; i
< fetch_req
.n_have_refs
; i
++) {
949 struct got_object_id
*id
;
952 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
954 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
958 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
960 if (imsg
.hdr
.type
!= GOT_IMSG_FETCH_HAVE_REF
) {
961 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
964 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
965 if (datalen
< sizeof(href
)) {
966 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
969 memcpy(&href
, imsg
.data
, sizeof(href
));
970 if (datalen
- sizeof(href
) < href
.name_len
) {
971 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
974 refname
= strndup(imsg
.data
+ sizeof(href
), href
.name_len
);
975 if (refname
== NULL
) {
976 err
= got_error_from_errno("strndup");
980 id
= malloc(sizeof(*id
));
983 err
= got_error_from_errno("malloc");
986 memcpy(id
, &href
.id
, sizeof(*id
));
987 err
= got_pathlist_append(&have_refs
, refname
, id
);
997 for (i
= 0; i
< fetch_req
.n_wanted_branches
; i
++) {
1000 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
1002 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
1006 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
1008 if (imsg
.hdr
.type
!= GOT_IMSG_FETCH_WANTED_BRANCH
) {
1009 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1012 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
1013 if (datalen
< sizeof(wbranch
)) {
1014 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1017 memcpy(&wbranch
, imsg
.data
, sizeof(wbranch
));
1018 if (datalen
- sizeof(wbranch
) < wbranch
.name_len
) {
1019 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1022 refname
= strndup(imsg
.data
+ sizeof(wbranch
),
1024 if (refname
== NULL
) {
1025 err
= got_error_from_errno("strndup");
1029 err
= got_pathlist_append(&wanted_branches
, refname
, NULL
);
1038 for (i
= 0; i
< fetch_req
.n_wanted_refs
; i
++) {
1041 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
1043 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
1047 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
1049 if (imsg
.hdr
.type
!= GOT_IMSG_FETCH_WANTED_REF
) {
1050 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1053 datalen
= imsg
.hdr
.len
- IMSG_HEADER_SIZE
;
1054 if (datalen
< sizeof(wref
)) {
1055 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1058 memcpy(&wref
, imsg
.data
, sizeof(wref
));
1059 if (datalen
- sizeof(wref
) < wref
.name_len
) {
1060 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1063 refname
= strndup(imsg
.data
+ sizeof(wref
), wref
.name_len
);
1064 if (refname
== NULL
) {
1065 err
= got_error_from_errno("strndup");
1069 err
= got_pathlist_append(&wanted_refs
, refname
, NULL
);
1078 err
= got_privsep_recv_imsg(&imsg
, &ibuf
, 0);
1080 if (err
->code
== GOT_ERR_PRIVSEP_PIPE
)
1084 if (imsg
.hdr
.type
== GOT_IMSG_STOP
)
1086 if (imsg
.hdr
.type
!= GOT_IMSG_FETCH_OUTFD
) {
1087 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
1090 if (imsg
.hdr
.len
- IMSG_HEADER_SIZE
!= 0) {
1091 err
= got_error(GOT_ERR_PRIVSEP_LEN
);
1094 packfd
= imsg_get_fd(&imsg
);
1096 err
= fetch_pack(fetchfd
, packfd
, pack_sha1
, &have_refs
,
1097 fetch_req
.fetch_all_branches
, &wanted_branches
,
1098 &wanted_refs
, fetch_req
.list_refs_only
,
1099 worktree_branch
, remote_head
, fetch_req
.no_head
, &ibuf
);
1101 free(worktree_branch
);
1103 got_pathlist_free(&have_refs
, GOT_PATHLIST_FREE_ALL
);
1104 got_pathlist_free(&wanted_branches
, GOT_PATHLIST_FREE_PATH
);
1105 if (fetchfd
!= -1 && close(fetchfd
) == -1 && err
== NULL
)
1106 err
= got_error_from_errno("close");
1107 if (packfd
!= -1 && close(packfd
) == -1 && err
== NULL
)
1108 err
= got_error_from_errno("close");
1110 got_privsep_send_error(&ibuf
, err
);
1112 err
= send_fetch_done(&ibuf
, pack_sha1
);
1114 fprintf(stderr
, "%s: %s\n", getprogname(), err
->msg
);
1115 got_privsep_send_error(&ibuf
, err
);