diff options
-rw-r--r-- | include/git2/remote.h | 8 | ||||
-rw-r--r-- | src/fetch.c | 34 | ||||
-rw-r--r-- | src/remote.c | 5 | ||||
-rw-r--r-- | src/revparse.c | 24 | ||||
-rw-r--r-- | src/transport.h | 2 | ||||
-rw-r--r-- | tests-clar/refs/isvalidname.c | 1 | ||||
-rw-r--r-- | tests-clar/refs/revparse.c | 34 |
7 files changed, 93 insertions, 15 deletions
diff --git a/include/git2/remote.h b/include/git2/remote.h index a40daec81..6471acc6a 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -199,6 +199,14 @@ GIT_EXTERN(int) git_remote_download(git_remote *remote, git_off_t *bytes, git_in GIT_EXTERN(int) git_remote_connected(git_remote *remote); /** + * Cancel the operation + * + * At certain points in its operation, the network code checks whether + * the operation has been cancelled and if so stops the operation. + */ +GIT_EXTERN(void) git_remote_stop(git_remote *remote); + +/** * Disconnect from the remote * * Close the connection to the remote and free the underlying diff --git a/src/fetch.c b/src/fetch.c index 737a1b4cb..dc01f6791 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -152,7 +152,7 @@ int git_fetch_negotiate(git_remote *remote) gitno_buffer *buf = &t->buffer; git_buf data = GIT_BUF_INIT; git_revwalk *walk = NULL; - int error, pkt_type; + int error = -1, pkt_type; unsigned int i; git_oid oid; @@ -190,6 +190,12 @@ int git_fetch_negotiate(git_remote *remote) git_pkt_buffer_have(&oid, &data); i++; if (i % 20 == 0) { + if (t->cancel.val) { + giterr_set(GITERR_NET, "The fetch was cancelled by the user"); + error = GIT_EUSER; + goto on_error; + } + git_pkt_buffer_flush(&data); if (git_buf_oom(&data)) goto on_error; @@ -254,6 +260,11 @@ int git_fetch_negotiate(git_remote *remote) } git_pkt_buffer_done(&data); + if (t->cancel.val) { + giterr_set(GITERR_NET, "The fetch was cancelled by the user"); + error = GIT_EUSER; + goto on_error; + } if (t->negotiation_step(t, data.ptr, data.size) < 0) goto on_error; @@ -288,7 +299,7 @@ int git_fetch_negotiate(git_remote *remote) on_error: git_revwalk_free(walk); git_buf_free(&data); - return -1; + return error; } int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats) @@ -305,11 +316,16 @@ int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_st } -static int no_sideband(git_indexer_stream *idx, gitno_buffer *buf, git_off_t *bytes, git_indexer_stats *stats) +static int no_sideband(git_transport *t, git_indexer_stream *idx, gitno_buffer *buf, git_off_t *bytes, git_indexer_stats *stats) { int recvd; do { + if (t->cancel.val) { + giterr_set(GITERR_NET, "The fetch was cancelled by the user"); + return GIT_EUSER; + } + if (git_indexer_stream_add(idx, buf->data, buf->offset, stats) < 0) return -1; @@ -337,6 +353,7 @@ int git_fetch__download_pack( git_buf path = GIT_BUF_INIT; gitno_buffer *buf = &t->buffer; git_indexer_stream *idx = NULL; + int error = -1; if (git_buf_joinpath(&path, git_repository_path(repo), "objects/pack") < 0) return -1; @@ -354,7 +371,7 @@ int git_fetch__download_pack( * check which one belongs there. */ if (!t->caps.side_band && !t->caps.side_band_64k) { - if (no_sideband(idx, buf, bytes, stats) < 0) + if (no_sideband(t, idx, buf, bytes, stats) < 0) goto on_error; git_indexer_stream_free(idx); @@ -363,6 +380,13 @@ int git_fetch__download_pack( do { git_pkt *pkt; + + if (t->cancel.val) { + giterr_set(GITERR_NET, "The fetch was cancelled by the user"); + error = GIT_EUSER; + goto on_error; + } + if (recv_pkt(&pkt, buf) < 0) goto on_error; @@ -395,7 +419,7 @@ int git_fetch__download_pack( on_error: git_buf_free(&path); git_indexer_stream_free(idx); - return -1; + return error; } int git_fetch_setup_walk(git_revwalk **out, git_repository *repo) diff --git a/src/remote.c b/src/remote.c index b73af0128..c47f2d1ec 100644 --- a/src/remote.c +++ b/src/remote.c @@ -558,6 +558,11 @@ int git_remote_connected(git_remote *remote) return remote->transport == NULL ? 0 : remote->transport->connected; } +void git_remote_stop(git_remote *remote) +{ + git_atomic_set(&remote->transport->cancel, 1); +} + void git_remote_disconnect(git_remote *remote) { assert(remote); diff --git a/src/revparse.c b/src/revparse.c index 191f6374c..83eea7d3f 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -795,20 +795,24 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec case '@': { - git_object *temp_object = NULL; + if (spec[pos+1] == '{') { + git_object *temp_object = NULL; - if ((error = extract_curly_braces_content(&buf, spec, &pos)) < 0) - goto cleanup; + if ((error = extract_curly_braces_content(&buf, spec, &pos)) < 0) + goto cleanup; - if ((error = ensure_base_rev_is_not_known_yet(base_rev, spec)) < 0) - goto cleanup; + if ((error = ensure_base_rev_is_not_known_yet(base_rev, spec)) < 0) + goto cleanup; - if ((error = handle_at_syntax(&temp_object, &reference, spec, identifier_len, repo, git_buf_cstr(&buf))) < 0) - goto cleanup; + if ((error = handle_at_syntax(&temp_object, &reference, spec, identifier_len, repo, git_buf_cstr(&buf))) < 0) + goto cleanup; - if (temp_object != NULL) - base_rev = temp_object; - break; + if (temp_object != NULL) + base_rev = temp_object; + break; + } else { + /* Fall through */ + } } default: diff --git a/src/transport.h b/src/transport.h index 9c91afd5b..4c944b9e7 100644 --- a/src/transport.h +++ b/src/transport.h @@ -91,6 +91,8 @@ struct git_transport { GIT_SOCKET socket; git_transport_caps caps; void *cb_data; + git_atomic cancel; + /** * Connect and store the remote heads */ diff --git a/tests-clar/refs/isvalidname.c b/tests-clar/refs/isvalidname.c index 99761de32..8a31f5cbe 100644 --- a/tests-clar/refs/isvalidname.c +++ b/tests-clar/refs/isvalidname.c @@ -20,4 +20,5 @@ void test_refs_isvalidname__wont_hopefully_choke_on_valid_formats(void) cl_assert_equal_i(true, git_reference_is_valid_name("HEAD")); cl_assert_equal_i(true, git_reference_is_valid_name("ONE_LEVEL")); cl_assert_equal_i(true, git_reference_is_valid_name("refs/stash")); + cl_assert_equal_i(true, git_reference_is_valid_name("refs/remotes/origin/bim_with_3d@11296")); } diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 14bd9fb84..a1f0dbf2b 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -451,3 +451,37 @@ void test_refs_revparse__a_too_short_objectid_returns_EAMBIGUOUS(void) cl_assert_equal_i(GIT_EAMBIGUOUS, result); } + +void test_refs_revparse__issue_994(void) +{ + git_repository *repo; + git_reference *head, *with_at; + git_object *target; + + repo = cl_git_sandbox_init("testrepo.git"); + + cl_assert_equal_i(GIT_ENOTFOUND, + git_revparse_single(&target, repo, "origin/bim_with_3d@11296")); + + cl_assert_equal_i(GIT_ENOTFOUND, + git_revparse_single(&target, repo, "refs/remotes/origin/bim_with_3d@11296")); + + + cl_git_pass(git_repository_head(&head, repo)); + cl_git_pass(git_reference_create_oid( + &with_at, + repo, + "refs/remotes/origin/bim_with_3d@11296", + git_reference_oid(head), + 0)); + + cl_git_pass(git_revparse_single(&target, repo, "origin/bim_with_3d@11296")); + git_object_free(target); + + cl_git_pass(git_revparse_single(&target, repo, "refs/remotes/origin/bim_with_3d@11296")); + git_object_free(target); + + git_reference_free(with_at); + git_reference_free(head); + cl_git_sandbox_cleanup(); +} |