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