]>
Commit | Line | Data |
---|---|---|
f7fc68df | 1 | /* |
359fc2d2 | 2 | * Copyright (C) the libgit2 contributors. All rights reserved. |
f7fc68df | 3 | * |
bb742ede VM |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
f7fc68df CMN |
6 | */ |
7 | ||
bdd18829 VM |
8 | #include "common.h" |
9 | ||
41fb1ca0 | 10 | #include "smart.h" |
f7fc68df | 11 | #include "util.h" |
c4d0fa85 | 12 | #include "netops.h" |
84dd3820 | 13 | #include "posix.h" |
e579e0f7 MB |
14 | #include "str.h" |
15 | ||
16 | #include "git2/types.h" | |
17 | #include "git2/errors.h" | |
18 | #include "git2/refs.h" | |
19 | #include "git2/revwalk.h" | |
f7fc68df | 20 | |
7632e249 CMN |
21 | #include <ctype.h> |
22 | ||
23 | #define PKT_LEN_SIZE 4 | |
3707b331 CMN |
24 | static const char pkt_done_str[] = "0009done\n"; |
25 | static const char pkt_flush_str[] = "0000"; | |
26 | static const char pkt_have_prefix[] = "0032have "; | |
27 | static const char pkt_want_prefix[] = "0032want "; | |
7632e249 | 28 | |
1d27446c CMN |
29 | static int flush_pkt(git_pkt **out) |
30 | { | |
31 | git_pkt *pkt; | |
32 | ||
6762fe08 | 33 | pkt = git__malloc(sizeof(git_pkt)); |
ac3d33df | 34 | GIT_ERROR_CHECK_ALLOC(pkt); |
1d27446c CMN |
35 | |
36 | pkt->type = GIT_PKT_FLUSH; | |
37 | *out = pkt; | |
38 | ||
84d250bf | 39 | return 0; |
1d27446c CMN |
40 | } |
41 | ||
2f8c481c | 42 | /* the rest of the line will be useful for multi_ack and multi_ack_detailed */ |
854eccbb | 43 | static int ack_pkt(git_pkt **out, const char *line, size_t len) |
7e1a94db | 44 | { |
b49c8f71 | 45 | git_pkt_ack *pkt; |
7e1a94db | 46 | |
6762fe08 | 47 | pkt = git__calloc(1, sizeof(git_pkt_ack)); |
ac3d33df | 48 | GIT_ERROR_CHECK_ALLOC(pkt); |
7e1a94db | 49 | pkt->type = GIT_PKT_ACK; |
b49c8f71 | 50 | |
6c7cee42 RD |
51 | if (git__prefixncmp(line, len, "ACK ")) |
52 | goto out_err; | |
53 | line += 4; | |
54 | len -= 4; | |
55 | ||
56 | if (len < GIT_OID_HEXSZ || git_oid_fromstr(&pkt->oid, line) < 0) | |
57 | goto out_err; | |
58 | line += GIT_OID_HEXSZ; | |
59 | len -= GIT_OID_HEXSZ; | |
b49c8f71 | 60 | |
6c7cee42 RD |
61 | if (len && line[0] == ' ') { |
62 | line++; | |
63 | len--; | |
64 | ||
65 | if (!git__prefixncmp(line, len, "continue")) | |
b49c8f71 | 66 | pkt->status = GIT_ACK_CONTINUE; |
6c7cee42 | 67 | else if (!git__prefixncmp(line, len, "common")) |
2f8c481c | 68 | pkt->status = GIT_ACK_COMMON; |
6c7cee42 | 69 | else if (!git__prefixncmp(line, len, "ready")) |
2f8c481c | 70 | pkt->status = GIT_ACK_READY; |
6c7cee42 RD |
71 | else |
72 | goto out_err; | |
b49c8f71 CMN |
73 | } |
74 | ||
75 | *out = (git_pkt *) pkt; | |
7e1a94db | 76 | |
84d250bf | 77 | return 0; |
6c7cee42 RD |
78 | |
79 | out_err: | |
ac3d33df | 80 | git_error_set(GIT_ERROR_NET, "error parsing ACK pkt-line"); |
6c7cee42 RD |
81 | git__free(pkt); |
82 | return -1; | |
7e1a94db CMN |
83 | } |
84 | ||
da290220 | 85 | static int nak_pkt(git_pkt **out) |
7e1a94db CMN |
86 | { |
87 | git_pkt *pkt; | |
88 | ||
6762fe08 | 89 | pkt = git__malloc(sizeof(git_pkt)); |
ac3d33df | 90 | GIT_ERROR_CHECK_ALLOC(pkt); |
7e1a94db | 91 | |
da290220 CMN |
92 | pkt->type = GIT_PKT_NAK; |
93 | *out = pkt; | |
94 | ||
84d250bf | 95 | return 0; |
da290220 CMN |
96 | } |
97 | ||
b76f7522 CMN |
98 | static int comment_pkt(git_pkt **out, const char *line, size_t len) |
99 | { | |
100 | git_pkt_comment *pkt; | |
f1453c59 | 101 | size_t alloclen; |
b76f7522 | 102 | |
ac3d33df JK |
103 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_comment), len); |
104 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); | |
f1453c59 | 105 | pkt = git__malloc(alloclen); |
ac3d33df | 106 | GIT_ERROR_CHECK_ALLOC(pkt); |
b76f7522 CMN |
107 | |
108 | pkt->type = GIT_PKT_COMMENT; | |
109 | memcpy(pkt->comment, line, len); | |
110 | pkt->comment[len] = '\0'; | |
111 | ||
112 | *out = (git_pkt *) pkt; | |
113 | ||
84d250bf | 114 | return 0; |
b76f7522 CMN |
115 | } |
116 | ||
39e6af6a CMN |
117 | static int err_pkt(git_pkt **out, const char *line, size_t len) |
118 | { | |
6c7cee42 | 119 | git_pkt_err *pkt = NULL; |
f1453c59 | 120 | size_t alloclen; |
39e6af6a CMN |
121 | |
122 | /* Remove "ERR " from the line */ | |
6c7cee42 RD |
123 | if (git__prefixncmp(line, len, "ERR ")) |
124 | goto out_err; | |
39e6af6a CMN |
125 | line += 4; |
126 | len -= 4; | |
392702ee | 127 | |
ac3d33df JK |
128 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len); |
129 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); | |
f1453c59 | 130 | pkt = git__malloc(alloclen); |
ac3d33df | 131 | GIT_ERROR_CHECK_ALLOC(pkt); |
39e6af6a | 132 | pkt->type = GIT_PKT_ERR; |
6c7cee42 RD |
133 | pkt->len = len; |
134 | ||
39e6af6a CMN |
135 | memcpy(pkt->error, line, len); |
136 | pkt->error[len] = '\0'; | |
137 | ||
138 | *out = (git_pkt *) pkt; | |
139 | ||
140 | return 0; | |
6c7cee42 RD |
141 | |
142 | out_err: | |
ac3d33df | 143 | git_error_set(GIT_ERROR_NET, "error parsing ERR pkt-line"); |
6c7cee42 RD |
144 | git__free(pkt); |
145 | return -1; | |
39e6af6a CMN |
146 | } |
147 | ||
e03e71da CMN |
148 | static int data_pkt(git_pkt **out, const char *line, size_t len) |
149 | { | |
150 | git_pkt_data *pkt; | |
f1453c59 | 151 | size_t alloclen; |
e03e71da CMN |
152 | |
153 | line++; | |
154 | len--; | |
392702ee | 155 | |
ac3d33df | 156 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len); |
f1453c59 | 157 | pkt = git__malloc(alloclen); |
ac3d33df | 158 | GIT_ERROR_CHECK_ALLOC(pkt); |
e03e71da CMN |
159 | |
160 | pkt->type = GIT_PKT_DATA; | |
6c7cee42 | 161 | pkt->len = len; |
e03e71da CMN |
162 | memcpy(pkt->data, line, len); |
163 | ||
164 | *out = (git_pkt *) pkt; | |
165 | ||
166 | return 0; | |
167 | } | |
168 | ||
98020d3a | 169 | static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len) |
e03e71da CMN |
170 | { |
171 | git_pkt_progress *pkt; | |
f1453c59 | 172 | size_t alloclen; |
e03e71da CMN |
173 | |
174 | line++; | |
175 | len--; | |
392702ee | 176 | |
ac3d33df | 177 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len); |
f1453c59 | 178 | pkt = git__malloc(alloclen); |
ac3d33df | 179 | GIT_ERROR_CHECK_ALLOC(pkt); |
e03e71da CMN |
180 | |
181 | pkt->type = GIT_PKT_PROGRESS; | |
6c7cee42 | 182 | pkt->len = len; |
e03e71da CMN |
183 | memcpy(pkt->data, line, len); |
184 | ||
185 | *out = (git_pkt *) pkt; | |
186 | ||
187 | return 0; | |
188 | } | |
189 | ||
b8c32580 PK |
190 | static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) |
191 | { | |
192 | git_pkt_err *pkt; | |
f1453c59 | 193 | size_t alloc_len; |
b8c32580 PK |
194 | |
195 | line++; | |
196 | len--; | |
392702ee | 197 | |
ac3d33df JK |
198 | GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, sizeof(git_pkt_err), len); |
199 | GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1); | |
f1453c59 | 200 | pkt = git__malloc(alloc_len); |
ac3d33df | 201 | GIT_ERROR_CHECK_ALLOC(pkt); |
b8c32580 PK |
202 | |
203 | pkt->type = GIT_PKT_ERR; | |
204 | pkt->len = (int)len; | |
205 | memcpy(pkt->error, line, len); | |
206 | pkt->error[len] = '\0'; | |
207 | ||
208 | *out = (git_pkt *)pkt; | |
209 | ||
210 | return 0; | |
211 | } | |
212 | ||
b31803f3 CMN |
213 | /* |
214 | * Parse an other-ref line. | |
215 | */ | |
7e1a94db | 216 | static int ref_pkt(git_pkt **out, const char *line, size_t len) |
b31803f3 CMN |
217 | { |
218 | git_pkt_ref *pkt; | |
f1453c59 | 219 | size_t alloclen; |
b31803f3 | 220 | |
6c7cee42 | 221 | pkt = git__calloc(1, sizeof(git_pkt_ref)); |
ac3d33df | 222 | GIT_ERROR_CHECK_ALLOC(pkt); |
b31803f3 | 223 | pkt->type = GIT_PKT_REF; |
b31803f3 | 224 | |
6c7cee42 RD |
225 | if (len < GIT_OID_HEXSZ || git_oid_fromstr(&pkt->head.oid, line) < 0) |
226 | goto out_err; | |
227 | line += GIT_OID_HEXSZ; | |
228 | len -= GIT_OID_HEXSZ; | |
229 | ||
230 | if (git__prefixncmp(line, len, " ")) | |
231 | goto out_err; | |
232 | line++; | |
233 | len--; | |
234 | ||
235 | if (!len) | |
236 | goto out_err; | |
b31803f3 | 237 | |
7632e249 CMN |
238 | if (line[len - 1] == '\n') |
239 | --len; | |
b31803f3 | 240 | |
ac3d33df | 241 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, len, 1); |
f1453c59 | 242 | pkt->head.name = git__malloc(alloclen); |
ac3d33df | 243 | GIT_ERROR_CHECK_ALLOC(pkt->head.name); |
84d250bf | 244 | |
7632e249 CMN |
245 | memcpy(pkt->head.name, line, len); |
246 | pkt->head.name[len] = '\0'; | |
b31803f3 | 247 | |
6c7cee42 | 248 | if (strlen(pkt->head.name) < len) |
7632e249 | 249 | pkt->capabilities = strchr(pkt->head.name, '\0') + 1; |
8b9e8de5 | 250 | |
84d250bf | 251 | *out = (git_pkt *)pkt; |
84d250bf CMN |
252 | return 0; |
253 | ||
6c7cee42 | 254 | out_err: |
ac3d33df | 255 | git_error_set(GIT_ERROR_NET, "error parsing REF pkt-line"); |
6c7cee42 RD |
256 | if (pkt) |
257 | git__free(pkt->head.name); | |
84d250bf | 258 | git__free(pkt); |
6c7cee42 | 259 | return -1; |
b31803f3 CMN |
260 | } |
261 | ||
613d5eb9 PK |
262 | static int ok_pkt(git_pkt **out, const char *line, size_t len) |
263 | { | |
264 | git_pkt_ok *pkt; | |
f1453c59 | 265 | size_t alloc_len; |
613d5eb9 | 266 | |
6762fe08 | 267 | pkt = git__malloc(sizeof(*pkt)); |
ac3d33df | 268 | GIT_ERROR_CHECK_ALLOC(pkt); |
613d5eb9 PK |
269 | pkt->type = GIT_PKT_OK; |
270 | ||
6c7cee42 RD |
271 | if (git__prefixncmp(line, len, "ok ")) |
272 | goto out_err; | |
273 | line += 3; | |
274 | len -= 3; | |
275 | ||
22a2d3d5 | 276 | if (len && line[len - 1] == '\n') |
6c7cee42 | 277 | --len; |
613d5eb9 | 278 | |
ac3d33df | 279 | GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, len, 1); |
f1453c59 | 280 | pkt->ref = git__malloc(alloc_len); |
ac3d33df | 281 | GIT_ERROR_CHECK_ALLOC(pkt->ref); |
613d5eb9 PK |
282 | |
283 | memcpy(pkt->ref, line, len); | |
284 | pkt->ref[len] = '\0'; | |
285 | ||
286 | *out = (git_pkt *)pkt; | |
287 | return 0; | |
6c7cee42 RD |
288 | |
289 | out_err: | |
ac3d33df | 290 | git_error_set(GIT_ERROR_NET, "error parsing OK pkt-line"); |
6c7cee42 RD |
291 | git__free(pkt); |
292 | return -1; | |
613d5eb9 PK |
293 | } |
294 | ||
295 | static int ng_pkt(git_pkt **out, const char *line, size_t len) | |
296 | { | |
297 | git_pkt_ng *pkt; | |
6c7cee42 | 298 | const char *ptr, *eol; |
f1453c59 | 299 | size_t alloclen; |
613d5eb9 | 300 | |
6762fe08 | 301 | pkt = git__malloc(sizeof(*pkt)); |
ac3d33df | 302 | GIT_ERROR_CHECK_ALLOC(pkt); |
613d5eb9 | 303 | |
003c5e46 | 304 | pkt->ref = NULL; |
613d5eb9 PK |
305 | pkt->type = GIT_PKT_NG; |
306 | ||
6c7cee42 RD |
307 | eol = line + len; |
308 | ||
309 | if (git__prefixncmp(line, len, "ng ")) | |
4b3ec53c | 310 | goto out_err; |
6c7cee42 RD |
311 | line += 3; |
312 | ||
313 | if (!(ptr = memchr(line, ' ', eol - line))) | |
003c5e46 | 314 | goto out_err; |
613d5eb9 PK |
315 | len = ptr - line; |
316 | ||
ac3d33df | 317 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, len, 1); |
f1453c59 | 318 | pkt->ref = git__malloc(alloclen); |
ac3d33df | 319 | GIT_ERROR_CHECK_ALLOC(pkt->ref); |
613d5eb9 PK |
320 | |
321 | memcpy(pkt->ref, line, len); | |
322 | pkt->ref[len] = '\0'; | |
323 | ||
324 | line = ptr + 1; | |
6c7cee42 RD |
325 | if (line >= eol) |
326 | goto out_err; | |
327 | ||
328 | if (!(ptr = memchr(line, '\n', eol - line))) | |
003c5e46 | 329 | goto out_err; |
613d5eb9 PK |
330 | len = ptr - line; |
331 | ||
ac3d33df | 332 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, len, 1); |
f1453c59 | 333 | pkt->msg = git__malloc(alloclen); |
ac3d33df | 334 | GIT_ERROR_CHECK_ALLOC(pkt->msg); |
613d5eb9 PK |
335 | |
336 | memcpy(pkt->msg, line, len); | |
337 | pkt->msg[len] = '\0'; | |
338 | ||
339 | *out = (git_pkt *)pkt; | |
340 | return 0; | |
003c5e46 PS |
341 | |
342 | out_err: | |
ac3d33df | 343 | git_error_set(GIT_ERROR_NET, "invalid packet line"); |
003c5e46 PS |
344 | git__free(pkt->ref); |
345 | git__free(pkt); | |
346 | return -1; | |
613d5eb9 PK |
347 | } |
348 | ||
349 | static int unpack_pkt(git_pkt **out, const char *line, size_t len) | |
350 | { | |
351 | git_pkt_unpack *pkt; | |
352 | ||
6762fe08 | 353 | pkt = git__malloc(sizeof(*pkt)); |
ac3d33df | 354 | GIT_ERROR_CHECK_ALLOC(pkt); |
613d5eb9 | 355 | pkt->type = GIT_PKT_UNPACK; |
6c7cee42 RD |
356 | |
357 | if (!git__prefixncmp(line, len, "unpack ok")) | |
613d5eb9 PK |
358 | pkt->unpack_ok = 1; |
359 | else | |
360 | pkt->unpack_ok = 0; | |
361 | ||
362 | *out = (git_pkt *)pkt; | |
363 | return 0; | |
364 | } | |
365 | ||
6c7cee42 | 366 | static int parse_len(size_t *out, const char *line, size_t linelen) |
7632e249 CMN |
367 | { |
368 | char num[PKT_LEN_SIZE + 1]; | |
2d1d2bb5 | 369 | int i, k, error; |
44ef8b1b | 370 | int32_t len; |
7632e249 CMN |
371 | const char *num_end; |
372 | ||
6c7cee42 RD |
373 | /* Not even enough for the length */ |
374 | if (linelen < PKT_LEN_SIZE) | |
375 | return GIT_EBUFS; | |
376 | ||
7632e249 CMN |
377 | memcpy(num, line, PKT_LEN_SIZE); |
378 | num[PKT_LEN_SIZE] = '\0'; | |
379 | ||
380 | for (i = 0; i < PKT_LEN_SIZE; ++i) { | |
44ef8b1b | 381 | if (!isxdigit(num[i])) { |
2d1d2bb5 AB |
382 | /* Make sure there are no special characters before passing to error message */ |
383 | for (k = 0; k < PKT_LEN_SIZE; ++k) { | |
384 | if(!isprint(num[k])) { | |
385 | num[k] = '.'; | |
386 | } | |
387 | } | |
6c7cee42 | 388 | |
ac3d33df | 389 | git_error_set(GIT_ERROR_NET, "invalid hex digit in length: '%s'", num); |
44ef8b1b RB |
390 | return -1; |
391 | } | |
7632e249 CMN |
392 | } |
393 | ||
6c7cee42 | 394 | if ((error = git__strntol32(&len, num, PKT_LEN_SIZE, &num_end, 16)) < 0) |
44ef8b1b | 395 | return error; |
7632e249 | 396 | |
6c7cee42 RD |
397 | if (len < 0) |
398 | return -1; | |
399 | ||
400 | *out = (size_t) len; | |
401 | return 0; | |
7632e249 CMN |
402 | } |
403 | ||
f7fc68df CMN |
404 | /* |
405 | * As per the documentation, the syntax is: | |
406 | * | |
87d9869f VM |
407 | * pkt-line = data-pkt / flush-pkt |
408 | * data-pkt = pkt-len pkt-payload | |
409 | * pkt-len = 4*(HEXDIG) | |
f7fc68df | 410 | * pkt-payload = (pkt-len -4)*(OCTET) |
87d9869f | 411 | * flush-pkt = "0000" |
f7fc68df CMN |
412 | * |
413 | * Which means that the first four bytes are the length of the line, | |
414 | * in ASCII hexadecimal (including itself) | |
415 | */ | |
416 | ||
44ef8b1b | 417 | int git_pkt_parse_line( |
6c7cee42 | 418 | git_pkt **pkt, const char **endptr, const char *line, size_t linelen) |
f7fc68df | 419 | { |
6c7cee42 RD |
420 | int error; |
421 | size_t len; | |
78fae478 | 422 | |
6c7cee42 | 423 | if ((error = parse_len(&len, line, linelen)) < 0) { |
da290220 | 424 | /* |
6c7cee42 RD |
425 | * If we fail to parse the length, it might be |
426 | * because the server is trying to send us the | |
427 | * packfile already or because we do not yet have | |
428 | * enough data. | |
da290220 | 429 | */ |
6c7cee42 RD |
430 | if (error == GIT_EBUFS) |
431 | ; | |
432 | else if (!git__prefixncmp(line, linelen, "PACK")) | |
ac3d33df | 433 | git_error_set(GIT_ERROR_NET, "unexpected pack file"); |
6c7cee42 | 434 | else |
ac3d33df | 435 | git_error_set(GIT_ERROR_NET, "bad packet length"); |
6c7cee42 | 436 | return error; |
c7c787ce | 437 | } |
f7fc68df | 438 | |
7632e249 | 439 | /* |
6c7cee42 RD |
440 | * Make sure there is enough in the buffer to satisfy |
441 | * this line. | |
7632e249 | 442 | */ |
6c7cee42 | 443 | if (linelen < len) |
904b67e6 | 444 | return GIT_EBUFS; |
7632e249 | 445 | |
66e3774d PS |
446 | /* |
447 | * The length has to be exactly 0 in case of a flush | |
448 | * packet or greater than PKT_LEN_SIZE, as the decoded | |
449 | * length includes its own encoded length of four bytes. | |
450 | */ | |
451 | if (len != 0 && len < PKT_LEN_SIZE) | |
452 | return GIT_ERROR; | |
453 | ||
7632e249 | 454 | line += PKT_LEN_SIZE; |
f7fc68df | 455 | /* |
2fdef641 PS |
456 | * The Git protocol does not specify empty lines as part |
457 | * of the protocol. Not knowing what to do with an empty | |
458 | * line, we should return an error upon hitting one. | |
f7fc68df | 459 | */ |
7632e249 | 460 | if (len == PKT_LEN_SIZE) { |
ac3d33df | 461 | git_error_set_str(GIT_ERROR_NET, "Invalid empty packet"); |
2fdef641 | 462 | return GIT_ERROR; |
f7fc68df CMN |
463 | } |
464 | ||
1d27446c | 465 | if (len == 0) { /* Flush pkt */ |
6c7cee42 RD |
466 | *endptr = line; |
467 | return flush_pkt(pkt); | |
f7fc68df CMN |
468 | } |
469 | ||
7632e249 | 470 | len -= PKT_LEN_SIZE; /* the encoded length includes its own size */ |
f7fc68df | 471 | |
e03e71da | 472 | if (*line == GIT_SIDE_BAND_DATA) |
6c7cee42 | 473 | error = data_pkt(pkt, line, len); |
e03e71da | 474 | else if (*line == GIT_SIDE_BAND_PROGRESS) |
6c7cee42 | 475 | error = sideband_progress_pkt(pkt, line, len); |
b8c32580 | 476 | else if (*line == GIT_SIDE_BAND_ERROR) |
6c7cee42 RD |
477 | error = sideband_error_pkt(pkt, line, len); |
478 | else if (!git__prefixncmp(line, len, "ACK")) | |
479 | error = ack_pkt(pkt, line, len); | |
480 | else if (!git__prefixncmp(line, len, "NAK")) | |
481 | error = nak_pkt(pkt); | |
482 | else if (!git__prefixncmp(line, len, "ERR")) | |
483 | error = err_pkt(pkt, line, len); | |
b76f7522 | 484 | else if (*line == '#') |
6c7cee42 RD |
485 | error = comment_pkt(pkt, line, len); |
486 | else if (!git__prefixncmp(line, len, "ok")) | |
487 | error = ok_pkt(pkt, line, len); | |
488 | else if (!git__prefixncmp(line, len, "ng")) | |
489 | error = ng_pkt(pkt, line, len); | |
490 | else if (!git__prefixncmp(line, len, "unpack")) | |
491 | error = unpack_pkt(pkt, line, len); | |
7e1a94db | 492 | else |
6c7cee42 | 493 | error = ref_pkt(pkt, line, len); |
b31803f3 | 494 | |
6c7cee42 | 495 | *endptr = line + len; |
b31803f3 | 496 | |
6c7cee42 | 497 | return error; |
f7fc68df | 498 | } |
6a9597c5 | 499 | |
be9fe679 CMN |
500 | void git_pkt_free(git_pkt *pkt) |
501 | { | |
ac3d33df JK |
502 | if (pkt == NULL) { |
503 | return; | |
504 | } | |
44ef8b1b | 505 | if (pkt->type == GIT_PKT_REF) { |
be9fe679 | 506 | git_pkt_ref *p = (git_pkt_ref *) pkt; |
3286c408 | 507 | git__free(p->head.name); |
306475eb | 508 | git__free(p->head.symref_target); |
be9fe679 CMN |
509 | } |
510 | ||
613d5eb9 PK |
511 | if (pkt->type == GIT_PKT_OK) { |
512 | git_pkt_ok *p = (git_pkt_ok *) pkt; | |
513 | git__free(p->ref); | |
514 | } | |
515 | ||
516 | if (pkt->type == GIT_PKT_NG) { | |
517 | git_pkt_ng *p = (git_pkt_ng *) pkt; | |
518 | git__free(p->ref); | |
519 | git__free(p->msg); | |
520 | } | |
521 | ||
3286c408 | 522 | git__free(pkt); |
be9fe679 CMN |
523 | } |
524 | ||
e579e0f7 | 525 | int git_pkt_buffer_flush(git_str *buf) |
65c86048 | 526 | { |
e579e0f7 | 527 | return git_str_put(buf, pkt_flush_str, strlen(pkt_flush_str)); |
65c86048 CMN |
528 | } |
529 | ||
e579e0f7 | 530 | static int buffer_want_with_caps(const git_remote_head *head, transport_smart_caps *caps, git_str *buf) |
0437d991 | 531 | { |
e579e0f7 | 532 | git_str str = GIT_STR_INIT; |
65c86048 | 533 | char oid[GIT_OID_HEXSZ +1] = {0}; |
ec3b4d35 | 534 | size_t len; |
0437d991 | 535 | |
2f8c481c CMN |
536 | /* Prefer multi_ack_detailed */ |
537 | if (caps->multi_ack_detailed) | |
e579e0f7 | 538 | git_str_puts(&str, GIT_CAP_MULTI_ACK_DETAILED " "); |
2f8c481c | 539 | else if (caps->multi_ack) |
e579e0f7 | 540 | git_str_puts(&str, GIT_CAP_MULTI_ACK " "); |
114dc6e1 | 541 | |
2f8c481c CMN |
542 | /* Prefer side-band-64k if the server supports both */ |
543 | if (caps->side_band_64k) | |
e579e0f7 | 544 | git_str_printf(&str, "%s ", GIT_CAP_SIDE_BAND_64K); |
2f8c481c | 545 | else if (caps->side_band) |
e579e0f7 | 546 | git_str_printf(&str, "%s ", GIT_CAP_SIDE_BAND); |
2f8c481c | 547 | |
24f2f94e | 548 | if (caps->include_tag) |
e579e0f7 | 549 | git_str_puts(&str, GIT_CAP_INCLUDE_TAG " "); |
24f2f94e | 550 | |
b4342b11 | 551 | if (caps->thin_pack) |
e579e0f7 | 552 | git_str_puts(&str, GIT_CAP_THIN_PACK " "); |
b4342b11 | 553 | |
2f8c481c | 554 | if (caps->ofs_delta) |
e579e0f7 | 555 | git_str_puts(&str, GIT_CAP_OFS_DELTA " "); |
2f8c481c | 556 | |
e579e0f7 | 557 | if (git_str_oom(&str)) |
114dc6e1 | 558 | return -1; |
0437d991 | 559 | |
ec3b4d35 | 560 | len = strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ + |
e579e0f7 | 561 | git_str_len(&str) + 1 /* LF */; |
ec3b4d35 ET |
562 | |
563 | if (len > 0xffff) { | |
ac3d33df | 564 | git_error_set(GIT_ERROR_NET, |
909d5494 | 565 | "tried to produce packet with invalid length %" PRIuZ, len); |
ec3b4d35 ET |
566 | return -1; |
567 | } | |
568 | ||
e579e0f7 | 569 | git_str_grow_by(buf, len); |
0437d991 | 570 | git_oid_fmt(oid, &head->oid); |
e579e0f7 MB |
571 | git_str_printf(buf, |
572 | "%04xwant %s %s\n", (unsigned int)len, oid, git_str_cstr(&str)); | |
573 | git_str_dispose(&str); | |
114dc6e1 | 574 | |
e579e0f7 | 575 | GIT_ERROR_CHECK_ALLOC_STR(buf); |
6e2a3755 PS |
576 | |
577 | return 0; | |
65c86048 CMN |
578 | } |
579 | ||
0132cf64 CMN |
580 | /* |
581 | * All "want" packets have the same length and format, so what we do | |
582 | * is overwrite the OID each time. | |
583 | */ | |
0132cf64 | 584 | |
41fb1ca0 PK |
585 | int git_pkt_buffer_wants( |
586 | const git_remote_head * const *refs, | |
587 | size_t count, | |
588 | transport_smart_caps *caps, | |
e579e0f7 | 589 | git_str *buf) |
65c86048 | 590 | { |
41fb1ca0 PK |
591 | size_t i = 0; |
592 | const git_remote_head *head; | |
65c86048 CMN |
593 | |
594 | if (caps->common) { | |
41fb1ca0 PK |
595 | for (; i < count; ++i) { |
596 | head = refs[i]; | |
65c86048 CMN |
597 | if (!head->local) |
598 | break; | |
599 | } | |
600 | ||
41fb1ca0 | 601 | if (buffer_want_with_caps(refs[i], caps, buf) < 0) |
84d250bf | 602 | return -1; |
65c86048 CMN |
603 | |
604 | i++; | |
605 | } | |
606 | ||
41fb1ca0 | 607 | for (; i < count; ++i) { |
65c86048 CMN |
608 | char oid[GIT_OID_HEXSZ]; |
609 | ||
41fb1ca0 | 610 | head = refs[i]; |
65c86048 CMN |
611 | if (head->local) |
612 | continue; | |
613 | ||
614 | git_oid_fmt(oid, &head->oid); | |
e579e0f7 MB |
615 | git_str_put(buf, pkt_want_prefix, strlen(pkt_want_prefix)); |
616 | git_str_put(buf, oid, GIT_OID_HEXSZ); | |
617 | git_str_putc(buf, '\n'); | |
618 | if (git_str_oom(buf)) | |
84d250bf | 619 | return -1; |
65c86048 CMN |
620 | } |
621 | ||
622 | return git_pkt_buffer_flush(buf); | |
623 | } | |
624 | ||
e579e0f7 | 625 | int git_pkt_buffer_have(git_oid *oid, git_str *buf) |
65c86048 CMN |
626 | { |
627 | char oidhex[GIT_OID_HEXSZ + 1]; | |
628 | ||
629 | memset(oidhex, 0x0, sizeof(oidhex)); | |
630 | git_oid_fmt(oidhex, oid); | |
e579e0f7 | 631 | return git_str_printf(buf, "%s%s\n", pkt_have_prefix, oidhex); |
65c86048 CMN |
632 | } |
633 | ||
e579e0f7 | 634 | int git_pkt_buffer_done(git_str *buf) |
65c86048 | 635 | { |
e579e0f7 | 636 | return git_str_puts(buf, pkt_done_str); |
65c86048 | 637 | } |