Bug Summary

File:libexec/got-fetch-pack/got-fetch-pack.c
Warning:line 738, column 7
Null pointer passed as 1st argument to string comparison function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd6.9 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name got-fetch-pack.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/local/lib/clang/11.1.0 -I /home/ben/Projects/got/libexec/got-fetch-pack/../../include -I /home/ben/Projects/got/libexec/got-fetch-pack/../../lib -D GOT_LIBEXECDIR=/home/ben/bin -D GOT_VERSION=0.53-current -internal-isystem /usr/local/lib/clang/11.1.0/include -internal-externc-isystem /usr/include -O0 -fdebug-compilation-dir /home/ben/Projects/got/libexec/got-fetch-pack/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/got/scan/2021-05-28-230913-68537-1 -x c /home/ben/Projects/got/libexec/got-fetch-pack/got-fetch-pack.c
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
56struct got_object *indexed;
57static int chattygot;
58static struct got_object_id zhash = {.sha1={0}};
59
60static const struct got_error *
61readn(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
77static const struct got_error *
78flushpkt(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 */
97static const struct got_error *
98read_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
156static const struct got_error *
157readpkt(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)
9
Assuming 'err' is null
10
Taking false branch
74
Assuming 'err' is null
75
Taking false branch
165 return err;
166
167 if (datalen > buflen)
11
Assuming 'datalen' is <= 'buflen'
12
Taking false branch
76
Assuming 'datalen' is > 'buflen'
77
Taking true branch
168 return got_error(GOT_ERR_NO_SPACE9);
78
Returning pointer, which participates in a condition later
169
170 err = readn(&n, fd, buf, datalen);
171 if (err)
13
Assuming 'err' is null
14
Taking false branch
172 return err;
173 if (n != datalen)
15
Assuming 'n' is equal to 'datalen'
16
Taking false branch
174 return got_error_msg(GOT_ERR_BAD_PACKET122, "short packet");
175
176 if (chattygot > 1) {
17
Assuming 'chattygot' is <= 1
18
Taking false branch
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);
19
Returning null pointer, which participates in a condition later
189}
190
191static const struct got_error *
192writepkt(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
223static void
224match_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
242static int
243match_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
254static int
255match_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
281static const struct got_error *
282tokenize_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++)
27
Loop condition is true. Entering loop body
28
Loop condition is true. Entering loop body
29
Loop condition is true. Entering loop body
30
Loop condition is false. Execution continues on line 291
289 tokens[i] = NULL((void *)0);
290
291 for (i = 0; n
30.1
'n' is < 'len'
< len && i < maxtokens; i++) {
31
Loop condition is true. Entering loop body
292 while (isspace(*line)) {
32
Loop condition is false. Execution continues on line 296
293 line++;
294 n++;
295 }
296 p = line;
297 while (*line != '\0' &&
33
Assuming the condition is false
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)) {
34
Assuming the condition is true
35
Taking true branch
304 err = got_error_from_errno("strndup");
305 goto done;
36
Control jumps to line 316
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);
315done:
316 if (err) {
37
Assuming 'err' is null, which participates in a condition later
38
Taking false branch
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;
39
Returning null pointer (loaded from 'err'), which participates in a condition later
324}
325
326static const struct got_error *
327parse_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])));
26
Calling 'tokenize_refline'
40
Returning from 'tokenize_refline'
334 if (err
40.1
'err' is null
)
41
Taking false branch
84
Assuming 'err' is null
85
Taking false branch
335 return err;
336
337 if (tokens[0])
42
Taking false branch
86
Assuming the condition is false
87
Taking false branch
338 *id_str = tokens[0];
339 if (tokens[1])
43
Taking false branch
88
Assuming the condition is false
89
Taking false branch
340 *refname = tokens[1];
341 if (tokens[2]) {
44
Taking false branch
90
Assuming the condition is false
91
Taking false branch
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);
45
Returning without writing to '*refname'
46
Returning null pointer, which participates in a condition later
92
Returning without writing to '*refname'
93
Returning null pointer, which participates in a condition later
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
361struct got_capability {
362 const char *key;
363 const char *value;
364};
365static 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
371static const struct got_error *
372match_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
399static const struct got_error *
400add_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);
426done:
427 if (err) {
428 free(name);
429 free(target);
430 }
431 return err;
432}
433
434static const struct got_error *
435match_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
51.1
'capa' is equal to NULL
== NULL((void *)0))
52
Taking true branch
446 return NULL((void *)0);
53
Returning null pointer, which participates in a condition later
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
473static const struct got_error *
474send_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
490static const struct got_error *
491send_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
501static const struct got_error *
502send_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
512static const struct got_error *
513fetch_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
539static const struct got_error *
540fetch_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
555static const struct got_error *
556send_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))
{
58
Loop condition is false. Execution continues on line 571
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))
59
Taking false branch
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))
60
Assuming 'wbuf' is not equal to NULL
61
Taking false branch
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) {
62
Assuming the condition is false
63
Taking false branch
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))
{
64
Loop condition is false. Execution continues on line 614
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);
65
Returning pointer, which participates in a condition later
617}
618
619static const struct got_error *
620send_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
652static const struct got_error *
653fetch_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);
1
'refname' initialized to a null pointer value
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)
;
2
Loop condition is false. Exiting loop
679 SHA1Init(&sha1_ctx);
680
681 have = malloc(refsz * sizeof(have[0]));
682 if (have == NULL((void *)0))
3
Assuming 'have' is not equal to NULL
4
Taking false branch
683 return got_error_from_errno("malloc");
684 want = malloc(refsz * sizeof(want[0]));
685 if (want == NULL((void *)0)) {
5
Assuming 'want' is not equal to NULL
6
Taking false branch
686 err = got_error_from_errno("malloc");
687 goto done;
688 }
689 while (1) {
7
Loop condition is true. Entering loop body
72
Loop condition is true. Entering loop body
690 err = readpkt(&n, fd, buf, sizeof(buf));
8
Calling 'readpkt'
20
Returning from 'readpkt'
73
Calling 'readpkt'
79
Returning from 'readpkt'
691 if (err
20.1
'err' is null
)
21
Taking false branch
80
Assuming 'err' is null
81
Taking false branch
692 goto done;
693 if (n
81.1
'n' is not equal to 0
== 0
)
22
Assuming 'n' is not equal to 0
23
Taking false branch
82
Taking false branch
694 break;
695 if (n
82.1
'n' is < 4
>= 4
&& strncmp(buf, "ERR ", 4) == 0) {
24
Assuming 'n' is < 4
696 err = fetch_error(&buf[4], n - 4);
697 goto done;
698 }
699 err = parse_refline(&id_str, &refname, &server_capabilities,
25
Calling 'parse_refline'
47
Returning from 'parse_refline'
83
Calling 'parse_refline'
94
Returning from 'parse_refline'
700 buf, n);
701 if (err
47.1
'err' is null
94.1
'err' is null
)
48
Taking false branch
95
Taking false branch
702 goto done;
703 if (is_firstpkt
48.1
'is_firstpkt' is 1
95.1
'is_firstpkt' is 0
) {
49
Taking true branch
96
Taking false branch
704 if (chattygot && server_capabilities[0] != '\0')
50
Assuming 'chattygot' is 0
705 fprintf(stderr(&__sF[2]), "%s: server capabilities: %s\n",
706 getprogname(), server_capabilities);
707 err = match_capabilities(&my_capabilities, &symrefs,
51
Calling 'match_capabilities'
54
Returning from 'match_capabilities'
708 server_capabilities);
709 if (err
54.1
'err' is null
)
55
Taking false branch
710 goto done;
711 if (chattygot
55.1
'chattygot' is 0
)
56
Taking false branch
712 fprintf(stderr(&__sF[2]), "%s: my capabilities:%s\n",
713 getprogname(), my_capabilities);
714 err = send_fetch_symrefs(ibuf, &symrefs);
57
Calling 'send_fetch_symrefs'
66
Returning from 'send_fetch_symrefs'
715 if (err)
67
Assuming 'err' is null
68
Taking false branch
716 goto done;
717 is_firstpkt = 0;
718 if (!fetch_all_branches) {
69
Assuming 'fetch_all_branches' is not equal to 0
70
Taking false branch
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;
71
Execution continues on line 689
729 }
730 if (strstr(refname, "^{}")) {
97
Assuming the condition is false
98
Taking false branch
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) {
99
Null pointer passed as 1st argument to string comparison function
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 }
1109done:
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
1124int
1125main(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);
1335done:
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}