summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/remote.h8
-rw-r--r--src/fetch.c34
-rw-r--r--src/remote.c5
-rw-r--r--src/revparse.c24
-rw-r--r--src/transport.h2
-rw-r--r--tests-clar/refs/isvalidname.c1
-rw-r--r--tests-clar/refs/revparse.c34
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();
+}