2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
11 #include "git2/odb_backend.h"
15 #include "repository.h"
17 #include "pack-objects.h"
22 #define NETWORK_XFER_THRESHOLD (100*1024)
23 /* The minimal interval between progress updates (in seconds). */
24 #define MIN_PROGRESS_UPDATE_INTERVAL 0.5
26 bool git_smart__ofs_delta_enabled
= true;
28 int git_smart__store_refs(transport_smart
*t
, int flushes
)
30 gitno_buffer
*buf
= &t
->buffer
;
31 git_vector
*refs
= &t
->refs
;
32 int error
, flush
= 0, recvd
;
33 const char *line_end
= NULL
;
37 /* Clear existing refs in case git_remote_connect() is called again
38 * after git_remote_disconnect().
40 git_vector_foreach(refs
, i
, pkt
) {
43 git_vector_clear(refs
);
48 error
= git_pkt_parse_line(&pkt
, &line_end
, buf
->data
, buf
->offset
);
52 if (error
< 0 && error
!= GIT_EBUFS
)
55 if (error
== GIT_EBUFS
) {
56 if ((recvd
= gitno_recv(buf
)) < 0)
60 git_error_set(GIT_ERROR_NET
, "early EOF");
67 if (gitno_consume(buf
, line_end
) < 0)
70 if (pkt
->type
== GIT_PKT_ERR
) {
71 git_error_set(GIT_ERROR_NET
, "remote error: %s", ((git_pkt_err
*)pkt
)->error
);
76 if (pkt
->type
!= GIT_PKT_FLUSH
&& git_vector_insert(refs
, pkt
) < 0)
79 if (pkt
->type
== GIT_PKT_FLUSH
) {
83 } while (flush
< flushes
);
88 static int append_symref(const char **out
, git_vector
*symrefs
, const char *ptr
)
92 git_str buf
= GIT_STR_INIT
;
93 git_refspec
*mapping
= NULL
;
95 ptr
+= strlen(GIT_CAP_SYMREF
);
100 if (!(end
= strchr(ptr
, ' ')) &&
101 !(end
= strchr(ptr
, '\0')))
104 if ((error
= git_str_put(&buf
, ptr
, end
- ptr
)) < 0)
107 /* symref mapping has refspec format */
108 mapping
= git__calloc(1, sizeof(git_refspec
));
109 GIT_ERROR_CHECK_ALLOC(mapping
);
111 error
= git_refspec__parse(mapping
, git_str_cstr(&buf
), true);
112 git_str_dispose(&buf
);
114 /* if the error isn't OOM, then it's a parse error; let's use a nicer message */
116 if (git_error_last()->klass
!= GIT_ERROR_NOMEMORY
)
123 if ((error
= git_vector_insert(symrefs
, mapping
)) < 0)
130 git_error_set(GIT_ERROR_NET
, "remote sent invalid symref");
131 git_refspec__dispose(mapping
);
136 int git_smart__detect_caps(git_pkt_ref
*pkt
, transport_smart_caps
*caps
, git_vector
*symrefs
)
140 /* No refs or capabilities, odd but not a problem */
141 if (pkt
== NULL
|| pkt
->capabilities
== NULL
)
142 return GIT_ENOTFOUND
;
144 ptr
= pkt
->capabilities
;
145 while (ptr
!= NULL
&& *ptr
!= '\0') {
149 if (git_smart__ofs_delta_enabled
&& !git__prefixcmp(ptr
, GIT_CAP_OFS_DELTA
)) {
150 caps
->common
= caps
->ofs_delta
= 1;
151 ptr
+= strlen(GIT_CAP_OFS_DELTA
);
155 /* Keep multi_ack_detailed before multi_ack */
156 if (!git__prefixcmp(ptr
, GIT_CAP_MULTI_ACK_DETAILED
)) {
157 caps
->common
= caps
->multi_ack_detailed
= 1;
158 ptr
+= strlen(GIT_CAP_MULTI_ACK_DETAILED
);
162 if (!git__prefixcmp(ptr
, GIT_CAP_MULTI_ACK
)) {
163 caps
->common
= caps
->multi_ack
= 1;
164 ptr
+= strlen(GIT_CAP_MULTI_ACK
);
168 if (!git__prefixcmp(ptr
, GIT_CAP_INCLUDE_TAG
)) {
169 caps
->common
= caps
->include_tag
= 1;
170 ptr
+= strlen(GIT_CAP_INCLUDE_TAG
);
174 /* Keep side-band check after side-band-64k */
175 if (!git__prefixcmp(ptr
, GIT_CAP_SIDE_BAND_64K
)) {
176 caps
->common
= caps
->side_band_64k
= 1;
177 ptr
+= strlen(GIT_CAP_SIDE_BAND_64K
);
181 if (!git__prefixcmp(ptr
, GIT_CAP_SIDE_BAND
)) {
182 caps
->common
= caps
->side_band
= 1;
183 ptr
+= strlen(GIT_CAP_SIDE_BAND
);
187 if (!git__prefixcmp(ptr
, GIT_CAP_DELETE_REFS
)) {
188 caps
->common
= caps
->delete_refs
= 1;
189 ptr
+= strlen(GIT_CAP_DELETE_REFS
);
193 if (!git__prefixcmp(ptr
, GIT_CAP_THIN_PACK
)) {
194 caps
->common
= caps
->thin_pack
= 1;
195 ptr
+= strlen(GIT_CAP_THIN_PACK
);
199 if (!git__prefixcmp(ptr
, GIT_CAP_SYMREF
)) {
202 if ((error
= append_symref(&ptr
, symrefs
, ptr
)) < 0)
208 if (!git__prefixcmp(ptr
, GIT_CAP_WANT_TIP_SHA1
)) {
209 caps
->common
= caps
->want_tip_sha1
= 1;
210 ptr
+= strlen(GIT_CAP_DELETE_REFS
);
214 if (!git__prefixcmp(ptr
, GIT_CAP_WANT_REACHABLE_SHA1
)) {
215 caps
->common
= caps
->want_reachable_sha1
= 1;
216 ptr
+= strlen(GIT_CAP_DELETE_REFS
);
220 /* We don't know this capability, so skip it */
221 ptr
= strchr(ptr
, ' ');
227 static int recv_pkt(git_pkt
**out_pkt
, git_pkt_type
*out_type
, gitno_buffer
*buf
)
229 const char *ptr
= buf
->data
, *line_end
= ptr
;
235 error
= git_pkt_parse_line(&pkt
, &line_end
, ptr
, buf
->offset
);
240 break; /* return the pkt */
242 if (error
< 0 && error
!= GIT_EBUFS
)
245 if ((ret
= gitno_recv(buf
)) < 0) {
247 } else if (ret
== 0) {
248 git_error_set(GIT_ERROR_NET
, "early EOF");
253 if (gitno_consume(buf
, line_end
) < 0)
256 if (out_type
!= NULL
)
257 *out_type
= pkt
->type
;
266 static int store_common(transport_smart
*t
)
269 gitno_buffer
*buf
= &t
->buffer
;
273 if ((error
= recv_pkt(&pkt
, NULL
, buf
)) < 0)
276 if (pkt
->type
!= GIT_PKT_ACK
) {
281 if (git_vector_insert(&t
->common
, pkt
) < 0) {
290 static int wait_while_ack(gitno_buffer
*buf
)
294 git_pkt_ack
*ack
= NULL
;
299 if ((error
= recv_pkt(&pkt
, NULL
, buf
)) < 0)
302 if (pkt
->type
== GIT_PKT_NAK
)
304 if (pkt
->type
!= GIT_PKT_ACK
)
307 ack
= (git_pkt_ack
*)pkt
;
309 if (ack
->status
!= GIT_ACK_CONTINUE
&&
310 ack
->status
!= GIT_ACK_COMMON
&&
311 ack
->status
!= GIT_ACK_READY
) {
320 int git_smart__negotiate_fetch(git_transport
*transport
, git_repository
*repo
, const git_remote_head
* const *wants
, size_t count
)
322 transport_smart
*t
= (transport_smart
*)transport
;
323 git_revwalk__push_options opts
= GIT_REVWALK__PUSH_OPTIONS_INIT
;
324 gitno_buffer
*buf
= &t
->buffer
;
325 git_str data
= GIT_STR_INIT
;
326 git_revwalk
*walk
= NULL
;
328 git_pkt_type pkt_type
;
332 if ((error
= git_pkt_buffer_wants(wants
, count
, &t
->caps
, &data
)) < 0)
335 if ((error
= git_revwalk_new(&walk
, repo
)) < 0)
338 opts
.insert_by_date
= 1;
339 if ((error
= git_revwalk__push_glob(walk
, "refs/*", &opts
)) < 0)
343 * Our support for ACK extensions is simply to parse them. On
344 * the first ACK we will accept that as enough common
345 * objects. We give up if we haven't found an answer in the
350 error
= git_revwalk_next(&oid
, walk
);
353 if (GIT_ITEROVER
== error
)
359 git_pkt_buffer_have(&oid
, &data
);
362 if (t
->cancelled
.val
) {
363 git_error_set(GIT_ERROR_NET
, "The fetch was cancelled by the user");
368 git_pkt_buffer_flush(&data
);
369 if (git_str_oom(&data
)) {
374 if ((error
= git_smart__negotiation_step(&t
->parent
, data
.ptr
, data
.size
)) < 0)
377 git_str_clear(&data
);
378 if (t
->caps
.multi_ack
|| t
->caps
.multi_ack_detailed
) {
379 if ((error
= store_common(t
)) < 0)
382 if ((error
= recv_pkt(NULL
, &pkt_type
, buf
)) < 0)
385 if (pkt_type
== GIT_PKT_ACK
) {
387 } else if (pkt_type
== GIT_PKT_NAK
) {
390 git_error_set(GIT_ERROR_NET
, "unexpected pkt type");
397 if (t
->common
.length
> 0)
400 if (i
% 20 == 0 && t
->rpc
) {
404 if ((error
= git_pkt_buffer_wants(wants
, count
, &t
->caps
, &data
)) < 0)
407 git_vector_foreach(&t
->common
, j
, pkt
) {
408 if ((error
= git_pkt_buffer_have(&pkt
->oid
, &data
)) < 0)
412 if (git_str_oom(&data
)) {
419 /* Tell the other end that we're done negotiating */
420 if (t
->rpc
&& t
->common
.length
> 0) {
424 if ((error
= git_pkt_buffer_wants(wants
, count
, &t
->caps
, &data
)) < 0)
427 git_vector_foreach(&t
->common
, j
, pkt
) {
428 if ((error
= git_pkt_buffer_have(&pkt
->oid
, &data
)) < 0)
432 if (git_str_oom(&data
)) {
438 if ((error
= git_pkt_buffer_done(&data
)) < 0)
441 if (t
->cancelled
.val
) {
442 git_error_set(GIT_ERROR_NET
, "The fetch was cancelled by the user");
446 if ((error
= git_smart__negotiation_step(&t
->parent
, data
.ptr
, data
.size
)) < 0)
449 git_str_dispose(&data
);
450 git_revwalk_free(walk
);
452 /* Now let's eat up whatever the server gives us */
453 if (!t
->caps
.multi_ack
&& !t
->caps
.multi_ack_detailed
) {
454 if ((error
= recv_pkt(NULL
, &pkt_type
, buf
)) < 0)
457 if (pkt_type
!= GIT_PKT_ACK
&& pkt_type
!= GIT_PKT_NAK
) {
458 git_error_set(GIT_ERROR_NET
, "unexpected pkt type");
462 error
= wait_while_ack(buf
);
468 git_revwalk_free(walk
);
469 git_str_dispose(&data
);
473 static int no_sideband(transport_smart
*t
, struct git_odb_writepack
*writepack
, gitno_buffer
*buf
, git_indexer_progress
*stats
)
478 if (t
->cancelled
.val
) {
479 git_error_set(GIT_ERROR_NET
, "the fetch was cancelled by the user");
483 if (writepack
->append(writepack
, buf
->data
, buf
->offset
, stats
) < 0)
486 gitno_consume_n(buf
, buf
->offset
);
488 if ((recvd
= gitno_recv(buf
)) < 0)
492 if (writepack
->commit(writepack
, stats
) < 0)
498 struct network_packetsize_payload
500 git_indexer_progress_cb callback
;
502 git_indexer_progress
*stats
;
503 size_t last_fired_bytes
;
506 static int network_packetsize(size_t received
, void *payload
)
508 struct network_packetsize_payload
*npp
= (struct network_packetsize_payload
*)payload
;
510 /* Accumulate bytes */
511 npp
->stats
->received_bytes
+= received
;
513 /* Fire notification if the threshold is reached */
514 if ((npp
->stats
->received_bytes
- npp
->last_fired_bytes
) > NETWORK_XFER_THRESHOLD
) {
515 npp
->last_fired_bytes
= npp
->stats
->received_bytes
;
517 if (npp
->callback(npp
->stats
, npp
->payload
))
524 int git_smart__download_pack(
525 git_transport
*transport
,
526 git_repository
*repo
,
527 git_indexer_progress
*stats
)
529 transport_smart
*t
= (transport_smart
*)transport
;
530 gitno_buffer
*buf
= &t
->buffer
;
532 struct git_odb_writepack
*writepack
= NULL
;
534 struct network_packetsize_payload npp
= {0};
536 git_indexer_progress_cb progress_cb
= t
->connect_opts
.callbacks
.transfer_progress
;
537 void *progress_payload
= t
->connect_opts
.callbacks
.payload
;
539 memset(stats
, 0, sizeof(git_indexer_progress
));
542 npp
.callback
= progress_cb
;
543 npp
.payload
= progress_payload
;
545 t
->packetsize_cb
= &network_packetsize
;
546 t
->packetsize_payload
= &npp
;
548 /* We might have something in the buffer already from negotiate_fetch */
549 if (t
->buffer
.offset
> 0 && !t
->cancelled
.val
)
550 if (t
->packetsize_cb(t
->buffer
.offset
, t
->packetsize_payload
))
551 git_atomic32_set(&t
->cancelled
, 1);
554 if ((error
= git_repository_odb__weakptr(&odb
, repo
)) < 0 ||
555 ((error
= git_odb_write_pack(&writepack
, odb
, progress_cb
, progress_payload
)) != 0))
559 * If the remote doesn't support the side-band, we can feed
560 * the data directly to the pack writer. Otherwise, we need to
561 * check which one belongs there.
563 if (!t
->caps
.side_band
&& !t
->caps
.side_band_64k
) {
564 error
= no_sideband(t
, writepack
, buf
, stats
);
571 /* Check cancellation before network call */
572 if (t
->cancelled
.val
) {
578 if ((error
= recv_pkt(&pkt
, NULL
, buf
)) >= 0) {
579 /* Check cancellation after network call */
580 if (t
->cancelled
.val
) {
583 } else if (pkt
->type
== GIT_PKT_PROGRESS
) {
584 if (t
->connect_opts
.callbacks
.sideband_progress
) {
585 git_pkt_progress
*p
= (git_pkt_progress
*) pkt
;
587 if (p
->len
> INT_MAX
) {
588 git_error_set(GIT_ERROR_NET
, "oversized progress message");
593 error
= t
->connect_opts
.callbacks
.sideband_progress(p
->data
, (int)p
->len
, t
->connect_opts
.callbacks
.payload
);
595 } else if (pkt
->type
== GIT_PKT_DATA
) {
596 git_pkt_data
*p
= (git_pkt_data
*) pkt
;
599 error
= writepack
->append(writepack
, p
->data
, p
->len
, stats
);
600 } else if (pkt
->type
== GIT_PKT_FLUSH
) {
601 /* A flush indicates the end of the packfile */
615 * Trailing execution of progress_cb, if necessary...
616 * Only the callback through the npp datastructure currently
617 * updates the last_fired_bytes value. It is possible that
618 * progress has already been reported with the correct
619 * "received_bytes" value, but until (if?) this is unified
620 * then we will report progress again to be sure that the
621 * correct last received_bytes value is reported.
623 if (npp
.callback
&& npp
.stats
->received_bytes
> npp
.last_fired_bytes
) {
624 error
= npp
.callback(npp
.stats
, npp
.payload
);
629 error
= writepack
->commit(writepack
, stats
);
633 writepack
->free(writepack
);
635 t
->packetsize_cb
= NULL
;
636 t
->packetsize_payload
= NULL
;
642 static int gen_pktline(git_str
*buf
, git_push
*push
)
646 char old_id
[GIT_OID_HEXSZ
+1], new_id
[GIT_OID_HEXSZ
+1];
648 old_id
[GIT_OID_HEXSZ
] = '\0'; new_id
[GIT_OID_HEXSZ
] = '\0';
650 git_vector_foreach(&push
->specs
, i
, spec
) {
651 len
= 2*GIT_OID_HEXSZ
+ 7 + strlen(spec
->refspec
.dst
);
655 if (push
->report_status
)
656 len
+= strlen(GIT_CAP_REPORT_STATUS
) + 1;
657 len
+= strlen(GIT_CAP_SIDE_BAND_64K
) + 1;
660 git_oid_fmt(old_id
, &spec
->roid
);
661 git_oid_fmt(new_id
, &spec
->loid
);
663 git_str_printf(buf
, "%04"PRIxZ
"%s %s %s", len
, old_id
, new_id
, spec
->refspec
.dst
);
666 git_str_putc(buf
, '\0');
667 /* Core git always starts their capabilities string with a space */
668 if (push
->report_status
) {
669 git_str_putc(buf
, ' ');
670 git_str_printf(buf
, GIT_CAP_REPORT_STATUS
);
672 git_str_putc(buf
, ' ');
673 git_str_printf(buf
, GIT_CAP_SIDE_BAND_64K
);
676 git_str_putc(buf
, '\n');
679 git_str_puts(buf
, "0000");
680 return git_str_oom(buf
) ? -1 : 0;
683 static int add_push_report_pkt(git_push
*push
, git_pkt
*pkt
)
689 status
= git__calloc(1, sizeof(push_status
));
690 GIT_ERROR_CHECK_ALLOC(status
);
692 status
->ref
= git__strdup(((git_pkt_ok
*)pkt
)->ref
);
694 git_vector_insert(&push
->status
, status
) < 0) {
695 git_push_status_free(status
);
700 status
= git__calloc(1, sizeof(push_status
));
701 GIT_ERROR_CHECK_ALLOC(status
);
702 status
->ref
= git__strdup(((git_pkt_ng
*)pkt
)->ref
);
703 status
->msg
= git__strdup(((git_pkt_ng
*)pkt
)->msg
);
704 if (!status
->ref
|| !status
->msg
||
705 git_vector_insert(&push
->status
, status
) < 0) {
706 git_push_status_free(status
);
711 push
->unpack_ok
= ((git_pkt_unpack
*)pkt
)->unpack_ok
;
716 git_error_set(GIT_ERROR_NET
, "report-status: protocol error");
723 static int add_push_report_sideband_pkt(git_push
*push
, git_pkt_data
*data_pkt
, git_str
*data_pkt_buf
)
726 const char *line
, *line_end
= NULL
;
729 int reading_from_buf
= data_pkt_buf
->size
> 0;
731 if (reading_from_buf
) {
732 /* We had an existing partial packet, so add the new
733 * packet to the buffer and parse the whole thing */
734 git_str_put(data_pkt_buf
, data_pkt
->data
, data_pkt
->len
);
735 line
= data_pkt_buf
->ptr
;
736 line_len
= data_pkt_buf
->size
;
739 line
= data_pkt
->data
;
740 line_len
= data_pkt
->len
;
743 while (line_len
> 0) {
744 error
= git_pkt_parse_line(&pkt
, &line_end
, line
, line_len
);
746 if (error
== GIT_EBUFS
) {
747 /* Buffer the data when the inner packet is split
748 * across multiple sideband packets */
749 if (!reading_from_buf
)
750 git_str_put(data_pkt_buf
, line
, line_len
);
757 /* Advance in the buffer */
758 line_len
-= (line_end
- line
);
761 error
= add_push_report_pkt(push
, pkt
);
765 if (error
< 0 && error
!= GIT_ITEROVER
)
772 if (reading_from_buf
)
773 git_str_consume(data_pkt_buf
, line_end
);
777 static int parse_report(transport_smart
*transport
, git_push
*push
)
780 const char *line_end
= NULL
;
781 gitno_buffer
*buf
= &transport
->buffer
;
783 git_str data_pkt_buf
= GIT_STR_INIT
;
787 error
= git_pkt_parse_line(&pkt
, &line_end
,
788 buf
->data
, buf
->offset
);
792 if (error
< 0 && error
!= GIT_EBUFS
) {
797 if (error
== GIT_EBUFS
) {
798 if ((recvd
= gitno_recv(buf
)) < 0) {
804 git_error_set(GIT_ERROR_NET
, "early EOF");
811 if (gitno_consume(buf
, line_end
) < 0)
818 /* This is a sideband packet which contains other packets */
819 error
= add_push_report_sideband_pkt(push
, (git_pkt_data
*)pkt
, &data_pkt_buf
);
822 git_error_set(GIT_ERROR_NET
, "report-status: Error reported: %s",
823 ((git_pkt_err
*)pkt
)->error
);
826 case GIT_PKT_PROGRESS
:
827 if (transport
->connect_opts
.callbacks
.sideband_progress
) {
828 git_pkt_progress
*p
= (git_pkt_progress
*) pkt
;
830 if (p
->len
> INT_MAX
) {
831 git_error_set(GIT_ERROR_NET
, "oversized progress message");
836 error
= transport
->connect_opts
.callbacks
.sideband_progress(p
->data
, (int)p
->len
, transport
->connect_opts
.callbacks
.payload
);
840 error
= add_push_report_pkt(push
, pkt
);
846 /* add_push_report_pkt returns GIT_ITEROVER when it receives a flush */
847 if (error
== GIT_ITEROVER
) {
849 if (data_pkt_buf
.size
> 0) {
850 /* If there was data remaining in the pack data buffer,
851 * then the server sent a partial pkt-line */
852 git_error_set(GIT_ERROR_NET
, "incomplete pack data pkt-line");
863 git_str_dispose(&data_pkt_buf
);
867 static int add_ref_from_push_spec(git_vector
*refs
, push_spec
*push_spec
)
869 git_pkt_ref
*added
= git__calloc(1, sizeof(git_pkt_ref
));
870 GIT_ERROR_CHECK_ALLOC(added
);
872 added
->type
= GIT_PKT_REF
;
873 git_oid_cpy(&added
->head
.oid
, &push_spec
->loid
);
874 added
->head
.name
= git__strdup(push_spec
->refspec
.dst
);
876 if (!added
->head
.name
||
877 git_vector_insert(refs
, added
) < 0) {
878 git_pkt_free((git_pkt
*)added
);
885 static int update_refs_from_report(
887 git_vector
*push_specs
,
888 git_vector
*push_report
)
891 push_spec
*push_spec
;
892 push_status
*push_status
;
893 size_t i
, j
, refs_len
;
896 /* For each push spec we sent to the server, we should have
897 * gotten back a status packet in the push report */
898 if (push_specs
->length
!= push_report
->length
) {
899 git_error_set(GIT_ERROR_NET
, "report-status: protocol error");
903 /* We require that push_specs be sorted with push_spec_rref_cmp,
904 * and that push_report be sorted with push_status_ref_cmp */
905 git_vector_sort(push_specs
);
906 git_vector_sort(push_report
);
908 git_vector_foreach(push_specs
, i
, push_spec
) {
909 push_status
= git_vector_get(push_report
, i
);
911 /* For each push spec we sent to the server, we should have
912 * gotten back a status packet in the push report which matches */
913 if (strcmp(push_spec
->refspec
.dst
, push_status
->ref
)) {
914 git_error_set(GIT_ERROR_NET
, "report-status: protocol error");
919 /* We require that refs be sorted with ref_name_cmp */
920 git_vector_sort(refs
);
922 refs_len
= refs
->length
;
924 /* Merge join push_specs with refs */
925 while (i
< push_specs
->length
&& j
< refs_len
) {
926 push_spec
= git_vector_get(push_specs
, i
);
927 push_status
= git_vector_get(push_report
, i
);
928 ref
= git_vector_get(refs
, j
);
930 cmp
= strcmp(push_spec
->refspec
.dst
, ref
->head
.name
);
932 /* Iterate appropriately */
939 add_ref_from_push_spec(refs
, push_spec
) < 0)
942 /* Update case, delete case */
945 git_oid_cpy(&ref
->head
.oid
, &push_spec
->loid
);
948 for (; i
< push_specs
->length
; i
++) {
949 push_spec
= git_vector_get(push_specs
, i
);
950 push_status
= git_vector_get(push_report
, i
);
953 if (!push_status
->msg
&&
954 add_ref_from_push_spec(refs
, push_spec
) < 0)
958 /* Remove any refs which we updated to have a zero OID. */
959 git_vector_rforeach(refs
, i
, ref
) {
960 if (git_oid_is_zero(&ref
->head
.oid
)) {
961 git_vector_remove(refs
, i
);
962 git_pkt_free((git_pkt
*)ref
);
966 git_vector_sort(refs
);
971 struct push_packbuilder_payload
973 git_smart_subtransport_stream
*stream
;
975 git_push_transfer_progress_cb cb
;
978 double last_progress_report_time
;
981 static int stream_thunk(void *buf
, size_t size
, void *data
)
984 struct push_packbuilder_payload
*payload
= data
;
986 if ((error
= payload
->stream
->write(payload
->stream
, (const char *)buf
, size
)) < 0)
990 double current_time
= git__timer();
991 double elapsed
= current_time
- payload
->last_progress_report_time
;
992 payload
->last_bytes
+= size
;
994 if (elapsed
< 0 || elapsed
>= MIN_PROGRESS_UPDATE_INTERVAL
) {
995 payload
->last_progress_report_time
= current_time
;
996 error
= payload
->cb(payload
->pb
->nr_written
, payload
->pb
->nr_objects
, payload
->last_bytes
, payload
->cb_payload
);
1003 int git_smart__push(git_transport
*transport
, git_push
*push
)
1005 transport_smart
*t
= (transport_smart
*)transport
;
1006 git_remote_callbacks
*cbs
= &t
->connect_opts
.callbacks
;
1007 struct push_packbuilder_payload packbuilder_payload
= {0};
1008 git_str pktline
= GIT_STR_INIT
;
1009 int error
= 0, need_pack
= 0;
1013 packbuilder_payload
.pb
= push
->pb
;
1015 if (cbs
&& cbs
->push_transfer_progress
) {
1016 packbuilder_payload
.cb
= cbs
->push_transfer_progress
;
1017 packbuilder_payload
.cb_payload
= cbs
->payload
;
1022 git_remote_head
*head
;
1023 char hex
[GIT_OID_HEXSZ
+1]; hex
[GIT_OID_HEXSZ
] = '\0';
1025 git_vector_foreach(&push
->remote
->refs
, i
, head
) {
1026 git_oid_fmt(hex
, &head
->oid
);
1027 fprintf(stderr
, "%s (%s)\n", hex
, head
->name
);
1030 git_vector_foreach(&push
->specs
, i
, spec
) {
1031 git_oid_fmt(hex
, &spec
->roid
);
1032 fprintf(stderr
, "%s (%s) -> ", hex
, spec
->lref
);
1033 git_oid_fmt(hex
, &spec
->loid
);
1034 fprintf(stderr
, "%s (%s)\n", hex
, spec
->rref
?
1035 spec
->rref
: spec
->lref
);
1041 * Figure out if we need to send a packfile; which is in all
1042 * cases except when we only send delete commands
1044 git_vector_foreach(&push
->specs
, i
, spec
) {
1045 if (spec
->refspec
.src
&& spec
->refspec
.src
[0] != '\0') {
1051 /* prepare pack before sending pack header to avoid timeouts */
1052 if (need_pack
&& ((error
= git_packbuilder__prepare(push
->pb
))) < 0)
1055 if ((error
= git_smart__get_push_stream(t
, &packbuilder_payload
.stream
)) < 0 ||
1056 (error
= gen_pktline(&pktline
, push
)) < 0 ||
1057 (error
= packbuilder_payload
.stream
->write(packbuilder_payload
.stream
, git_str_cstr(&pktline
), git_str_len(&pktline
))) < 0)
1061 (error
= git_packbuilder_foreach(push
->pb
, &stream_thunk
, &packbuilder_payload
)) < 0)
1064 /* If we sent nothing or the server doesn't support report-status, then
1065 * we consider the pack to have been unpacked successfully */
1066 if (!push
->specs
.length
|| !push
->report_status
)
1067 push
->unpack_ok
= 1;
1068 else if ((error
= parse_report(t
, push
)) < 0)
1071 /* If progress is being reported write the final report */
1072 if (cbs
&& cbs
->push_transfer_progress
) {
1073 error
= cbs
->push_transfer_progress(
1074 push
->pb
->nr_written
,
1075 push
->pb
->nr_objects
,
1076 packbuilder_payload
.last_bytes
,
1083 if (push
->status
.length
) {
1084 error
= update_refs_from_report(&t
->refs
, &push
->specs
, &push
->status
);
1088 error
= git_smart__update_heads(t
, NULL
);
1092 git_str_dispose(&pktline
);