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.h"
11 - #include "git2/odb_backend.h"
12 -
13 - #include "smart.h"
14 - #include "refs.h"
15 - #include "repository.h"
16 - #include "push.h"
17 - #include "pack-objects.h"
18 - #include "remote.h"
19 - #include "util.h"
20 - #include "revwalk.h"
21 -
22 - #define NETWORK_XFER_THRESHOLD (100*1024)
23 - /* The minimal interval between progress updates (in seconds). */
24 - #define MIN_PROGRESS_UPDATE_INTERVAL 0.5
25 -
26 - bool git_smart__ofs_delta_enabled = true;
27 -
28 67 2 int git_smart__store_refs(transport_smart *t, int flushes)
29 - {
30 67 2 gitno_buffer *buf = &t->buffer;
31 67 2 git_vector *refs = &t->refs;
32 67 2 int error, flush = 0, recvd;
33 67 2 const char *line_end = NULL;
34 67 2 git_pkt *pkt = NULL;
35 - size_t i;
36 -
37 - /* Clear existing refs in case git_remote_connect() is called again
38 - * after git_remote_disconnect().
39 - */
40 85 2,4-6 git_vector_foreach(refs, i, pkt) {
41 18 3 git_pkt_free(pkt);
42 - }
43 67 7 git_vector_clear(refs);
44 67 8 pkt = NULL;
45 -
46 - do {
47 754 9 if (buf->offset > 0)
48 582 10 error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset);
49 - else
50 172 11 error = GIT_EBUFS;
51 -
52 754 12,13 if (error < 0 && error != GIT_EBUFS)
53 ##### 14 return error;
54 -
55 754 15 if (error == GIT_EBUFS) {
56 175 16,17 if ((recvd = gitno_recv(buf)) < 0)
57 11 18 return recvd;
58 -
59 164 19 if (recvd == 0) {
60 ##### 20 git_error_set(GIT_ERROR_NET, "early EOF");
61 ##### 21 return GIT_EEOF;
62 - }
63 -
64 164 22 continue;
65 - }
66 -
67 579 23 gitno_consume(buf, line_end);
68 579 24 if (pkt->type == GIT_PKT_ERR) {
69 1 25 git_error_set(GIT_ERROR_NET, "remote error: %s", ((git_pkt_err *)pkt)->error);
70 1 26 git__free(pkt);
71 1 27 return -1;
72 - }
73 -
74 578 28-30 if (pkt->type != GIT_PKT_FLUSH && git_vector_insert(refs, pkt) < 0)
75 ##### 31 return -1;
76 -
77 578 32 if (pkt->type == GIT_PKT_FLUSH) {
78 85 33 flush++;
79 85 33 git_pkt_free(pkt);
80 - }
81 742 34 } while (flush < flushes);
82 -
83 55 35 return flush;
84 - }
85 -
86 54 2 static int append_symref(const char **out, git_vector *symrefs, const char *ptr)
87 - {
88 - int error;
89 - const char *end;
90 54 2 git_buf buf = GIT_BUF_INIT;
91 54 2 git_refspec *mapping = NULL;
92 -
93 54 2 ptr += strlen(GIT_CAP_SYMREF);
94 54 2 if (*ptr != '=')
95 ##### 3 goto on_invalid;
96 -
97 54 4 ptr++;
98 54 4,5 if (!(end = strchr(ptr, ' ')) &&
99 - !(end = strchr(ptr, '\0')))
100 ##### 6 goto on_invalid;
101 -
102 54 7,8 if ((error = git_buf_put(&buf, ptr, end - ptr)) < 0)
103 ##### 9 return error;
104 -
105 - /* symref mapping has refspec format */
106 54 10 mapping = git__calloc(1, sizeof(git_refspec));
107 54 11,12 GIT_ERROR_CHECK_ALLOC(mapping);
108 -
109 54 13,14 error = git_refspec__parse(mapping, git_buf_cstr(&buf), true);
110 54 15 git_buf_dispose(&buf);
111 -
112 - /* if the error isn't OOM, then it's a parse error; let's use a nicer message */
113 54 16 if (error < 0) {
114 ##### 17,18 if (git_error_last()->klass != GIT_ERROR_NOMEMORY)
115 ##### 19 goto on_invalid;
116 -
117 ##### 20 git__free(mapping);
118 ##### 21 return error;
119 - }
120 -
121 54 22,23 if ((error = git_vector_insert(symrefs, mapping)) < 0)
122 ##### 24 return error;
123 -
124 54 25 *out = end;
125 54 25 return 0;
126 -
127 - on_invalid:
128 ##### 26 git_error_set(GIT_ERROR_NET, "remote sent invalid symref");
129 ##### 27 git_refspec__dispose(mapping);
130 ##### 28 git__free(mapping);
131 ##### 29 return -1;
132 - }
133 -
134 55 2 int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vector *symrefs)
135 - {
136 - const char *ptr;
137 -
138 - /* No refs or capabilites, odd but not a problem */
139 55 2,3 if (pkt == NULL || pkt->capabilities == NULL)
140 1 4 return GIT_ENOTFOUND;
141 -
142 54 5 ptr = pkt->capabilities;
143 958 5,40,41 while (ptr != NULL && *ptr != '\0') {
144 904 6 if (*ptr == ' ')
145 853 7 ptr++;
146 -
147 904 8-10 if (git_smart__ofs_delta_enabled && !git__prefixcmp(ptr, GIT_CAP_OFS_DELTA)) {
148 52 11 caps->common = caps->ofs_delta = 1;
149 52 11 ptr += strlen(GIT_CAP_OFS_DELTA);
150 52 11 continue;
151 - }
152 -
153 - /* Keep multi_ack_detailed before multi_ack */
154 852 12,13 if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK_DETAILED)) {
155 54 14 caps->common = caps->multi_ack_detailed = 1;
156 54 14 ptr += strlen(GIT_CAP_MULTI_ACK_DETAILED);
157 54 14 continue;
158 - }
159 -
160 798 15,16 if (!git__prefixcmp(ptr, GIT_CAP_MULTI_ACK)) {
161 54 17 caps->common = caps->multi_ack = 1;
162 54 17 ptr += strlen(GIT_CAP_MULTI_ACK);
163 54 17 continue;
164 - }
165 -
166 744 18,19 if (!git__prefixcmp(ptr, GIT_CAP_INCLUDE_TAG)) {
167 52 20 caps->common = caps->include_tag = 1;
168 52 20 ptr += strlen(GIT_CAP_INCLUDE_TAG);
169 52 20 continue;
170 - }
171 -
172 - /* Keep side-band check after side-band-64k */
173 692 21,22 if (!git__prefixcmp(ptr, GIT_CAP_SIDE_BAND_64K)) {
174 54 23 caps->common = caps->side_band_64k = 1;
175 54 23 ptr += strlen(GIT_CAP_SIDE_BAND_64K);
176 54 23 continue;
177 - }
178 -
179 638 24,25 if (!git__prefixcmp(ptr, GIT_CAP_SIDE_BAND)) {
180 54 26 caps->common = caps->side_band = 1;
181 54 26 ptr += strlen(GIT_CAP_SIDE_BAND);
182 54 26 continue;
183 - }
184 -
185 584 27,28 if (!git__prefixcmp(ptr, GIT_CAP_DELETE_REFS)) {
186 ##### 29 caps->common = caps->delete_refs = 1;
187 ##### 29 ptr += strlen(GIT_CAP_DELETE_REFS);
188 ##### 29 continue;
189 - }
190 -
191 584 30,31 if (!git__prefixcmp(ptr, GIT_CAP_THIN_PACK)) {
192 54 32 caps->common = caps->thin_pack = 1;
193 54 32 ptr += strlen(GIT_CAP_THIN_PACK);
194 54 32 continue;
195 - }
196 -
197 530 33,34 if (!git__prefixcmp(ptr, GIT_CAP_SYMREF)) {
198 - int error;
199 -
200 54 35,36 if ((error = append_symref(&ptr, symrefs, ptr)) < 0)
201 ##### 37 return error;
202 -
203 54 38 continue;
204 - }
205 -
206 - /* We don't know this capability, so skip it */
207 476 39 ptr = strchr(ptr, ' ');
208 - }
209 -
210 54 42 return 0;
211 - }
212 -
213 443 2 static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf)
214 - {
215 443 2 const char *ptr = buf->data, *line_end = ptr;
216 443 2 git_pkt *pkt = NULL;
217 443 2 int error = 0, ret;
218 -
219 - do {
220 911 3 if (buf->offset > 0)
221 798 4 error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset);
222 - else
223 113 5 error = GIT_EBUFS;
224 -
225 911 6 if (error == 0)
226 443 7 break; /* return the pkt */
227 -
228 468 8,9 if (error < 0 && error != GIT_EBUFS)
229 ##### 10 return error;
230 -
231 468 11,12 if ((ret = gitno_recv(buf)) < 0) {
232 ##### 13 return ret;
233 468 14 } else if (ret == 0) {
234 ##### 15 git_error_set(GIT_ERROR_NET, "early EOF");
235 ##### 16 return GIT_EEOF;
236 - }
237 468 17 } while (error);
238 -
239 443 18 gitno_consume(buf, line_end);
240 443 19 if (out_type != NULL)
241 ##### 20 *out_type = pkt->type;
242 443 21 if (out_pkt != NULL)
243 443 22 *out_pkt = pkt;
244 - else
245 ##### 23 git__free(pkt);
246 -
247 443 24 return error;
248 - }
249 -
250 ##### 2 static int store_common(transport_smart *t)
251 - {
252 ##### 2 git_pkt *pkt = NULL;
253 ##### 2 gitno_buffer *buf = &t->buffer;
254 - int error;
255 -
256 - do {
257 ##### 3,4 if ((error = recv_pkt(&pkt, NULL, buf)) < 0)
258 ##### 5 return error;
259 -
260 ##### 6 if (pkt->type != GIT_PKT_ACK) {
261 ##### 7 git__free(pkt);
262 ##### 8 return 0;
263 - }
264 -
265 ##### 9,10 if (git_vector_insert(&t->common, pkt) < 0) {
266 ##### 11 git__free(pkt);
267 ##### 12 return -1;
268 - }
269 ##### 13 } while (1);
270 -
271 - return 0;
272 - }
273 -
274 36 2 static int wait_while_ack(gitno_buffer *buf)
275 - {
276 - int error;
277 36 2 git_pkt *pkt = NULL;
278 36 2 git_pkt_ack *ack = NULL;
279 -
280 - while (1) {
281 36 3 git_pkt_free(pkt);
282 -
283 36 4,5 if ((error = recv_pkt(&pkt, NULL, buf)) < 0)
284 ##### 6 return error;
285 -
286 36 7 if (pkt->type == GIT_PKT_NAK)
287 36 8 break;
288 ##### 9 if (pkt->type != GIT_PKT_ACK)
289 ##### 10 continue;
290 -
291 ##### 11 ack = (git_pkt_ack*)pkt;
292 -
293 ##### 11,12 if (ack->status != GIT_ACK_CONTINUE &&
294 ##### 12,13 ack->status != GIT_ACK_COMMON &&
295 ##### 13 ack->status != GIT_ACK_READY) {
296 ##### 14 break;
297 - }
298 ##### 15 }
299 -
300 36 16 git_pkt_free(pkt);
301 36 17 return 0;
302 - }
303 -
304 36 2 int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *wants, size_t count)
305 - {
306 36 2 transport_smart *t = (transport_smart *)transport;
307 36 2 git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
308 36 2 gitno_buffer *buf = &t->buffer;
309 36 2 git_buf data = GIT_BUF_INIT;
310 36 2 git_revwalk *walk = NULL;
311 36 2 int error = -1;
312 - git_pkt_type pkt_type;
313 - unsigned int i;
314 - git_oid oid;
315 -
316 36 2,3 if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
317 ##### 4 return error;
318 -
319 36 5,6 if ((error = git_revwalk_new(&walk, repo)) < 0)
320 ##### 7 goto on_error;
321 -
322 36 8 opts.insert_by_date = 1;
323 36 8,9 if ((error = git_revwalk__push_glob(walk, "refs/*", &opts)) < 0)
324 ##### 10 goto on_error;
325 -
326 - /*
327 - * Our support for ACK extensions is simply to parse them. On
328 - * the first ACK we will accept that as enough common
329 - * objects. We give up if we haven't found an answer in the
330 - * first 256 we send.
331 - */
332 36 11 i = 0;
333 36 11,62 while (i < 256) {
334 36 12 error = git_revwalk_next(&oid, walk);
335 -
336 36 13 if (error < 0) {
337 36 14 if (GIT_ITEROVER == error)
338 36 15 break;
339 -
340 ##### 16 goto on_error;
341 - }
342 -
343 ##### 17 git_pkt_buffer_have(&oid, &data);
344 ##### 18 i++;
345 ##### 18 if (i % 20 == 0) {
346 ##### 19 if (t->cancelled.val) {
347 ##### 20 git_error_set(GIT_ERROR_NET, "The fetch was cancelled by the user");
348 ##### 21 error = GIT_EUSER;
349 ##### 21 goto on_error;
350 - }
351 -
352 ##### 22 git_pkt_buffer_flush(&data);
353 ##### 23,24 if (git_buf_oom(&data)) {
354 ##### 25 error = -1;
355 ##### 25 goto on_error;
356 - }
357 -
358 ##### 26,27 if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0)
359 ##### 28 goto on_error;
360 -
361 ##### 29 git_buf_clear(&data);
362 ##### 30,31 if (t->caps.multi_ack || t->caps.multi_ack_detailed) {
363 ##### 32,33,35 if ((error = store_common(t)) < 0)
364 ##### 34 goto on_error;
365 - } else {
366 ##### 36,37 if ((error = recv_pkt(NULL, &pkt_type, buf)) < 0)
367 ##### 38 goto on_error;
368 -
369 ##### 39 if (pkt_type == GIT_PKT_ACK) {
370 ##### 40 break;
371 ##### 41 } else if (pkt_type == GIT_PKT_NAK) {
372 ##### 42 continue;
373 - } else {
374 ##### 43 git_error_set(GIT_ERROR_NET, "unexpected pkt type");
375 ##### 44 error = -1;
376 ##### 44 goto on_error;
377 - }
378 - }
379 - }
380 -
381 ##### 45 if (t->common.length > 0)
382 ##### 46 break;
383 -
384 ##### 47,48 if (i % 20 == 0 && t->rpc) {
385 - git_pkt_ack *pkt;
386 - unsigned int j;
387 -
388 ##### 49,50 if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
389 ##### 51 goto on_error;
390 -
391 ##### 52,56-58 git_vector_foreach(&t->common, j, pkt) {
392 ##### 53,54 if ((error = git_pkt_buffer_have(&pkt->oid, &data)) < 0)
393 ##### 55 goto on_error;
394 - }
395 -
396 ##### 59,60 if (git_buf_oom(&data)) {
397 ##### 61 error = -1;
398 ##### 61 goto on_error;
399 - }
400 - }
401 - }
402 -
403 - /* Tell the other end that we're done negotiating */
404 36 63,64 if (t->rpc && t->common.length > 0) {
405 - git_pkt_ack *pkt;
406 - unsigned int j;
407 -
408 ##### 65,66 if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
409 ##### 67 goto on_error;
410 -
411 ##### 68,72-74 git_vector_foreach(&t->common, j, pkt) {
412 ##### 69,70 if ((error = git_pkt_buffer_have(&pkt->oid, &data)) < 0)
413 ##### 71 goto on_error;
414 - }
415 -
416 ##### 75,76 if (git_buf_oom(&data)) {
417 ##### 77 error = -1;
418 ##### 77 goto on_error;
419 - }
420 - }
421 -
422 36 78,79 if ((error = git_pkt_buffer_done(&data)) < 0)
423 ##### 80 goto on_error;
424 -
425 36 81 if (t->cancelled.val) {
426 ##### 82 git_error_set(GIT_ERROR_NET, "The fetch was cancelled by the user");
427 ##### 83 error = GIT_EUSER;
428 ##### 83 goto on_error;
429 - }
430 36 84,85 if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0)
431 ##### 86 goto on_error;
432 -
433 36 87 git_buf_dispose(&data);
434 36 88 git_revwalk_free(walk);
435 -
436 - /* Now let's eat up whatever the server gives us */
437 36 89,90 if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) {
438 ##### 91,92 if ((error = recv_pkt(NULL, &pkt_type, buf)) < 0)
439 ##### 93 return error;
440 -
441 ##### 94,95,98 if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) {
442 ##### 96 git_error_set(GIT_ERROR_NET, "unexpected pkt type");
443 ##### 97 return -1;
444 - }
445 - } else {
446 36 99 error = wait_while_ack(buf);
447 - }
448 -
449 36 100 return error;
450 -
451 - on_error:
452 ##### 101 git_revwalk_free(walk);
453 ##### 102 git_buf_dispose(&data);
454 ##### 103 return error;
455 - }
456 -
457 ##### 2 static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, gitno_buffer *buf, git_indexer_progress *stats)
458 - {
459 - int recvd;
460 -
461 - do {
462 ##### 2 if (t->cancelled.val) {
463 ##### 3 git_error_set(GIT_ERROR_NET, "the fetch was cancelled by the user");
464 ##### 4 return GIT_EUSER;
465 - }
466 -
467 ##### 5,6 if (writepack->append(writepack, buf->data, buf->offset, stats) < 0)
468 ##### 7 return -1;
469 -
470 ##### 8 gitno_consume_n(buf, buf->offset);
471 -
472 ##### 9,10 if ((recvd = gitno_recv(buf)) < 0)
473 ##### 11 return recvd;
474 ##### 12 } while(recvd > 0);
475 -
476 ##### 13,14 if (writepack->commit(writepack, stats) < 0)
477 ##### 15 return -1;
478 -
479 ##### 16 return 0;
480 - }
481 -
482 - struct network_packetsize_payload
483 - {
484 - git_indexer_progress_cb callback;
485 - void *payload;
486 - git_indexer_progress *stats;
487 - size_t last_fired_bytes;
488 - };
489 -
490 49 2 static int network_packetsize(size_t received, void *payload)
491 - {
492 49 2 struct network_packetsize_payload *npp = (struct network_packetsize_payload*)payload;
493 -
494 - /* Accumulate bytes */
495 49 2 npp->stats->received_bytes += received;
496 -
497 - /* Fire notification if the threshold is reached */
498 49 2 if ((npp->stats->received_bytes - npp->last_fired_bytes) > NETWORK_XFER_THRESHOLD) {
499 ##### 3 npp->last_fired_bytes = npp->stats->received_bytes;
500 -
501 ##### 3,4 if (npp->callback(npp->stats, npp->payload))
502 ##### 5 return GIT_EUSER;
503 - }
504 -
505 49 6 return 0;
506 - }
507 -
508 36 2 int git_smart__download_pack(
509 - git_transport *transport,
510 - git_repository *repo,
511 - git_indexer_progress *stats,
512 - git_indexer_progress_cb progress_cb,
513 - void *progress_payload)
514 - {
515 36 2 transport_smart *t = (transport_smart *)transport;
516 36 2 gitno_buffer *buf = &t->buffer;
517 - git_odb *odb;
518 36 2 struct git_odb_writepack *writepack = NULL;
519 36 2 int error = 0;
520 36 2 struct network_packetsize_payload npp = {0};
521 -
522 36 2 memset(stats, 0, sizeof(git_indexer_progress));
523 -
524 36 2 if (progress_cb) {
525 9 3 npp.callback = progress_cb;
526 9 3 npp.payload = progress_payload;
527 9 3 npp.stats = stats;
528 9 3 t->packetsize_cb = &network_packetsize;
529 9 3 t->packetsize_payload = &npp;
530 -
531 - /* We might have something in the buffer already from negotiate_fetch */
532 9 3,4 if (t->buffer.offset > 0 && !t->cancelled.val)
533 ##### 5,6 if (t->packetsize_cb(t->buffer.offset, t->packetsize_payload))
534 ##### 7 git_atomic_set(&t->cancelled, 1);
535 - }
536 -
537 36 8-11 if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 ||
538 36 10 ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) != 0))
539 - goto done;
540 -
541 - /*
542 - * If the remote doesn't support the side-band, we can feed
543 - * the data directly to the pack writer. Otherwise, we need to
544 - * check which one belongs there.
545 - */
546 36 12,13 if (!t->caps.side_band && !t->caps.side_band_64k) {
547 ##### 14 error = no_sideband(t, writepack, buf, stats);
548 ##### 15 goto done;
549 - }
550 -
551 - do {
552 407 16 git_pkt *pkt = NULL;
553 -
554 - /* Check cancellation before network call */
555 407 16 if (t->cancelled.val) {
556 ##### 17 git_error_clear();
557 ##### 18 error = GIT_EUSER;
558 1 18,42 goto done;
559 - }
560 -
561 407 19,20 if ((error = recv_pkt(&pkt, NULL, buf)) >= 0) {
562 - /* Check cancellation after network call */
563 407 21 if (t->cancelled.val) {
564 ##### 22 git_error_clear();
565 ##### 23 error = GIT_EUSER;
566 407 24 } else if (pkt->type == GIT_PKT_PROGRESS) {
567 271 25 if (t->progress_cb) {
568 ##### 26 git_pkt_progress *p = (git_pkt_progress *) pkt;
569 -
570 ##### 26 if (p->len > INT_MAX) {
571 ##### 27 git_error_set(GIT_ERROR_NET, "oversized progress message");
572 ##### 28 error = GIT_ERROR;
573 ##### 28 goto done;
574 - }
575 -
576 271 29,30 error = t->progress_cb(p->data, (int)p->len, t->message_cb_payload);
577 - }
578 136 31 } else if (pkt->type == GIT_PKT_DATA) {
579 101 32 git_pkt_data *p = (git_pkt_data *) pkt;
580 -
581 101 32 if (p->len)
582 101 33,34 error = writepack->append(writepack, p->data, p->len, stats);
583 35 35 } else if (pkt->type == GIT_PKT_FLUSH) {
584 - /* A flush indicates the end of the packfile */
585 35 36 git__free(pkt);
586 35 37 break;
587 - }
588 - }
589 -
590 372 38 git_pkt_free(pkt);
591 -
592 372 39 if (error < 0)
593 1 40 goto done;
594 -
595 371 41 } while (1);
596 -
597 - /*
598 - * Trailing execution of progress_cb, if necessary...
599 - * Only the callback through the npp datastructure currently
600 - * updates the last_fired_bytes value. It is possible that
601 - * progress has already been reported with the correct
602 - * "received_bytes" value, but until (if?) this is unified
603 - * then we will report progress again to be sure that the
604 - * correct last received_bytes value is reported.
605 - */
606 35 37,43 if (npp.callback && npp.stats->received_bytes > npp.last_fired_bytes) {
607 8 44 error = npp.callback(npp.stats, npp.payload);
608 8 45 if (error != 0)
609 1 46 goto done;
610 - }
611 -
612 34 47 error = writepack->commit(writepack, stats);
613 -
614 - done:
615 36 48 if (writepack)
616 36 49 writepack->free(writepack);
617 36 50 if (progress_cb) {
618 9 51 t->packetsize_cb = NULL;
619 9 51 t->packetsize_payload = NULL;
620 - }
621 -
622 36 52 return error;
623 - }
624 -
625 ##### 2 static int gen_pktline(git_buf *buf, git_push *push)
626 - {
627 - push_spec *spec;
628 - size_t i, len;
629 - char old_id[GIT_OID_HEXSZ+1], new_id[GIT_OID_HEXSZ+1];
630 -
631 ##### 2 old_id[GIT_OID_HEXSZ] = '\0'; new_id[GIT_OID_HEXSZ] = '\0';
632 -
633 ##### 2,18-20 git_vector_foreach(&push->specs, i, spec) {
634 ##### 3 len = 2*GIT_OID_HEXSZ + 7 + strlen(spec->refspec.dst);
635 -
636 ##### 3 if (i == 0) {
637 ##### 4 ++len; /* '\0' */
638 ##### 4 if (push->report_status)
639 ##### 5 len += strlen(GIT_CAP_REPORT_STATUS) + 1;
640 ##### 6 len += strlen(GIT_CAP_SIDE_BAND_64K) + 1;
641 - }
642 -
643 ##### 7 git_oid_fmt(old_id, &spec->roid);
644 ##### 8 git_oid_fmt(new_id, &spec->loid);
645 -
646 ##### 9 git_buf_printf(buf, "%04"PRIxZ"%s %s %s", len, old_id, new_id, spec->refspec.dst);
647 -
648 ##### 10 if (i == 0) {
649 ##### 11 git_buf_putc(buf, '\0');
650 - /* Core git always starts their capabilities string with a space */
651 ##### 12 if (push->report_status) {
652 ##### 13 git_buf_putc(buf, ' ');
653 ##### 14 git_buf_printf(buf, GIT_CAP_REPORT_STATUS);
654 - }
655 ##### 15 git_buf_putc(buf, ' ');
656 ##### 16 git_buf_printf(buf, GIT_CAP_SIDE_BAND_64K);
657 - }
658 -
659 ##### 17 git_buf_putc(buf, '\n');
660 - }
661 -
662 ##### 21 git_buf_puts(buf, "0000");
663 ##### 22 return git_buf_oom(buf) ? -1 : 0;
664 - }
665 -
666 ##### 2 static int add_push_report_pkt(git_push *push, git_pkt *pkt)
667 - {
668 - push_status *status;
669 -
670 ##### 2 switch (pkt->type) {
671 - case GIT_PKT_OK:
672 ##### 3 status = git__calloc(1, sizeof(push_status));
673 ##### 4,5 GIT_ERROR_CHECK_ALLOC(status);
674 ##### 6 status->msg = NULL;
675 ##### 6 status->ref = git__strdup(((git_pkt_ok *)pkt)->ref);
676 ##### 7,9 if (!status->ref ||
677 ##### 8 git_vector_insert(&push->status, status) < 0) {
678 ##### 10 git_push_status_free(status);
679 ##### 11 return -1;
680 - }
681 ##### 12 break;
682 - case GIT_PKT_NG:
683 ##### 13 status = git__calloc(1, sizeof(push_status));
684 ##### 14,15 GIT_ERROR_CHECK_ALLOC(status);
685 ##### 16 status->ref = git__strdup(((git_pkt_ng *)pkt)->ref);
686 ##### 17 status->msg = git__strdup(((git_pkt_ng *)pkt)->msg);
687 ##### 18,19,21 if (!status->ref || !status->msg ||
688 ##### 20 git_vector_insert(&push->status, status) < 0) {
689 ##### 22 git_push_status_free(status);
690 ##### 23 return -1;
691 - }
692 ##### 24 break;
693 - case GIT_PKT_UNPACK:
694 ##### 25 push->unpack_ok = ((git_pkt_unpack *)pkt)->unpack_ok;
695 ##### 25 break;
696 - case GIT_PKT_FLUSH:
697 ##### 26 return GIT_ITEROVER;
698 - default:
699 ##### 27 git_error_set(GIT_ERROR_NET, "report-status: protocol error");
700 ##### 28 return -1;
701 - }
702 -
703 ##### 29 return 0;
704 - }
705 -
706 ##### 2 static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_buf *data_pkt_buf)
707 - {
708 - git_pkt *pkt;
709 ##### 2 const char *line, *line_end = NULL;
710 - size_t line_len;
711 - int error;
712 ##### 2 int reading_from_buf = data_pkt_buf->size > 0;
713 -
714 ##### 2 if (reading_from_buf) {
715 - /* We had an existing partial packet, so add the new
716 - * packet to the buffer and parse the whole thing */
717 ##### 3 git_buf_put(data_pkt_buf, data_pkt->data, data_pkt->len);
718 ##### 4 line = data_pkt_buf->ptr;
719 ##### 4 line_len = data_pkt_buf->size;
720 - }
721 - else {
722 ##### 5 line = data_pkt->data;
723 ##### 5 line_len = data_pkt->len;
724 - }
725 -
726 ##### 6,19 while (line_len > 0) {
727 ##### 7 error = git_pkt_parse_line(&pkt, &line_end, line, line_len);
728 -
729 ##### 8 if (error == GIT_EBUFS) {
730 - /* Buffer the data when the inner packet is split
731 - * across multiple sideband packets */
732 ##### 9 if (!reading_from_buf)
733 ##### 10 git_buf_put(data_pkt_buf, line, line_len);
734 ##### 11 error = 0;
735 ##### 11 goto done;
736 - }
737 ##### 12 else if (error < 0)
738 ##### 13 goto done;
739 -
740 - /* Advance in the buffer */
741 ##### 14 line_len -= (line_end - line);
742 ##### 14 line = line_end;
743 -
744 ##### 14 error = add_push_report_pkt(push, pkt);
745 -
746 ##### 15 git_pkt_free(pkt);
747 -
748 ##### 16,17 if (error < 0 && error != GIT_ITEROVER)
749 ##### 18 goto done;
750 - }
751 -
752 ##### 20 error = 0;
753 -
754 - done:
755 ##### 21 if (reading_from_buf)
756 ##### 22 git_buf_consume(data_pkt_buf, line_end);
757 ##### 23 return error;
758 - }
759 -
760 ##### 2 static int parse_report(transport_smart *transport, git_push *push)
761 - {
762 ##### 2 git_pkt *pkt = NULL;
763 ##### 2 const char *line_end = NULL;
764 ##### 2 gitno_buffer *buf = &transport->buffer;
765 - int error, recvd;
766 ##### 2 git_buf data_pkt_buf = GIT_BUF_INIT;
767 -
768 - for (;;) {
769 ##### 3 if (buf->offset > 0)
770 ##### 4,4 error = git_pkt_parse_line(&pkt, &line_end,
771 ##### 4 buf->data, buf->offset);
772 - else
773 ##### 5 error = GIT_EBUFS;
774 -
775 ##### 6,7 if (error < 0 && error != GIT_EBUFS) {
776 ##### 8 error = -1;
777 ##### 8 goto done;
778 - }
779 -
780 ##### 9 if (error == GIT_EBUFS) {
781 ##### 10,11 if ((recvd = gitno_recv(buf)) < 0) {
782 ##### 12 error = recvd;
783 ##### 12 goto done;
784 - }
785 -
786 ##### 13 if (recvd == 0) {
787 ##### 14 git_error_set(GIT_ERROR_NET, "early EOF");
788 ##### 15 error = GIT_EEOF;
789 ##### 15 goto done;
790 - }
791 ##### 16 continue;
792 - }
793 -
794 ##### 17 gitno_consume(buf, line_end);
795 -
796 ##### 18 error = 0;
797 -
798 ##### 18 switch (pkt->type) {
799 - case GIT_PKT_DATA:
800 - /* This is a sideband packet which contains other packets */
801 ##### 19 error = add_push_report_sideband_pkt(push, (git_pkt_data *)pkt, &data_pkt_buf);
802 ##### 20 break;
803 - case GIT_PKT_ERR:
804 ##### 21 git_error_set(GIT_ERROR_NET, "report-status: Error reported: %s",
805 ##### 21 ((git_pkt_err *)pkt)->error);
806 ##### 22 error = -1;
807 ##### 22 break;
808 - case GIT_PKT_PROGRESS:
809 ##### 23 if (transport->progress_cb) {
810 ##### 24 git_pkt_progress *p = (git_pkt_progress *) pkt;
811 -
812 ##### 24 if (p->len > INT_MAX) {
813 ##### 25 git_error_set(GIT_ERROR_NET, "oversized progress message");
814 ##### 26 error = GIT_ERROR;
815 ##### 26 goto done;
816 - }
817 -
818 ##### 27 error = transport->progress_cb(p->data, (int)p->len, transport->message_cb_payload);
819 - }
820 ##### 28 break;
821 - default:
822 ##### 29 error = add_push_report_pkt(push, pkt);
823 ##### 30 break;
824 - }
825 -
826 ##### 31 git_pkt_free(pkt);
827 -
828 - /* add_push_report_pkt returns GIT_ITEROVER when it receives a flush */
829 ##### 32 if (error == GIT_ITEROVER) {
830 ##### 33 error = 0;
831 ##### 33 if (data_pkt_buf.size > 0) {
832 - /* If there was data remaining in the pack data buffer,
833 - * then the server sent a partial pkt-line */
834 ##### 34 git_error_set(GIT_ERROR_NET, "incomplete pack data pkt-line");
835 ##### 35 error = GIT_ERROR;
836 - }
837 ##### 36 goto done;
838 - }
839 -
840 ##### 37 if (error < 0) {
841 ##### 38 goto done;
842 - }
843 ##### 39 }
844 - done:
845 ##### 40 git_buf_dispose(&data_pkt_buf);
846 ##### 41 return error;
847 - }
848 -
849 ##### 2 static int add_ref_from_push_spec(git_vector *refs, push_spec *push_spec)
850 - {
851 ##### 2 git_pkt_ref *added = git__calloc(1, sizeof(git_pkt_ref));
852 ##### 3,4 GIT_ERROR_CHECK_ALLOC(added);
853 -
854 ##### 5 added->type = GIT_PKT_REF;
855 ##### 5 git_oid_cpy(&added->head.oid, &push_spec->loid);
856 ##### 6 added->head.name = git__strdup(push_spec->refspec.dst);
857 -
858 ##### 7,9 if (!added->head.name ||
859 ##### 8 git_vector_insert(refs, added) < 0) {
860 ##### 10 git_pkt_free((git_pkt *)added);
861 ##### 11 return -1;
862 - }
863 -
864 ##### 12 return 0;
865 - }
866 -
867 ##### 2 static int update_refs_from_report(
868 - git_vector *refs,
869 - git_vector *push_specs,
870 - git_vector *push_report)
871 - {
872 - git_pkt_ref *ref;
873 - push_spec *push_spec;
874 - push_status *push_status;
875 - size_t i, j, refs_len;
876 - int cmp;
877 -
878 - /* For each push spec we sent to the server, we should have
879 - * gotten back a status packet in the push report */
880 ##### 2 if (push_specs->length != push_report->length) {
881 ##### 3 git_error_set(GIT_ERROR_NET, "report-status: protocol error");
882 ##### 4 return -1;
883 - }
884 -
885 - /* We require that push_specs be sorted with push_spec_rref_cmp,
886 - * and that push_report be sorted with push_status_ref_cmp */
887 ##### 5 git_vector_sort(push_specs);
888 ##### 6 git_vector_sort(push_report);
889 -
890 ##### 7,12-14 git_vector_foreach(push_specs, i, push_spec) {
891 ##### 8 push_status = git_vector_get(push_report, i);
892 -
893 - /* For each push spec we sent to the server, we should have
894 - * gotten back a status packet in the push report which matches */
895 ##### 9 if (strcmp(push_spec->refspec.dst, push_status->ref)) {
896 ##### 10 git_error_set(GIT_ERROR_NET, "report-status: protocol error");
897 ##### 11 return -1;
898 - }
899 - }
900 -
901 - /* We require that refs be sorted with ref_name_cmp */
902 ##### 15 git_vector_sort(refs);
903 ##### 16 i = j = 0;
904 ##### 16 refs_len = refs->length;
905 -
906 - /* Merge join push_specs with refs */
907 ##### 16,32,33 while (i < push_specs->length && j < refs_len) {
908 ##### 17 push_spec = git_vector_get(push_specs, i);
909 ##### 18 push_status = git_vector_get(push_report, i);
910 ##### 19 ref = git_vector_get(refs, j);
911 -
912 ##### 20 cmp = strcmp(push_spec->refspec.dst, ref->head.name);
913 -
914 - /* Iterate appropriately */
915 ##### 20,21 if (cmp <= 0) i++;
916 ##### 22,23 if (cmp >= 0) j++;
917 -
918 - /* Add case */
919 ##### 24,25 if (cmp < 0 &&
920 ##### 25,27 !push_status->msg &&
921 ##### 26 add_ref_from_push_spec(refs, push_spec) < 0)
922 ##### 28 return -1;
923 -
924 - /* Update case, delete case */
925 ##### 29,30 if (cmp == 0 &&
926 ##### 30 !push_status->msg)
927 ##### 31 git_oid_cpy(&ref->head.oid, &push_spec->loid);
928 - }
929 -
930 ##### 34,41,42 for (; i < push_specs->length; i++) {
931 ##### 35 push_spec = git_vector_get(push_specs, i);
932 ##### 36 push_status = git_vector_get(push_report, i);
933 -
934 - /* Add case */
935 ##### 37,39 if (!push_status->msg &&
936 ##### 38 add_ref_from_push_spec(refs, push_spec) < 0)
937 ##### 40 return -1;
938 - }
939 -
940 - /* Remove any refs which we updated to have a zero OID. */
941 ##### 43,48-50 git_vector_rforeach(refs, i, ref) {
942 ##### 44,45 if (git_oid_is_zero(&ref->head.oid)) {
943 ##### 46 git_vector_remove(refs, i);
944 ##### 47 git_pkt_free((git_pkt *)ref);
945 - }
946 - }
947 -
948 ##### 51 git_vector_sort(refs);
949 -
950 ##### 52 return 0;
951 - }
952 -
953 - struct push_packbuilder_payload
954 - {
955 - git_smart_subtransport_stream *stream;
956 - git_packbuilder *pb;
957 - git_push_transfer_progress_cb cb;
958 - void *cb_payload;
959 - size_t last_bytes;
960 - double last_progress_report_time;
961 - };
962 -
963 ##### 2 static int stream_thunk(void *buf, size_t size, void *data)
964 - {
965 ##### 2 int error = 0;
966 ##### 2 struct push_packbuilder_payload *payload = data;
967 -
968 ##### 2,3 if ((error = payload->stream->write(payload->stream, (const char *)buf, size)) < 0)
969 ##### 4 return error;
970 -
971 ##### 5 if (payload->cb) {
972 ##### 6 double current_time = git__timer();
973 ##### 7 payload->last_bytes += size;
974 -
975 ##### 7 if ((current_time - payload->last_progress_report_time) >= MIN_PROGRESS_UPDATE_INTERVAL) {
976 ##### 8 payload->last_progress_report_time = current_time;
977 ##### 8 error = payload->cb(payload->pb->nr_written, payload->pb->nr_objects, payload->last_bytes, payload->cb_payload);
978 - }
979 - }
980 -
981 ##### 9 return error;
982 - }
983 -
984 ##### 2 int git_smart__push(git_transport *transport, git_push *push, const git_remote_callbacks *cbs)
985 - {
986 ##### 2 transport_smart *t = (transport_smart *)transport;
987 ##### 2 struct push_packbuilder_payload packbuilder_payload = {0};
988 ##### 2 git_buf pktline = GIT_BUF_INIT;
989 ##### 2 int error = 0, need_pack = 0;
990 - push_spec *spec;
991 - unsigned int i;
992 -
993 ##### 2 packbuilder_payload.pb = push->pb;
994 -
995 ##### 2,3 if (cbs && cbs->push_transfer_progress) {
996 ##### 4 packbuilder_payload.cb = cbs->push_transfer_progress;
997 ##### 4 packbuilder_payload.cb_payload = cbs->payload;
998 - }
999 -
1000 - #ifdef PUSH_DEBUG
1001 - {
1002 - git_remote_head *head;
1003 - char hex[GIT_OID_HEXSZ+1]; hex[GIT_OID_HEXSZ] = '\0';
1004 -
1005 - git_vector_foreach(&push->remote->refs, i, head) {
1006 - git_oid_fmt(hex, &head->oid);
1007 - fprintf(stderr, "%s (%s)\n", hex, head->name);
1008 - }
1009 -
1010 - git_vector_foreach(&push->specs, i, spec) {
1011 - git_oid_fmt(hex, &spec->roid);
1012 - fprintf(stderr, "%s (%s) -> ", hex, spec->lref);
1013 - git_oid_fmt(hex, &spec->loid);
1014 - fprintf(stderr, "%s (%s)\n", hex, spec->rref ?
1015 - spec->rref : spec->lref);
1016 - }
1017 - }
1018 - #endif
1019 -
1020 - /*
1021 - * Figure out if we need to send a packfile; which is in all
1022 - * cases except when we only send delete commands
1023 - */
1024 ##### 5,9-11 git_vector_foreach(&push->specs, i, spec) {
1025 ##### 6,7 if (spec->refspec.src && spec->refspec.src[0] != '\0') {
1026 ##### 8 need_pack = 1;
1027 ##### 8 break;
1028 - }
1029 - }
1030 -
1031 ##### 12-15 if ((error = git_smart__get_push_stream(t, &packbuilder_payload.stream)) < 0 ||
1032 ##### 18,19 (error = gen_pktline(&pktline, push)) < 0 ||
1033 ##### 16,17 (error = packbuilder_payload.stream->write(packbuilder_payload.stream, git_buf_cstr(&pktline), git_buf_len(&pktline))) < 0)
1034 - goto done;
1035 -
1036 ##### 20-22 if (need_pack &&
1037 ##### 21 (error = git_packbuilder_foreach(push->pb, &stream_thunk, &packbuilder_payload)) < 0)
1038 ##### 23 goto done;
1039 -
1040 - /* If we sent nothing or the server doesn't support report-status, then
1041 - * we consider the pack to have been unpacked successfully */
1042 ##### 24,25 if (!push->specs.length || !push->report_status)
1043 ##### 26 push->unpack_ok = 1;
1044 ##### 27,28 else if ((error = parse_report(t, push)) < 0)
1045 ##### 29 goto done;
1046 -
1047 - /* If progress is being reported write the final report */
1048 ##### 30,31 if (cbs && cbs->push_transfer_progress) {
1049 ##### 32,32,32 error = cbs->push_transfer_progress(
1050 ##### 32 push->pb->nr_written,
1051 ##### 32 push->pb->nr_objects,
1052 - packbuilder_payload.last_bytes,
1053 - cbs->payload);
1054 -
1055 ##### 33 if (error < 0)
1056 ##### 34 goto done;
1057 - }
1058 -
1059 ##### 35 if (push->status.length) {
1060 ##### 36 error = update_refs_from_report(&t->refs, &push->specs, &push->status);
1061 ##### 37 if (error < 0)
1062 ##### 38 goto done;
1063 -
1064 ##### 39 error = git_smart__update_heads(t, NULL);
1065 - }
1066 -
1067 - done:
1068 ##### 40 git_buf_dispose(&pktline);
1069 ##### 41 return error;
1070 - }