Commit 96869a4e by Russell Belfer

Improve GIT_EUSER handling

This adds giterr_user_cancel to return GIT_EUSER and clear any
error message that is sitting around.  As a result of using that
in places, we need to be more thorough with capturing errors that
happen inside a callback when used internally.  To help with that,
this also adds giterr_capture and giterr_restore so that when we
internally use a foreach-type function that clears errors and
converts them to GIT_EUSER, it is easier to restore not just the
return value, but the actual error message text.
parent 9f77b3f6
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#define INCLUDE_git_errors_h__ #define INCLUDE_git_errors_h__
#include "common.h" #include "common.h"
#include "buffer.h"
/** /**
* @file git2/errors.h * @file git2/errors.h
...@@ -91,7 +90,7 @@ GIT_EXTERN(void) giterr_clear(void); ...@@ -91,7 +90,7 @@ GIT_EXTERN(void) giterr_clear(void);
* Get the last error data and clear it. * Get the last error data and clear it.
* *
* This copies the last error into the given `git_error` struct * This copies the last error into the given `git_error` struct
* and returns 0 if the copy was successful, leaving the error * and returns 0 if the copy was successful, leaving the error
* cleared as if `giterr_clear` had been called. * cleared as if `giterr_clear` had been called.
* *
* If there was no existing error in the library, -1 will be returned * If there was no existing error in the library, -1 will be returned
......
...@@ -193,8 +193,7 @@ int git_attr_foreach( ...@@ -193,8 +193,7 @@ int git_attr_foreach(
error = callback(assign->name, assign->value, payload); error = callback(assign->name, assign->value, payload);
if (error) { if (error) {
giterr_clear(); error = giterr_user_cancel();
error = GIT_EUSER;
goto cleanup; goto cleanup;
} }
} }
......
...@@ -108,17 +108,23 @@ git_blame* git_blame__alloc( ...@@ -108,17 +108,23 @@ git_blame* git_blame__alloc(
git_blame_options opts, git_blame_options opts,
const char *path) const char *path)
{ {
git_blame *gbr = (git_blame*)git__calloc(1, sizeof(git_blame)); git_blame *gbr = git__calloc(1, sizeof(git_blame));
if (!gbr) { if (!gbr)
giterr_set_oom();
return NULL; return NULL;
}
git_vector_init(&gbr->hunks, 8, hunk_cmp);
git_vector_init(&gbr->paths, 8, paths_cmp);
gbr->repository = repo; gbr->repository = repo;
gbr->options = opts; gbr->options = opts;
gbr->path = git__strdup(path);
git_vector_insert(&gbr->paths, git__strdup(path)); if (git_vector_init(&gbr->hunks, 8, hunk_cmp) < 0 ||
git_vector_init(&gbr->paths, 8, paths_cmp) < 0 ||
(gbr->path = git__strdup(path)) == NULL ||
git_vector_insert(&gbr->paths, git__strdup(path)) < 0)
{
git_blame_free(gbr);
git__free(gbr);
return NULL;
}
return gbr; return gbr;
} }
...@@ -140,7 +146,7 @@ void git_blame_free(git_blame *blame) ...@@ -140,7 +146,7 @@ void git_blame_free(git_blame *blame)
git_array_clear(blame->line_index); git_array_clear(blame->line_index);
git__free((void*)blame->path); git__free(blame->path);
git_blob_free(blame->final_blob); git_blob_free(blame->final_blob);
git__free(blame); git__free(blame);
} }
......
...@@ -64,7 +64,7 @@ typedef struct git_blame__entry { ...@@ -64,7 +64,7 @@ typedef struct git_blame__entry {
} git_blame__entry; } git_blame__entry;
struct git_blame { struct git_blame {
const char *path; char *path;
git_repository *repository; git_repository *repository;
git_blame_options options; git_blame_options options;
......
...@@ -90,29 +90,28 @@ int git_branch_delete(git_reference *branch) ...@@ -90,29 +90,28 @@ int git_branch_delete(git_reference *branch)
assert(branch); assert(branch);
if (!git_reference_is_branch(branch) && if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) {
!git_reference_is_remote(branch)) { giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.",
giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", git_reference_name(branch)); git_reference_name(branch));
return -1; return GIT_ENOTFOUND;
} }
if ((is_head = git_branch_is_head(branch)) < 0) if ((is_head = git_branch_is_head(branch)) < 0)
return is_head; return is_head;
if (is_head) { if (is_head) {
giterr_set(GITERR_REFERENCE, giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is "
"Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch)); "the current HEAD of the repository.", git_reference_name(branch));
return -1; return -1;
} }
if (git_buf_printf(&config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0) if (git_buf_join(&config_section, '.', "branch",
git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
goto on_error; goto on_error;
if (git_config_rename_section( if (git_config_rename_section(
git_reference_owner(branch), git_reference_owner(branch), git_buf_cstr(&config_section), NULL) < 0)
git_buf_cstr(&config_section), goto on_error;
NULL) < 0)
goto on_error;
if (git_reference_delete(branch) < 0) if (git_reference_delete(branch) < 0)
goto on_error; goto on_error;
...@@ -206,17 +205,21 @@ int git_branch_move( ...@@ -206,17 +205,21 @@ int git_branch_move(
if (error < 0) if (error < 0)
goto done; goto done;
git_buf_printf(&old_config_section, /* first update ref then config so failure won't trash config */
"branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR));
git_buf_printf(&new_config_section, "branch.%s", new_branch_name);
if ((error = git_config_rename_section(git_reference_owner(branch), error = git_reference_rename(
git_buf_cstr(&old_config_section), out, branch, git_buf_cstr(&new_reference_name), force);
git_buf_cstr(&new_config_section))) < 0) if (error < 0)
goto done; goto done;
error = git_reference_rename(out, branch, git_buf_cstr(&new_reference_name), force); git_buf_join(&old_config_section, '.', "branch",
git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR));
git_buf_join(&new_config_section, '.', "branch", new_branch_name);
error = git_config_rename_section(
git_reference_owner(branch),
git_buf_cstr(&old_config_section),
git_buf_cstr(&new_config_section));
done: done:
git_buf_free(&new_reference_name); git_buf_free(&new_reference_name);
......
...@@ -216,7 +216,7 @@ static int checkout_action_common( ...@@ -216,7 +216,7 @@ static int checkout_action_common(
if (notify != GIT_CHECKOUT_NOTIFY_NONE && if (notify != GIT_CHECKOUT_NOTIFY_NONE &&
checkout_notify(data, notify, delta, wd) != 0) checkout_notify(data, notify, delta, wd) != 0)
return GIT_EUSER; return giterr_user_cancel();
return action; return action;
} }
...@@ -230,7 +230,7 @@ static int checkout_action_no_wd( ...@@ -230,7 +230,7 @@ static int checkout_action_no_wd(
switch (delta->status) { switch (delta->status) {
case GIT_DELTA_UNMODIFIED: /* case 12 */ case GIT_DELTA_UNMODIFIED: /* case 12 */
if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL)) if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL))
return GIT_EUSER; return giterr_user_cancel();
action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE); action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE);
break; break;
case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */ case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */
...@@ -302,7 +302,7 @@ static int checkout_action_wd_only( ...@@ -302,7 +302,7 @@ static int checkout_action_wd_only(
} }
if (checkout_notify(data, notify, NULL, wd)) if (checkout_notify(data, notify, NULL, wd))
return GIT_EUSER; return giterr_user_cancel();
if (remove) { if (remove) {
char *path = git_pool_strdup(&data->pool, wd->path); char *path = git_pool_strdup(&data->pool, wd->path);
...@@ -342,7 +342,7 @@ static int checkout_action_with_wd( ...@@ -342,7 +342,7 @@ static int checkout_action_with_wd(
if (checkout_is_workdir_modified(data, &delta->old_file, wd)) { if (checkout_is_workdir_modified(data, &delta->old_file, wd)) {
if (checkout_notify( if (checkout_notify(
data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd)) data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd))
return GIT_EUSER; return giterr_user_cancel();
action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE); action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE);
} }
break; break;
...@@ -406,7 +406,7 @@ static int checkout_action_with_wd_blocker( ...@@ -406,7 +406,7 @@ static int checkout_action_with_wd_blocker(
case GIT_DELTA_UNMODIFIED: case GIT_DELTA_UNMODIFIED:
/* should show delta as dirty / deleted */ /* should show delta as dirty / deleted */
if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd)) if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd))
return GIT_EUSER; return giterr_user_cancel();
action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE); action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE);
break; break;
case GIT_DELTA_ADDED: case GIT_DELTA_ADDED:
...@@ -439,7 +439,7 @@ static int checkout_action_with_wd_dir( ...@@ -439,7 +439,7 @@ static int checkout_action_with_wd_dir(
if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL) || if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL) ||
checkout_notify( checkout_notify(
data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd)) data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd))
return GIT_EUSER; return giterr_user_cancel();
break; break;
case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */ case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */
case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */ case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */
...@@ -452,7 +452,7 @@ static int checkout_action_with_wd_dir( ...@@ -452,7 +452,7 @@ static int checkout_action_with_wd_dir(
if (delta->old_file.mode != GIT_FILEMODE_TREE && if (delta->old_file.mode != GIT_FILEMODE_TREE &&
checkout_notify( checkout_notify(
data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd)) data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd))
return GIT_EUSER; return giterr_user_cancel();
break; break;
case GIT_DELTA_TYPECHANGE: /* case 24 or 31 */ case GIT_DELTA_TYPECHANGE: /* case 24 or 31 */
if (delta->old_file.mode == GIT_FILEMODE_TREE) { if (delta->old_file.mode == GIT_FILEMODE_TREE) {
...@@ -1998,9 +1998,6 @@ int git_checkout_iterator( ...@@ -1998,9 +1998,6 @@ int git_checkout_iterator(
assert(data.completed_steps == data.total_steps); assert(data.completed_steps == data.total_steps);
cleanup: cleanup:
if (error == GIT_EUSER)
giterr_clear();
if (!error && data.index != NULL && if (!error && data.index != NULL &&
(data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) (data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
error = git_index_write(data.index); error = git_index_write(data.index);
......
...@@ -78,28 +78,42 @@ int giterr_set_regex(const regex_t *regex, int error_code); ...@@ -78,28 +78,42 @@ int giterr_set_regex(const regex_t *regex, int error_code);
/** /**
* Gets the system error code for this thread. * Gets the system error code for this thread.
*/ */
GIT_INLINE(int) giterr_system_last(void) int giterr_system_last(void);
{
#ifdef GIT_WIN32
return GetLastError();
#else
return errno;
#endif
}
/** /**
* Sets the system error code for this thread. * Sets the system error code for this thread.
*/ */
GIT_INLINE(void) giterr_system_set(int code) void giterr_system_set(int code);
/**
* Note that a user cancelled an operation with GIT_EUSER
*/
GIT_INLINE(int) giterr_user_cancel(void)
{ {
#ifdef GIT_WIN32 giterr_clear();
SetLastError(code); return GIT_EUSER;
#else
errno = code;
#endif
} }
/** /**
* Structure to preserve libgit2 error state
*/
typedef struct {
int error_code;
git_error error_msg;
} git_error_state;
/**
* Capture current error state to restore later, returning error code.
* If `error_code` is zero, this does nothing and returns zero.
*/
int giterr_capture(git_error_state *state, int error_code);
/**
* Restore error state to a previous value, returning saved error code.
*/
int giterr_restore(git_error_state *state);
/**
* Check a versioned structure for validity * Check a versioned structure for validity
*/ */
GIT_INLINE(int) giterr__check_version(const void *structure, unsigned int expected_max, const char *name) GIT_INLINE(int) giterr__check_version(const void *structure, unsigned int expected_max, const char *name)
......
...@@ -501,20 +501,18 @@ int git_config_backend_foreach_match( ...@@ -501,20 +501,18 @@ int git_config_backend_foreach_match(
return -1; return -1;
} }
while(!(iter->next(&entry, iter) < 0)) { while (!(iter->next(&entry, iter) < 0)) {
/* skip non-matching keys if regexp was provided */ /* skip non-matching keys if regexp was provided */
if (regexp && regexec(&regex, entry->name, 0, NULL, 0) != 0) if (regexp && regexec(&regex, entry->name, 0, NULL, 0) != 0)
continue; continue;
/* abort iterator on non-zero return value */ /* abort iterator on non-zero return value */
if (fn(entry, data)) { if (fn(entry, data)) {
giterr_clear(); result = giterr_user_cancel();
result = GIT_EUSER; break;
goto cleanup;
} }
} }
cleanup:
if (regexp != NULL) if (regexp != NULL)
regfree(&regex); regfree(&regex);
...@@ -537,9 +535,8 @@ int git_config_foreach_match( ...@@ -537,9 +535,8 @@ int git_config_foreach_match(
return error; return error;
while ((error = git_config_next(&entry, iter)) == 0) { while ((error = git_config_next(&entry, iter)) == 0) {
if(cb(entry, payload)) { if (cb(entry, payload)) {
giterr_clear(); error = giterr_user_cancel();
error = GIT_EUSER;
break; break;
} }
} }
...@@ -800,9 +797,10 @@ int git_config_get_multivar_foreach( ...@@ -800,9 +797,10 @@ int git_config_get_multivar_foreach(
found = 0; found = 0;
while ((err = iter->next(&entry, iter)) == 0) { while ((err = iter->next(&entry, iter)) == 0) {
found = 1; found = 1;
if(cb(entry, payload)) {
if (cb(entry, payload)) {
iter->free(iter); iter->free(iter);
return GIT_EUSER; return giterr_user_cancel();
} }
} }
...@@ -1214,7 +1212,7 @@ struct rename_data { ...@@ -1214,7 +1212,7 @@ struct rename_data {
git_config *config; git_config *config;
git_buf *name; git_buf *name;
size_t old_len; size_t old_len;
int actual_error; git_error_state error;
}; };
static int rename_config_entries_cb( static int rename_config_entries_cb(
...@@ -1237,9 +1235,8 @@ static int rename_config_entries_cb( ...@@ -1237,9 +1235,8 @@ static int rename_config_entries_cb(
if (!error) if (!error)
error = git_config_delete_entry(data->config, entry->name); error = git_config_delete_entry(data->config, entry->name);
data->actual_error = error; /* preserve actual error code */ /* capture error message as needed, since it will become EUSER */
return giterr_capture(&data->error, error);
return error;
} }
int git_config_rename_section( int git_config_rename_section(
...@@ -1260,10 +1257,10 @@ int git_config_rename_section( ...@@ -1260,10 +1257,10 @@ int git_config_rename_section(
if ((error = git_repository_config__weakptr(&config, repo)) < 0) if ((error = git_repository_config__weakptr(&config, repo)) < 0)
goto cleanup; goto cleanup;
memset(&data, 0, sizeof(data));
data.config = config; data.config = config;
data.name = &replace; data.name = &replace;
data.old_len = strlen(old_section_name) + 1; data.old_len = strlen(old_section_name) + 1;
data.actual_error = 0;
if ((error = git_buf_join(&replace, '.', new_section_name, "")) < 0) if ((error = git_buf_join(&replace, '.', new_section_name, "")) < 0)
goto cleanup; goto cleanup;
...@@ -1281,7 +1278,7 @@ int git_config_rename_section( ...@@ -1281,7 +1278,7 @@ int git_config_rename_section(
config, git_buf_cstr(&pattern), rename_config_entries_cb, &data); config, git_buf_cstr(&pattern), rename_config_entries_cb, &data);
if (error == GIT_EUSER) if (error == GIT_EUSER)
error = data.actual_error; error = giterr_restore(&data.error);
cleanup: cleanup:
git_buf_free(&pattern); git_buf_free(&pattern);
......
...@@ -120,7 +120,7 @@ static int diff_delta__from_one( ...@@ -120,7 +120,7 @@ static int diff_delta__from_one(
return -1; return -1;
} }
return notify_res < 0 ? GIT_EUSER : 0; return notify_res < 0 ? giterr_user_cancel() : 0;
} }
static int diff_delta__from_two( static int diff_delta__from_two(
...@@ -182,7 +182,7 @@ static int diff_delta__from_two( ...@@ -182,7 +182,7 @@ static int diff_delta__from_two(
return -1; return -1;
} }
return notify_res < 0 ? GIT_EUSER : 0; return notify_res < 0 ? giterr_user_cancel() : 0;
} }
static git_diff_delta *diff_delta__last_for_item( static git_diff_delta *diff_delta__last_for_item(
...@@ -1343,7 +1343,7 @@ int git_diff__paired_foreach( ...@@ -1343,7 +1343,7 @@ int git_diff__paired_foreach(
int (*cb)(git_diff_delta *h2i, git_diff_delta *i2w, void *payload), int (*cb)(git_diff_delta *h2i, git_diff_delta *i2w, void *payload),
void *payload) void *payload)
{ {
int cmp; int cmp, error = 0;
git_diff_delta *h2i, *i2w; git_diff_delta *h2i, *i2w;
size_t i, j, i_max, j_max; size_t i, j, i_max, j_max;
int (*strcomp)(const char *, const char *) = git__strcmp; int (*strcomp)(const char *, const char *) = git__strcmp;
...@@ -1399,18 +1399,17 @@ int git_diff__paired_foreach( ...@@ -1399,18 +1399,17 @@ int git_diff__paired_foreach(
strcomp(h2i->new_file.path, i2w->old_file.path); strcomp(h2i->new_file.path, i2w->old_file.path);
if (cmp < 0) { if (cmp < 0) {
if (cb(h2i, NULL, payload)) i++; i2w = NULL;
return GIT_EUSER;
i++;
} else if (cmp > 0) { } else if (cmp > 0) {
if (cb(NULL, i2w, payload)) j++; h2i = NULL;
return GIT_EUSER;
j++;
} else { } else {
if (cb(h2i, i2w, payload))
return GIT_EUSER;
i++; j++; i++; j++;
} }
if (cb(h2i, i2w, payload)) {
error = giterr_user_cancel();
break;
}
} }
/* restore case-insensitive delta sort */ /* restore case-insensitive delta sort */
...@@ -1426,5 +1425,5 @@ int git_diff__paired_foreach( ...@@ -1426,5 +1425,5 @@ int git_diff__paired_foreach(
git_vector_sort(&idx2wd->deltas); git_vector_sort(&idx2wd->deltas);
} }
return 0; return error;
} }
...@@ -32,6 +32,7 @@ struct git_patch { ...@@ -32,6 +32,7 @@ struct git_patch {
git_array_t(git_diff_line) lines; git_array_t(git_diff_line) lines;
size_t content_size, context_size, header_size; size_t content_size, context_size, header_size;
git_pool flattened; git_pool flattened;
git_error_state error;
}; };
enum { enum {
...@@ -193,21 +194,17 @@ cleanup: ...@@ -193,21 +194,17 @@ cleanup:
return error; return error;
} }
static int diff_patch_file_callback( static int diff_patch_invoke_file_callback(
git_patch *patch, git_diff_output *output) git_patch *patch, git_diff_output *output)
{ {
float progress; float progress = patch->diff ?
if (!output->file_cb)
return 0;
progress = patch->diff ?
((float)patch->delta_index / patch->diff->deltas.length) : 1.0f; ((float)patch->delta_index / patch->diff->deltas.length) : 1.0f;
if (output->file_cb(patch->delta, progress, output->payload) != 0) if (output->file_cb &&
output->error = GIT_EUSER; output->file_cb(patch->delta, progress, output->payload) != 0)
return giterr_user_cancel();
return output->error; return 0;
} }
static int diff_patch_generate(git_patch *patch, git_diff_output *output) static int diff_patch_generate(git_patch *patch, git_diff_output *output)
...@@ -229,7 +226,7 @@ static int diff_patch_generate(git_patch *patch, git_diff_output *output) ...@@ -229,7 +226,7 @@ static int diff_patch_generate(git_patch *patch, git_diff_output *output)
return 0; return 0;
if (output->diff_cb != NULL && if (output->diff_cb != NULL &&
!(error = output->diff_cb(output, patch))) (error = output->diff_cb(output, patch)) < 0)
patch->flags |= GIT_DIFF_PATCH_DIFFED; patch->flags |= GIT_DIFF_PATCH_DIFFED;
return error; return error;
...@@ -272,9 +269,10 @@ int git_diff_foreach( ...@@ -272,9 +269,10 @@ int git_diff_foreach(
size_t idx; size_t idx;
git_patch patch; git_patch patch;
if (diff_required(diff, "git_diff_foreach") < 0) if ((error = diff_required(diff, "git_diff_foreach")) < 0)
return -1; return error;
memset(&xo, 0, sizeof(xo));
diff_output_init( diff_output_init(
&xo.output, &diff->opts, file_cb, hunk_cb, data_cb, payload); &xo.output, &diff->opts, file_cb, hunk_cb, data_cb, payload);
git_xdiff_init(&xo, &diff->opts); git_xdiff_init(&xo, &diff->opts);
...@@ -285,22 +283,18 @@ int git_diff_foreach( ...@@ -285,22 +283,18 @@ int git_diff_foreach(
if (git_diff_delta__should_skip(&diff->opts, patch.delta)) if (git_diff_delta__should_skip(&diff->opts, patch.delta))
continue; continue;
if (!(error = diff_patch_init_from_diff(&patch, diff, idx))) { if ((error = diff_patch_init_from_diff(&patch, diff, idx)) < 0)
break;
error = diff_patch_file_callback(&patch, &xo.output);
if (!error) if (!(error = diff_patch_invoke_file_callback(&patch, &xo.output)))
error = diff_patch_generate(&patch, &xo.output); error = diff_patch_generate(&patch, &xo.output);
git_patch_free(&patch); git_patch_free(&patch);
}
if (error < 0) if (error < 0)
break; break;
} }
if (error == GIT_EUSER)
giterr_clear(); /* don't leave error message set invalidly */
return error; return error;
} }
...@@ -332,7 +326,7 @@ static int diff_single_generate(diff_patch_with_delta *pd, git_xdiff_output *xo) ...@@ -332,7 +326,7 @@ static int diff_single_generate(diff_patch_with_delta *pd, git_xdiff_output *xo)
!(patch->ofile.opts_flags & GIT_DIFF_INCLUDE_UNMODIFIED)) !(patch->ofile.opts_flags & GIT_DIFF_INCLUDE_UNMODIFIED))
return error; return error;
error = diff_patch_file_callback(patch, (git_diff_output *)xo); error = diff_patch_invoke_file_callback(patch, (git_diff_output *)xo);
if (!error) if (!error)
error = diff_patch_generate(patch, (git_diff_output *)xo); error = diff_patch_generate(patch, (git_diff_output *)xo);
...@@ -424,9 +418,7 @@ int git_diff_blobs( ...@@ -424,9 +418,7 @@ int git_diff_blobs(
diff_patch_with_delta pd; diff_patch_with_delta pd;
git_xdiff_output xo; git_xdiff_output xo;
memset(&pd, 0, sizeof(pd));
memset(&xo, 0, sizeof(xo)); memset(&xo, 0, sizeof(xo));
diff_output_init( diff_output_init(
&xo.output, opts, file_cb, hunk_cb, data_cb, payload); &xo.output, opts, file_cb, hunk_cb, data_cb, payload);
git_xdiff_init(&xo, opts); git_xdiff_init(&xo, opts);
...@@ -436,6 +428,7 @@ int git_diff_blobs( ...@@ -436,6 +428,7 @@ int git_diff_blobs(
else if (!new_path && old_path) else if (!new_path && old_path)
new_path = old_path; new_path = old_path;
memset(&pd, 0, sizeof(pd));
error = diff_patch_from_blobs( error = diff_patch_from_blobs(
&pd, &xo, old_blob, old_path, new_blob, new_path, opts); &pd, &xo, old_blob, old_path, new_blob, new_path, opts);
...@@ -463,13 +456,15 @@ int git_patch_from_blobs( ...@@ -463,13 +456,15 @@ int git_patch_from_blobs(
return -1; return -1;
memset(&xo, 0, sizeof(xo)); memset(&xo, 0, sizeof(xo));
diff_output_to_patch(&xo.output, &pd->patch); diff_output_to_patch(&xo.output, &pd->patch);
git_xdiff_init(&xo, opts); git_xdiff_init(&xo, opts);
error = diff_patch_from_blobs( error = diff_patch_from_blobs(
pd, &xo, old_blob, old_path, new_blob, new_path, opts); pd, &xo, old_blob, old_path, new_blob, new_path, opts);
if (error == GIT_EUSER)
error = giterr_restore(&pd->patch.error);
if (!error) if (!error)
*out = (git_patch *)pd; *out = (git_patch *)pd;
else else
...@@ -536,9 +531,7 @@ int git_diff_blob_to_buffer( ...@@ -536,9 +531,7 @@ int git_diff_blob_to_buffer(
diff_patch_with_delta pd; diff_patch_with_delta pd;
git_xdiff_output xo; git_xdiff_output xo;
memset(&pd, 0, sizeof(pd));
memset(&xo, 0, sizeof(xo)); memset(&xo, 0, sizeof(xo));
diff_output_init( diff_output_init(
&xo.output, opts, file_cb, hunk_cb, data_cb, payload); &xo.output, opts, file_cb, hunk_cb, data_cb, payload);
git_xdiff_init(&xo, opts); git_xdiff_init(&xo, opts);
...@@ -548,6 +541,7 @@ int git_diff_blob_to_buffer( ...@@ -548,6 +541,7 @@ int git_diff_blob_to_buffer(
else if (!buf_path && old_path) else if (!buf_path && old_path)
buf_path = old_path; buf_path = old_path;
memset(&pd, 0, sizeof(pd));
error = diff_patch_from_blob_and_buffer( error = diff_patch_from_blob_and_buffer(
&pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts); &pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts);
...@@ -576,13 +570,15 @@ int git_patch_from_blob_and_buffer( ...@@ -576,13 +570,15 @@ int git_patch_from_blob_and_buffer(
return -1; return -1;
memset(&xo, 0, sizeof(xo)); memset(&xo, 0, sizeof(xo));
diff_output_to_patch(&xo.output, &pd->patch); diff_output_to_patch(&xo.output, &pd->patch);
git_xdiff_init(&xo, opts); git_xdiff_init(&xo, opts);
error = diff_patch_from_blob_and_buffer( error = diff_patch_from_blob_and_buffer(
pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts); pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts);
if (error == GIT_EUSER)
error = giterr_restore(&pd->patch.error);
if (!error) if (!error)
*out = (git_patch *)pd; *out = (git_patch *)pd;
else else
...@@ -622,14 +618,18 @@ int git_patch_from_diff( ...@@ -622,14 +618,18 @@ int git_patch_from_diff(
if ((error = diff_patch_alloc_from_diff(&patch, diff, idx)) < 0) if ((error = diff_patch_alloc_from_diff(&patch, diff, idx)) < 0)
return error; return error;
memset(&xo, 0, sizeof(xo));
diff_output_to_patch(&xo.output, patch); diff_output_to_patch(&xo.output, patch);
git_xdiff_init(&xo, &diff->opts); git_xdiff_init(&xo, &diff->opts);
error = diff_patch_file_callback(patch, &xo.output); error = diff_patch_invoke_file_callback(patch, &xo.output);
if (!error) if (!error)
error = diff_patch_generate(patch, &xo.output); error = diff_patch_generate(patch, &xo.output);
if (error == GIT_EUSER)
error = giterr_restore(&patch->error);
if (!error) { if (!error) {
/* if cumulative diff size is < 0.5 total size, flatten the patch */ /* if cumulative diff size is < 0.5 total size, flatten the patch */
/* unload the file content */ /* unload the file content */
...@@ -879,7 +879,8 @@ static int diff_patch_hunk_cb( ...@@ -879,7 +879,8 @@ static int diff_patch_hunk_cb(
GIT_UNUSED(delta); GIT_UNUSED(delta);
hunk = git_array_alloc(patch->hunks); hunk = git_array_alloc(patch->hunks);
GITERR_CHECK_ALLOC(hunk); if (!hunk)
return giterr_capture(&patch->error, -1);
memcpy(&hunk->hunk, hunk_, sizeof(hunk->hunk)); memcpy(&hunk->hunk, hunk_, sizeof(hunk->hunk));
...@@ -905,10 +906,11 @@ static int diff_patch_line_cb( ...@@ -905,10 +906,11 @@ static int diff_patch_line_cb(
GIT_UNUSED(hunk_); GIT_UNUSED(hunk_);
hunk = git_array_last(patch->hunks); hunk = git_array_last(patch->hunks);
GITERR_CHECK_ALLOC(hunk); assert(hunk); /* programmer error if no hunk is available */
line = git_array_alloc(patch->lines); line = git_array_alloc(patch->lines);
GITERR_CHECK_ALLOC(line); if (!line)
return giterr_capture(&patch->error, -1);
memcpy(line, line_, sizeof(*line)); memcpy(line, line_, sizeof(*line));
......
...@@ -18,6 +18,7 @@ typedef struct { ...@@ -18,6 +18,7 @@ typedef struct {
uint32_t flags; uint32_t flags;
int oid_strlen; int oid_strlen;
git_diff_line line; git_diff_line line;
git_error_state error;
} diff_print_info; } diff_print_info;
static int diff_print_info_init( static int diff_print_info_init(
...@@ -33,6 +34,7 @@ static int diff_print_info_init( ...@@ -33,6 +34,7 @@ static int diff_print_info_init(
pi->print_cb = cb; pi->print_cb = cb;
pi->payload = payload; pi->payload = payload;
pi->buf = out; pi->buf = out;
memset(&pi->error, 0, sizeof(pi->error));
if (diff) if (diff)
pi->flags = diff->opts.flags; pi->flags = diff->opts.flags;
...@@ -89,12 +91,6 @@ char git_diff_status_char(git_delta_t status) ...@@ -89,12 +91,6 @@ char git_diff_status_char(git_delta_t status)
return code; return code;
} }
static int callback_error(void)
{
giterr_clear();
return GIT_EUSER;
}
static int diff_print_one_name_only( static int diff_print_one_name_only(
const git_diff_delta *delta, float progress, void *data) const git_diff_delta *delta, float progress, void *data)
{ {
...@@ -111,14 +107,14 @@ static int diff_print_one_name_only( ...@@ -111,14 +107,14 @@ static int diff_print_one_name_only(
if (git_buf_puts(out, delta->new_file.path) < 0 || if (git_buf_puts(out, delta->new_file.path) < 0 ||
git_buf_putc(out, '\n')) git_buf_putc(out, '\n'))
return -1; return giterr_capture(&pi->error, -1);
pi->line.origin = GIT_DIFF_LINE_FILE_HDR; pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
pi->line.content = git_buf_cstr(out); pi->line.content = git_buf_cstr(out);
pi->line.content_len = git_buf_len(out); pi->line.content_len = git_buf_len(out);
if (pi->print_cb(delta, NULL, &pi->line, pi->payload)) if (pi->print_cb(delta, NULL, &pi->line, pi->payload))
return callback_error(); return giterr_user_cancel();
return 0; return 0;
} }
...@@ -156,14 +152,14 @@ static int diff_print_one_name_status( ...@@ -156,14 +152,14 @@ static int diff_print_one_name_status(
git_buf_printf(out, "%c\t%s\n", code, delta->old_file.path); git_buf_printf(out, "%c\t%s\n", code, delta->old_file.path);
if (git_buf_oom(out)) if (git_buf_oom(out))
return -1; return giterr_capture(&pi->error, -1);
pi->line.origin = GIT_DIFF_LINE_FILE_HDR; pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
pi->line.content = git_buf_cstr(out); pi->line.content = git_buf_cstr(out);
pi->line.content_len = git_buf_len(out); pi->line.content_len = git_buf_len(out);
if (pi->print_cb(delta, NULL, &pi->line, pi->payload)) if (pi->print_cb(delta, NULL, &pi->line, pi->payload))
return callback_error(); return giterr_user_cancel();
return 0; return 0;
} }
...@@ -202,14 +198,14 @@ static int diff_print_one_raw( ...@@ -202,14 +198,14 @@ static int diff_print_one_raw(
delta->old_file.path : delta->new_file.path); delta->old_file.path : delta->new_file.path);
if (git_buf_oom(out)) if (git_buf_oom(out))
return -1; return giterr_capture(&pi->error, -1);
pi->line.origin = GIT_DIFF_LINE_FILE_HDR; pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
pi->line.content = git_buf_cstr(out); pi->line.content = git_buf_cstr(out);
pi->line.content_len = git_buf_len(out); pi->line.content_len = git_buf_len(out);
if (pi->print_cb(delta, NULL, &pi->line, pi->payload)) if (pi->print_cb(delta, NULL, &pi->line, pi->payload))
return callback_error(); return giterr_user_cancel();
return 0; return 0;
} }
...@@ -315,14 +311,14 @@ static int diff_print_patch_file( ...@@ -315,14 +311,14 @@ static int diff_print_patch_file(
if (git_diff_delta__format_file_header( if (git_diff_delta__format_file_header(
pi->buf, delta, oldpfx, newpfx, pi->oid_strlen) < 0) pi->buf, delta, oldpfx, newpfx, pi->oid_strlen) < 0)
return -1; return giterr_capture(&pi->error, -1);
pi->line.origin = GIT_DIFF_LINE_FILE_HDR; pi->line.origin = GIT_DIFF_LINE_FILE_HDR;
pi->line.content = git_buf_cstr(pi->buf); pi->line.content = git_buf_cstr(pi->buf);
pi->line.content_len = git_buf_len(pi->buf); pi->line.content_len = git_buf_len(pi->buf);
if (pi->print_cb(delta, NULL, &pi->line, pi->payload)) if (pi->print_cb(delta, NULL, &pi->line, pi->payload))
return callback_error(); return giterr_user_cancel();
if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0)
return 0; return 0;
...@@ -332,7 +328,7 @@ static int diff_print_patch_file( ...@@ -332,7 +328,7 @@ static int diff_print_patch_file(
if (diff_delta_format_with_paths( if (diff_delta_format_with_paths(
pi->buf, delta, oldpfx, newpfx, pi->buf, delta, oldpfx, newpfx,
"Binary files %s%s and %s%s differ\n") < 0) "Binary files %s%s and %s%s differ\n") < 0)
return -1; return giterr_capture(&pi->error, -1);
pi->line.origin = GIT_DIFF_LINE_BINARY; pi->line.origin = GIT_DIFF_LINE_BINARY;
pi->line.content = git_buf_cstr(pi->buf); pi->line.content = git_buf_cstr(pi->buf);
...@@ -340,7 +336,7 @@ static int diff_print_patch_file( ...@@ -340,7 +336,7 @@ static int diff_print_patch_file(
pi->line.num_lines = 1; pi->line.num_lines = 1;
if (pi->print_cb(delta, NULL, &pi->line, pi->payload)) if (pi->print_cb(delta, NULL, &pi->line, pi->payload))
return callback_error(); return giterr_user_cancel();
return 0; return 0;
} }
...@@ -360,7 +356,7 @@ static int diff_print_patch_hunk( ...@@ -360,7 +356,7 @@ static int diff_print_patch_hunk(
pi->line.content_len = h->header_len; pi->line.content_len = h->header_len;
if (pi->print_cb(d, h, &pi->line, pi->payload)) if (pi->print_cb(d, h, &pi->line, pi->payload))
return callback_error(); return giterr_user_cancel();
return 0; return 0;
} }
...@@ -377,7 +373,7 @@ static int diff_print_patch_line( ...@@ -377,7 +373,7 @@ static int diff_print_patch_line(
return 0; return 0;
if (pi->print_cb(delta, hunk, line, pi->payload)) if (pi->print_cb(delta, hunk, line, pi->payload))
return callback_error(); return giterr_user_cancel();
return 0; return 0;
} }
...@@ -421,9 +417,14 @@ int git_diff_print( ...@@ -421,9 +417,14 @@ int git_diff_print(
if (!(error = diff_print_info_init( if (!(error = diff_print_info_init(
&pi, &buf, diff, format, print_cb, payload))) &pi, &buf, diff, format, print_cb, payload)))
{
error = git_diff_foreach( error = git_diff_foreach(
diff, print_file, print_hunk, print_line, &pi); diff, print_file, print_hunk, print_line, &pi);
if (error == GIT_EUSER && pi.error.error_code)
error = giterr_restore(&pi.error);
}
git_buf_free(&buf); git_buf_free(&buf);
return error; return error;
...@@ -444,10 +445,15 @@ int git_patch_print( ...@@ -444,10 +445,15 @@ int git_patch_print(
if (!(error = diff_print_info_init( if (!(error = diff_print_info_init(
&pi, &temp, git_patch__diff(patch), &pi, &temp, git_patch__diff(patch),
GIT_DIFF_FORMAT_PATCH, print_cb, payload))) GIT_DIFF_FORMAT_PATCH, print_cb, payload)))
{
error = git_patch__invoke_callbacks( error = git_patch__invoke_callbacks(
patch, diff_print_patch_file, diff_print_patch_hunk, patch, diff_print_patch_file, diff_print_patch_hunk,
diff_print_patch_line, &pi); diff_print_patch_line, &pi);
if (error && error != GIT_EUSER)
error = giterr_restore(&pi.error);
}
git_buf_free(&temp); git_buf_free(&temp);
return error; return error;
...@@ -483,8 +489,10 @@ int git_patch_to_str( ...@@ -483,8 +489,10 @@ int git_patch_to_str(
/* GIT_EUSER means git_buf_put in print_to_buffer_cb returned -1, /* GIT_EUSER means git_buf_put in print_to_buffer_cb returned -1,
* meaning a memory allocation failure, so just map to -1... * meaning a memory allocation failure, so just map to -1...
*/ */
if (error == GIT_EUSER) if (error == GIT_EUSER) {
giterr_set_oom();
error = -1; error = -1;
}
*string = git_buf_detach(&output); *string = git_buf_detach(&output);
......
...@@ -28,25 +28,29 @@ static int git_xdiff_parse_hunk(git_diff_hunk *hunk, const char *header) ...@@ -28,25 +28,29 @@ static int git_xdiff_parse_hunk(git_diff_hunk *hunk, const char *header)
{ {
/* expect something of the form "@@ -%d[,%d] +%d[,%d] @@" */ /* expect something of the form "@@ -%d[,%d] +%d[,%d] @@" */
if (*header != '@') if (*header != '@')
return -1; goto fail;
if (git_xdiff_scan_int(&header, &hunk->old_start) < 0) if (git_xdiff_scan_int(&header, &hunk->old_start) < 0)
return -1; goto fail;
if (*header == ',') { if (*header == ',') {
if (git_xdiff_scan_int(&header, &hunk->old_lines) < 0) if (git_xdiff_scan_int(&header, &hunk->old_lines) < 0)
return -1; goto fail;
} else } else
hunk->old_lines = 1; hunk->old_lines = 1;
if (git_xdiff_scan_int(&header, &hunk->new_start) < 0) if (git_xdiff_scan_int(&header, &hunk->new_start) < 0)
return -1; goto fail;
if (*header == ',') { if (*header == ',') {
if (git_xdiff_scan_int(&header, &hunk->new_lines) < 0) if (git_xdiff_scan_int(&header, &hunk->new_lines) < 0)
return -1; goto fail;
} else } else
hunk->new_lines = 1; hunk->new_lines = 1;
if (hunk->old_start < 0 || hunk->new_start < 0) if (hunk->old_start < 0 || hunk->new_start < 0)
return -1; goto fail;
return 0; return 0;
fail:
giterr_set(GITERR_INVALID, "Malformed hunk header from xdiff");
return -1;
} }
typedef struct { typedef struct {
...@@ -123,7 +127,7 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len) ...@@ -123,7 +127,7 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len)
if (output->hunk_cb != NULL && if (output->hunk_cb != NULL &&
output->hunk_cb(delta, &info->hunk, output->payload)) output->hunk_cb(delta, &info->hunk, output->payload))
output->error = GIT_EUSER; return (output->error = giterr_user_cancel());
info->old_lineno = info->hunk.old_start; info->old_lineno = info->hunk.old_start;
info->new_lineno = info->hunk.new_start; info->new_lineno = info->hunk.new_start;
...@@ -149,7 +153,7 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len) ...@@ -149,7 +153,7 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len)
if (!output->error && if (!output->error &&
output->data_cb != NULL && output->data_cb != NULL &&
output->data_cb(delta, &info->hunk, &line, output->payload)) output->data_cb(delta, &info->hunk, &line, output->payload))
output->error = GIT_EUSER; output->error = giterr_user_cancel();
} }
if (len == 3 && !output->error) { if (len == 3 && !output->error) {
...@@ -171,7 +175,7 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len) ...@@ -171,7 +175,7 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len)
if (!output->error && if (!output->error &&
output->data_cb != NULL && output->data_cb != NULL &&
output->data_cb(delta, &info->hunk, &line, output->payload)) output->data_cb(delta, &info->hunk, &line, output->payload))
output->error = GIT_EUSER; output->error = giterr_user_cancel();
} }
return output->error; return output->error;
...@@ -219,11 +223,9 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts) ...@@ -219,11 +223,9 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts)
xo->output.diff_cb = git_xdiff; xo->output.diff_cb = git_xdiff;
memset(&xo->config, 0, sizeof(xo->config));
xo->config.ctxlen = opts ? opts->context_lines : 3; xo->config.ctxlen = opts ? opts->context_lines : 3;
xo->config.interhunkctxlen = opts ? opts->interhunk_lines : 0; xo->config.interhunkctxlen = opts ? opts->interhunk_lines : 0;
memset(&xo->params, 0, sizeof(xo->params));
if (flags & GIT_DIFF_IGNORE_WHITESPACE) if (flags & GIT_DIFF_IGNORE_WHITESPACE)
xo->params.flags |= XDF_WHITESPACE_FLAGS; xo->params.flags |= XDF_WHITESPACE_FLAGS;
if (flags & GIT_DIFF_IGNORE_WHITESPACE_CHANGE) if (flags & GIT_DIFF_IGNORE_WHITESPACE_CHANGE)
...@@ -236,6 +238,5 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts) ...@@ -236,6 +238,5 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts)
if (flags & GIT_DIFF_MINIMAL) if (flags & GIT_DIFF_MINIMAL)
xo->params.flags |= XDF_NEED_MINIMAL; xo->params.flags |= XDF_NEED_MINIMAL;
memset(&xo->callback, 0, sizeof(xo->callback));
xo->callback.outf = git_xdiff_cb; xo->callback.outf = git_xdiff_cb;
} }
...@@ -23,7 +23,8 @@ static void set_error(int error_class, char *string) ...@@ -23,7 +23,8 @@ static void set_error(int error_class, char *string)
{ {
git_error *error = &GIT_GLOBAL->error_t; git_error *error = &GIT_GLOBAL->error_t;
git__free(error->message); if (error->message != string)
git__free(error->message);
error->message = string; error->message = string;
error->klass = error_class; error->klass = error_class;
...@@ -103,8 +104,10 @@ int giterr_set_regex(const regex_t *regex, int error_code) ...@@ -103,8 +104,10 @@ int giterr_set_regex(const regex_t *regex, int error_code)
void giterr_clear(void) void giterr_clear(void)
{ {
set_error(0, NULL); if (GIT_GLOBAL->last_error != NULL) {
GIT_GLOBAL->last_error = NULL; set_error(0, NULL);
GIT_GLOBAL->last_error = NULL;
}
errno = 0; errno = 0;
#ifdef GIT_WIN32 #ifdef GIT_WIN32
...@@ -134,3 +137,39 @@ const git_error *giterr_last(void) ...@@ -134,3 +137,39 @@ const git_error *giterr_last(void)
{ {
return GIT_GLOBAL->last_error; return GIT_GLOBAL->last_error;
} }
int giterr_capture(git_error_state *state, int error_code)
{
state->error_code = error_code;
if (error_code)
giterr_detach(&state->error_msg);
return error_code;
}
int giterr_restore(git_error_state *state)
{
if (state && state->error_code && state->error_msg.message)
set_error(state->error_msg.klass, state->error_msg.message);
else
giterr_clear();
return state ? state->error_code : 0;
}
int giterr_system_last(void)
{
#ifdef GIT_WIN32
return GetLastError();
#else
return errno;
#endif
}
void giterr_system_set(int code)
{
#ifdef GIT_WIN32
SetLastError(code);
#else
errno = code;
#endif
}
...@@ -403,8 +403,8 @@ typedef struct { ...@@ -403,8 +403,8 @@ typedef struct {
const char *base; const char *base;
size_t baselen; size_t baselen;
uint32_t flags; uint32_t flags;
int error;
int depth; int depth;
git_error_state error;
} futils__rmdir_data; } futils__rmdir_data;
#define FUTILS_MAX_DEPTH 100 #define FUTILS_MAX_DEPTH 100
...@@ -447,8 +447,8 @@ static int futils__rm_first_parent(git_buf *path, const char *ceiling) ...@@ -447,8 +447,8 @@ static int futils__rm_first_parent(git_buf *path, const char *ceiling)
static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path) static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
{ {
int error = 0;
futils__rmdir_data *data = opaque; futils__rmdir_data *data = opaque;
int error = data->error;
struct stat st; struct stat st;
if (data->depth > FUTILS_MAX_DEPTH) if (data->depth > FUTILS_MAX_DEPTH)
...@@ -474,13 +474,16 @@ static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path) ...@@ -474,13 +474,16 @@ static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
data->depth++; data->depth++;
error = git_path_direach(path, 0, futils__rmdir_recurs_foreach, data); error = git_path_direach(path, 0, futils__rmdir_recurs_foreach, data);
if (error < 0) if (error == GIT_EUSER)
return (error == GIT_EUSER) ? data->error : error; return error;
data->depth--; data->depth--;
if (error < 0)
goto done;
if (data->depth == 0 && (data->flags & GIT_RMDIR_SKIP_ROOT) != 0) if (data->depth == 0 && (data->flags & GIT_RMDIR_SKIP_ROOT) != 0)
return data->error; goto done;
if ((error = p_rmdir(path->ptr)) < 0) { if ((error = p_rmdir(path->ptr)) < 0) {
if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 && if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 &&
...@@ -499,35 +502,31 @@ static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path) ...@@ -499,35 +502,31 @@ static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0) else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0)
error = futils__error_cannot_rmdir(path->ptr, "still present"); error = futils__error_cannot_rmdir(path->ptr, "still present");
data->error = error; done:
return error; return giterr_capture(&data->error, error);
} }
static int futils__rmdir_empty_parent(void *opaque, git_buf *path) static int futils__rmdir_empty_parent(void *opaque, git_buf *path)
{ {
futils__rmdir_data *data = opaque; futils__rmdir_data *data = opaque;
int error; int error = 0;
if (git_buf_len(path) <= data->baselen) if (git_buf_len(path) <= data->baselen)
return GIT_ITEROVER; return giterr_capture(&data->error, GIT_ITEROVER);
error = p_rmdir(git_buf_cstr(path));
if (error) { if (p_rmdir(git_buf_cstr(path)) < 0) {
int en = errno; int en = errno;
if (en == ENOENT || en == ENOTDIR) { if (en == ENOENT || en == ENOTDIR) {
giterr_clear(); /* do nothing */
error = 0;
} else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) { } else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) {
giterr_clear();
error = GIT_ITEROVER; error = GIT_ITEROVER;
} else { } else {
error = git_path_set_error(errno, git_buf_cstr(path), "rmdir"); error = git_path_set_error(errno, git_buf_cstr(path), "rmdir");
} }
} }
return error; return giterr_capture(&data->error, error);
} }
int git_futils_rmdir_r( int git_futils_rmdir_r(
...@@ -535,12 +534,13 @@ int git_futils_rmdir_r( ...@@ -535,12 +534,13 @@ int git_futils_rmdir_r(
{ {
int error; int error;
git_buf fullpath = GIT_BUF_INIT; git_buf fullpath = GIT_BUF_INIT;
futils__rmdir_data data = { 0 }; futils__rmdir_data data;
/* build path and find "root" where we should start calling mkdir */ /* build path and find "root" where we should start calling mkdir */
if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0) if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0)
return -1; return -1;
memset(&data, 0, sizeof(data));
data.base = base ? base : ""; data.base = base ? base : "";
data.baselen = base ? strlen(base) : 0; data.baselen = base ? strlen(base) : 0;
data.flags = flags; data.flags = flags;
...@@ -548,13 +548,14 @@ int git_futils_rmdir_r( ...@@ -548,13 +548,14 @@ int git_futils_rmdir_r(
error = futils__rmdir_recurs_foreach(&data, &fullpath); error = futils__rmdir_recurs_foreach(&data, &fullpath);
/* remove now-empty parents if requested */ /* remove now-empty parents if requested */
if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0) { if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0)
error = git_path_walk_up( error = git_path_walk_up(
&fullpath, base, futils__rmdir_empty_parent, &data); &fullpath, base, futils__rmdir_empty_parent, &data);
if (error == GIT_ITEROVER) if (error == GIT_EUSER)
error = 0; error = giterr_restore(&data.error);
} if (error == GIT_ITEROVER)
error = 0;
git_buf_free(&fullpath); git_buf_free(&fullpath);
...@@ -858,7 +859,7 @@ typedef struct { ...@@ -858,7 +859,7 @@ typedef struct {
uint32_t flags; uint32_t flags;
uint32_t mkdir_flags; uint32_t mkdir_flags;
mode_t dirmode; mode_t dirmode;
int error; git_error_state error;
} cp_r_info; } cp_r_info;
#define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10) #define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10)
...@@ -896,23 +897,21 @@ static int _cp_r_callback(void *ref, git_buf *from) ...@@ -896,23 +897,21 @@ static int _cp_r_callback(void *ref, git_buf *from)
from->ptr[git_path_basename_offset(from)] == '.') from->ptr[git_path_basename_offset(from)] == '.')
return 0; return 0;
if (git_buf_joinpath( if ((error = git_buf_joinpath(
&info->to, info->to_root, from->ptr + info->from_prefix) < 0) { &info->to, info->to_root, from->ptr + info->from_prefix)) < 0)
error = -1; goto done;
goto exit;
}
if (!(error = git_path_lstat(info->to.ptr, &to_st))) if (!(error = git_path_lstat(info->to.ptr, &to_st)))
exists = true; exists = true;
else if (error != GIT_ENOTFOUND) else if (error != GIT_ENOTFOUND)
goto exit; goto done;
else { else {
giterr_clear(); giterr_clear();
error = 0; error = 0;
} }
if ((error = git_path_lstat(from->ptr, &from_st)) < 0) if ((error = git_path_lstat(from->ptr, &from_st)) < 0)
goto exit; goto done;
if (S_ISDIR(from_st.st_mode)) { if (S_ISDIR(from_st.st_mode)) {
mode_t oldmode = info->dirmode; mode_t oldmode = info->dirmode;
...@@ -928,15 +927,14 @@ static int _cp_r_callback(void *ref, git_buf *from) ...@@ -928,15 +927,14 @@ static int _cp_r_callback(void *ref, git_buf *from)
/* recurse onto target directory */ /* recurse onto target directory */
if (!error && (!exists || S_ISDIR(to_st.st_mode))) { if (!error && (!exists || S_ISDIR(to_st.st_mode))) {
error = git_path_direach(from, 0, _cp_r_callback, info); error = git_path_direach(from, 0, _cp_r_callback, info);
if (error == GIT_EUSER) if (error == GIT_EUSER)
error = info->error; return error;
} }
if (oldmode != 0) if (oldmode != 0)
info->dirmode = oldmode; info->dirmode = oldmode;
goto exit; goto done;
} }
if (exists) { if (exists) {
...@@ -947,7 +945,7 @@ static int _cp_r_callback(void *ref, git_buf *from) ...@@ -947,7 +945,7 @@ static int _cp_r_callback(void *ref, git_buf *from)
giterr_set(GITERR_OS, "Cannot overwrite existing file '%s'", giterr_set(GITERR_OS, "Cannot overwrite existing file '%s'",
info->to.ptr); info->to.ptr);
error = -1; error = -1;
goto exit; goto done;
} }
} }
...@@ -960,7 +958,7 @@ static int _cp_r_callback(void *ref, git_buf *from) ...@@ -960,7 +958,7 @@ static int _cp_r_callback(void *ref, git_buf *from)
/* Make container directory on demand if needed */ /* Make container directory on demand if needed */
if ((info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0 && if ((info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0 &&
(error = _cp_r_mkdir(info, from)) < 0) (error = _cp_r_mkdir(info, from)) < 0)
goto exit; goto done;
/* make symlink or regular file */ /* make symlink or regular file */
if (S_ISLNK(from_st.st_mode)) if (S_ISLNK(from_st.st_mode))
...@@ -974,9 +972,8 @@ static int _cp_r_callback(void *ref, git_buf *from) ...@@ -974,9 +972,8 @@ static int _cp_r_callback(void *ref, git_buf *from)
error = git_futils_cp(from->ptr, info->to.ptr, usemode); error = git_futils_cp(from->ptr, info->to.ptr, usemode);
} }
exit: done:
info->error = error; return giterr_capture(&info->error, error);
return error;
} }
int git_futils_cp_r( int git_futils_cp_r(
...@@ -992,11 +989,11 @@ int git_futils_cp_r( ...@@ -992,11 +989,11 @@ int git_futils_cp_r(
if (git_buf_joinpath(&path, from, "") < 0) /* ensure trailing slash */ if (git_buf_joinpath(&path, from, "") < 0) /* ensure trailing slash */
return -1; return -1;
memset(&info, 0, sizeof(info));
info.to_root = to; info.to_root = to;
info.flags = flags; info.flags = flags;
info.dirmode = dirmode; info.dirmode = dirmode;
info.from_prefix = path.size; info.from_prefix = path.size;
info.error = 0;
git_buf_init(&info.to, 0); git_buf_init(&info.to, 0);
/* precalculate mkdir flags */ /* precalculate mkdir flags */
...@@ -1019,7 +1016,7 @@ int git_futils_cp_r( ...@@ -1019,7 +1016,7 @@ int git_futils_cp_r(
git_buf_free(&info.to); git_buf_free(&info.to);
if (error == GIT_EUSER) if (error == GIT_EUSER)
error = info.error; error = giterr_restore(&info.error);
return error; return error;
} }
......
...@@ -991,9 +991,8 @@ static int fs_iterator__expand_dir(fs_iterator *fi) ...@@ -991,9 +991,8 @@ static int fs_iterator__expand_dir(fs_iterator *fi)
fi->base.start, fi->base.end, &ff->entries); fi->base.start, fi->base.end, &ff->entries);
if (error < 0) { if (error < 0) {
git_error last_error = {0}; git_error_state last_error = { 0 };
giterr_capture(&last_error, error);
giterr_detach(&last_error);
/* these callbacks may clear the error message */ /* these callbacks may clear the error message */
fs_iterator__free_frame(ff); fs_iterator__free_frame(ff);
...@@ -1001,12 +1000,7 @@ static int fs_iterator__expand_dir(fs_iterator *fi) ...@@ -1001,12 +1000,7 @@ static int fs_iterator__expand_dir(fs_iterator *fi)
/* next time return value we skipped to */ /* next time return value we skipped to */
fi->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS; fi->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS;
if (last_error.message) { return giterr_restore(&last_error);
giterr_set_str(last_error.klass, last_error.message);
free(last_error.message);
}
return error;
} }
if (ff->entries.length == 0) { if (ff->entries.length == 0) {
......
...@@ -696,7 +696,7 @@ struct foreach_state { ...@@ -696,7 +696,7 @@ struct foreach_state {
size_t dir_len; size_t dir_len;
git_odb_foreach_cb cb; git_odb_foreach_cb cb;
void *data; void *data;
int cb_error; git_error_state cb_error;
}; };
GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr) GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr)
...@@ -735,10 +735,8 @@ static int foreach_object_dir_cb(void *_state, git_buf *path) ...@@ -735,10 +735,8 @@ static int foreach_object_dir_cb(void *_state, git_buf *path)
if (filename_to_oid(&oid, path->ptr + state->dir_len) < 0) if (filename_to_oid(&oid, path->ptr + state->dir_len) < 0)
return 0; return 0;
if (state->cb(&oid, state->data)) { if (state->cb(&oid, state->data))
state->cb_error = GIT_EUSER; return giterr_user_cancel();
return -1;
}
return 0; return 0;
} }
...@@ -747,7 +745,9 @@ static int foreach_cb(void *_state, git_buf *path) ...@@ -747,7 +745,9 @@ static int foreach_cb(void *_state, git_buf *path)
{ {
struct foreach_state *state = (struct foreach_state *) _state; struct foreach_state *state = (struct foreach_state *) _state;
return git_path_direach(path, 0, foreach_object_dir_cb, state); return giterr_capture(
&state->cb_error,
git_path_direach(path, 0, foreach_object_dir_cb, state));
} }
static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb cb, void *data) static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb cb, void *data)
...@@ -762,7 +762,8 @@ static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb ...@@ -762,7 +762,8 @@ static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb
objects_dir = backend->objects_dir; objects_dir = backend->objects_dir;
git_buf_sets(&buf, objects_dir); if (git_buf_sets(&buf, objects_dir) < 0)
return -1;
git_path_to_dir(&buf); git_path_to_dir(&buf);
memset(&state, 0, sizeof(state)); memset(&state, 0, sizeof(state));
...@@ -772,9 +773,12 @@ static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb ...@@ -772,9 +773,12 @@ static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb
error = git_path_direach(&buf, 0, foreach_cb, &state); error = git_path_direach(&buf, 0, foreach_cb, &state);
if (error == GIT_EUSER)
error = giterr_restore(&state.cb_error);
git_buf_free(&buf); git_buf_free(&buf);
return state.cb_error ? state.cb_error : error; return error;
} }
static int loose_backend__stream_fwrite(git_odb_stream *_stream, const git_oid *oid) static int loose_backend__stream_fwrite(git_odb_stream *_stream, const git_oid *oid)
......
...@@ -190,31 +190,45 @@ static int packfile_sort__cb(const void *a_, const void *b_) ...@@ -190,31 +190,45 @@ static int packfile_sort__cb(const void *a_, const void *b_)
} }
struct packfile_load_data {
struct pack_backend *backend;
git_error_state error;
};
static int packfile_load__cb(void *_data, git_buf *path) static int packfile_load__cb(void *_data, git_buf *path)
{ {
struct pack_backend *backend = (struct pack_backend *)_data; struct packfile_load_data *data = _data;
struct pack_backend *backend = data->backend;
struct git_pack_file *pack; struct git_pack_file *pack;
const char *path_str = git_buf_cstr(path);
size_t i, cmp_len = git_buf_len(path);
int error; int error;
size_t i;
if (git__suffixcmp(path->ptr, ".idx") != 0) if (cmp_len <= strlen(".idx") || git__suffixcmp(path_str, ".idx") != 0)
return 0; /* not an index */ return 0; /* not an index */
cmp_len -= strlen(".idx");
for (i = 0; i < backend->packs.length; ++i) { for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p = git_vector_get(&backend->packs, i); struct git_pack_file *p = git_vector_get(&backend->packs, i);
if (memcmp(p->pack_name, git_buf_cstr(path), git_buf_len(path) - strlen(".idx")) == 0)
if (memcmp(p->pack_name, path_str, cmp_len) == 0)
return 0; return 0;
} }
error = git_packfile_alloc(&pack, path->ptr); error = git_packfile_alloc(&pack, path->ptr);
if (error == GIT_ENOTFOUND)
/* ignore missing .pack file as git does */ /* ignore missing .pack file as git does */
if (error == GIT_ENOTFOUND) {
giterr_clear();
return 0; return 0;
else if (error < 0) }
return error;
if (!error)
error = git_vector_insert(&backend->packs, pack);
return giterr_capture(&data->error, error);
return git_vector_insert(&backend->packs, pack);
} }
static int pack_entry_find_inner( static int pack_entry_find_inner(
...@@ -314,32 +328,34 @@ static int pack_entry_find_prefix( ...@@ -314,32 +328,34 @@ static int pack_entry_find_prefix(
* Implement the git_odb_backend API calls * Implement the git_odb_backend API calls
* *
***********************************************************/ ***********************************************************/
static int pack_backend__refresh(git_odb_backend *_backend) static int pack_backend__refresh(git_odb_backend *backend)
{ {
struct pack_backend *backend = (struct pack_backend *)_backend; struct packfile_load_data data;
int error; int error;
struct stat st; struct stat st;
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
if (backend->pack_folder == NULL) memset(&data, 0, sizeof(data));
data.backend = (struct pack_backend *)backend;
if (data.backend->pack_folder == NULL)
return 0; return 0;
if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode)) if (p_stat(data.backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode))
return git_odb__error_notfound("failed to refresh packfiles", NULL); return git_odb__error_notfound("failed to refresh packfiles", NULL);
git_buf_sets(&path, backend->pack_folder); git_buf_sets(&path, data.backend->pack_folder);
/* reload all packs */ /* reload all packs */
error = git_path_direach(&path, 0, packfile_load__cb, backend); error = git_path_direach(&path, 0, packfile_load__cb, &data);
git_buf_free(&path); if (error == GIT_EUSER)
error = giterr_restore(&data.error);
if (error < 0) git_buf_free(&path);
return -1; git_vector_sort(&data.backend->packs);
git_vector_sort(&backend->packs); return error;
return 0;
} }
static int pack_backend__read_header_internal( static int pack_backend__read_header_internal(
......
...@@ -434,7 +434,8 @@ int git_path_walk_up( ...@@ -434,7 +434,8 @@ int git_path_walk_up(
iter.asize = path->asize; iter.asize = path->asize;
while (scan >= stop) { while (scan >= stop) {
error = cb(data, &iter); if (cb(data, &iter))
error = giterr_user_cancel();
iter.ptr[scan] = oldc; iter.ptr[scan] = oldc;
if (error < 0) if (error < 0)
break; break;
...@@ -528,7 +529,9 @@ bool git_path_is_empty_dir(const char *path) ...@@ -528,7 +529,9 @@ bool git_path_is_empty_dir(const char *path)
if (!git_path_isdir(path)) if (!git_path_isdir(path))
return false; return false;
if (!(error = git_buf_sets(&dir, path))) if ((error = git_buf_sets(&dir, path)) != 0)
giterr_clear();
else
error = git_path_direach(&dir, 0, path_found_entry, NULL); error = git_path_direach(&dir, 0, path_found_entry, NULL);
git_buf_free(&dir); git_buf_free(&dir);
...@@ -867,7 +870,7 @@ int git_path_direach( ...@@ -867,7 +870,7 @@ int git_path_direach(
if ((error = git_path_iconv(&ic, &de_path, &de_len)) < 0) if ((error = git_path_iconv(&ic, &de_path, &de_len)) < 0)
break; break;
#endif #endif
if ((error = git_buf_put(path, de_path, de_len)) < 0) if ((error = git_buf_put(path, de_path, de_len)) < 0)
break; break;
...@@ -876,7 +879,7 @@ int git_path_direach( ...@@ -876,7 +879,7 @@ int git_path_direach(
git_buf_truncate(path, wd_len); /* restore path */ git_buf_truncate(path, wd_len); /* restore path */
if (error) { if (error) {
error = GIT_EUSER; error = giterr_user_cancel();
break; break;
} }
} }
......
...@@ -217,7 +217,14 @@ char *git_pool_strdup(git_pool *pool, const char *str) ...@@ -217,7 +217,14 @@ char *git_pool_strdup(git_pool *pool, const char *str)
char *git_pool_strdup_safe(git_pool *pool, const char *str) char *git_pool_strdup_safe(git_pool *pool, const char *str)
{ {
return str ? git_pool_strdup(pool, str) : NULL; if (!str)
return NULL;
else {
char *result = git_pool_strdup(pool, str);
if (!result)
giterr_clear();
return result;
}
} }
char *git_pool_strcat(git_pool *pool, const char *a, const char *b) char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
......
...@@ -264,9 +264,14 @@ done: ...@@ -264,9 +264,14 @@ done:
return error; return error;
} }
static int _dirent_loose_load(void *data, git_buf *full_path) struct packed_loadloose_data {
refdb_fs_backend *backend;
git_error_state error;
};
static int _dirent_loose_load(void *data_, git_buf *full_path)
{ {
refdb_fs_backend *backend = (refdb_fs_backend *)data; struct packed_loadloose_data *data = data_;
const char *file_path; const char *file_path;
if (git__suffixcmp(full_path->ptr, ".lock") == 0) if (git__suffixcmp(full_path->ptr, ".lock") == 0)
...@@ -274,11 +279,12 @@ static int _dirent_loose_load(void *data, git_buf *full_path) ...@@ -274,11 +279,12 @@ static int _dirent_loose_load(void *data, git_buf *full_path)
if (git_path_isdir(full_path->ptr)) if (git_path_isdir(full_path->ptr))
return git_path_direach( return git_path_direach(
full_path, backend->direach_flags, _dirent_loose_load, backend); full_path, data->backend->direach_flags, _dirent_loose_load, data);
file_path = full_path->ptr + strlen(backend->path); file_path = full_path->ptr + strlen(data->backend->path);
return loose_lookup_to_packfile(backend, file_path); return giterr_capture(
&data->error, loose_lookup_to_packfile(data->backend, file_path));
} }
/* /*
...@@ -291,21 +297,28 @@ static int packed_loadloose(refdb_fs_backend *backend) ...@@ -291,21 +297,28 @@ static int packed_loadloose(refdb_fs_backend *backend)
{ {
int error; int error;
git_buf refs_path = GIT_BUF_INIT; git_buf refs_path = GIT_BUF_INIT;
struct packed_loadloose_data data;
if (git_buf_joinpath(&refs_path, backend->path, GIT_REFS_DIR) < 0) if (git_buf_joinpath(&refs_path, backend->path, GIT_REFS_DIR) < 0)
return -1; return -1;
memset(&data, 0, sizeof(data));
data.backend = backend;
/* /*
* Load all the loose files from disk into the Packfile table. * Load all the loose files from disk into the Packfile table.
* This will overwrite any old packed entries with their * This will overwrite any old packed entries with their
* updated loose versions * updated loose versions
*/ */
error = git_path_direach( error = git_path_direach(
&refs_path, backend->direach_flags, _dirent_loose_load, backend); &refs_path, backend->direach_flags, _dirent_loose_load, &data);
git_buf_free(&refs_path); git_buf_free(&refs_path);
return (error == GIT_EUSER) ? -1 : error; if (error == GIT_EUSER)
error = giterr_restore(&data.error);
return error;
} }
static int refdb_fs_backend__exists( static int refdb_fs_backend__exists(
......
...@@ -471,7 +471,7 @@ int git_reference_rename( ...@@ -471,7 +471,7 @@ int git_reference_rename(
if ((error = git_refdb_rename(out, ref->db, ref->name, new_name, force)) < 0) if ((error = git_refdb_rename(out, ref->db, ref->name, new_name, force)) < 0)
return error; return error;
/* Update HEAD it was poiting to the reference being renamed. */ /* Update HEAD it was pointing to the reference being renamed */
if (should_head_be_updated && if (should_head_be_updated &&
(error = git_repository_set_head(ref->db->repo, new_name)) < 0) { (error = git_repository_set_head(ref->db->repo, new_name)) < 0) {
giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference");
......
...@@ -251,13 +251,14 @@ int git_remote_create_inmemory(git_remote **out, git_repository *repo, const cha ...@@ -251,13 +251,14 @@ int git_remote_create_inmemory(git_remote **out, git_repository *repo, const cha
struct refspec_cb_data { struct refspec_cb_data {
git_remote *remote; git_remote *remote;
int fetch; int fetch;
git_error_state error;
}; };
static int refspec_cb(const git_config_entry *entry, void *payload) static int refspec_cb(const git_config_entry *entry, void *payload)
{ {
const struct refspec_cb_data *data = (struct refspec_cb_data *)payload; struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
return giterr_capture(
return add_refspec(data->remote, entry->value, data->fetch); &data->error, add_refspec(data->remote, entry->value, data->fetch));
} }
static int get_optional_config( static int get_optional_config(
...@@ -283,9 +284,6 @@ static int get_optional_config( ...@@ -283,9 +284,6 @@ static int get_optional_config(
error = 0; error = 0;
} }
if (error < 0)
error = -1;
return error; return error;
} }
...@@ -296,7 +294,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) ...@@ -296,7 +294,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
const char *val; const char *val;
int error = 0; int error = 0;
git_config *config; git_config *config;
struct refspec_cb_data data; struct refspec_cb_data data = { NULL };
bool optional_setting_found = false, found; bool optional_setting_found = false, found;
assert(out && repo && name); assert(out && repo && name);
...@@ -363,6 +361,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) ...@@ -363,6 +361,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
data.remote = remote; data.remote = remote;
data.fetch = true; data.fetch = true;
git_buf_clear(&buf); git_buf_clear(&buf);
git_buf_printf(&buf, "remote.%s.fetch", name); git_buf_printf(&buf, "remote.%s.fetch", name);
...@@ -388,6 +387,9 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) ...@@ -388,6 +387,9 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
cleanup: cleanup:
git_buf_free(&buf); git_buf_free(&buf);
if (error == GIT_EUSER)
error = giterr_restore(&data.error);
if (error < 0) if (error < 0)
git_remote_free(remote); git_remote_free(remote);
...@@ -1110,9 +1112,14 @@ void git_remote_free(git_remote *remote) ...@@ -1110,9 +1112,14 @@ void git_remote_free(git_remote *remote)
git__free(remote); git__free(remote);
} }
struct remote_list_data {
git_vector list;
git_error_state error;
};
static int remote_list_cb(const git_config_entry *entry, void *payload) static int remote_list_cb(const git_config_entry *entry, void *payload)
{ {
git_vector *list = payload; struct remote_list_data *data = payload;
const char *name = entry->name + strlen("remote."); const char *name = entry->name + strlen("remote.");
size_t namelen = strlen(name); size_t namelen = strlen(name);
char *remote_name; char *remote_name;
...@@ -1123,47 +1130,50 @@ static int remote_list_cb(const git_config_entry *entry, void *payload) ...@@ -1123,47 +1130,50 @@ static int remote_list_cb(const git_config_entry *entry, void *payload)
remote_name = git__strndup(name, namelen - 4); /* strip ".url" */ remote_name = git__strndup(name, namelen - 4); /* strip ".url" */
else else
remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */ remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */
GITERR_CHECK_ALLOC(remote_name); if (!remote_name)
return giterr_capture(&data->error, -1);
return git_vector_insert(list, remote_name); return giterr_capture(
&data->error, git_vector_insert(&data->list, remote_name));
} }
int git_remote_list(git_strarray *remotes_list, git_repository *repo) int git_remote_list(git_strarray *remotes_list, git_repository *repo)
{ {
git_config *cfg;
git_vector list;
int error; int error;
git_config *cfg;
struct remote_list_data data;
if (git_repository_config__weakptr(&cfg, repo) < 0) if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
return -1; return error;
if (git_vector_init(&list, 4, git__strcmp_cb) < 0) memset(&data, 0, sizeof(data));
return -1; if ((error = git_vector_init(&data.list, 4, git__strcmp_cb)) < 0)
return error;
error = git_config_foreach_match( error = git_config_foreach_match(
cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list); cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &data);
/* cb error is converted to GIT_EUSER by git_config_foreach */
if (error == GIT_EUSER)
error = giterr_restore(&data.error);
if (error < 0) { if (error < 0) {
size_t i; size_t i;
char *elem; char *elem;
git_vector_foreach(&list, i, elem) { git_vector_foreach(&data.list, i, elem) {
git__free(elem); git__free(elem);
} }
git_vector_free(&list); git_vector_free(&data.list);
/* cb error is converted to GIT_EUSER by git_config_foreach */
if (error == GIT_EUSER)
error = -1;
return error; return error;
} }
git_vector_uniq(&list, git__free); git_vector_uniq(&data.list, git__free);
remotes_list->strings = (char **)list.contents; remotes_list->strings = (char **)data.list.contents;
remotes_list->count = list.length; remotes_list->count = data.list.length;
return 0; return 0;
} }
...@@ -1250,11 +1260,11 @@ cleanup: ...@@ -1250,11 +1260,11 @@ cleanup:
return error; return error;
} }
struct update_data struct update_data {
{
git_config *config; git_config *config;
const char *old_remote_name; const char *old_remote_name;
const char *new_remote_name; const char *new_remote_name;
git_error_state error;
}; };
static int update_config_entries_cb( static int update_config_entries_cb(
...@@ -1266,10 +1276,9 @@ static int update_config_entries_cb( ...@@ -1266,10 +1276,9 @@ static int update_config_entries_cb(
if (strcmp(entry->value, data->old_remote_name)) if (strcmp(entry->value, data->old_remote_name))
return 0; return 0;
return git_config_set_string( return giterr_capture(
data->config, &data->error, git_config_set_string(
entry->name, data->config, entry->name, data->new_remote_name));
data->new_remote_name);
} }
static int update_branch_remote_config_entry( static int update_branch_remote_config_entry(
...@@ -1277,20 +1286,22 @@ static int update_branch_remote_config_entry( ...@@ -1277,20 +1286,22 @@ static int update_branch_remote_config_entry(
const char *old_name, const char *old_name,
const char *new_name) const char *new_name)
{ {
git_config *config; int error;
struct update_data data; struct update_data data = { NULL };
if (git_repository_config__weakptr(&config, repo) < 0) if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
return -1; return error;
data.config = config;
data.old_remote_name = old_name; data.old_remote_name = old_name;
data.new_remote_name = new_name; data.new_remote_name = new_name;
return git_config_foreach_match( error = git_config_foreach_match(
config, data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
"branch\\..+\\.remote",
update_config_entries_cb, &data); if (error == GIT_EUSER)
error = giterr_restore(&data.error);
return error;
} }
static int rename_one_remote_reference( static int rename_one_remote_reference(
...@@ -1298,18 +1309,20 @@ static int rename_one_remote_reference( ...@@ -1298,18 +1309,20 @@ static int rename_one_remote_reference(
const char *old_remote_name, const char *old_remote_name,
const char *new_remote_name) const char *new_remote_name)
{ {
int error = -1; int error;
git_buf new_name = GIT_BUF_INIT; git_buf new_name = GIT_BUF_INIT;
if (git_buf_printf( error = git_buf_printf(
&new_name, &new_name,
GIT_REFS_REMOTES_DIR "%s%s", GIT_REFS_REMOTES_DIR "%s%s",
new_remote_name, new_remote_name,
reference->name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name)) < 0) reference->name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name));
return -1;
error = git_reference_rename(NULL, reference, git_buf_cstr(&new_name), 0); if (!error) {
git_reference_free(reference); error = git_reference_rename(
NULL, reference, git_buf_cstr(&new_name), 0);
git_reference_free(reference);
}
git_buf_free(&new_name); git_buf_free(&new_name);
return error; return error;
...@@ -1320,12 +1333,12 @@ static int rename_remote_references( ...@@ -1320,12 +1333,12 @@ static int rename_remote_references(
const char *old_name, const char *old_name,
const char *new_name) const char *new_name)
{ {
int error = -1; int error;
git_reference *ref; git_reference *ref;
git_reference_iterator *iter; git_reference_iterator *iter;
if (git_reference_iterator_new(&iter, repo) < 0) if ((error = git_reference_iterator_new(&iter, repo)) < 0)
return -1; return error;
while ((error = git_reference_next(&ref, iter)) == 0) { while ((error = git_reference_next(&ref, iter)) == 0) {
if (git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR)) { if (git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR)) {
...@@ -1333,18 +1346,13 @@ static int rename_remote_references( ...@@ -1333,18 +1346,13 @@ static int rename_remote_references(
continue; continue;
} }
if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0) { if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
git_reference_iterator_free(iter); break;
return error;
}
} }
git_reference_iterator_free(iter); git_reference_iterator_free(iter);
if (error == GIT_ITEROVER) return (error == GIT_ITEROVER) ? 0 : error;
return 0;
return error;
} }
static int rename_fetch_refspecs( static int rename_fetch_refspecs(
......
...@@ -152,25 +152,32 @@ static git_status_t status_compute( ...@@ -152,25 +152,32 @@ static git_status_t status_compute(
return st; return st;
} }
struct status_data {
git_status_list *status;
git_error_state err;
};
static int status_collect( static int status_collect(
git_diff_delta *head2idx, git_diff_delta *head2idx,
git_diff_delta *idx2wd, git_diff_delta *idx2wd,
void *payload) void *payload)
{ {
git_status_list *status = payload; struct status_data *data = payload;
git_status_entry *status_entry; git_status_entry *status_entry;
if (!status_is_included(status, head2idx, idx2wd)) if (!status_is_included(data->status, head2idx, idx2wd))
return 0; return 0;
status_entry = git__malloc(sizeof(git_status_entry)); status_entry = git__malloc(sizeof(git_status_entry));
GITERR_CHECK_ALLOC(status_entry); if (!status_entry)
return giterr_capture(&data->err, -1);
status_entry->status = status_compute(status, head2idx, idx2wd); status_entry->status = status_compute(data->status, head2idx, idx2wd);
status_entry->head_to_index = head2idx; status_entry->head_to_index = head2idx;
status_entry->index_to_workdir = idx2wd; status_entry->index_to_workdir = idx2wd;
return git_vector_insert(&status->paired, status_entry); return giterr_capture(
&data->err, git_vector_insert(&data->status->paired, status_entry));
} }
GIT_INLINE(int) status_entry_cmp_base( GIT_INLINE(int) status_entry_cmp_base(
...@@ -314,9 +321,18 @@ int git_status_list_new( ...@@ -314,9 +321,18 @@ int git_status_list_new(
goto done; goto done;
} }
if ((error = git_diff__paired_foreach( {
status->head2idx, status->idx2wd, status_collect, status)) < 0) struct status_data data = { 0 };
goto done; data.status = status;
error = git_diff__paired_foreach(
status->head2idx, status->idx2wd, status_collect, &data);
if (error == GIT_EUSER)
error = giterr_restore(&data.err);
if (error < 0)
goto done;
}
if (flags & GIT_STATUS_OPT_SORT_CASE_SENSITIVELY) if (flags & GIT_STATUS_OPT_SORT_CASE_SENSITIVELY)
git_vector_set_cmp(&status->paired, status_entry_cmp); git_vector_set_cmp(&status->paired, status_entry_cmp);
......
...@@ -71,6 +71,11 @@ __KHASH_IMPL( ...@@ -71,6 +71,11 @@ __KHASH_IMPL(
str, static kh_inline, const char *, void *, 1, str, static kh_inline, const char *, void *, 1,
str_hash_no_trailing_slash, str_equal_no_trailing_slash); str_hash_no_trailing_slash, str_equal_no_trailing_slash);
struct submodule_callback_payload {
git_repository *repo;
git_error_state error;
};
static int load_submodule_config(git_repository *repo); static int load_submodule_config(git_repository *repo);
static git_config_backend *open_gitmodules(git_repository *, bool, const git_oid *); static git_config_backend *open_gitmodules(git_repository *, bool, const git_oid *);
static int lookup_head_remote(git_buf *url, git_repository *repo); static int lookup_head_remote(git_buf *url, git_repository *repo);
...@@ -169,8 +174,7 @@ int git_submodule_foreach( ...@@ -169,8 +174,7 @@ int git_submodule_foreach(
} }
if (callback(sm, sm->name, payload)) { if (callback(sm, sm->name, payload)) {
giterr_clear(); error = giterr_user_cancel();
error = GIT_EUSER;
break; break;
} }
}); });
...@@ -821,20 +825,21 @@ int git_submodule_reload(git_submodule *submodule) ...@@ -821,20 +825,21 @@ int git_submodule_reload(git_submodule *submodule)
{ {
int error = 0; int error = 0;
git_config_backend *mods; git_config_backend *mods;
struct submodule_callback_payload p;
assert(submodule); assert(submodule);
/* refresh index data */ /* refresh index data */
if ((error = submodule_update_index(submodule)) < 0)
if (submodule_update_index(submodule) < 0) return error;
return -1;
/* refresh HEAD tree data */ /* refresh HEAD tree data */
if ((error = submodule_update_head(submodule)) < 0)
if (submodule_update_head(submodule) < 0) return error;
return -1;
/* refresh config data */ /* refresh config data */
memset(&p, 0, sizeof(p));
p.repo = submodule->repo;
mods = open_gitmodules(submodule->repo, false, NULL); mods = open_gitmodules(submodule->repo, false, NULL);
if (mods != NULL) { if (mods != NULL) {
...@@ -846,23 +851,29 @@ int git_submodule_reload(git_submodule *submodule) ...@@ -846,23 +851,29 @@ int git_submodule_reload(git_submodule *submodule)
if (git_buf_oom(&path)) if (git_buf_oom(&path))
error = -1; error = -1;
else else {
error = git_config_file_foreach_match( error = git_config_file_foreach_match(
mods, path.ptr, submodule_load_from_config, submodule->repo); mods, path.ptr, submodule_load_from_config, &p);
if (error == GIT_EUSER)
error = giterr_restore(&p.error);
}
git_buf_free(&path); git_buf_free(&path);
git_config_file_free(mods); git_config_file_free(mods);
}
if (error < 0) if (error < 0)
return error; return error;
}
/* refresh wd data */ /* refresh wd data */
submodule->flags = submodule->flags & submodule->flags = submodule->flags &
~(GIT_SUBMODULE_STATUS_IN_WD | GIT_SUBMODULE_STATUS__WD_OID_VALID); ~(GIT_SUBMODULE_STATUS_IN_WD | GIT_SUBMODULE_STATUS__WD_OID_VALID);
error = submodule_load_from_wd_lite(submodule, submodule->path, NULL); error = submodule_load_from_wd_lite(submodule, submodule->path, &p);
if (error)
error = giterr_restore(&p.error);
return error; return error;
} }
...@@ -1087,15 +1098,14 @@ int git_submodule_parse_update(git_submodule_update_t *out, const char *value) ...@@ -1087,15 +1098,14 @@ int git_submodule_parse_update(git_submodule_update_t *out, const char *value)
} }
static int submodule_load_from_config( static int submodule_load_from_config(
const git_config_entry *entry, void *data) const git_config_entry *entry, void *payload)
{ {
git_repository *repo = data; struct submodule_callback_payload *p = payload;
git_strmap *smcfg = repo->submodules; git_strmap *smcfg = p->repo->submodules;
const char *namestart, *property, *alternate = NULL; const char *namestart, *property, *alternate = NULL;
const char *key = entry->name, *value = entry->value; const char *key = entry->name, *value = entry->value, *path;
git_buf name = GIT_BUF_INIT; git_buf name = GIT_BUF_INIT;
git_submodule *sm; git_submodule *sm;
bool is_path;
int error = 0; int error = 0;
if (git__prefixcmp(key, "submodule.") != 0) if (git__prefixcmp(key, "submodule.") != 0)
...@@ -1108,15 +1118,11 @@ static int submodule_load_from_config( ...@@ -1108,15 +1118,11 @@ static int submodule_load_from_config(
return 0; return 0;
property++; property++;
is_path = (strcasecmp(property, "path") == 0); path = !strcasecmp(property, "path") ? value : NULL;
if (git_buf_set(&name, namestart, property - namestart - 1) < 0) if ((error = git_buf_set(&name, namestart, property - namestart - 1)) < 0 ||
return -1; (error = submodule_get(&sm, p->repo, name.ptr, path)) < 0)
goto done;
if (submodule_get(&sm, repo, name.ptr, is_path ? value : NULL) < 0) {
git_buf_free(&name);
return -1;
}
sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG; sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
...@@ -1130,15 +1136,20 @@ static int submodule_load_from_config( ...@@ -1130,15 +1136,20 @@ static int submodule_load_from_config(
if (strcmp(sm->name, name.ptr) != 0) { if (strcmp(sm->name, name.ptr) != 0) {
alternate = sm->name = git_buf_detach(&name); alternate = sm->name = git_buf_detach(&name);
} else if (is_path && value && strcmp(sm->path, value) != 0) { } else if (path && strcmp(path, sm->path) != 0) {
alternate = sm->path = git__strdup(value); alternate = sm->path = git__strdup(value);
if (!sm->path) if (!sm->path) {
error = -1; error = -1;
goto done;
}
} }
if (alternate) { if (alternate) {
void *old_sm = NULL; void *old_sm = NULL;
git_strmap_insert2(smcfg, alternate, sm, old_sm, error); git_strmap_insert2(smcfg, alternate, sm, old_sm, error);
if (error < 0)
goto done;
if (error >= 0) if (error >= 0)
GIT_REFCOUNT_INC(sm); /* inserted under a new key */ GIT_REFCOUNT_INC(sm); /* inserted under a new key */
...@@ -1149,15 +1160,11 @@ static int submodule_load_from_config( ...@@ -1149,15 +1160,11 @@ static int submodule_load_from_config(
} }
} }
git_buf_free(&name);
if (error < 0)
return error;
/* TODO: Look up path in index and if it is present but not a GITLINK /* TODO: Look up path in index and if it is present but not a GITLINK
* then this should be deleted (at least to match git's behavior) * then this should be deleted (at least to match git's behavior)
*/ */
if (is_path) if (path)
return 0; return 0;
/* copy other properties into submodule entry */ /* copy other properties into submodule entry */
...@@ -1165,41 +1172,47 @@ static int submodule_load_from_config( ...@@ -1165,41 +1172,47 @@ static int submodule_load_from_config(
git__free(sm->url); git__free(sm->url);
sm->url = NULL; sm->url = NULL;
if (value != NULL && (sm->url = git__strdup(value)) == NULL) if (value != NULL && (sm->url = git__strdup(value)) == NULL) {
return -1; error = -1;
goto done;
}
} }
else if (strcasecmp(property, "update") == 0) { else if (strcasecmp(property, "update") == 0) {
if (git_submodule_parse_update(&sm->update, value) < 0) if ((error = git_submodule_parse_update(&sm->update, value)) < 0)
return -1; goto done;
sm->update_default = sm->update; sm->update_default = sm->update;
} }
else if (strcasecmp(property, "fetchRecurseSubmodules") == 0) { else if (strcasecmp(property, "fetchRecurseSubmodules") == 0) {
if (git__parse_bool(&sm->fetch_recurse, value) < 0) if (git__parse_bool(&sm->fetch_recurse, value) < 0) {
return submodule_config_error("fetchRecurseSubmodules", value); error = submodule_config_error("fetchRecurseSubmodules", value);
goto done;
}
} }
else if (strcasecmp(property, "ignore") == 0) { else if (strcasecmp(property, "ignore") == 0) {
if (git_submodule_parse_ignore(&sm->ignore, value) < 0) if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0)
return -1; goto done;
sm->ignore_default = sm->ignore; sm->ignore_default = sm->ignore;
} }
/* ignore other unknown submodule properties */ /* ignore other unknown submodule properties */
return 0; done:
git_buf_free(&name);
return giterr_capture(&p->error, error);
} }
static int submodule_load_from_wd_lite( static int submodule_load_from_wd_lite(
git_submodule *sm, const char *name, void *payload) git_submodule *sm, const char *name, void *payload)
{ {
struct submodule_callback_payload *p = payload;
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
GIT_UNUSED(name); GIT_UNUSED(name);
GIT_UNUSED(payload);
if (git_repository_is_bare(sm->repo)) if (git_repository_is_bare(sm->repo))
return 0; return 0;
if (git_buf_joinpath(&path, git_repository_workdir(sm->repo), sm->path) < 0) if (git_buf_joinpath(&path, git_repository_workdir(sm->repo), sm->path) < 0)
return -1; return giterr_capture(&p->error, -1);
if (git_path_isdir(path.ptr)) if (git_path_isdir(path.ptr))
sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED; sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
...@@ -1208,7 +1221,6 @@ static int submodule_load_from_wd_lite( ...@@ -1208,7 +1221,6 @@ static int submodule_load_from_wd_lite(
sm->flags |= GIT_SUBMODULE_STATUS_IN_WD; sm->flags |= GIT_SUBMODULE_STATUS_IN_WD;
git_buf_free(&path); git_buf_free(&path);
return 0; return 0;
} }
...@@ -1342,13 +1354,15 @@ static int load_submodule_config(git_repository *repo) ...@@ -1342,13 +1354,15 @@ static int load_submodule_config(git_repository *repo)
{ {
int error; int error;
git_oid gitmodules_oid; git_oid gitmodules_oid;
git_buf path = GIT_BUF_INIT;
git_config_backend *mods = NULL; git_config_backend *mods = NULL;
struct submodule_callback_payload p;
if (repo->submodules) if (repo->submodules)
return 0; return 0;
memset(&gitmodules_oid, 0, sizeof(gitmodules_oid)); memset(&gitmodules_oid, 0, sizeof(gitmodules_oid));
memset(&p, 0, sizeof(p));
p.repo = repo;
/* Submodule data is kept in a hashtable keyed by both name and path. /* Submodule data is kept in a hashtable keyed by both name and path.
* These are usually the same, but that is not guaranteed. * These are usually the same, but that is not guaranteed.
...@@ -1370,23 +1384,23 @@ static int load_submodule_config(git_repository *repo) ...@@ -1370,23 +1384,23 @@ static int load_submodule_config(git_repository *repo)
/* add submodule information from .gitmodules */ /* add submodule information from .gitmodules */
if ((mods = open_gitmodules(repo, false, &gitmodules_oid)) != NULL) if ((mods = open_gitmodules(repo, false, &gitmodules_oid)) != NULL &&
error = git_config_file_foreach(mods, submodule_load_from_config, repo); (error = git_config_file_foreach(
mods, submodule_load_from_config, &p)) < 0)
if (error != 0)
goto cleanup; goto cleanup;
/* shallow scan submodules in work tree */ /* shallow scan submodules in work tree */
if (!git_repository_is_bare(repo)) if (!git_repository_is_bare(repo))
error = git_submodule_foreach(repo, submodule_load_from_wd_lite, NULL); error = git_submodule_foreach(repo, submodule_load_from_wd_lite, &p);
cleanup: cleanup:
git_buf_free(&path);
if (mods != NULL) if (mods != NULL)
git_config_file_free(mods); git_config_file_free(mods);
if (error == GIT_EUSER)
error = giterr_restore(&p.error);
if (error) if (error)
git_submodule_config_free(repo); git_submodule_config_free(repo);
......
#include "clar_libgit2.h"
#include "config.h"
static git_repository *g_repo = NULL;
static git_config *g_config = NULL;
void test_config_rename__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_repository_config(&g_config, g_repo));
}
void test_config_rename__cleanup(void)
{
git_config_free(g_config);
g_config = NULL;
cl_git_sandbox_cleanup();
g_repo = NULL;
}
void test_config_rename__can_rename(void)
{
const git_config_entry *ce;
cl_git_pass(git_config_get_entry(
&ce, g_config, "branch.track-local.remote"));
cl_assert_equal_s(".", ce->value);
cl_git_fail(git_config_get_entry(
&ce, g_config, "branch.local-track.remote"));
cl_git_pass(git_config_rename_section(
g_repo, "branch.track-local", "branch.local-track"));
cl_git_pass(git_config_get_entry(
&ce, g_config, "branch.local-track.remote"));
cl_assert_equal_s(".", ce->value);
cl_git_fail(git_config_get_entry(
&ce, g_config, "branch.track-local.remote"));
}
void test_config_rename__prevent_overwrite(void)
{
const git_config_entry *ce;
const git_error *err;
cl_git_pass(git_config_set_string(
g_config, "branch.local-track.remote", "yellow"));
cl_git_pass(git_config_get_entry(
&ce, g_config, "branch.local-track.remote"));
cl_assert_equal_s("yellow", ce->value);
cl_git_pass(git_config_rename_section(
g_repo, "branch.track-local", "branch.local-track"));
cl_git_pass(git_config_get_entry(
&ce, g_config, "branch.local-track.remote"));
cl_assert_equal_s(".", ce->value);
// cl_assert((err = giterr_last()) != NULL);
// cl_assert(err->message != NULL);
}
static void assert_invalid_config_section_name(
git_repository *repo, const char *name)
{
cl_git_fail_with(
git_config_rename_section(repo, "branch.remoteless", name),
GIT_EINVALIDSPEC);
}
void test_config_rename__require_a_valid_new_name(void)
{
assert_invalid_config_section_name(g_repo, "");
assert_invalid_config_section_name(g_repo, "bra\nch");
assert_invalid_config_section_name(g_repo, "branc#");
assert_invalid_config_section_name(g_repo, "bra\nch.duh");
assert_invalid_config_section_name(g_repo, "branc#.duh");
}
...@@ -46,23 +46,3 @@ void test_config_validkeyname__accessing_requires_a_valid_name(void) ...@@ -46,23 +46,3 @@ void test_config_validkeyname__accessing_requires_a_valid_name(void)
assert_invalid_config_key_name("dif.dir\nstat.lines"); assert_invalid_config_key_name("dif.dir\nstat.lines");
assert_invalid_config_key_name("dif.dirstat.li\nes"); assert_invalid_config_key_name("dif.dirstat.li\nes");
} }
static void assert_invalid_config_section_name(git_repository *repo, const char *name)
{
cl_git_fail_with(git_config_rename_section(repo, "branch.remoteless", name), GIT_EINVALIDSPEC);
}
void test_config_validkeyname__renaming_a_section_requires_a_valid_name(void)
{
git_repository *repo;
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
assert_invalid_config_section_name(repo, "");
assert_invalid_config_section_name(repo, "bra\nch");
assert_invalid_config_section_name(repo, "branc#");
assert_invalid_config_section_name(repo, "bra\nch.duh");
assert_invalid_config_section_name(repo, "branc#.duh");
git_repository_free(repo);
}
...@@ -303,3 +303,4 @@ void test_config_write__updating_a_locked_config_file_returns_ELOCKED(void) ...@@ -303,3 +303,4 @@ void test_config_write__updating_a_locked_config_file_returns_ELOCKED(void)
git_config_free(cfg); git_config_free(cfg);
} }
...@@ -66,12 +66,54 @@ void test_refs_branches_move__can_move_a_local_branch_to_a_partially_colliding_n ...@@ -66,12 +66,54 @@ void test_refs_branches_move__can_move_a_local_branch_to_a_partially_colliding_n
void test_refs_branches_move__can_not_move_a_branch_if_its_destination_name_collide_with_an_existing_one(void) void test_refs_branches_move__can_not_move_a_branch_if_its_destination_name_collide_with_an_existing_one(void)
{ {
git_reference *original_ref, *new_ref; git_reference *original_ref, *new_ref;
git_config *config;
const git_config_entry *ce;
char *original_remote, *original_merge;
cl_git_pass(git_repository_config(&config, repo));
cl_git_pass(git_config_get_entry(&ce, config, "branch.master.remote"));
original_remote = strdup(ce->value);
cl_git_pass(git_config_get_entry(&ce, config, "branch.master.merge"));
original_merge = strdup(ce->value);
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2")); cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/br2"));
cl_assert_equal_i(GIT_EEXISTS, git_branch_move(&new_ref, original_ref, "master", 0)); cl_assert_equal_i(GIT_EEXISTS,
git_branch_move(&new_ref, original_ref, "master", 0));
cl_assert(giterr_last()->message != NULL);
cl_git_pass(git_config_get_entry(&ce, config, "branch.master.remote"));
cl_assert_equal_s(original_remote, ce->value);
cl_git_pass(git_config_get_entry(&ce, config, "branch.master.merge"));
cl_assert_equal_s(original_merge, ce->value);
cl_assert_equal_i(GIT_EEXISTS,
git_branch_move(&new_ref, original_ref, "cannot-fetch", 0));
cl_assert(giterr_last()->message != NULL);
cl_git_pass(git_config_get_entry(&ce, config, "branch.master.remote"));
cl_assert_equal_s(original_remote, ce->value);
cl_git_pass(git_config_get_entry(&ce, config, "branch.master.merge"));
cl_assert_equal_s(original_merge, ce->value);
git_reference_free(original_ref);
cl_git_pass(git_reference_lookup(&original_ref, repo, "refs/heads/track-local"));
cl_assert_equal_i(GIT_EEXISTS,
git_branch_move(&new_ref, original_ref, "master", 0));
cl_assert(giterr_last()->message != NULL);
cl_git_pass(git_config_get_entry(&ce, config, "branch.master.remote"));
cl_assert_equal_s(original_remote, ce->value);
cl_git_pass(git_config_get_entry(&ce, config, "branch.master.merge"));
cl_assert_equal_s(original_merge, ce->value);
free(original_remote); free(original_merge);
git_reference_free(original_ref); git_reference_free(original_ref);
git_config_free(config);
} }
void test_refs_branches_move__moving_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void) void test_refs_branches_move__moving_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment