summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-12-04 21:22:57 -0800
committerRussell Belfer <rb@github.com>2013-12-11 10:57:49 -0800
commitdab89f9b6821b67dd07c8bd4dbb53e25a3e687c7 (patch)
treec7f4f4738dfb249b7534635226128d2e20dac6a5
parent96869a4edb2872934e0e167a726ab240f4270fea (diff)
downloadlibgit2-dab89f9b6821b67dd07c8bd4dbb53e25a3e687c7.tar.gz
Further EUSER and error propagation fixes
This continues auditing all the places where GIT_EUSER is being returned and making sure to clear any existing error using the new giterr_user_cancel helper. As a result, places that relied on intercepting GIT_EUSER but having the old error preserved also needed to be cleaned up to correctly stash and then retrieve the actual error. Additionally, as I encountered places where error codes were not being propagated correctly, I tried to fix them up. A number of those fixes are included in the this commit as well.
-rw-r--r--src/attr.c7
-rw-r--r--src/clone.c120
-rw-r--r--src/fetchhead.c4
-rw-r--r--src/ignore.c21
-rw-r--r--src/index.c12
-rw-r--r--src/indexer.c6
-rw-r--r--src/merge.c5
-rw-r--r--src/notes.c2
-rw-r--r--src/pack-objects.c47
-rw-r--r--src/pack.c6
-rw-r--r--src/push.c2
-rw-r--r--src/refs.c27
-rw-r--r--src/remote.c47
-rw-r--r--src/revwalk.c21
-rw-r--r--src/stash.c4
-rw-r--r--src/status.c3
-rw-r--r--src/tag.c42
-rw-r--r--src/transports/git.c27
-rw-r--r--src/transports/smart.c3
-rw-r--r--src/tree.c13
-rw-r--r--tests/core/path.c46
21 files changed, 273 insertions, 192 deletions
diff --git a/src/attr.c b/src/attr.c
index 2fccf21f8..1a0f1f97f 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -480,6 +480,7 @@ typedef struct {
const char *workdir;
git_index *index;
git_vector *files;
+ git_error_state error;
} attr_walk_up_info;
int git_attr_cache__decide_sources(
@@ -523,7 +524,7 @@ static int push_one_attr(void *ref, git_buf *path)
info->repo, path->ptr, GIT_ATTR_FILE, src[i],
git_attr_file__parse_buffer, NULL, info->files);
- return error;
+ return giterr_capture(&info->error, error);
}
static int collect_attr_files(
@@ -535,7 +536,7 @@ static int collect_attr_files(
int error;
git_buf dir = GIT_BUF_INIT;
const char *workdir = git_repository_workdir(repo);
- attr_walk_up_info info;
+ attr_walk_up_info info = { NULL };
if (git_attr_cache__init(repo) < 0 ||
git_vector_init(files, 4, NULL) < 0)
@@ -569,6 +570,8 @@ static int collect_attr_files(
info.files = files;
error = git_path_walk_up(&dir, workdir, push_one_attr, &info);
+ if (error == GIT_EUSER)
+ error = giterr_restore(&info.error);
if (error < 0)
goto cleanup;
diff --git a/src/clone.c b/src/clone.c
index 23aacd478..415efabba 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -107,6 +107,7 @@ struct head_info {
git_buf branchname;
const git_refspec *refspec;
bool found;
+ git_error_state error;
};
static int reference_matches_remote_head(
@@ -115,43 +116,38 @@ static int reference_matches_remote_head(
{
struct head_info *head_info = (struct head_info *)payload;
git_oid oid;
+ int error;
/* TODO: Should we guard against references
* which name doesn't start with refs/heads/ ?
*/
- /* Stop looking if we've already found a match */
- if (head_info->found)
+ error = git_reference_name_to_id(&oid, head_info->repo, reference_name);
+ if (error == GIT_ENOTFOUND) {
+ /* If the reference doesn't exists, it obviously cannot match the
+ * expected oid. */
+ giterr_clear();
return 0;
-
- if (git_reference_name_to_id(
- &oid,
- head_info->repo,
- reference_name) < 0) {
- /* If the reference doesn't exists, it obviously cannot match the expected oid. */
- giterr_clear();
- return 0;
}
- if (git_oid__cmp(&head_info->remote_head_oid, &oid) == 0) {
+ if (!error && !git_oid__cmp(&head_info->remote_head_oid, &oid)) {
/* Determine the local reference name from the remote tracking one */
- if (git_refspec_transform_l(
- &head_info->branchname,
- head_info->refspec,
- reference_name) < 0)
- return -1;
-
- if (git_buf_len(&head_info->branchname) > 0) {
- if (git_buf_sets(
- &head_info->branchname,
- git_buf_cstr(&head_info->branchname) + strlen(GIT_REFS_HEADS_DIR)) < 0)
- return -1;
+ error = git_refspec_transform_l(
+ &head_info->branchname, head_info->refspec, reference_name);
- head_info->found = 1;
+ if (!error &&
+ git_buf_len(&head_info->branchname) > 0 &&
+ !(error = git_buf_sets(
+ &head_info->branchname,
+ git_buf_cstr(&head_info->branchname) +
+ strlen(GIT_REFS_HEADS_DIR))))
+ {
+ head_info->found = true;
+ error = GIT_ITEROVER;
}
}
- return 0;
+ return giterr_capture(&head_info->error, error);
}
static int update_head_to_new_branch(
@@ -160,16 +156,11 @@ static int update_head_to_new_branch(
const char *name)
{
git_reference *tracking_branch = NULL;
- int error;
-
- if ((error = create_tracking_branch(
- &tracking_branch,
- repo,
- target,
- name)) < 0)
- return error;
+ int error = create_tracking_branch(&tracking_branch, repo, target, name);
- error = git_repository_set_head(repo, git_reference_name(tracking_branch));
+ if (!error)
+ error = git_repository_set_head(
+ repo, git_reference_name(tracking_branch));
git_reference_free(tracking_branch);
@@ -178,34 +169,30 @@ static int update_head_to_new_branch(
static int update_head_to_remote(git_repository *repo, git_remote *remote)
{
- int retcode = -1;
+ int error = 0;
size_t refs_len;
git_refspec dummy_spec;
const git_remote_head *remote_head, **refs;
struct head_info head_info;
git_buf remote_master_name = GIT_BUF_INIT;
- if (git_remote_ls(&refs, &refs_len, remote) < 0)
- return -1;
+ if ((error = git_remote_ls(&refs, &refs_len, remote)) < 0)
+ return error;
/* Did we just clone an empty repository? */
- if (refs_len == 0) {
+ if (refs_len == 0)
return setup_tracking_config(
- repo,
- "master",
- GIT_REMOTE_ORIGIN,
- GIT_REFS_HEADS_MASTER_FILE);
- }
+ repo, "master", GIT_REMOTE_ORIGIN, GIT_REFS_HEADS_MASTER_FILE);
/* Get the remote's HEAD. This is always the first ref in the list. */
remote_head = refs[0];
assert(remote_head);
+ memset(&head_info, 0, sizeof(head_info));
git_oid_cpy(&head_info.remote_head_oid, &remote_head->oid);
- git_buf_init(&head_info.branchname, 16);
head_info.repo = repo;
- head_info.refspec = git_remote__matching_refspec(remote, GIT_REFS_HEADS_MASTER_FILE);
- head_info.found = 0;
+ head_info.refspec =
+ git_remote__matching_refspec(remote, GIT_REFS_HEADS_MASTER_FILE);
if (head_info.refspec == NULL) {
memset(&dummy_spec, 0, sizeof(git_refspec));
@@ -213,50 +200,53 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)
}
/* Determine the remote tracking reference name from the local master */
- if (git_refspec_transform_r(
+ if ((error = git_refspec_transform_r(
&remote_master_name,
head_info.refspec,
- GIT_REFS_HEADS_MASTER_FILE) < 0)
- return -1;
+ GIT_REFS_HEADS_MASTER_FILE)) < 0)
+ return error;
/* Check to see if the remote HEAD points to the remote master */
- if (reference_matches_remote_head(git_buf_cstr(&remote_master_name), &head_info) < 0)
- goto cleanup;
+ error = reference_matches_remote_head(
+ git_buf_cstr(&remote_master_name), &head_info);
+
+ if (error < 0) {
+ error = giterr_restore(&head_info.error);
+ if (error < 0 && error != GIT_ITEROVER)
+ goto cleanup;
+ }
if (head_info.found) {
- retcode = update_head_to_new_branch(
+ error = update_head_to_new_branch(
repo,
&head_info.remote_head_oid,
git_buf_cstr(&head_info.branchname));
-
goto cleanup;
}
/* Not master. Check all the other refs. */
- if (git_reference_foreach_name(
- repo,
- reference_matches_remote_head,
- &head_info) < 0)
- goto cleanup;
+ error = git_reference_foreach_name(
+ repo, reference_matches_remote_head, &head_info);
+
+ if (error == GIT_EUSER)
+ error = giterr_restore(&head_info.error);
+ if (error < 0 && error != GIT_ITEROVER)
+ goto cleanup;
if (head_info.found) {
- retcode = update_head_to_new_branch(
+ error = update_head_to_new_branch(
repo,
&head_info.remote_head_oid,
git_buf_cstr(&head_info.branchname));
-
- goto cleanup;
} else {
- retcode = git_repository_set_head_detached(
- repo,
- &head_info.remote_head_oid);
- goto cleanup;
+ error = git_repository_set_head_detached(
+ repo, &head_info.remote_head_oid);
}
cleanup:
git_buf_free(&remote_master_name);
git_buf_free(&head_info.branchname);
- return retcode;
+ return error;
}
static int update_head_to_branch(
diff --git a/src/fetchhead.c b/src/fetchhead.c
index 67089d13d..ee1492211 100644
--- a/src/fetchhead.c
+++ b/src/fetchhead.c
@@ -269,8 +269,8 @@ int git_repository_fetchhead_foreach(git_repository *repo,
else
ref_name = NULL;
- if ((cb(ref_name, remote_url, &oid, is_merge, payload)) != 0) {
- error = GIT_EUSER;
+ if (cb(ref_name, remote_url, &oid, is_merge, payload) != 0) {
+ error = giterr_user_cancel();
goto done;
}
}
diff --git a/src/ignore.c b/src/ignore.c
index 27d7c7ec4..aa53d409d 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -74,10 +74,20 @@ static int parse_ignore_file(
#define push_ignore_file(R,IGN,S,B,F) \
git_attr_cache__push_file((R),(B),(F),GIT_ATTR_FILE_FROM_FILE,parse_ignore_file,(IGN),(S))
+struct ignores_walk_up_data {
+ git_ignores *ign;
+ git_error_state error;
+};
+
static int push_one_ignore(void *ref, git_buf *path)
{
- git_ignores *ign = (git_ignores *)ref;
- return push_ignore_file(ign->repo, ign, &ign->ign_path, path->ptr, GIT_IGNORE_FILE);
+ struct ignores_walk_up_data *data = ref;
+
+ return giterr_capture(
+ &data->error,
+ push_ignore_file(
+ data->ign->repo, data->ign, &data->ign->ign_path,
+ path->ptr, GIT_IGNORE_FILE) );
}
static int get_internal_ignores(git_attr_file **ign, git_repository *repo)
@@ -132,8 +142,13 @@ int git_ignore__for_path(
/* load .gitignore up the path */
if (workdir != NULL) {
+ struct ignores_walk_up_data data = { ignores };
+
error = git_path_walk_up(
- &ignores->dir, workdir, push_one_ignore, ignores);
+ &ignores->dir, workdir, push_one_ignore, &data);
+
+ if (error == GIT_EUSER)
+ error = giterr_restore(&data.error);
if (error < 0)
goto cleanup;
}
diff --git a/src/index.c b/src/index.c
index 09e7b2346..d0d2cf187 100644
--- a/src/index.c
+++ b/src/index.c
@@ -2036,6 +2036,12 @@ int git_index_read_tree(git_index *index, const git_tree *tree)
error = git_tree_walk(tree, GIT_TREEWALK_POST, read_tree_cb, &data);
+ if (error == GIT_EUSER) {
+ giterr_set_oom();
+ git_vector_free(&entries);
+ return -1;
+ }
+
git_vector_sort(&entries);
git_index_clear(index);
@@ -2116,8 +2122,7 @@ int git_index_add_all(
if (error > 0) /* return > 0 means skip this one */
continue;
if (error < 0) { /* return < 0 means abort */
- giterr_clear();
- error = GIT_EUSER;
+ error = giterr_user_cancel();
break;
}
}
@@ -2205,8 +2210,7 @@ static int index_apply_to_all(
continue;
}
if (error < 0) { /* return < 0 means abort */
- giterr_clear();
- error = GIT_EUSER;
+ error = giterr_user_cancel();
break;
}
}
diff --git a/src/indexer.c b/src/indexer.c
index 852a04120..7312809bf 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -387,10 +387,8 @@ on_error:
static int do_progress_callback(git_indexer *idx, git_transfer_progress *stats)
{
if (idx->progress_cb &&
- idx->progress_cb(stats, idx->progress_payload)) {
- giterr_clear();
- return GIT_EUSER;
- }
+ idx->progress_cb(stats, idx->progress_payload))
+ return giterr_user_cancel();
return 0;
}
diff --git a/src/merge.c b/src/merge.c
index e552b037b..0d89da5a0 100644
--- a/src/merge.c
+++ b/src/merge.c
@@ -254,7 +254,8 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
return 0;
}
-int git_repository_mergehead_foreach(git_repository *repo,
+int git_repository_mergehead_foreach(
+ git_repository *repo,
git_repository_mergehead_foreach_cb cb,
void *payload)
{
@@ -287,7 +288,7 @@ int git_repository_mergehead_foreach(git_repository *repo,
goto cleanup;
if (cb(&oid, payload) != 0) {
- error = GIT_EUSER;
+ error = giterr_user_cancel();
goto cleanup;
}
diff --git a/src/notes.c b/src/notes.c
index d8ed32f82..7e8aecbae 100644
--- a/src/notes.c
+++ b/src/notes.c
@@ -584,7 +584,7 @@ int git_note_foreach(
while (!(error = git_note_next(&note_id, &annotated_id, iter))) {
if (note_cb(&note_id, &annotated_id, payload)) {
- error = GIT_EUSER;
+ error = giterr_user_cancel();
break;
}
}
diff --git a/src/pack-objects.c b/src/pack-objects.c
index 2d62507f2..ac0615064 100644
--- a/src/pack-objects.c
+++ b/src/pack-objects.c
@@ -32,6 +32,7 @@ struct unpacked {
struct tree_walk_context {
git_packbuilder *pb;
git_buf buf;
+ git_error_state error;
};
struct pack_write_context {
@@ -220,12 +221,15 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
if (pb->progress_cb) {
double current_time = git__timer();
- if ((current_time - pb->last_progress_report_time) >= MIN_PROGRESS_UPDATE_INTERVAL) {
+ double elapsed = current_time - pb->last_progress_report_time;
+
+ if (elapsed >= MIN_PROGRESS_UPDATE_INTERVAL) {
pb->last_progress_report_time = current_time;
- if (pb->progress_cb(GIT_PACKBUILDER_ADDING_OBJECTS, pb->nr_objects, 0, pb->progress_cb_payload)) {
- giterr_clear();
- return GIT_EUSER;
- }
+
+ if (pb->progress_cb(
+ GIT_PACKBUILDER_ADDING_OBJECTS,
+ pb->nr_objects, 0, pb->progress_cb_payload))
+ return giterr_user_cancel();
}
}
@@ -1284,21 +1288,22 @@ const git_oid *git_packbuilder_hash(git_packbuilder *pb)
return &pb->pack_oid;
}
-static int cb_tree_walk(const char *root, const git_tree_entry *entry, void *payload)
+static int cb_tree_walk(
+ const char *root, const git_tree_entry *entry, void *payload)
{
+ int error;
struct tree_walk_context *ctx = payload;
/* A commit inside a tree represents a submodule commit and should be skipped. */
if (git_tree_entry_type(entry) == GIT_OBJ_COMMIT)
return 0;
- if (git_buf_sets(&ctx->buf, root) < 0 ||
- git_buf_puts(&ctx->buf, git_tree_entry_name(entry)) < 0)
- return -1;
+ if (!(error = git_buf_sets(&ctx->buf, root)) &&
+ !(error = git_buf_puts(&ctx->buf, git_tree_entry_name(entry))))
+ error = git_packbuilder_insert(
+ ctx->pb, git_tree_entry_id(entry), git_buf_cstr(&ctx->buf));
- return git_packbuilder_insert(ctx->pb,
- git_tree_entry_id(entry),
- git_buf_cstr(&ctx->buf));
+ return giterr_capture(&ctx->error, error);
}
int git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *oid)
@@ -1318,22 +1323,20 @@ int git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *oid)
int git_packbuilder_insert_tree(git_packbuilder *pb, const git_oid *oid)
{
- git_tree *tree;
+ int error;
+ git_tree *tree = NULL;
struct tree_walk_context context = { pb, GIT_BUF_INIT };
- if (git_tree_lookup(&tree, pb->repo, oid) < 0 ||
- git_packbuilder_insert(pb, oid, NULL) < 0)
- return -1;
+ if (!(error = git_tree_lookup(&tree, pb->repo, oid)) &&
+ !(error = git_packbuilder_insert(pb, oid, NULL)))
+ error = git_tree_walk(tree, GIT_TREEWALK_PRE, cb_tree_walk, &context);
- if (git_tree_walk(tree, GIT_TREEWALK_PRE, cb_tree_walk, &context) < 0) {
- git_tree_free(tree);
- git_buf_free(&context.buf);
- return -1;
- }
+ if (error == GIT_EUSER)
+ error = giterr_restore(&context.error);
git_tree_free(tree);
git_buf_free(&context.buf);
- return 0;
+ return error;
}
uint32_t git_packbuilder_object_count(git_packbuilder *pb)
diff --git a/src/pack.c b/src/pack.c
index 644b2d465..f69fe85e8 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -1042,10 +1042,9 @@ int git_pack_foreach_entry(
{
const unsigned char *index = p->index_map.data, *current;
uint32_t i;
+ int error = 0;
if (index == NULL) {
- int error;
-
if ((error = pack_index_open(p)) < 0)
return error;
@@ -1062,7 +1061,6 @@ int git_pack_foreach_entry(
if (p->oids == NULL) {
git_vector offsets, oids;
- int error;
if ((error = git_vector_init(&oids, p->num_objects, NULL)))
return error;
@@ -1090,7 +1088,7 @@ int git_pack_foreach_entry(
for (i = 0; i < p->num_objects; i++)
if (cb(p->oids[i], data))
- return GIT_EUSER;
+ return giterr_user_cancel();
return 0;
}
diff --git a/src/push.c b/src/push.c
index 3c9d5bb35..e592249d9 100644
--- a/src/push.c
+++ b/src/push.c
@@ -663,7 +663,7 @@ int git_push_status_foreach(git_push *push,
git_vector_foreach(&push->status, i, status) {
if (cb(status->ref, status->msg, data) < 0)
- return GIT_EUSER;
+ return giterr_user_cancel();
}
return 0;
diff --git a/src/refs.c b/src/refs.c
index bae62158b..60ed9ffb1 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -513,20 +513,19 @@ int git_reference_foreach(
git_reference *ref;
int error;
- if (git_reference_iterator_new(&iter, repo) < 0)
- return -1;
+ if ((error = git_reference_iterator_new(&iter, repo)) < 0)
+ return error;
while ((error = git_reference_next(&ref, iter)) == 0) {
if (callback(ref, payload)) {
- error = GIT_EUSER;
- goto out;
+ error = giterr_user_cancel();
+ break;
}
}
if (error == GIT_ITEROVER)
error = 0;
-out:
git_reference_iterator_free(iter);
return error;
}
@@ -540,20 +539,19 @@ int git_reference_foreach_name(
const char *refname;
int error;
- if (git_reference_iterator_new(&iter, repo) < 0)
- return -1;
+ if ((error = git_reference_iterator_new(&iter, repo)) < 0)
+ return error;
while ((error = git_reference_next_name(&refname, iter)) == 0) {
if (callback(refname, payload)) {
- error = GIT_EUSER;
- goto out;
+ error = giterr_user_cancel();
+ break;
}
}
if (error == GIT_ITEROVER)
error = 0;
-out:
git_reference_iterator_free(iter);
return error;
}
@@ -568,20 +566,19 @@ int git_reference_foreach_glob(
const char *refname;
int error;
- if (git_reference_iterator_glob_new(&iter, repo, glob) < 0)
- return -1;
+ if ((error = git_reference_iterator_glob_new(&iter, repo, glob)) < 0)
+ return error;
while ((error = git_reference_next_name(&refname, iter)) == 0) {
if (callback(refname, payload)) {
- error = GIT_EUSER;
- goto out;
+ error = giterr_user_cancel();
+ break;
}
}
if (error == GIT_ITEROVER)
error = 0;
-out:
git_reference_iterator_free(iter);
return error;
}
diff --git a/src/remote.c b/src/remote.c
index e4bebe1c6..e9d079db5 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -1370,46 +1370,43 @@ static int rename_fetch_refspecs(
if (git_buf_printf(&base, "+refs/heads/*:refs/remotes/%s/*", remote->name) < 0)
goto cleanup;
+ if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
+ goto cleanup;
+
git_vector_foreach(&remote->refspecs, i, spec) {
if (spec->push)
continue;
- /* Every refspec is a problem refspec for an in-memory remote */
- if (!remote->name) {
- if (callback(spec->string, payload) < 0) {
- error = GIT_EUSER;
- goto cleanup;
- }
-
- continue;
- }
+ /* Every refspec is a problem refspec for an in-memory remote, OR */
+ /* Does the dst part of the refspec follow the expected format? */
+ if (!remote->name ||
+ strcmp(git_buf_cstr(&base), spec->string)) {
- /* Does the dst part of the refspec follow the extected standard format? */
- if (strcmp(git_buf_cstr(&base), spec->string)) {
if (callback(spec->string, payload) < 0) {
- error = GIT_EUSER;
+ error = giterr_user_cancel();
goto cleanup;
}
-
continue;
}
/* If we do want to move it to the new section */
- if (git_buf_printf(&val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0)
- goto cleanup;
- if (git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
- goto cleanup;
+ git_buf_clear(&val);
+ git_buf_clear(&var);
- if (git_repository_config__weakptr(&config, remote->repo) < 0)
+ if (git_buf_printf(
+ &val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0 ||
+ git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
+ {
+ error = -1;
goto cleanup;
+ }
- if (git_config_set_string(config, git_buf_cstr(&var), git_buf_cstr(&val)) < 0)
+ if ((error = git_config_set_string(
+ config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
goto cleanup;
}
- error = 0;
-
cleanup:
git_buf_free(&base);
git_buf_free(&var);
@@ -1445,11 +1442,11 @@ int git_remote_rename(
new_name,
callback,
payload)) < 0)
- return error;
+ return error;
remote->name = git__strdup(new_name);
+ GITERR_CHECK_ALLOC(remote->name);
- if (!remote->name) return 0;
return git_remote_save(remote);
}
@@ -1476,11 +1473,13 @@ int git_remote_rename(
new_name,
callback,
payload)) < 0)
- return error;
+ return error;
}
git__free(remote->name);
+
remote->name = git__strdup(new_name);
+ GITERR_CHECK_ALLOC(remote->name);
return 0;
}
diff --git a/src/revwalk.c b/src/revwalk.c
index 3dd14b419..e8c7f23ec 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -112,12 +112,13 @@ static int process_commit_parents(git_revwalk *walk, git_commit_list_node *commi
static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
{
+ int error;
git_object *obj;
git_otype type;
git_commit_list_node *commit;
- if (git_object_lookup(&obj, walk->repo, oid, GIT_OBJ_ANY) < 0)
- return -1;
+ if ((error = git_object_lookup(&obj, walk->repo, oid, GIT_OBJ_ANY)) < 0)
+ return error;
type = git_object_type(obj);
git_object_free(obj);
@@ -168,13 +169,15 @@ static int push_ref(git_revwalk *walk, const char *refname, int hide)
struct push_cb_data {
git_revwalk *walk;
int hide;
+ git_error_state error;
};
static int push_glob_cb(const char *refname, void *data_)
{
struct push_cb_data *data = (struct push_cb_data *)data_;
- return push_ref(data->walk, refname, data->hide);
+ return giterr_capture(
+ &data->error, push_ref(data->walk, refname, data->hide) );
}
static int push_glob(git_revwalk *walk, const char *glob, int hide)
@@ -191,6 +194,8 @@ static int push_glob(git_revwalk *walk, const char *glob, int hide)
git_buf_joinpath(&buf, GIT_REFS_DIR, glob);
else
git_buf_puts(&buf, glob);
+ if (git_buf_oom(&buf))
+ return -1;
/* If no '?', '*' or '[' exist, we append '/ *' to the glob */
wildcard = strcspn(glob, "?*[");
@@ -199,12 +204,12 @@ static int push_glob(git_revwalk *walk, const char *glob, int hide)
data.walk = walk;
data.hide = hide;
+ memset(&data.error, 0, sizeof(data.error));
- if (git_buf_oom(&buf))
- error = -1;
- else
- error = git_reference_foreach_glob(
- walk->repo, git_buf_cstr(&buf), push_glob_cb, &data);
+ error = git_reference_foreach_glob(
+ walk->repo, git_buf_cstr(&buf), push_glob_cb, &data);
+ if (error == GIT_EUSER)
+ error = giterr_restore(&data.error);
git_buf_free(&buf);
return error;
diff --git a/src/stash.c b/src/stash.c
index 083c2a4cd..06a7b9a33 100644
--- a/src/stash.c
+++ b/src/stash.c
@@ -586,8 +586,8 @@ int git_stash_foreach(
git_reflog_entry_message(entry),
git_reflog_entry_id_new(entry),
payload)) {
- error = GIT_EUSER;
- break;
+ error = giterr_user_cancel();
+ break;
}
}
diff --git a/src/status.c b/src/status.c
index fb99fb4e4..777b7964a 100644
--- a/src/status.c
+++ b/src/status.c
@@ -414,8 +414,7 @@ int git_status_foreach_ext(
status_entry->index_to_workdir->old_file.path;
if (cb(path, status_entry->status, payload) != 0) {
- error = GIT_EUSER;
- giterr_clear();
+ error = giterr_user_cancel();
break;
}
}
diff --git a/src/tag.c b/src/tag.c
index 31a3c8b80..5d4e45e5d 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -414,24 +414,29 @@ typedef struct {
git_repository *repo;
git_tag_foreach_cb cb;
void *cb_data;
+ git_error_state error;
} tag_cb_data;
static int tags_cb(const char *ref, void *data)
{
+ int error;
git_oid oid;
tag_cb_data *d = (tag_cb_data *)data;
if (git__prefixcmp(ref, GIT_REFS_TAGS_DIR) != 0)
return 0; /* no tag */
- if (git_reference_name_to_id(&oid, d->repo, ref) < 0)
- return -1;
+ if (!(error = git_reference_name_to_id(&oid, d->repo, ref))) {
+ if (d->cb(ref, &oid, d->cb_data))
+ error = giterr_user_cancel();
+ }
- return d->cb(ref, &oid, d->cb_data);
+ return giterr_capture(&d->error, error);
}
int git_tag_foreach(git_repository *repo, git_tag_foreach_cb cb, void *cb_data)
{
+ int error;
tag_cb_data data;
assert(repo && cb);
@@ -439,8 +444,14 @@ int git_tag_foreach(git_repository *repo, git_tag_foreach_cb cb, void *cb_data)
data.cb = cb;
data.cb_data = cb_data;
data.repo = repo;
+ memset(&data.error, 0, sizeof(data.error));
- return git_reference_foreach_name(repo, &tags_cb, &data);
+ error = git_reference_foreach_name(repo, &tags_cb, &data);
+
+ if (error == GIT_EUSER)
+ error = giterr_restore(&data.error);
+
+ return error;
}
typedef struct {
@@ -455,8 +466,14 @@ static int tag_list_cb(const char *tag_name, git_oid *oid, void *data)
tag_filter_data *filter = (tag_filter_data *)data;
GIT_UNUSED(oid);
- if (!*filter->pattern || p_fnmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == 0)
- return git_vector_insert(filter->taglist, git__strdup(tag_name + GIT_REFS_TAGS_DIR_LEN));
+ if (!*filter->pattern ||
+ p_fnmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == 0)
+ {
+ char *matched = git__strdup(tag_name + GIT_REFS_TAGS_DIR_LEN);
+ if (!matched)
+ return -1;
+ return git_vector_insert(filter->taglist, matched);
+ }
return 0;
}
@@ -469,16 +486,23 @@ int git_tag_list_match(git_strarray *tag_names, const char *pattern, git_reposit
assert(tag_names && repo && pattern);
- if (git_vector_init(&taglist, 8, NULL) < 0)
- return -1;
+ if ((error = git_vector_init(&taglist, 8, NULL)) < 0)
+ return error;
filter.taglist = &taglist;
filter.pattern = pattern;
error = git_tag_foreach(repo, &tag_list_cb, (void *)&filter);
+
+ /* the only case where callback will return an error is oom */
+ if (error == GIT_EUSER) {
+ giterr_set_oom();
+ error = -1;
+ }
+
if (error < 0) {
git_vector_free(&taglist);
- return -1;
+ return error;
}
tag_names->strings = (char **)taglist.contents;
diff --git a/src/transports/git.c b/src/transports/git.c
index 5dcd4eff7..21507c1c7 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -93,18 +93,19 @@ static int git_stream_read(
size_t buf_size,
size_t *bytes_read)
{
+ int error;
git_stream *s = (git_stream *)stream;
gitno_buffer buf;
*bytes_read = 0;
- if (!s->sent_command && send_command(s) < 0)
- return -1;
+ if (!s->sent_command && (error = send_command(s)) < 0)
+ return error;
gitno_buffer_setup(&s->socket, &buf, buffer, buf_size);
- if (gitno_recv(&buf) < 0)
- return -1;
+ if ((error = gitno_recv(&buf)) < 0)
+ return error;
*bytes_read = buf.offset;
@@ -116,10 +117,11 @@ static int git_stream_write(
const char *buffer,
size_t len)
{
+ int error;
git_stream *s = (git_stream *)stream;
- if (!s->sent_command && send_command(s) < 0)
- return -1;
+ if (!s->sent_command && (error = send_command(s)) < 0)
+ return error;
return gitno_send(&s->socket, buffer, len, 0);
}
@@ -140,7 +142,7 @@ static void git_stream_free(git_smart_subtransport_stream *stream)
}
git__free(s->url);
- git__free(s);
+ git__free(s);
}
static int git_stream_alloc(
@@ -182,18 +184,21 @@ static int _git_uploadpack_ls(
char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL;
const char *stream_url = url;
git_stream *s;
- int error = -1;
+ int error;
*stream = NULL;
+
if (!git__prefixcmp(url, prefix_git))
stream_url += strlen(prefix_git);
- if (git_stream_alloc(t, stream_url, cmd_uploadpack, stream) < 0)
- return -1;
+ if ((error = git_stream_alloc(t, stream_url, cmd_uploadpack, stream)) < 0)
+ return error;
s = (git_stream *)*stream;
- if (!(error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, GIT_DEFAULT_PORT))) {
+ if (!(error = gitno_extract_url_parts(
+ &host, &port, &path, &user, &pass, url, GIT_DEFAULT_PORT))) {
+
if (!(error = gitno_connect(&s->socket, host, port, 0)))
t->current_stream = s;
diff --git a/src/transports/smart.c b/src/transports/smart.c
index 5242beb65..e298f3510 100644
--- a/src/transports/smart.c
+++ b/src/transports/smart.c
@@ -27,8 +27,7 @@ static int git_smart__recv_cb(gitno_buffer *buf)
if (t->packetsize_cb(bytes_read, t->packetsize_payload)) {
git_atomic_set(&t->cancelled, 1);
- giterr_clear();
- return GIT_EUSER;
+ return giterr_user_cancel();
}
return (int)(buf->offset - old_len);
diff --git a/src/tree.c b/src/tree.c
index bb59ff82b..8ded007eb 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -884,14 +884,12 @@ static int tree_walk(
git_vector_foreach(&tree->entries, i, entry) {
if (preorder) {
error = callback(path->ptr, entry, payload);
+ if (error < 0)
+ return giterr_user_cancel();
if (error > 0) {
error = 0;
continue;
}
- if (error < 0) {
- giterr_clear();
- return GIT_EUSER;
- }
}
if (git_tree_entry__is_tree(entry)) {
@@ -918,11 +916,8 @@ static int tree_walk(
git_buf_truncate(path, path_len);
}
- if (!preorder && callback(path->ptr, entry, payload) < 0) {
- giterr_clear();
- error = GIT_EUSER;
- break;
- }
+ if (!preorder && callback(path->ptr, entry, payload) < 0)
+ return giterr_user_cancel();
}
return error;
diff --git a/tests/core/path.c b/tests/core/path.c
index cf2d5e944..3858e30dd 100644
--- a/tests/core/path.c
+++ b/tests/core/path.c
@@ -350,15 +350,24 @@ void test_core_path__10_fromurl(void)
typedef struct {
int expect_idx;
+ int cancel_after;
char **expect;
} check_walkup_info;
static int check_one_walkup_step(void *ref, git_buf *path)
{
check_walkup_info *info = (check_walkup_info *)ref;
+
+ if (!info->cancel_after) {
+ cl_assert_equal_s(info->expect[info->expect_idx], "[CANCEL]");
+ return -1;
+ }
+ info->cancel_after--;
+
cl_assert(info->expect[info->expect_idx] != NULL);
cl_assert_equal_s(info->expect[info->expect_idx], path->ptr);
info->expect_idx++;
+
return 0;
}
@@ -381,6 +390,7 @@ void test_core_path__11_walkup(void)
check_walkup_info info;
info.expect = expect;
+ info.cancel_after = -1;
for (i = 0, j = 0; expect[i] != NULL; i++, j++) {
@@ -400,6 +410,42 @@ void test_core_path__11_walkup(void)
git_buf_free(&p);
}
+void test_core_path__11a_walkup_cancel(void)
+{
+ git_buf p = GIT_BUF_INIT;
+ int cancel[] = { 3, 2, 1, 0 };
+ char *expect[] = {
+ "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "[CANCEL]", NULL,
+ "/a/b/c/d/e", "/a/b/c/d/", "[CANCEL]", NULL,
+ "/a/b/c/d/e", "[CANCEL]", NULL,
+ "[CANCEL]", NULL,
+ NULL
+ };
+ char *root[] = { NULL, NULL, "/", "", NULL };
+ int i, j;
+ check_walkup_info info;
+
+ info.expect = expect;
+
+ for (i = 0, j = 0; expect[i] != NULL; i++, j++) {
+
+ git_buf_sets(&p, expect[i]);
+
+ info.cancel_after = cancel[j];
+ info.expect_idx = i;
+
+ cl_assert_equal_i(
+ GIT_EUSER,
+ git_path_walk_up(&p, root[j], check_one_walkup_step, &info)
+ );
+
+ /* skip to next run of expectations */
+ while (expect[i] != NULL) i++;
+ }
+
+ git_buf_free(&p);
+}
+
void test_core_path__12_offset_to_path_root(void)
{
cl_assert(git_path_root("non/rooted/path") == -1);