File: | libexec/got-fetch-pack/got-fetch-pack.c |
Warning: | line 738, column 7 Null pointer passed as 1st argument to string comparison function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||
2 | * Copyright (c) 2019 Ori Bernstein <ori@openbsd.org> | ||||
3 | * | ||||
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. | ||||
7 | * | ||||
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. | ||||
15 | */ | ||||
16 | |||||
17 | #include <sys/types.h> | ||||
18 | #include <sys/queue.h> | ||||
19 | #include <sys/uio.h> | ||||
20 | #include <sys/time.h> | ||||
21 | #include <sys/stat.h> | ||||
22 | |||||
23 | #include <stdint.h> | ||||
24 | #include <errno(*__errno()).h> | ||||
25 | #include <imsg.h> | ||||
26 | #include <limits.h> | ||||
27 | #include <signal.h> | ||||
28 | #include <stdio.h> | ||||
29 | #include <stdlib.h> | ||||
30 | #include <string.h> | ||||
31 | #include <ctype.h> | ||||
32 | #include <sha1.h> | ||||
33 | #include <fcntl.h> | ||||
34 | #include <unistd.h> | ||||
35 | #include <zlib.h> | ||||
36 | #include <err.h> | ||||
37 | |||||
38 | #include "got_error.h" | ||||
39 | #include "got_object.h" | ||||
40 | #include "got_path.h" | ||||
41 | #include "got_version.h" | ||||
42 | #include "got_fetch.h" | ||||
43 | #include "got_reference.h" | ||||
44 | |||||
45 | #include "got_lib_sha1.h" | ||||
46 | #include "got_lib_delta.h" | ||||
47 | #include "got_lib_object.h" | ||||
48 | #include "got_lib_object_parse.h" | ||||
49 | #include "got_lib_privsep.h" | ||||
50 | #include "got_lib_pack.h" | ||||
51 | |||||
52 | #ifndef nitems | ||||
53 | #define nitems(_a)(sizeof((_a)) / sizeof((_a)[0])) (sizeof((_a)) / sizeof((_a)[0])) | ||||
54 | #endif | ||||
55 | |||||
56 | struct got_object *indexed; | ||||
57 | static int chattygot; | ||||
58 | static struct got_object_id zhash = {.sha1={0}}; | ||||
59 | |||||
60 | static const struct got_error * | ||||
61 | readn(ssize_t *off, int fd, void *buf, size_t n) | ||||
62 | { | ||||
63 | ssize_t r; | ||||
64 | |||||
65 | *off = 0; | ||||
66 | while (*off != n) { | ||||
67 | r = read(fd, buf + *off, n - *off); | ||||
68 | if (r == -1) | ||||
69 | return got_error_from_errno("read"); | ||||
70 | if (r == 0) | ||||
71 | return NULL((void *)0); | ||||
72 | *off += r; | ||||
73 | } | ||||
74 | return NULL((void *)0); | ||||
75 | } | ||||
76 | |||||
77 | static const struct got_error * | ||||
78 | flushpkt(int fd) | ||||
79 | { | ||||
80 | ssize_t w; | ||||
81 | |||||
82 | if (chattygot > 1) | ||||
83 | fprintf(stderr(&__sF[2]), "%s: writepkt: 0000\n", getprogname()); | ||||
84 | |||||
85 | w = write(fd, "0000", 4); | ||||
86 | if (w == -1) | ||||
87 | return got_error_from_errno("write"); | ||||
88 | if (w != 4) | ||||
89 | return got_error(GOT_ERR_IO6); | ||||
90 | return NULL((void *)0); | ||||
91 | } | ||||
92 | |||||
93 | /* | ||||
94 | * Packet header contains a 4-byte hexstring which specifies the length | ||||
95 | * of data which follows. | ||||
96 | */ | ||||
97 | static const struct got_error * | ||||
98 | read_pkthdr(int *datalen, int fd) | ||||
99 | { | ||||
100 | static const struct got_error *err = NULL((void *)0); | ||||
101 | char lenstr[5]; | ||||
102 | long len; | ||||
103 | char *e; | ||||
104 | int n, i; | ||||
105 | ssize_t r; | ||||
106 | |||||
107 | *datalen = 0; | ||||
108 | |||||
109 | err = readn(&r, fd, lenstr, 4); | ||||
110 | if (err) | ||||
111 | return err; | ||||
112 | if (r == 0) { | ||||
113 | /* implicit "0000" */ | ||||
114 | if (chattygot > 1) | ||||
115 | fprintf(stderr(&__sF[2]), "%s: readpkt: 0000\n", getprogname()); | ||||
116 | return NULL((void *)0); | ||||
117 | } | ||||
118 | if (r != 4) | ||||
119 | return got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
120 | "wrong packet header length"); | ||||
121 | |||||
122 | lenstr[4] = '\0'; | ||||
123 | for (i = 0; i < 4; i++) { | ||||
124 | if (!isprint((unsigned char)lenstr[i])) | ||||
125 | return got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
126 | "unprintable character in packet length field"); | ||||
127 | } | ||||
128 | for (i = 0; i < 4; i++) { | ||||
129 | if (!isxdigit((unsigned char)lenstr[i])) { | ||||
130 | if (chattygot) | ||||
131 | fprintf(stderr(&__sF[2]), "%s: bad length: '%s'\n", | ||||
132 | getprogname(), lenstr); | ||||
133 | return got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
134 | "packet length not specified in hex"); | ||||
135 | } | ||||
136 | } | ||||
137 | errno(*__errno()) = 0; | ||||
138 | len = strtol(lenstr, &e, 16); | ||||
139 | if (lenstr[0] == '\0' || *e != '\0') | ||||
140 | return got_error(GOT_ERR_BAD_PACKET122); | ||||
141 | if (errno(*__errno()) == ERANGE34 && (len == LONG_MAX9223372036854775807L || len == LONG_MIN(-9223372036854775807L -1L))) | ||||
142 | return got_error_msg(GOT_ERR_BAD_PACKET122, "bad packet length"); | ||||
143 | if (len > INT_MAX2147483647 || len < INT_MIN(-2147483647 -1)) | ||||
144 | return got_error_msg(GOT_ERR_BAD_PACKET122, "bad packet length"); | ||||
145 | n = len; | ||||
146 | if (n == 0) | ||||
147 | return NULL((void *)0); | ||||
148 | if (n <= 4) | ||||
149 | return got_error_msg(GOT_ERR_BAD_PACKET122, "packet too short"); | ||||
150 | n -= 4; | ||||
151 | |||||
152 | *datalen = n; | ||||
153 | return NULL((void *)0); | ||||
154 | } | ||||
155 | |||||
156 | static const struct got_error * | ||||
157 | readpkt(int *outlen, int fd, char *buf, int buflen) | ||||
158 | { | ||||
159 | const struct got_error *err = NULL((void *)0); | ||||
160 | int datalen, i; | ||||
161 | ssize_t n; | ||||
162 | |||||
163 | err = read_pkthdr(&datalen, fd); | ||||
164 | if (err) | ||||
165 | return err; | ||||
166 | |||||
167 | if (datalen > buflen) | ||||
168 | return got_error(GOT_ERR_NO_SPACE9); | ||||
169 | |||||
170 | err = readn(&n, fd, buf, datalen); | ||||
171 | if (err) | ||||
172 | return err; | ||||
173 | if (n != datalen) | ||||
174 | return got_error_msg(GOT_ERR_BAD_PACKET122, "short packet"); | ||||
175 | |||||
176 | if (chattygot > 1) { | ||||
177 | fprintf(stderr(&__sF[2]), "%s: readpkt: %zd:\t", getprogname(), n); | ||||
178 | for (i = 0; i < n; i++) { | ||||
179 | if (isprint(buf[i])) | ||||
180 | fputc(buf[i], stderr(&__sF[2])); | ||||
181 | else | ||||
182 | fprintf(stderr(&__sF[2]), "[0x%.2x]", buf[i]); | ||||
183 | } | ||||
184 | fputc('\n', stderr(&__sF[2])); | ||||
185 | } | ||||
186 | |||||
187 | *outlen = n; | ||||
188 | return NULL((void *)0); | ||||
189 | } | ||||
190 | |||||
191 | static const struct got_error * | ||||
192 | writepkt(int fd, char *buf, int nbuf) | ||||
193 | { | ||||
194 | char len[5]; | ||||
195 | int i; | ||||
196 | ssize_t w; | ||||
197 | |||||
198 | if (snprintf(len, sizeof(len), "%04x", nbuf + 4) >= sizeof(len)) | ||||
199 | return got_error(GOT_ERR_NO_SPACE9); | ||||
200 | w = write(fd, len, 4); | ||||
201 | if (w == -1) | ||||
202 | return got_error_from_errno("write"); | ||||
203 | if (w != 4) | ||||
204 | return got_error(GOT_ERR_IO6); | ||||
205 | w = write(fd, buf, nbuf); | ||||
206 | if (w == -1) | ||||
207 | return got_error_from_errno("write"); | ||||
208 | if (w != nbuf) | ||||
209 | return got_error(GOT_ERR_IO6); | ||||
210 | if (chattygot > 1) { | ||||
211 | fprintf(stderr(&__sF[2]), "%s: writepkt: %s:\t", getprogname(), len); | ||||
212 | for (i = 0; i < nbuf; i++) { | ||||
213 | if (isprint(buf[i])) | ||||
214 | fputc(buf[i], stderr(&__sF[2])); | ||||
215 | else | ||||
216 | fprintf(stderr(&__sF[2]), "[0x%.2x]", buf[i]); | ||||
217 | } | ||||
218 | fputc('\n', stderr(&__sF[2])); | ||||
219 | } | ||||
220 | return NULL((void *)0); | ||||
221 | } | ||||
222 | |||||
223 | static void | ||||
224 | match_remote_ref(struct got_pathlist_head *have_refs, | ||||
225 | struct got_object_id *my_id, char *refname) | ||||
226 | { | ||||
227 | struct got_pathlist_entry *pe; | ||||
228 | |||||
229 | /* XXX zero-hash signifies we don't have this ref; | ||||
230 | * we should use a flag instead */ | ||||
231 | memset(my_id, 0, sizeof(*my_id)); | ||||
232 | |||||
233 | TAILQ_FOREACH(pe, have_refs, entry)for((pe) = ((have_refs)->tqh_first); (pe) != ((void *)0); ( pe) = ((pe)->entry.tqe_next)) { | ||||
234 | struct got_object_id *id = pe->data; | ||||
235 | if (strcmp(pe->path, refname) == 0) { | ||||
236 | memcpy(my_id, id, sizeof(*my_id)); | ||||
237 | break; | ||||
238 | } | ||||
239 | } | ||||
240 | } | ||||
241 | |||||
242 | static int | ||||
243 | match_branch(const char *branch, const char *wanted_branch) | ||||
244 | { | ||||
245 | if (strncmp(branch, "refs/heads/", 11) != 0) | ||||
246 | return 0; | ||||
247 | |||||
248 | if (strncmp(wanted_branch, "refs/heads/", 11) == 0) | ||||
249 | wanted_branch += 11; | ||||
250 | |||||
251 | return (strcmp(branch + 11, wanted_branch) == 0); | ||||
252 | } | ||||
253 | |||||
254 | static int | ||||
255 | match_wanted_ref(const char *refname, const char *wanted_ref) | ||||
256 | { | ||||
257 | if (strncmp(refname, "refs/", 5) != 0) | ||||
258 | return 0; | ||||
259 | refname += 5; | ||||
260 | |||||
261 | /* | ||||
262 | * Prevent fetching of references that won't make any | ||||
263 | * sense outside of the remote repository's context. | ||||
264 | */ | ||||
265 | if (strncmp(refname, "got/", 4) == 0) | ||||
266 | return 0; | ||||
267 | if (strncmp(refname, "remotes/", 8) == 0) | ||||
268 | return 0; | ||||
269 | |||||
270 | if (strncmp(wanted_ref, "refs/", 5) == 0) | ||||
271 | wanted_ref += 5; | ||||
272 | |||||
273 | /* Allow prefix match. */ | ||||
274 | if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref))) | ||||
275 | return 1; | ||||
276 | |||||
277 | /* Allow exact match. */ | ||||
278 | return (strcmp(refname, wanted_ref) == 0); | ||||
279 | } | ||||
280 | |||||
281 | static const struct got_error * | ||||
282 | tokenize_refline(char **tokens, char *line, int len, int maxtokens) | ||||
283 | { | ||||
284 | const struct got_error *err = NULL((void *)0); | ||||
285 | char *p; | ||||
286 | size_t i, n = 0; | ||||
287 | |||||
288 | for (i = 0; i < maxtokens; i++) | ||||
289 | tokens[i] = NULL((void *)0); | ||||
290 | |||||
291 | for (i = 0; n
| ||||
292 | while (isspace(*line)) { | ||||
293 | line++; | ||||
294 | n++; | ||||
295 | } | ||||
296 | p = line; | ||||
297 | while (*line != '\0' && | ||||
298 | (!isspace(*line) || i == maxtokens - 1)) { | ||||
299 | line++; | ||||
300 | n++; | ||||
301 | } | ||||
302 | tokens[i] = strndup(p, line - p); | ||||
303 | if (tokens[i] == NULL((void *)0)) { | ||||
304 | err = got_error_from_errno("strndup"); | ||||
305 | goto done; | ||||
306 | } | ||||
307 | /* Skip \0 field-delimiter at end of token. */ | ||||
308 | while (line[0] == '\0' && n < len) { | ||||
309 | line++; | ||||
310 | n++; | ||||
311 | } | ||||
312 | } | ||||
313 | if (i <= 2) | ||||
314 | err = got_error(GOT_ERR_NOT_REF5); | ||||
315 | done: | ||||
316 | if (err) { | ||||
317 | int j; | ||||
318 | for (j = 0; j < i; j++) { | ||||
319 | free(tokens[j]); | ||||
320 | tokens[j] = NULL((void *)0); | ||||
321 | } | ||||
322 | } | ||||
323 | return err; | ||||
324 | } | ||||
325 | |||||
326 | static const struct got_error * | ||||
327 | parse_refline(char **id_str, char **refname, char **server_capabilities, | ||||
328 | char *line, int len) | ||||
329 | { | ||||
330 | const struct got_error *err = NULL((void *)0); | ||||
331 | char *tokens[3]; | ||||
332 | |||||
333 | err = tokenize_refline(tokens, line, len, nitems(tokens)(sizeof((tokens)) / sizeof((tokens)[0]))); | ||||
334 | if (err
| ||||
335 | return err; | ||||
336 | |||||
337 | if (tokens[0]) | ||||
338 | *id_str = tokens[0]; | ||||
339 | if (tokens[1]) | ||||
340 | *refname = tokens[1]; | ||||
341 | if (tokens[2]) { | ||||
342 | char *p; | ||||
343 | *server_capabilities = tokens[2]; | ||||
344 | p = strrchr(*server_capabilities, '\n'); | ||||
345 | if (p) | ||||
346 | *p = '\0'; | ||||
347 | } | ||||
348 | |||||
349 | return NULL((void *)0); | ||||
350 | } | ||||
351 | |||||
352 | #define GOT_CAPA_AGENT"agent" "agent" | ||||
353 | #define GOT_CAPA_OFS_DELTA"ofs-delta" "ofs-delta" | ||||
354 | #define GOT_CAPA_SIDE_BAND_64K"side-band-64k" "side-band-64k" | ||||
355 | |||||
356 | #define GOT_SIDEBAND_PACKFILE_DATA1 1 | ||||
357 | #define GOT_SIDEBAND_PROGRESS_INFO2 2 | ||||
358 | #define GOT_SIDEBAND_ERROR_INFO3 3 | ||||
359 | |||||
360 | |||||
361 | struct got_capability { | ||||
362 | const char *key; | ||||
363 | const char *value; | ||||
364 | }; | ||||
365 | static const struct got_capability got_capabilities[] = { | ||||
366 | { GOT_CAPA_AGENT"agent", "got/" GOT_VERSION_STR"0.53-current" }, | ||||
367 | { GOT_CAPA_OFS_DELTA"ofs-delta", NULL((void *)0) }, | ||||
368 | { GOT_CAPA_SIDE_BAND_64K"side-band-64k", NULL((void *)0) }, | ||||
369 | }; | ||||
370 | |||||
371 | static const struct got_error * | ||||
372 | match_capability(char **my_capabilities, const char *capa, | ||||
373 | const struct got_capability *mycapa) | ||||
374 | { | ||||
375 | char *equalsign; | ||||
376 | char *s; | ||||
377 | |||||
378 | equalsign = strchr(capa, '='); | ||||
379 | if (equalsign) { | ||||
380 | if (strncmp(capa, mycapa->key, equalsign - capa) != 0) | ||||
381 | return NULL((void *)0); | ||||
382 | } else { | ||||
383 | if (strcmp(capa, mycapa->key) != 0) | ||||
384 | return NULL((void *)0); | ||||
385 | } | ||||
386 | |||||
387 | if (asprintf(&s, "%s %s%s%s", | ||||
388 | *my_capabilities != NULL((void *)0) ? *my_capabilities : "", | ||||
389 | mycapa->key, | ||||
390 | mycapa->value != NULL((void *)0) ? "=" : "", | ||||
391 | mycapa->value != NULL((void *)0)? mycapa->value : "") == -1) | ||||
392 | return got_error_from_errno("asprintf"); | ||||
393 | |||||
394 | free(*my_capabilities); | ||||
395 | *my_capabilities = s; | ||||
396 | return NULL((void *)0); | ||||
397 | } | ||||
398 | |||||
399 | static const struct got_error * | ||||
400 | add_symref(struct got_pathlist_head *symrefs, char *capa) | ||||
401 | { | ||||
402 | const struct got_error *err = NULL((void *)0); | ||||
403 | char *colon, *name = NULL((void *)0), *target = NULL((void *)0); | ||||
404 | |||||
405 | /* Need at least "A:B" */ | ||||
406 | if (strlen(capa) < 3) | ||||
407 | return NULL((void *)0); | ||||
408 | |||||
409 | colon = strchr(capa, ':'); | ||||
410 | if (colon == NULL((void *)0)) | ||||
411 | return NULL((void *)0); | ||||
412 | |||||
413 | *colon = '\0'; | ||||
414 | name = strdup(capa); | ||||
415 | if (name == NULL((void *)0)) | ||||
416 | return got_error_from_errno("strdup"); | ||||
417 | |||||
418 | target = strdup(colon + 1); | ||||
419 | if (target == NULL((void *)0)) { | ||||
420 | err = got_error_from_errno("strdup"); | ||||
421 | goto done; | ||||
422 | } | ||||
423 | |||||
424 | /* We can't validate the ref itself here. The main process will. */ | ||||
425 | err = got_pathlist_append(symrefs, name, target); | ||||
426 | done: | ||||
427 | if (err) { | ||||
428 | free(name); | ||||
429 | free(target); | ||||
430 | } | ||||
431 | return err; | ||||
432 | } | ||||
433 | |||||
434 | static const struct got_error * | ||||
435 | match_capabilities(char **my_capabilities, struct got_pathlist_head *symrefs, | ||||
436 | char *server_capabilities) | ||||
437 | { | ||||
438 | const struct got_error *err = NULL((void *)0); | ||||
439 | char *capa, *equalsign; | ||||
440 | size_t i; | ||||
441 | |||||
442 | *my_capabilities = NULL((void *)0); | ||||
443 | do { | ||||
444 | capa = strsep(&server_capabilities, " "); | ||||
445 | if (capa
| ||||
446 | return NULL((void *)0); | ||||
447 | |||||
448 | equalsign = strchr(capa, '='); | ||||
449 | if (equalsign != NULL((void *)0) && | ||||
450 | strncmp(capa, "symref", equalsign - capa) == 0) { | ||||
451 | err = add_symref(symrefs, equalsign + 1); | ||||
452 | if (err) | ||||
453 | break; | ||||
454 | continue; | ||||
455 | } | ||||
456 | |||||
457 | for (i = 0; i < nitems(got_capabilities)(sizeof((got_capabilities)) / sizeof((got_capabilities)[0])); i++) { | ||||
458 | err = match_capability(my_capabilities, | ||||
459 | capa, &got_capabilities[i]); | ||||
460 | if (err) | ||||
461 | break; | ||||
462 | } | ||||
463 | } while (capa); | ||||
464 | |||||
465 | if (*my_capabilities == NULL((void *)0)) { | ||||
466 | *my_capabilities = strdup(""); | ||||
467 | if (*my_capabilities == NULL((void *)0)) | ||||
468 | err = got_error_from_errno("strdup"); | ||||
469 | } | ||||
470 | return err; | ||||
471 | } | ||||
472 | |||||
473 | static const struct got_error * | ||||
474 | send_fetch_server_progress(struct imsgbuf *ibuf, const char *msg, size_t msglen) | ||||
475 | { | ||||
476 | if (msglen > MAX_IMSGSIZE16384 - IMSG_HEADER_SIZEsizeof(struct imsg_hdr)) | ||||
477 | return got_error(GOT_ERR_NO_SPACE9); | ||||
478 | |||||
479 | if (msglen == 0) | ||||
480 | return NULL((void *)0); | ||||
481 | |||||
482 | if (imsg_compose(ibuf, GOT_IMSG_FETCH_SERVER_PROGRESS, 0, 0, -1, | ||||
483 | msg, msglen) == -1) | ||||
484 | return got_error_from_errno( | ||||
485 | "imsg_compose FETCH_SERVER_PROGRESS"); | ||||
486 | |||||
487 | return got_privsep_flush_imsg(ibuf); | ||||
488 | } | ||||
489 | |||||
490 | static const struct got_error * | ||||
491 | send_fetch_download_progress(struct imsgbuf *ibuf, off_t bytes) | ||||
492 | { | ||||
493 | if (imsg_compose(ibuf, GOT_IMSG_FETCH_DOWNLOAD_PROGRESS, 0, 0, -1, | ||||
494 | &bytes, sizeof(bytes)) == -1) | ||||
495 | return got_error_from_errno( | ||||
496 | "imsg_compose FETCH_DOWNLOAD_PROGRESS"); | ||||
497 | |||||
498 | return got_privsep_flush_imsg(ibuf); | ||||
499 | } | ||||
500 | |||||
501 | static const struct got_error * | ||||
502 | send_fetch_done(struct imsgbuf *ibuf, uint8_t *pack_sha1) | ||||
503 | { | ||||
504 | if (imsg_compose(ibuf, GOT_IMSG_FETCH_DONE, 0, 0, -1, | ||||
505 | pack_sha1, SHA1_DIGEST_LENGTH20) == -1) | ||||
506 | return got_error_from_errno("imsg_compose FETCH"); | ||||
507 | return got_privsep_flush_imsg(ibuf); | ||||
508 | } | ||||
509 | |||||
510 | |||||
511 | |||||
512 | static const struct got_error * | ||||
513 | fetch_progress(struct imsgbuf *ibuf, const char *buf, size_t len) | ||||
514 | { | ||||
515 | size_t i; | ||||
516 | |||||
517 | if (len == 0) | ||||
518 | return NULL((void *)0); | ||||
519 | |||||
520 | /* | ||||
521 | * Truncate messages which exceed the maximum imsg payload size. | ||||
522 | * Server may send up to 64k. | ||||
523 | */ | ||||
524 | if (len > MAX_IMSGSIZE16384 - IMSG_HEADER_SIZEsizeof(struct imsg_hdr)) | ||||
525 | len = MAX_IMSGSIZE16384 - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | ||||
526 | |||||
527 | /* Only allow printable ASCII. */ | ||||
528 | for (i = 0; i < len; i++) { | ||||
529 | if (isprint((unsigned char)buf[i]) || | ||||
530 | isspace((unsigned char)buf[i])) | ||||
531 | continue; | ||||
532 | return got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
533 | "non-printable progress message received from server"); | ||||
534 | } | ||||
535 | |||||
536 | return send_fetch_server_progress(ibuf, buf, len); | ||||
537 | } | ||||
538 | |||||
539 | static const struct got_error * | ||||
540 | fetch_error(const char *buf, size_t len) | ||||
541 | { | ||||
542 | static char msg[1024]; | ||||
543 | size_t i; | ||||
544 | |||||
545 | for (i = 0; i < len && i < sizeof(msg) - 1; i++) { | ||||
546 | if (!isprint(buf[i])) | ||||
547 | return got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
548 | "non-printable error message received from server"); | ||||
549 | msg[i] = buf[i]; | ||||
550 | } | ||||
551 | msg[i] = '\0'; | ||||
552 | return got_error_msg(GOT_ERR_FETCH_FAILED118, msg); | ||||
553 | } | ||||
554 | |||||
555 | static const struct got_error * | ||||
556 | send_fetch_symrefs(struct imsgbuf *ibuf, struct got_pathlist_head *symrefs) | ||||
557 | { | ||||
558 | const struct got_error *err = NULL((void *)0); | ||||
559 | struct ibuf *wbuf; | ||||
560 | size_t len, nsymrefs = 0; | ||||
561 | struct got_pathlist_entry *pe; | ||||
562 | |||||
563 | len = sizeof(struct got_imsg_fetch_symrefs); | ||||
564 | TAILQ_FOREACH(pe, symrefs, entry)for((pe) = ((symrefs)->tqh_first); (pe) != ((void *)0); (pe ) = ((pe)->entry.tqe_next)) { | ||||
565 | const char *target = pe->data; | ||||
566 | len += sizeof(struct got_imsg_fetch_symref) + | ||||
567 | pe->path_len + strlen(target); | ||||
568 | nsymrefs++; | ||||
569 | } | ||||
570 | |||||
571 | if (len >= MAX_IMSGSIZE16384 - IMSG_HEADER_SIZEsizeof(struct imsg_hdr)) | ||||
572 | return got_error(GOT_ERR_NO_SPACE9); | ||||
573 | |||||
574 | wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_SYMREFS, 0, 0, len); | ||||
575 | if (wbuf == NULL((void *)0)) | ||||
576 | return got_error_from_errno("imsg_create FETCH_SYMREFS"); | ||||
577 | |||||
578 | /* Keep in sync with struct got_imsg_fetch_symrefs definition! */ | ||||
579 | if (imsg_add(wbuf, &nsymrefs, sizeof(nsymrefs)) == -1) { | ||||
580 | err = got_error_from_errno("imsg_add FETCH_SYMREFS"); | ||||
581 | ibuf_free(wbuf); | ||||
582 | return err; | ||||
583 | } | ||||
584 | |||||
585 | TAILQ_FOREACH(pe, symrefs, entry)for((pe) = ((symrefs)->tqh_first); (pe) != ((void *)0); (pe ) = ((pe)->entry.tqe_next)) { | ||||
586 | const char *name = pe->path; | ||||
587 | size_t name_len = pe->path_len; | ||||
588 | const char *target = pe->data; | ||||
589 | size_t target_len = strlen(target); | ||||
590 | |||||
591 | /* Keep in sync with struct got_imsg_fetch_symref definition! */ | ||||
592 | if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1) { | ||||
593 | err = got_error_from_errno("imsg_add FETCH_SYMREFS"); | ||||
594 | ibuf_free(wbuf); | ||||
595 | return err; | ||||
596 | } | ||||
597 | if (imsg_add(wbuf, &target_len, sizeof(target_len)) == -1) { | ||||
598 | err = got_error_from_errno("imsg_add FETCH_SYMREFS"); | ||||
599 | ibuf_free(wbuf); | ||||
600 | return err; | ||||
601 | } | ||||
602 | if (imsg_add(wbuf, name, name_len) == -1) { | ||||
603 | err = got_error_from_errno("imsg_add FETCH_SYMREFS"); | ||||
604 | ibuf_free(wbuf); | ||||
605 | return err; | ||||
606 | } | ||||
607 | if (imsg_add(wbuf, target, target_len) == -1) { | ||||
608 | err = got_error_from_errno("imsg_add FETCH_SYMREFS"); | ||||
609 | ibuf_free(wbuf); | ||||
610 | return err; | ||||
611 | } | ||||
612 | } | ||||
613 | |||||
614 | wbuf->fd = -1; | ||||
615 | imsg_close(ibuf, wbuf); | ||||
616 | return got_privsep_flush_imsg(ibuf); | ||||
617 | } | ||||
618 | |||||
619 | static const struct got_error * | ||||
620 | send_fetch_ref(struct imsgbuf *ibuf, struct got_object_id *refid, | ||||
621 | const char *refname) | ||||
622 | { | ||||
623 | const struct got_error *err = NULL((void *)0); | ||||
624 | struct ibuf *wbuf; | ||||
625 | size_t len, reflen = strlen(refname); | ||||
626 | |||||
627 | len = sizeof(struct got_imsg_fetch_ref) + reflen; | ||||
628 | if (len >= MAX_IMSGSIZE16384 - IMSG_HEADER_SIZEsizeof(struct imsg_hdr)) | ||||
629 | return got_error(GOT_ERR_NO_SPACE9); | ||||
630 | |||||
631 | wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_REF, 0, 0, len); | ||||
632 | if (wbuf == NULL((void *)0)) | ||||
633 | return got_error_from_errno("imsg_create FETCH_REF"); | ||||
634 | |||||
635 | /* Keep in sync with struct got_imsg_fetch_ref definition! */ | ||||
636 | if (imsg_add(wbuf, refid->sha1, SHA1_DIGEST_LENGTH20) == -1) { | ||||
637 | err = got_error_from_errno("imsg_add FETCH_REF"); | ||||
638 | ibuf_free(wbuf); | ||||
639 | return err; | ||||
640 | } | ||||
641 | if (imsg_add(wbuf, refname, reflen) == -1) { | ||||
642 | err = got_error_from_errno("imsg_add FETCH_REF"); | ||||
643 | ibuf_free(wbuf); | ||||
644 | return err; | ||||
645 | } | ||||
646 | |||||
647 | wbuf->fd = -1; | ||||
648 | imsg_close(ibuf, wbuf); | ||||
649 | return got_privsep_flush_imsg(ibuf); | ||||
650 | } | ||||
651 | |||||
652 | static const struct got_error * | ||||
653 | fetch_pack(int fd, int packfd, uint8_t *pack_sha1, | ||||
654 | struct got_pathlist_head *have_refs, int fetch_all_branches, | ||||
655 | struct got_pathlist_head *wanted_branches, | ||||
656 | struct got_pathlist_head *wanted_refs, int list_refs_only, | ||||
657 | struct imsgbuf *ibuf) | ||||
658 | { | ||||
659 | const struct got_error *err = NULL((void *)0); | ||||
660 | char buf[GOT_FETCH_PKTMAX65536]; | ||||
661 | char hashstr[SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1)]; | ||||
662 | struct got_object_id *have, *want; | ||||
663 | int is_firstpkt = 1, nref = 0, refsz = 16; | ||||
664 | int i, n, nwant = 0, nhave = 0, acked = 0; | ||||
665 | off_t packsz = 0, last_reported_packsz = 0; | ||||
666 | char *id_str = NULL((void *)0), *refname = NULL((void *)0); | ||||
| |||||
667 | char *server_capabilities = NULL((void *)0), *my_capabilities = NULL((void *)0); | ||||
668 | const char *default_branch = NULL((void *)0); | ||||
669 | struct got_pathlist_head symrefs; | ||||
670 | struct got_pathlist_entry *pe; | ||||
671 | int sent_my_capabilites = 0, have_sidebands = 0; | ||||
672 | int found_branch = 0; | ||||
673 | SHA1_CTX sha1_ctx; | ||||
674 | uint8_t sha1_buf[SHA1_DIGEST_LENGTH20]; | ||||
675 | size_t sha1_buf_len = 0; | ||||
676 | ssize_t w; | ||||
677 | |||||
678 | TAILQ_INIT(&symrefs)do { (&symrefs)->tqh_first = ((void *)0); (&symrefs )->tqh_last = &(&symrefs)->tqh_first; } while ( 0); | ||||
679 | SHA1Init(&sha1_ctx); | ||||
680 | |||||
681 | have = malloc(refsz * sizeof(have[0])); | ||||
682 | if (have == NULL((void *)0)) | ||||
683 | return got_error_from_errno("malloc"); | ||||
684 | want = malloc(refsz * sizeof(want[0])); | ||||
685 | if (want == NULL((void *)0)) { | ||||
686 | err = got_error_from_errno("malloc"); | ||||
687 | goto done; | ||||
688 | } | ||||
689 | while (1) { | ||||
690 | err = readpkt(&n, fd, buf, sizeof(buf)); | ||||
691 | if (err
| ||||
692 | goto done; | ||||
693 | if (n
| ||||
694 | break; | ||||
695 | if (n
| ||||
696 | err = fetch_error(&buf[4], n - 4); | ||||
697 | goto done; | ||||
698 | } | ||||
699 | err = parse_refline(&id_str, &refname, &server_capabilities, | ||||
700 | buf, n); | ||||
701 | if (err
| ||||
702 | goto done; | ||||
703 | if (is_firstpkt
| ||||
704 | if (chattygot && server_capabilities[0] != '\0') | ||||
705 | fprintf(stderr(&__sF[2]), "%s: server capabilities: %s\n", | ||||
706 | getprogname(), server_capabilities); | ||||
707 | err = match_capabilities(&my_capabilities, &symrefs, | ||||
708 | server_capabilities); | ||||
709 | if (err
| ||||
710 | goto done; | ||||
711 | if (chattygot
| ||||
712 | fprintf(stderr(&__sF[2]), "%s: my capabilities:%s\n", | ||||
713 | getprogname(), my_capabilities); | ||||
714 | err = send_fetch_symrefs(ibuf, &symrefs); | ||||
715 | if (err) | ||||
716 | goto done; | ||||
717 | is_firstpkt = 0; | ||||
718 | if (!fetch_all_branches) { | ||||
719 | TAILQ_FOREACH(pe, &symrefs, entry)for((pe) = ((&symrefs)->tqh_first); (pe) != ((void *)0 ); (pe) = ((pe)->entry.tqe_next)) { | ||||
720 | const char *name = pe->path; | ||||
721 | const char *symref_target = pe->data; | ||||
722 | if (strcmp(name, GOT_REF_HEAD"HEAD") != 0) | ||||
723 | continue; | ||||
724 | default_branch = symref_target; | ||||
725 | break; | ||||
726 | } | ||||
727 | } | ||||
728 | continue; | ||||
729 | } | ||||
730 | if (strstr(refname, "^{}")) { | ||||
731 | if (chattygot) { | ||||
732 | fprintf(stderr(&__sF[2]), "%s: ignoring %s\n", | ||||
733 | getprogname(), refname); | ||||
734 | } | ||||
735 | continue; | ||||
736 | } | ||||
737 | |||||
738 | if (strncmp(refname, "refs/heads/", 11) == 0) { | ||||
| |||||
739 | if (fetch_all_branches || list_refs_only) { | ||||
740 | found_branch = 1; | ||||
741 | } else if (!TAILQ_EMPTY(wanted_branches)(((wanted_branches)->tqh_first) == ((void *)0))) { | ||||
742 | TAILQ_FOREACH(pe, wanted_branches, entry)for((pe) = ((wanted_branches)->tqh_first); (pe) != ((void * )0); (pe) = ((pe)->entry.tqe_next)) { | ||||
743 | if (match_branch(refname, pe->path)) | ||||
744 | break; | ||||
745 | } | ||||
746 | if (pe == NULL((void *)0)) { | ||||
747 | if (chattygot) { | ||||
748 | fprintf(stderr(&__sF[2]), | ||||
749 | "%s: ignoring %s\n", | ||||
750 | getprogname(), refname); | ||||
751 | } | ||||
752 | continue; | ||||
753 | } | ||||
754 | found_branch = 1; | ||||
755 | } else if (default_branch != NULL((void *)0)) { | ||||
756 | if (!match_branch(refname, default_branch)) { | ||||
757 | if (chattygot) { | ||||
758 | fprintf(stderr(&__sF[2]), | ||||
759 | "%s: ignoring %s\n", | ||||
760 | getprogname(), refname); | ||||
761 | } | ||||
762 | continue; | ||||
763 | } | ||||
764 | found_branch = 1; | ||||
765 | } | ||||
766 | } else if (strncmp(refname, "refs/tags/", 10) != 0) { | ||||
767 | if (!TAILQ_EMPTY(wanted_refs)(((wanted_refs)->tqh_first) == ((void *)0))) { | ||||
768 | TAILQ_FOREACH(pe, wanted_refs, entry)for((pe) = ((wanted_refs)->tqh_first); (pe) != ((void *)0) ; (pe) = ((pe)->entry.tqe_next)) { | ||||
769 | if (match_wanted_ref(refname, pe->path)) | ||||
770 | break; | ||||
771 | } | ||||
772 | if (pe == NULL((void *)0)) { | ||||
773 | if (chattygot) { | ||||
774 | fprintf(stderr(&__sF[2]), | ||||
775 | "%s: ignoring %s\n", | ||||
776 | getprogname(), refname); | ||||
777 | } | ||||
778 | continue; | ||||
779 | } | ||||
780 | found_branch = 1; | ||||
781 | } else if (!list_refs_only) { | ||||
782 | if (chattygot) { | ||||
783 | fprintf(stderr(&__sF[2]), "%s: ignoring %s\n", | ||||
784 | getprogname(), refname); | ||||
785 | } | ||||
786 | continue; | ||||
787 | } | ||||
788 | } | ||||
789 | |||||
790 | if (refsz == nref + 1) { | ||||
791 | refsz *= 2; | ||||
792 | have = reallocarray(have, refsz, sizeof(have[0])); | ||||
793 | if (have == NULL((void *)0)) { | ||||
794 | err = got_error_from_errno("reallocarray"); | ||||
795 | goto done; | ||||
796 | } | ||||
797 | want = reallocarray(want, refsz, sizeof(want[0])); | ||||
798 | if (want == NULL((void *)0)) { | ||||
799 | err = got_error_from_errno("reallocarray"); | ||||
800 | goto done; | ||||
801 | } | ||||
802 | } | ||||
803 | if (!got_parse_sha1_digest(want[nref].sha1, id_str)) { | ||||
804 | err = got_error(GOT_ERR_BAD_OBJ_ID_STR23); | ||||
805 | goto done; | ||||
806 | } | ||||
807 | match_remote_ref(have_refs, &have[nref], refname); | ||||
808 | err = send_fetch_ref(ibuf, &want[nref], refname); | ||||
809 | if (err) | ||||
810 | goto done; | ||||
811 | |||||
812 | if (chattygot) | ||||
813 | fprintf(stderr(&__sF[2]), "%s: %s will be fetched\n", | ||||
814 | getprogname(), refname); | ||||
815 | if (chattygot > 1) { | ||||
816 | char *theirs, *mine; | ||||
817 | err = got_object_id_str(&theirs, &want[nref]); | ||||
818 | if (err) | ||||
819 | goto done; | ||||
820 | err = got_object_id_str(&mine, &have[nref]); | ||||
821 | if (err) { | ||||
822 | free(theirs); | ||||
823 | goto done; | ||||
824 | } | ||||
825 | fprintf(stderr(&__sF[2]), "%s: remote: %s\n%s: local: %s\n", | ||||
826 | getprogname(), theirs, getprogname(), mine); | ||||
827 | free(theirs); | ||||
828 | free(mine); | ||||
829 | } | ||||
830 | nref++; | ||||
831 | } | ||||
832 | |||||
833 | if (list_refs_only) | ||||
834 | goto done; | ||||
835 | |||||
836 | /* Abort if we haven't found any branch to fetch. */ | ||||
837 | if (!found_branch) { | ||||
838 | err = got_error(GOT_ERR_FETCH_NO_BRANCH124); | ||||
839 | goto done; | ||||
840 | } | ||||
841 | |||||
842 | for (i = 0; i < nref; i++) { | ||||
843 | if (got_object_id_cmp(&have[i], &want[i]) == 0) | ||||
844 | continue; | ||||
845 | got_sha1_digest_to_str(want[i].sha1, hashstr, sizeof(hashstr)); | ||||
846 | n = snprintf(buf, sizeof(buf), "want %s%s\n", hashstr, | ||||
847 | sent_my_capabilites ? "" : my_capabilities); | ||||
848 | if (n >= sizeof(buf)) { | ||||
849 | err = got_error(GOT_ERR_NO_SPACE9); | ||||
850 | goto done; | ||||
851 | } | ||||
852 | err = writepkt(fd, buf, n); | ||||
853 | if (err) | ||||
854 | goto done; | ||||
855 | sent_my_capabilites = 1; | ||||
856 | nwant++; | ||||
857 | } | ||||
858 | err = flushpkt(fd); | ||||
859 | if (err) | ||||
860 | goto done; | ||||
861 | |||||
862 | if (nwant == 0) | ||||
863 | goto done; | ||||
864 | |||||
865 | for (i = 0; i < nref; i++) { | ||||
866 | if (got_object_id_cmp(&have[i], &zhash) == 0) | ||||
867 | continue; | ||||
868 | got_sha1_digest_to_str(have[i].sha1, hashstr, sizeof(hashstr)); | ||||
869 | n = snprintf(buf, sizeof(buf), "have %s\n", hashstr); | ||||
870 | if (n >= sizeof(buf)) { | ||||
871 | err = got_error(GOT_ERR_NO_SPACE9); | ||||
872 | goto done; | ||||
873 | } | ||||
874 | err = writepkt(fd, buf, n); | ||||
875 | if (err) | ||||
876 | goto done; | ||||
877 | nhave++; | ||||
878 | } | ||||
879 | |||||
880 | while (nhave > 0 && !acked) { | ||||
881 | struct got_object_id common_id; | ||||
882 | |||||
883 | /* The server should ACK the object IDs we need. */ | ||||
884 | err = readpkt(&n, fd, buf, sizeof(buf)); | ||||
885 | if (err) | ||||
886 | goto done; | ||||
887 | if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) { | ||||
888 | err = fetch_error(&buf[4], n - 4); | ||||
889 | goto done; | ||||
890 | } | ||||
891 | if (n >= 4 && strncmp(buf, "NAK\n", 4) == 0) { | ||||
892 | /* Server has not located our objects yet. */ | ||||
893 | continue; | ||||
894 | } | ||||
895 | if (n < 4 + SHA1_DIGEST_STRING_LENGTH(20 * 2 + 1) || | ||||
896 | strncmp(buf, "ACK ", 4) != 0) { | ||||
897 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
898 | "unexpected message from server"); | ||||
899 | goto done; | ||||
900 | } | ||||
901 | if (!got_parse_sha1_digest(common_id.sha1, buf + 4)) { | ||||
902 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
903 | "bad object ID in ACK packet from server"); | ||||
904 | goto done; | ||||
905 | } | ||||
906 | acked++; | ||||
907 | } | ||||
908 | |||||
909 | n = snprintf(buf, sizeof(buf), "done\n"); | ||||
910 | err = writepkt(fd, buf, n); | ||||
911 | if (err) | ||||
912 | goto done; | ||||
913 | |||||
914 | if (nhave == 0) { | ||||
915 | err = readpkt(&n, fd, buf, sizeof(buf)); | ||||
916 | if (err) | ||||
917 | goto done; | ||||
918 | if (n != 4 || strncmp(buf, "NAK\n", n) != 0) { | ||||
919 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
920 | "unexpected message from server"); | ||||
921 | goto done; | ||||
922 | } | ||||
923 | } | ||||
924 | |||||
925 | if (chattygot) | ||||
926 | fprintf(stderr(&__sF[2]), "%s: fetching...\n", getprogname()); | ||||
927 | |||||
928 | if (my_capabilities != NULL((void *)0) && | ||||
929 | strstr(my_capabilities, GOT_CAPA_SIDE_BAND_64K"side-band-64k") != NULL((void *)0)) | ||||
930 | have_sidebands = 1; | ||||
931 | |||||
932 | while (1) { | ||||
933 | ssize_t r = 0; | ||||
934 | int datalen = -1; | ||||
935 | |||||
936 | if (have_sidebands) { | ||||
937 | err = read_pkthdr(&datalen, fd); | ||||
938 | if (err) | ||||
939 | goto done; | ||||
940 | if (datalen <= 0) | ||||
941 | break; | ||||
942 | |||||
943 | /* Read sideband channel ID (one byte). */ | ||||
944 | r = read(fd, buf, 1); | ||||
945 | if (r == -1) { | ||||
946 | err = got_error_from_errno("read"); | ||||
947 | goto done; | ||||
948 | } | ||||
949 | if (r != 1) { | ||||
950 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
951 | "short packet"); | ||||
952 | goto done; | ||||
953 | } | ||||
954 | if (datalen > sizeof(buf) - 5) { | ||||
955 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
956 | "bad packet length"); | ||||
957 | goto done; | ||||
958 | } | ||||
959 | datalen--; /* sideband ID has been read */ | ||||
960 | if (buf[0] == GOT_SIDEBAND_PACKFILE_DATA1) { | ||||
961 | /* Read packfile data. */ | ||||
962 | err = readn(&r, fd, buf, datalen); | ||||
963 | if (err) | ||||
964 | goto done; | ||||
965 | if (r != datalen) { | ||||
966 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
967 | "packet too short"); | ||||
968 | goto done; | ||||
969 | } | ||||
970 | } else if (buf[0] == GOT_SIDEBAND_PROGRESS_INFO2) { | ||||
971 | err = readn(&r, fd, buf, datalen); | ||||
972 | if (err) | ||||
973 | goto done; | ||||
974 | if (r != datalen) { | ||||
975 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
976 | "packet too short"); | ||||
977 | goto done; | ||||
978 | } | ||||
979 | err = fetch_progress(ibuf, buf, r); | ||||
980 | if (err) | ||||
981 | goto done; | ||||
982 | continue; | ||||
983 | } else if (buf[0] == GOT_SIDEBAND_ERROR_INFO3) { | ||||
984 | err = readn(&r, fd, buf, datalen); | ||||
985 | if (err) | ||||
986 | goto done; | ||||
987 | if (r != datalen) { | ||||
988 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
989 | "packet too short"); | ||||
990 | goto done; | ||||
991 | } | ||||
992 | err = fetch_error(buf, r); | ||||
993 | goto done; | ||||
994 | } else if (buf[0] == 'A') { | ||||
995 | err = readn(&r, fd, buf, datalen); | ||||
996 | if (err) | ||||
997 | goto done; | ||||
998 | if (r != datalen) { | ||||
999 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
1000 | "packet too short"); | ||||
1001 | goto done; | ||||
1002 | } | ||||
1003 | /* | ||||
1004 | * Git server responds with ACK after 'done' | ||||
1005 | * even though multi_ack is disabled?!? | ||||
1006 | */ | ||||
1007 | buf[r] = '\0'; | ||||
1008 | if (strncmp(buf, "CK ", 3) == 0) | ||||
1009 | continue; /* ignore */ | ||||
1010 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
1011 | "unexpected message from server"); | ||||
1012 | goto done; | ||||
1013 | } else { | ||||
1014 | err = got_error_msg(GOT_ERR_BAD_PACKET122, | ||||
1015 | "unknown side-band received from server"); | ||||
1016 | goto done; | ||||
1017 | } | ||||
1018 | } else { | ||||
1019 | /* No sideband channel. Every byte is packfile data. */ | ||||
1020 | err = readn(&r, fd, buf, sizeof buf); | ||||
1021 | if (err) | ||||
1022 | goto done; | ||||
1023 | if (r <= 0) | ||||
1024 | break; | ||||
1025 | } | ||||
1026 | |||||
1027 | /* | ||||
1028 | * An expected SHA1 checksum sits at the end of the pack file. | ||||
1029 | * Since we don't know the file size ahead of time we have to | ||||
1030 | * keep SHA1_DIGEST_LENGTH bytes buffered and avoid mixing | ||||
1031 | * those bytes into our SHA1 checksum computation until we | ||||
1032 | * know for sure that additional pack file data bytes follow. | ||||
1033 | * | ||||
1034 | * We can assume r > 0 since otherwise the loop would exit. | ||||
1035 | */ | ||||
1036 | if (r < SHA1_DIGEST_LENGTH20) { | ||||
1037 | if (sha1_buf_len < SHA1_DIGEST_LENGTH20) { | ||||
1038 | /* | ||||
1039 | * If there's enough buffered + read data to | ||||
1040 | * fill up the buffer then shift a sufficient | ||||
1041 | * amount of bytes out at the front to make | ||||
1042 | * room, mixing those bytes into the checksum. | ||||
1043 | */ | ||||
1044 | while (sha1_buf_len > 0 && | ||||
1045 | sha1_buf_len + r > SHA1_DIGEST_LENGTH20) { | ||||
1046 | SHA1Update(&sha1_ctx, sha1_buf, 1); | ||||
1047 | memmove(sha1_buf, sha1_buf + 1, 1); | ||||
1048 | sha1_buf_len--; | ||||
1049 | } | ||||
1050 | |||||
1051 | /* Buffer potential checksum bytes. */ | ||||
1052 | memcpy(sha1_buf + sha1_buf_len, buf, r); | ||||
1053 | sha1_buf_len += r; | ||||
1054 | } else { | ||||
1055 | /* | ||||
1056 | * Mix in previously buffered bytes which | ||||
1057 | * are not part of the checksum after all. | ||||
1058 | */ | ||||
1059 | SHA1Update(&sha1_ctx, sha1_buf, r); | ||||
1060 | |||||
1061 | /* Update potential checksum buffer. */ | ||||
1062 | memmove(sha1_buf, sha1_buf + r, | ||||
1063 | sha1_buf_len - r); | ||||
1064 | memcpy(sha1_buf + sha1_buf_len - r, buf, r); | ||||
1065 | } | ||||
1066 | } else { | ||||
1067 | /* Mix in any previously buffered bytes. */ | ||||
1068 | SHA1Update(&sha1_ctx, sha1_buf, sha1_buf_len); | ||||
1069 | |||||
1070 | /* Mix in bytes read minus potential checksum bytes. */ | ||||
1071 | SHA1Update(&sha1_ctx, buf, r - SHA1_DIGEST_LENGTH20); | ||||
1072 | |||||
1073 | /* Buffer potential checksum bytes. */ | ||||
1074 | memcpy(sha1_buf, buf + r - SHA1_DIGEST_LENGTH20, | ||||
1075 | SHA1_DIGEST_LENGTH20); | ||||
1076 | sha1_buf_len = SHA1_DIGEST_LENGTH20; | ||||
1077 | } | ||||
1078 | |||||
1079 | /* Write packfile data to temporary pack file. */ | ||||
1080 | w = write(packfd, buf, r); | ||||
1081 | if (w == -1) { | ||||
1082 | err = got_error_from_errno("write"); | ||||
1083 | goto done; | ||||
1084 | } | ||||
1085 | if (w != r) { | ||||
1086 | err = got_error(GOT_ERR_IO6); | ||||
1087 | goto done; | ||||
1088 | } | ||||
1089 | packsz += w; | ||||
1090 | |||||
1091 | /* Don't send too many progress privsep messages. */ | ||||
1092 | if (packsz > last_reported_packsz + 1024) { | ||||
1093 | err = send_fetch_download_progress(ibuf, packsz); | ||||
1094 | if (err) | ||||
1095 | goto done; | ||||
1096 | last_reported_packsz = packsz; | ||||
1097 | } | ||||
1098 | } | ||||
1099 | err = send_fetch_download_progress(ibuf, packsz); | ||||
1100 | if (err) | ||||
1101 | goto done; | ||||
1102 | |||||
1103 | SHA1Final(pack_sha1, &sha1_ctx); | ||||
1104 | if (sha1_buf_len != SHA1_DIGEST_LENGTH20 || | ||||
1105 | memcmp(pack_sha1, sha1_buf, sha1_buf_len) != 0) { | ||||
1106 | err = got_error_msg(GOT_ERR_BAD_PACKFILE16, | ||||
1107 | "pack file checksum mismatch"); | ||||
1108 | } | ||||
1109 | done: | ||||
1110 | TAILQ_FOREACH(pe, &symrefs, entry)for((pe) = ((&symrefs)->tqh_first); (pe) != ((void *)0 ); (pe) = ((pe)->entry.tqe_next)) { | ||||
1111 | free((void *)pe->path); | ||||
1112 | free(pe->data); | ||||
1113 | } | ||||
1114 | got_pathlist_free(&symrefs); | ||||
1115 | free(have); | ||||
1116 | free(want); | ||||
1117 | free(id_str); | ||||
1118 | free(refname); | ||||
1119 | free(server_capabilities); | ||||
1120 | return err; | ||||
1121 | } | ||||
1122 | |||||
1123 | |||||
1124 | int | ||||
1125 | main(int argc, char **argv) | ||||
1126 | { | ||||
1127 | const struct got_error *err = NULL((void *)0); | ||||
1128 | int fetchfd, packfd = -1, i; | ||||
1129 | uint8_t pack_sha1[SHA1_DIGEST_LENGTH20]; | ||||
1130 | struct imsgbuf ibuf; | ||||
1131 | struct imsg imsg; | ||||
1132 | struct got_pathlist_head have_refs; | ||||
1133 | struct got_pathlist_head wanted_branches; | ||||
1134 | struct got_pathlist_head wanted_refs; | ||||
1135 | struct got_pathlist_entry *pe; | ||||
1136 | struct got_imsg_fetch_request fetch_req; | ||||
1137 | struct got_imsg_fetch_have_ref href; | ||||
1138 | struct got_imsg_fetch_wanted_branch wbranch; | ||||
1139 | struct got_imsg_fetch_wanted_ref wref; | ||||
1140 | size_t datalen; | ||||
1141 | #if 0 | ||||
1142 | static int attached; | ||||
1143 | while (!attached) | ||||
1144 | sleep (1); | ||||
1145 | #endif | ||||
1146 | |||||
1147 | TAILQ_INIT(&have_refs)do { (&have_refs)->tqh_first = ((void *)0); (&have_refs )->tqh_last = &(&have_refs)->tqh_first; } while (0); | ||||
1148 | TAILQ_INIT(&wanted_branches)do { (&wanted_branches)->tqh_first = ((void *)0); (& wanted_branches)->tqh_last = &(&wanted_branches)-> tqh_first; } while (0); | ||||
1149 | TAILQ_INIT(&wanted_refs)do { (&wanted_refs)->tqh_first = ((void *)0); (&wanted_refs )->tqh_last = &(&wanted_refs)->tqh_first; } while (0); | ||||
1150 | |||||
1151 | imsg_init(&ibuf, GOT_IMSG_FD_CHILD(2 + 1)); | ||||
1152 | #ifndef PROFILE | ||||
1153 | /* revoke access to most system calls */ | ||||
1154 | if (pledge("stdio recvfd", NULL((void *)0)) == -1) { | ||||
1155 | err = got_error_from_errno("pledge"); | ||||
1156 | got_privsep_send_error(&ibuf, err); | ||||
1157 | return 1; | ||||
1158 | } | ||||
1159 | #endif | ||||
1160 | if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) { | ||||
1161 | if (err->code == GOT_ERR_PRIVSEP_PIPE37) | ||||
1162 | err = NULL((void *)0); | ||||
1163 | goto done; | ||||
1164 | } | ||||
1165 | if (imsg.hdr.type == GOT_IMSG_STOP) | ||||
1166 | goto done; | ||||
1167 | if (imsg.hdr.type != GOT_IMSG_FETCH_REQUEST) { | ||||
1168 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | ||||
1169 | goto done; | ||||
1170 | } | ||||
1171 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | ||||
1172 | if (datalen < sizeof(fetch_req)) { | ||||
1173 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | ||||
1174 | goto done; | ||||
1175 | } | ||||
1176 | memcpy(&fetch_req, imsg.data, sizeof(fetch_req)); | ||||
1177 | fetchfd = imsg.fd; | ||||
1178 | imsg_free(&imsg); | ||||
1179 | |||||
1180 | if (fetch_req.verbosity > 0) | ||||
1181 | chattygot += fetch_req.verbosity; | ||||
1182 | |||||
1183 | for (i = 0; i < fetch_req.n_have_refs; i++) { | ||||
1184 | struct got_object_id *id; | ||||
1185 | char *refname; | ||||
1186 | |||||
1187 | if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) { | ||||
1188 | if (err->code == GOT_ERR_PRIVSEP_PIPE37) | ||||
1189 | err = NULL((void *)0); | ||||
1190 | goto done; | ||||
1191 | } | ||||
1192 | if (imsg.hdr.type == GOT_IMSG_STOP) | ||||
1193 | goto done; | ||||
1194 | if (imsg.hdr.type != GOT_IMSG_FETCH_HAVE_REF) { | ||||
1195 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | ||||
1196 | goto done; | ||||
1197 | } | ||||
1198 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | ||||
1199 | if (datalen < sizeof(href)) { | ||||
1200 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | ||||
1201 | goto done; | ||||
1202 | } | ||||
1203 | memcpy(&href, imsg.data, sizeof(href)); | ||||
1204 | if (datalen - sizeof(href) < href.name_len) { | ||||
1205 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | ||||
1206 | goto done; | ||||
1207 | } | ||||
1208 | refname = malloc(href.name_len + 1); | ||||
1209 | if (refname == NULL((void *)0)) { | ||||
1210 | err = got_error_from_errno("malloc"); | ||||
1211 | goto done; | ||||
1212 | } | ||||
1213 | memcpy(refname, imsg.data + sizeof(href), href.name_len); | ||||
1214 | refname[href.name_len] = '\0'; | ||||
1215 | |||||
1216 | id = malloc(sizeof(*id)); | ||||
1217 | if (id == NULL((void *)0)) { | ||||
1218 | free(refname); | ||||
1219 | err = got_error_from_errno("malloc"); | ||||
1220 | goto done; | ||||
1221 | } | ||||
1222 | memcpy(id->sha1, href.id, SHA1_DIGEST_LENGTH20); | ||||
1223 | err = got_pathlist_append(&have_refs, refname, id); | ||||
1224 | if (err) { | ||||
1225 | free(refname); | ||||
1226 | free(id); | ||||
1227 | goto done; | ||||
1228 | } | ||||
1229 | |||||
1230 | imsg_free(&imsg); | ||||
1231 | } | ||||
1232 | |||||
1233 | for (i = 0; i < fetch_req.n_wanted_branches; i++) { | ||||
1234 | char *refname; | ||||
1235 | |||||
1236 | if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) { | ||||
1237 | if (err->code == GOT_ERR_PRIVSEP_PIPE37) | ||||
1238 | err = NULL((void *)0); | ||||
1239 | goto done; | ||||
1240 | } | ||||
1241 | if (imsg.hdr.type == GOT_IMSG_STOP) | ||||
1242 | goto done; | ||||
1243 | if (imsg.hdr.type != GOT_IMSG_FETCH_WANTED_BRANCH) { | ||||
1244 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | ||||
1245 | goto done; | ||||
1246 | } | ||||
1247 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | ||||
1248 | if (datalen < sizeof(wbranch)) { | ||||
1249 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | ||||
1250 | goto done; | ||||
1251 | } | ||||
1252 | memcpy(&wbranch, imsg.data, sizeof(wbranch)); | ||||
1253 | if (datalen - sizeof(wbranch) < wbranch.name_len) { | ||||
1254 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | ||||
1255 | goto done; | ||||
1256 | } | ||||
1257 | refname = malloc(wbranch.name_len + 1); | ||||
1258 | if (refname == NULL((void *)0)) { | ||||
1259 | err = got_error_from_errno("malloc"); | ||||
1260 | goto done; | ||||
1261 | } | ||||
1262 | memcpy(refname, imsg.data + sizeof(wbranch), wbranch.name_len); | ||||
1263 | refname[wbranch.name_len] = '\0'; | ||||
1264 | |||||
1265 | err = got_pathlist_append(&wanted_branches, refname, NULL((void *)0)); | ||||
1266 | if (err) { | ||||
1267 | free(refname); | ||||
1268 | goto done; | ||||
1269 | } | ||||
1270 | |||||
1271 | imsg_free(&imsg); | ||||
1272 | } | ||||
1273 | |||||
1274 | for (i = 0; i < fetch_req.n_wanted_refs; i++) { | ||||
1275 | char *refname; | ||||
1276 | |||||
1277 | if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) { | ||||
1278 | if (err->code == GOT_ERR_PRIVSEP_PIPE37) | ||||
1279 | err = NULL((void *)0); | ||||
1280 | goto done; | ||||
1281 | } | ||||
1282 | if (imsg.hdr.type == GOT_IMSG_STOP) | ||||
1283 | goto done; | ||||
1284 | if (imsg.hdr.type != GOT_IMSG_FETCH_WANTED_REF) { | ||||
1285 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | ||||
1286 | goto done; | ||||
1287 | } | ||||
1288 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | ||||
1289 | if (datalen < sizeof(wref)) { | ||||
1290 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | ||||
1291 | goto done; | ||||
1292 | } | ||||
1293 | memcpy(&wref, imsg.data, sizeof(wref)); | ||||
1294 | if (datalen - sizeof(wref) < wref.name_len) { | ||||
1295 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | ||||
1296 | goto done; | ||||
1297 | } | ||||
1298 | refname = malloc(wref.name_len + 1); | ||||
1299 | if (refname == NULL((void *)0)) { | ||||
1300 | err = got_error_from_errno("malloc"); | ||||
1301 | goto done; | ||||
1302 | } | ||||
1303 | memcpy(refname, imsg.data + sizeof(wref), wref.name_len); | ||||
1304 | refname[wref.name_len] = '\0'; | ||||
1305 | |||||
1306 | err = got_pathlist_append(&wanted_refs, refname, NULL((void *)0)); | ||||
1307 | if (err) { | ||||
1308 | free(refname); | ||||
1309 | goto done; | ||||
1310 | } | ||||
1311 | |||||
1312 | imsg_free(&imsg); | ||||
1313 | } | ||||
1314 | |||||
1315 | if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) { | ||||
1316 | if (err->code == GOT_ERR_PRIVSEP_PIPE37) | ||||
1317 | err = NULL((void *)0); | ||||
1318 | goto done; | ||||
1319 | } | ||||
1320 | if (imsg.hdr.type == GOT_IMSG_STOP) | ||||
1321 | goto done; | ||||
1322 | if (imsg.hdr.type != GOT_IMSG_FETCH_OUTFD) { | ||||
1323 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | ||||
1324 | goto done; | ||||
1325 | } | ||||
1326 | if (imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr) != 0) { | ||||
1327 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | ||||
1328 | goto done; | ||||
1329 | } | ||||
1330 | packfd = imsg.fd; | ||||
1331 | |||||
1332 | err = fetch_pack(fetchfd, packfd, pack_sha1, &have_refs, | ||||
1333 | fetch_req.fetch_all_branches, &wanted_branches, | ||||
1334 | &wanted_refs, fetch_req.list_refs_only, &ibuf); | ||||
1335 | done: | ||||
1336 | TAILQ_FOREACH(pe, &have_refs, entry)for((pe) = ((&have_refs)->tqh_first); (pe) != ((void * )0); (pe) = ((pe)->entry.tqe_next)) { | ||||
1337 | free((char *)pe->path); | ||||
1338 | free(pe->data); | ||||
1339 | } | ||||
1340 | got_pathlist_free(&have_refs); | ||||
1341 | TAILQ_FOREACH(pe, &wanted_branches, entry)for((pe) = ((&wanted_branches)->tqh_first); (pe) != (( void *)0); (pe) = ((pe)->entry.tqe_next)) | ||||
1342 | free((char *)pe->path); | ||||
1343 | got_pathlist_free(&wanted_branches); | ||||
1344 | if (fetchfd != -1 && close(fetchfd) == -1 && err == NULL((void *)0)) | ||||
1345 | err = got_error_from_errno("close"); | ||||
1346 | if (packfd != -1 && close(packfd) == -1 && err == NULL((void *)0)) | ||||
1347 | err = got_error_from_errno("close"); | ||||
1348 | if (err != NULL((void *)0)) | ||||
1349 | got_privsep_send_error(&ibuf, err); | ||||
1350 | else | ||||
1351 | err = send_fetch_done(&ibuf, pack_sha1); | ||||
1352 | if (err != NULL((void *)0)) { | ||||
1353 | fprintf(stderr(&__sF[2]), "%s: %s\n", getprogname(), err->msg); | ||||
1354 | got_privsep_send_error(&ibuf, err); | ||||
1355 | } | ||||
1356 | |||||
1357 | exit(0); | ||||
1358 | } |