diff options
Diffstat (limited to 'src')
60 files changed, 1311 insertions, 1338 deletions
diff --git a/src/amiga/map.c b/src/amiga/map.c deleted file mode 100644 index 0ba7995c6..000000000 --- a/src/amiga/map.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ -#include <git2/common.h> - -#ifndef GIT_WIN32 - -#include "posix.h" -#include "map.h" -#include <errno.h> - -int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) -{ - GIT_MMAP_VALIDATE(out, len, prot, flags); - - out->data = NULL; - out->len = 0; - - if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) { - giterr_set(GITERR_OS, "Trying to map shared-writeable"); - return -1; - } - - out->data = malloc(len); - GITERR_CHECK_ALLOC(out->data); - - if ((p_lseek(fd, offset, SEEK_SET) < 0) || ((size_t)p_read(fd, out->data, len) != len)) { - giterr_set(GITERR_OS, "mmap emulation failed"); - return -1; - } - - out->len = len; - return 0; -} - -int p_munmap(git_map *map) -{ - assert(map != NULL); - free(map->data); - - return 0; -} - -#endif - diff --git a/src/attr.c b/src/attr.c index 98a328a55..e6e274e42 100644 --- a/src/attr.c +++ b/src/attr.c @@ -193,8 +193,7 @@ int git_attr_foreach( error = callback(assign->name, assign->value, payload); if (error) { - giterr_clear(); - error = GIT_EUSER; + giterr_set_after_callback(error); goto cleanup; } } @@ -536,7 +535,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) @@ -603,11 +602,15 @@ static int attr_cache__lookup_path( { git_buf buf = GIT_BUF_INIT; int error; - const char *cfgval = NULL; + const git_config_entry *entry = NULL; *out = NULL; - if (!(error = git_config_get_string(&cfgval, cfg, key))) { + if ((error = git_config__lookup_entry(&entry, cfg, key, false)) < 0) + return error; + + if (entry) { + const char *cfgval = entry->value; /* expand leading ~/ as needed */ if (cfgval && cfgval[0] == '~' && cfgval[1] == '/' && @@ -616,13 +619,9 @@ static int attr_cache__lookup_path( else if (cfgval) *out = git__strdup(cfgval); - } else if (error == GIT_ENOTFOUND) { - giterr_clear(); - error = 0; - - if (!git_futils_find_xdg_file(&buf, fallback)) - *out = git_buf_detach(&buf); } + else if (!git_futils_find_xdg_file(&buf, fallback)) + *out = git_buf_detach(&buf); git_buf_free(&buf); diff --git a/src/blame.c b/src/blame.c index ea9f77af5..a1357415a 100644 --- a/src/blame.c +++ b/src/blame.c @@ -108,17 +108,23 @@ git_blame* git_blame__alloc( git_blame_options opts, const char *path) { - git_blame *gbr = (git_blame*)git__calloc(1, sizeof(git_blame)); - if (!gbr) { - giterr_set_oom(); + git_blame *gbr = git__calloc(1, sizeof(git_blame)); + if (!gbr) return NULL; - } - git_vector_init(&gbr->hunks, 8, hunk_cmp); - git_vector_init(&gbr->paths, 8, paths_cmp); + gbr->repository = repo; 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; } @@ -126,7 +132,6 @@ void git_blame_free(git_blame *blame) { size_t i; git_blame_hunk *hunk; - char *path; if (!blame) return; @@ -134,13 +139,11 @@ void git_blame_free(git_blame *blame) free_hunk(hunk); git_vector_free(&blame->hunks); - git_vector_foreach(&blame->paths, i, path) - git__free(path); - git_vector_free(&blame->paths); + git_vector_free_deep(&blame->paths); git_array_clear(blame->line_index); - git__free((void*)blame->path); + git__free(blame->path); git_blob_free(blame->final_blob); git__free(blame); } diff --git a/src/blame.h b/src/blame.h index 637e43985..7e23de808 100644 --- a/src/blame.h +++ b/src/blame.h @@ -64,7 +64,7 @@ typedef struct git_blame__entry { } git_blame__entry; struct git_blame { - const char *path; + char *path; git_repository *repository; git_blame_options options; diff --git a/src/blob.c b/src/blob.c index 2c6d52800..ab344ae98 100644 --- a/src/blob.c +++ b/src/blob.c @@ -272,37 +272,44 @@ int git_blob_create_fromchunks( int (*source_cb)(char *content, size_t max_length, void *payload), void *payload) { - int error = -1, read_bytes; + int error; char *content = NULL; git_filebuf file = GIT_FILEBUF_INIT; git_buf path = GIT_BUF_INIT; - if (git_buf_joinpath( - &path, git_repository_path(repo), GIT_OBJECTS_DIR "streamed") < 0) + assert(oid && repo && source_cb); + + if ((error = git_buf_joinpath( + &path, git_repository_path(repo), GIT_OBJECTS_DIR "streamed")) < 0) goto cleanup; content = git__malloc(BUFFER_SIZE); GITERR_CHECK_ALLOC(content); - if (git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY, 0666) < 0) + if ((error = git_filebuf_open( + &file, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY, 0666)) < 0) goto cleanup; while (1) { - read_bytes = source_cb(content, BUFFER_SIZE, payload); - - assert(read_bytes <= BUFFER_SIZE); + int read_bytes = source_cb(content, BUFFER_SIZE, payload); - if (read_bytes <= 0) + if (!read_bytes) break; - if (git_filebuf_write(&file, content, read_bytes) < 0) + if (read_bytes > BUFFER_SIZE) { + giterr_set(GITERR_OBJECT, "Invalid chunk size while creating blob"); + error = GIT_EBUFS; + } else if (read_bytes < 0) { + error = giterr_set_after_callback(read_bytes); + } else { + error = git_filebuf_write(&file, content, read_bytes); + } + + if (error < 0) goto cleanup; } - if (read_bytes < 0) - goto cleanup; - - if (git_filebuf_flush(&file) < 0) + if ((error = git_filebuf_flush(&file)) < 0) goto cleanup; error = git_blob__create_from_paths( @@ -312,6 +319,7 @@ cleanup: git_buf_free(&path); git_filebuf_cleanup(&file); git__free(content); + return error; } diff --git a/src/branch.c b/src/branch.c index 95b3fd980..ef71c2cd1 100644 --- a/src/branch.c +++ b/src/branch.c @@ -90,29 +90,28 @@ int git_branch_delete(git_reference *branch) assert(branch); - if (!git_reference_is_branch(branch) && - !git_reference_is_remote(branch)) { - giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", git_reference_name(branch)); - return -1; + if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) { + giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", + git_reference_name(branch)); + return GIT_ENOTFOUND; } if ((is_head = git_branch_is_head(branch)) < 0) return is_head; if (is_head) { - giterr_set(GITERR_REFERENCE, - "Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch)); + giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is " + "the current HEAD of the repository.", git_reference_name(branch)); 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; if (git_config_rename_section( - git_reference_owner(branch), - git_buf_cstr(&config_section), - NULL) < 0) - goto on_error; + git_reference_owner(branch), git_buf_cstr(&config_section), NULL) < 0) + goto on_error; if (git_reference_delete(branch) < 0) goto on_error; @@ -206,17 +205,21 @@ int git_branch_move( if (error < 0) goto done; - git_buf_printf(&old_config_section, - "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)); - - git_buf_printf(&new_config_section, "branch.%s", new_branch_name); + /* first update ref then config so failure won't trash config */ - if ((error = git_config_rename_section(git_reference_owner(branch), - git_buf_cstr(&old_config_section), - git_buf_cstr(&new_config_section))) < 0) + error = git_reference_rename( + out, branch, git_buf_cstr(&new_reference_name), force); + if (error < 0) 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: git_buf_free(&new_reference_name); diff --git a/src/checkout.c b/src/checkout.c index 6d7e3cfd4..0f30d16f3 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -83,10 +83,8 @@ static int checkout_notify( const git_diff_file *baseline = NULL, *target = NULL, *workdir = NULL; const char *path = NULL; - if (!data->opts.notify_cb) - return 0; - - if ((why & data->opts.notify_flags) == 0) + if (!data->opts.notify_cb || + (why & data->opts.notify_flags) == 0) return 0; if (wditem) { @@ -125,8 +123,13 @@ static int checkout_notify( path = delta->old_file.path; } - return data->opts.notify_cb( - why, path, baseline, target, workdir, data->opts.notify_payload); + { + int error = data->opts.notify_cb( + why, path, baseline, target, workdir, data->opts.notify_payload); + + return giterr_set_after_callback_function( + error, "git_checkout notification"); + } } static bool checkout_is_workdir_modified( @@ -186,69 +189,66 @@ static bool checkout_is_workdir_modified( ((data->strategy & GIT_CHECKOUT_##FLAG) ? CHECKOUT_ACTION__##YES : CHECKOUT_ACTION__##NO) static int checkout_action_common( + int *action, checkout_data *data, - int action, const git_diff_delta *delta, const git_index_entry *wd) { git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE; - if (action <= 0) - return action; - if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) - action = (action & ~CHECKOUT_ACTION__REMOVE); + *action = (*action & ~CHECKOUT_ACTION__REMOVE); - if ((action & CHECKOUT_ACTION__UPDATE_BLOB) != 0) { + if ((*action & CHECKOUT_ACTION__UPDATE_BLOB) != 0) { if (S_ISGITLINK(delta->new_file.mode)) - action = (action & ~CHECKOUT_ACTION__UPDATE_BLOB) | + *action = (*action & ~CHECKOUT_ACTION__UPDATE_BLOB) | CHECKOUT_ACTION__UPDATE_SUBMODULE; /* to "update" a symlink, we must remove the old one first */ if (delta->new_file.mode == GIT_FILEMODE_LINK && wd != NULL) - action |= CHECKOUT_ACTION__REMOVE; + *action |= CHECKOUT_ACTION__REMOVE; notify = GIT_CHECKOUT_NOTIFY_UPDATED; } - if ((action & CHECKOUT_ACTION__CONFLICT) != 0) + if ((*action & CHECKOUT_ACTION__CONFLICT) != 0) notify = GIT_CHECKOUT_NOTIFY_CONFLICT; - if (notify != GIT_CHECKOUT_NOTIFY_NONE && - checkout_notify(data, notify, delta, wd) != 0) - return GIT_EUSER; - - return action; + return checkout_notify(data, notify, delta, wd); } static int checkout_action_no_wd( + int *action, checkout_data *data, const git_diff_delta *delta) { - int action = CHECKOUT_ACTION__NONE; + int error = 0; + + *action = CHECKOUT_ACTION__NONE; switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 12 */ - if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL)) - return GIT_EUSER; - action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE); + error = checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL); + if (error) + return error; + *action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE); break; case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */ - action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); break; case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */ - action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, CONFLICT); + *action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, CONFLICT); break; case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/ if (delta->new_file.mode == GIT_FILEMODE_TREE) - action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); break; case GIT_DELTA_DELETED: /* case 8 or 25 */ default: /* impossible */ break; } - return checkout_action_common(data, action, delta, NULL); + return checkout_action_common(action, data, delta, NULL); } static int checkout_action_wd_only( @@ -257,6 +257,7 @@ static int checkout_action_wd_only( const git_index_entry *wd, git_vector *pathspec) { + int error = 0; bool remove = false; git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE; @@ -269,13 +270,13 @@ static int checkout_action_wd_only( /* check if item is tracked in the index but not in the checkout diff */ if (data->index != NULL) { if (wd->mode != GIT_FILEMODE_TREE) { - int error; - - if ((error = git_index_find(NULL, data->index, wd->path)) == 0) { + if (!(error = git_index_find(NULL, data->index, wd->path))) { notify = GIT_CHECKOUT_NOTIFY_DIRTY; remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0); } else if (error != GIT_ENOTFOUND) return error; + else + giterr_clear(); } else { /* for tree entries, we have to see if there are any index * entries that are contained inside that tree @@ -301,18 +302,16 @@ static int checkout_action_wd_only( remove = ((data->strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0); } - if (checkout_notify(data, notify, NULL, wd)) - return GIT_EUSER; + error = checkout_notify(data, notify, NULL, wd); - if (remove) { + if (!error && remove) { char *path = git_pool_strdup(&data->pool, wd->path); GITERR_CHECK_ALLOC(path); - if (git_vector_insert(&data->removes, path) < 0) - return -1; + error = git_vector_insert(&data->removes, path); } - return 0; + return error; } static bool submodule_is_config_only( @@ -331,35 +330,35 @@ static bool submodule_is_config_only( } static int checkout_action_with_wd( + int *action, checkout_data *data, const git_diff_delta *delta, const git_index_entry *wd) { - int action = CHECKOUT_ACTION__NONE; + *action = CHECKOUT_ACTION__NONE; switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */ if (checkout_is_workdir_modified(data, &delta->old_file, wd)) { - if (checkout_notify( - data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd)) - return GIT_EUSER; - action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE); + GITERR_CHECK_ERROR( + checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) ); + *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE); } break; case GIT_DELTA_ADDED: /* case 3, 4 or 6 */ - action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); break; case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */ if (checkout_is_workdir_modified(data, &delta->old_file, wd)) - action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); else - action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE); + *action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE); break; case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */ if (checkout_is_workdir_modified(data, &delta->old_file, wd)) - action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); else - action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); break; case GIT_DELTA_TYPECHANGE: /* case 22, 23, 29, 30 */ if (delta->old_file.mode == GIT_FILEMODE_TREE) { @@ -367,92 +366,93 @@ static int checkout_action_with_wd( /* either deleting items in old tree will delete the wd dir, * or we'll get a conflict when we attempt blob update... */ - action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); else if (wd->mode == GIT_FILEMODE_COMMIT) { /* workdir is possibly a "phantom" submodule - treat as a * tree if the only submodule info came from the config */ if (submodule_is_config_only(data, wd->path)) - action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); else - action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); } else - action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); } else if (checkout_is_workdir_modified(data, &delta->old_file, wd)) - action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); else - action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE); + *action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE); /* don't update if the typechange is to a tree */ if (delta->new_file.mode == GIT_FILEMODE_TREE) - action = (action & ~CHECKOUT_ACTION__UPDATE_BLOB); + *action = (*action & ~CHECKOUT_ACTION__UPDATE_BLOB); break; default: /* impossible */ break; } - return checkout_action_common(data, action, delta, wd); + return checkout_action_common(action, data, delta, wd); } static int checkout_action_with_wd_blocker( + int *action, checkout_data *data, const git_diff_delta *delta, const git_index_entry *wd) { - int action = CHECKOUT_ACTION__NONE; + *action = CHECKOUT_ACTION__NONE; switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* should show delta as dirty / deleted */ - if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd)) - return GIT_EUSER; - action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE); + GITERR_CHECK_ERROR( + checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) ); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE); break; case GIT_DELTA_ADDED: case GIT_DELTA_MODIFIED: - action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); break; case GIT_DELTA_DELETED: - action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); break; case GIT_DELTA_TYPECHANGE: /* not 100% certain about this... */ - action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); break; default: /* impossible */ break; } - return checkout_action_common(data, action, delta, wd); + return checkout_action_common(action, data, delta, wd); } static int checkout_action_with_wd_dir( + int *action, checkout_data *data, const git_diff_delta *delta, const git_index_entry *wd) { - int action = CHECKOUT_ACTION__NONE; + *action = CHECKOUT_ACTION__NONE; switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 19 or 24 (or 34 but not really) */ - if (checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL) || - checkout_notify( - data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd)) - return GIT_EUSER; + GITERR_CHECK_ERROR( + checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL)); + GITERR_CHECK_ERROR( + checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd)); break; case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */ case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */ if (delta->old_file.mode == GIT_FILEMODE_COMMIT) /* expected submodule (and maybe found one) */; else if (delta->new_file.mode != GIT_FILEMODE_TREE) - action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); break; case GIT_DELTA_DELETED: /* case 11 (and 27 for dir) */ - if (delta->old_file.mode != GIT_FILEMODE_TREE && - checkout_notify( - data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd)) - return GIT_EUSER; + if (delta->old_file.mode != GIT_FILEMODE_TREE) + GITERR_CHECK_ERROR( + checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd)); break; case GIT_DELTA_TYPECHANGE: /* case 24 or 31 */ if (delta->old_file.mode == GIT_FILEMODE_TREE) { @@ -462,39 +462,41 @@ static int checkout_action_with_wd_dir( * directory if is it left empty, so we can defer removing the * dir and it will succeed if no children are left. */ - action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); - if (action != CHECKOUT_ACTION__NONE) - action |= CHECKOUT_ACTION__DEFER_REMOVE; + *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); + if (*action != CHECKOUT_ACTION__NONE) + *action |= CHECKOUT_ACTION__DEFER_REMOVE; } else if (delta->new_file.mode != GIT_FILEMODE_TREE) /* For typechange to dir, dir is already created so no action */ - action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); + *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); break; default: /* impossible */ break; } - return checkout_action_common(data, action, delta, wd); + return checkout_action_common(action, data, delta, wd); } static int checkout_action( + int *action, checkout_data *data, git_diff_delta *delta, git_iterator *workdir, - const git_index_entry **wditem_ptr, + const git_index_entry **wditem, git_vector *pathspec) { - const git_index_entry *wd = *wditem_ptr; - int cmp = -1, act; + int cmp = -1, error; int (*strcomp)(const char *, const char *) = data->diff->strcomp; int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp; - int error; + int (*advance)(const git_index_entry **, git_iterator *) = NULL; /* move workdir iterator to follow along with deltas */ while (1) { + const git_index_entry *wd = *wditem; + if (!wd) - return checkout_action_no_wd(data, delta); + return checkout_action_no_wd(action, data, delta); cmp = strcomp(wd->path, delta->old_file.path); @@ -512,79 +514,77 @@ static int checkout_action( if (cmp == 0) { if (wd->mode == GIT_FILEMODE_TREE) { /* case 2 - entry prefixed by workdir tree */ - error = git_iterator_advance_into_or_over(&wd, workdir); - if (error && error != GIT_ITEROVER) - goto fail; - *wditem_ptr = wd; + error = git_iterator_advance_into_or_over(wditem, workdir); + if (error < 0 && error != GIT_ITEROVER) + goto done; continue; } /* case 3 maybe - wd contains non-dir where dir expected */ if (delta->old_file.path[strlen(wd->path)] == '/') { - act = checkout_action_with_wd_blocker(data, delta, wd); - *wditem_ptr = - git_iterator_advance(&wd, workdir) ? NULL : wd; - return act; + error = checkout_action_with_wd_blocker( + action, data, delta, wd); + advance = git_iterator_advance; + goto done; } } /* case 1 - handle wd item (if it matches pathspec) */ - if (checkout_action_wd_only(data, workdir, wd, pathspec) < 0) - goto fail; - if ((error = git_iterator_advance(&wd, workdir)) < 0 && + error = checkout_action_wd_only(data, workdir, wd, pathspec); + if (error) + goto done; + if ((error = git_iterator_advance(wditem, workdir)) < 0 && error != GIT_ITEROVER) - goto fail; - - *wditem_ptr = wd; + goto done; continue; } if (cmp == 0) { /* case 4 */ - act = checkout_action_with_wd(data, delta, wd); - *wditem_ptr = git_iterator_advance(&wd, workdir) ? NULL : wd; - return act; + error = checkout_action_with_wd(action, data, delta, wd); + advance = git_iterator_advance; + goto done; } cmp = pfxcomp(wd->path, delta->old_file.path); if (cmp == 0) { /* case 5 */ if (wd->path[strlen(delta->old_file.path)] != '/') - return checkout_action_no_wd(data, delta); + return checkout_action_no_wd(action, data, delta); if (delta->status == GIT_DELTA_TYPECHANGE) { if (delta->old_file.mode == GIT_FILEMODE_TREE) { - act = checkout_action_with_wd(data, delta, wd); - if ((error = git_iterator_advance_into(&wd, workdir)) < 0 && - error != GIT_ENOTFOUND) - goto fail; - *wditem_ptr = wd; - return act; + error = checkout_action_with_wd(action, data, delta, wd); + advance = git_iterator_advance_into; + goto done; } if (delta->new_file.mode == GIT_FILEMODE_TREE || delta->new_file.mode == GIT_FILEMODE_COMMIT || delta->old_file.mode == GIT_FILEMODE_COMMIT) { - act = checkout_action_with_wd(data, delta, wd); - if ((error = git_iterator_advance(&wd, workdir)) < 0 && - error != GIT_ITEROVER) - goto fail; - *wditem_ptr = wd; - return act; + error = checkout_action_with_wd(action, data, delta, wd); + advance = git_iterator_advance; + goto done; } } - return checkout_action_with_wd_dir(data, delta, wd); + return checkout_action_with_wd_dir(action, data, delta, wd); } /* case 6 - wd is after delta */ - return checkout_action_no_wd(data, delta); + return checkout_action_no_wd(action, data, delta); } -fail: - *wditem_ptr = NULL; - return -1; +done: + if (!error && advance != NULL && + (error = advance(wditem, workdir)) < 0) { + *wditem = NULL; + if (error == GIT_ITEROVER) + error = 0; + } + + return error; } static int checkout_remaining_wd_items( @@ -846,7 +846,7 @@ static int checkout_conflicts_coalesce_renames( /* Juggle entries based on renames */ names = git_index_name_entrycount(data->index); - + for (i = 0; i < names; i++) { name_entry = git_index_name_get_byindex(data->index, i); @@ -965,7 +965,7 @@ static int checkout_get_actions( checkout_data *data, git_iterator *workdir) { - int error = 0; + int error = 0, act; const git_index_entry *wditem; git_vector pathspec = GIT_VECTOR_INIT, *deltas; git_pool pathpool = GIT_POOL_INIT_STRINGPOOL; @@ -992,12 +992,9 @@ static int checkout_get_actions( } git_vector_foreach(deltas, i, delta) { - int act = checkout_action(data, delta, workdir, &wditem, &pathspec); - - if (act < 0) { - error = act; + error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec); + if (error != 0) goto fail; - } actions[i] = act; @@ -1012,7 +1009,7 @@ static int checkout_get_actions( } error = checkout_remaining_wd_items(data, workdir, wditem, &pathspec); - if (error < 0) + if (error) goto fail; counts[CHECKOUT_ACTION__REMOVE] += data->removes.length; @@ -1760,9 +1757,6 @@ static int checkout_create_conflicts(checkout_data *data) static void checkout_data_clear(checkout_data *data) { - checkout_conflictdata *conflict; - size_t i; - if (data->opts_free_baseline) { git_tree_free(data->opts.baseline); data->opts.baseline = NULL; @@ -1771,10 +1765,7 @@ static void checkout_data_clear(checkout_data *data) git_vector_free(&data->removes); git_pool_clear(&data->pool); - git_vector_foreach(&data->conflicts, i, conflict) - git__free(conflict); - - git_vector_free(&data->conflicts); + git_vector_free_deep(&data->conflicts); git__free(data->pfx); data->pfx = NULL; @@ -1966,7 +1957,7 @@ int git_checkout_iterator( * actions to be taken, plus look for conflicts and send notifications, * then loop through conflicts. */ - if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) < 0) + if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) != 0) goto cleanup; data.total_steps = counts[CHECKOUT_ACTION__REMOVE] + @@ -1998,9 +1989,6 @@ int git_checkout_iterator( assert(data.completed_steps == data.total_steps); cleanup: - if (error == GIT_EUSER) - giterr_clear(); - if (!error && data.index != NULL && (data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) error = git_index_write(data.index); diff --git a/src/clone.c b/src/clone.c index 23aacd478..828c47ffb 100644 --- a/src/clone.c +++ b/src/clone.c @@ -115,43 +115,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 error; } static int update_head_to_new_branch( @@ -160,16 +155,11 @@ static int update_head_to_new_branch( const char *name) { git_reference *tracking_branch = NULL; - int error; + int error = create_tracking_branch(&tracking_branch, repo, target, name); - if ((error = create_tracking_branch( - &tracking_branch, - repo, - target, - name)) < 0) - return error; - - 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 +168,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 +199,46 @@ 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) + error = reference_matches_remote_head( + git_buf_cstr(&remote_master_name), &head_info); + 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 < 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( @@ -359,7 +341,7 @@ int git_clone_into(git_repository *repo, git_remote *remote, const git_checkout_ old_fetchhead = git_remote_update_fetchhead(remote); git_remote_set_update_fetchhead(remote, 0); - if ((error = git_remote_fetch(remote)) < 0) + if ((error = git_remote_fetch(remote)) != 0) goto cleanup; if (branch) @@ -373,10 +355,12 @@ int git_clone_into(git_repository *repo, git_remote *remote, const git_checkout_ cleanup: git_remote_set_update_fetchhead(remote, old_fetchhead); + /* Go back to the original refspecs */ - if (git_remote_set_fetch_refspecs(remote, &refspecs) < 0) { - git_strarray_free(&refspecs); - return -1; + { + int error_alt = git_remote_set_fetch_refspecs(remote, &refspecs); + if (!error) + error = error_alt; } git_strarray_free(&refspecs); @@ -424,9 +408,10 @@ int git_clone( git_remote_free(origin); } - if (error < 0) { + if (error != 0) { git_repository_free(repo); repo = NULL; + (void)git_futils_rmdir_r(local_path, NULL, rmdir_flags); } diff --git a/src/common.h b/src/common.h index a1888785e..e315b5979 100644 --- a/src/common.h +++ b/src/common.h @@ -62,7 +62,7 @@ * Check a return value and propogate result if non-zero. */ #define GITERR_CHECK_ERROR(code) \ - do { int _err = (code); if (_err < 0) return _err; } while (0) + do { int _err = (code); if (_err) return _err; } while (0) /** * Set the error message for this thread, formatting as needed. @@ -76,28 +76,61 @@ void giterr_set(int error_class, const char *string, ...); int giterr_set_regex(const regex_t *regex, int error_code); /** - * Gets the system error code for this thread. + * Set error message for user callback if needed. + * + * If the error code in non-zero and no error message is set, this + * sets a generic error message. + * + * @return This always returns the `error_code` parameter. */ -GIT_INLINE(int) giterr_system_last(void) +GIT_INLINE(int) giterr_set_after_callback_function( + int error_code, const char *action) { + if (error_code) { + const git_error *e = giterr_last(); + if (!e || !e->message) + giterr_set(e ? e->klass : GITERR_CALLBACK, + "%s callback returned %d", action, error_code); + } + return error_code; +} + #ifdef GIT_WIN32 - return GetLastError(); +#define giterr_set_after_callback(code) \ + giterr_set_after_callback_function((code), __FUNCTION__) #else - return errno; +#define giterr_set_after_callback(code) \ + giterr_set_after_callback_function((code), __func__) #endif -} + +/** + * Gets the system error code for this thread. + */ +int giterr_system_last(void); /** * Sets the system error code for this thread. */ -GIT_INLINE(void) giterr_system_set(int code) -{ -#ifdef GIT_WIN32 - SetLastError(code); -#else - errno = code; -#endif -} +void giterr_system_set(int code); + +/** + * 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 diff --git a/src/config.c b/src/config.c index 0d9471383..056a6ae13 100644 --- a/src/config.c +++ b/src/config.c @@ -480,47 +480,45 @@ int git_config_foreach( int git_config_backend_foreach_match( git_config_backend *backend, const char *regexp, - int (*fn)(const git_config_entry *, void *), - void *data) + git_config_foreach_cb cb, + void *payload) { git_config_entry *entry; git_config_iterator* iter; regex_t regex; - int result = 0; + int error = 0; if (regexp != NULL) { - if ((result = regcomp(®ex, regexp, REG_EXTENDED)) < 0) { - giterr_set_regex(®ex, result); + if ((error = regcomp(®ex, regexp, REG_EXTENDED)) < 0) { + giterr_set_regex(®ex, error); regfree(®ex); return -1; } } - if ((result = backend->iterator(&iter, backend)) < 0) { + if ((error = backend->iterator(&iter, backend)) < 0) { iter = NULL; return -1; } - while(!(iter->next(&entry, iter) < 0)) { + while (!(iter->next(&entry, iter) < 0)) { /* skip non-matching keys if regexp was provided */ if (regexp && regexec(®ex, entry->name, 0, NULL, 0) != 0) continue; /* abort iterator on non-zero return value */ - if (fn(entry, data)) { - giterr_clear(); - result = GIT_EUSER; - goto cleanup; + if ((error = cb(entry, payload)) != 0) { + giterr_set_after_callback(error); + break; } } -cleanup: if (regexp != NULL) regfree(®ex); iter->free(iter); - return result; + return error; } int git_config_foreach_match( @@ -536,10 +534,9 @@ int git_config_foreach_match( if ((error = git_config_iterator_glob_new(&iter, cfg, regexp)) < 0) return error; - while ((error = git_config_next(&entry, iter)) == 0) { - if(cb(entry, payload)) { - giterr_clear(); - error = GIT_EUSER; + while (!(error = git_config_next(&entry, iter))) { + if ((error = cb(entry, payload)) != 0) { + giterr_set_after_callback(error); break; } } @@ -620,6 +617,78 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) /*********** * Getters ***********/ + +static int config_error_notfound(const char *name) +{ + giterr_set(GITERR_CONFIG, "Config value '%s' was not found", name); + return GIT_ENOTFOUND; +} + +enum { + GET_ALL_ERRORS = 0, + GET_NO_MISSING = 1, + GET_NO_ERRORS = 2 +}; + +static int get_entry( + const git_config_entry **out, + const git_config *cfg, + const char *name, + bool normalize_name, + int want_errors) +{ + int res = GIT_ENOTFOUND; + const char *key = name; + char *normalized = NULL; + size_t i; + file_internal *internal; + + *out = NULL; + + if (normalize_name) { + if ((res = git_config__normalize_name(name, &normalized)) < 0) + goto cleanup; + key = normalized; + } + + git_vector_foreach(&cfg->files, i, internal) { + if (!internal || !internal->file) + continue; + + res = internal->file->get(internal->file, key, out); + if (res != GIT_ENOTFOUND) + break; + } + + git__free(normalized); + +cleanup: + if (res == GIT_ENOTFOUND) + res = (want_errors > GET_ALL_ERRORS) ? 0 : config_error_notfound(name); + else if (res && (want_errors == GET_NO_ERRORS)) { + giterr_clear(); + res = 0; + } + + return res; +} + +int git_config_get_entry( + const git_config_entry **out, const git_config *cfg, const char *name) +{ + return get_entry(out, cfg, name, true, GET_ALL_ERRORS); +} + +int git_config__lookup_entry( + const git_config_entry **out, + const git_config *cfg, + const char *key, + bool no_errors) +{ + return get_entry( + out, cfg, key, false, no_errors ? GET_NO_ERRORS : GET_NO_MISSING); +} + int git_config_get_mapped( int *out, const git_config *cfg, @@ -627,116 +696,91 @@ int git_config_get_mapped( const git_cvar_map *maps, size_t map_n) { - const char *value; + const git_config_entry *entry; int ret; - if ((ret = git_config_get_string(&value, cfg, name)) < 0) + if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) return ret; - return git_config_lookup_map_value(out, maps, map_n, value); + return git_config_lookup_map_value(out, maps, map_n, entry->value); } int git_config_get_int64(int64_t *out, const git_config *cfg, const char *name) { - const char *value; + const git_config_entry *entry; int ret; - if ((ret = git_config_get_string(&value, cfg, name)) < 0) + if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) return ret; - return git_config_parse_int64(out, value); + return git_config_parse_int64(out, entry->value); } int git_config_get_int32(int32_t *out, const git_config *cfg, const char *name) { - const char *value; + const git_config_entry *entry; int ret; - if ((ret = git_config_get_string(&value, cfg, name)) < 0) + if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) return ret; - return git_config_parse_int32(out, value); + return git_config_parse_int32(out, entry->value); } -static int get_string_at_file(const char **out, const git_config_backend *file, const char *name) +int git_config_get_bool(int *out, const git_config *cfg, const char *name) { const git_config_entry *entry; - int res; + int ret; - res = file->get(file, name, &entry); - if (!res) - *out = entry->value; + if ((ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS)) < 0) + return ret; - return res; + return git_config_parse_bool(out, entry->value); } -static int config_error_notfound(const char *name) +int git_config_get_string( + const char **out, const git_config *cfg, const char *name) { - giterr_set(GITERR_CONFIG, "Config value '%s' was not found", name); - return GIT_ENOTFOUND; + const git_config_entry *entry; + int ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS); + *out = !ret ? (entry->value ? entry->value : "") : NULL; + return ret; } -static int get_string(const char **out, const git_config *cfg, const char *name) +const char *git_config__get_string_force( + const git_config *cfg, const char *key, const char *fallback_value) { - file_internal *internal; - unsigned int i; - int res; - - git_vector_foreach(&cfg->files, i, internal) { - if (!internal || !internal->file) - continue; - - res = get_string_at_file(out, internal->file, name); - if (res != GIT_ENOTFOUND) - return res; - } - - return config_error_notfound(name); + const git_config_entry *entry; + get_entry(&entry, cfg, key, false, GET_NO_ERRORS); + return (entry && entry->value) ? entry->value : fallback_value; } -int git_config_get_bool(int *out, const git_config *cfg, const char *name) +int git_config__get_bool_force( + const git_config *cfg, const char *key, int fallback_value) { - const char *value = NULL; - int ret; - - if ((ret = get_string(&value, cfg, name)) < 0) - return ret; - - return git_config_parse_bool(out, value); -} + int val = fallback_value; + const git_config_entry *entry; -int git_config_get_string(const char **out, const git_config *cfg, const char *name) -{ - int ret; - const char *str = NULL; + get_entry(&entry, cfg, key, false, GET_NO_ERRORS); - if ((ret = get_string(&str, cfg, name)) < 0) - return ret; + if (entry && git_config_parse_bool(&val, entry->value) < 0) + giterr_clear(); - *out = str == NULL ? "" : str; - return 0; + return val; } -int git_config_get_entry(const git_config_entry **out, const git_config *cfg, const char *name) +int git_config__get_int_force( + const git_config *cfg, const char *key, int fallback_value) { - file_internal *internal; - unsigned int i; - git_config_backend *file; - int ret; - - *out = NULL; + int32_t val = (int32_t)fallback_value; + const git_config_entry *entry; - git_vector_foreach(&cfg->files, i, internal) { - if (!internal || !internal->file) - continue; - file = internal->file; + get_entry(&entry, cfg, key, false, GET_NO_ERRORS); - ret = file->get(file, name, out); - if (ret != GIT_ENOTFOUND) - return ret; - } + if (entry && git_config_parse_int32(&val, entry->value) < 0) + giterr_clear(); - return config_error_notfound(name); + return (int)val; } int git_config_get_multivar_foreach( @@ -753,9 +797,10 @@ int git_config_get_multivar_foreach( found = 0; while ((err = iter->next(&entry, iter)) == 0) { found = 1; - if(cb(entry, payload)) { - iter->free(iter); - return GIT_EUSER; + + if ((err = cb(entry, payload)) != 0) { + giterr_set_after_callback(err); + break; } } @@ -1070,7 +1115,7 @@ int git_config_parse_int64(int64_t *out, const char *value) const char *num_end; int64_t num; - if (git__strtol64(&num, value, &num_end, 0) < 0) + if (!value || git__strtol64(&num, value, &num_end, 0) < 0) goto fail_parse; switch (*num_end) { @@ -1167,7 +1212,6 @@ struct rename_data { git_config *config; git_buf *name; size_t old_len; - int actual_error; }; static int rename_config_entries_cb( @@ -1190,8 +1234,6 @@ static int rename_config_entries_cb( if (!error) error = git_config_delete_entry(data->config, entry->name); - data->actual_error = error; /* preserve actual error code */ - return error; } @@ -1216,7 +1258,6 @@ int git_config_rename_section( data.config = config; data.name = &replace; data.old_len = strlen(old_section_name) + 1; - data.actual_error = 0; if ((error = git_buf_join(&replace, '.', new_section_name, "")) < 0) goto cleanup; @@ -1233,9 +1274,6 @@ int git_config_rename_section( error = git_config_foreach_match( config, git_buf_cstr(&pattern), rename_config_entries_cb, &data); - if (error == GIT_EUSER) - error = data.actual_error; - cleanup: git_buf_free(&pattern); git_buf_free(&replace); diff --git a/src/config.h b/src/config.h index 01e8465cc..3cd888c88 100644 --- a/src/config.h +++ b/src/config.h @@ -51,5 +51,26 @@ extern int git_config_file__ondisk(git_config_backend **out, const char *path); extern int git_config__normalize_name(const char *in, char **out); +/* internal only: does not normalize key and sets out to NULL if not found */ +extern int git_config__lookup_entry( + const git_config_entry **out, + const git_config *cfg, + const char *key, + bool no_errors); + +/* + * Lookup functions that cannot fail. These functions look up a config + * value and return a fallback value if the value is missing or if any + * failures occur while trying to access the value. + */ + +extern const char *git_config__get_string_force( + const git_config *cfg, const char *key, const char *fallback_value); + +extern int git_config__get_bool_force( + const git_config *cfg, const char *key, int fallback_value); + +extern int git_config__get_int_force( + const git_config *cfg, const char *key, int fallback_value); #endif diff --git a/src/config_cache.c b/src/config_cache.c index 6808521a3..ec75d1501 100644 --- a/src/config_cache.c +++ b/src/config_cache.c @@ -78,22 +78,22 @@ int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) struct map_data *data = &_cvar_maps[(int)cvar]; git_config *config; int error; + const git_config_entry *entry; - error = git_repository_config__weakptr(&config, repo); - if (error < 0) + if ((error = git_repository_config__weakptr(&config, repo)) < 0) return error; - if (data->maps) - error = git_config_get_mapped( - out, config, data->cvar_name, data->maps, data->map_count); - else - error = git_config_get_bool(out, config, data->cvar_name); + git_config__lookup_entry(&entry, config, data->cvar_name, false); - if (error == GIT_ENOTFOUND) { - giterr_clear(); + if (!entry) *out = data->default_value; - } - else if (error < 0) + else if (data->maps) + error = git_config_lookup_map_value( + out, data->maps, data->map_count, entry->value); + else + error = git_config_parse_bool(out, entry->value); + + if (error < 0) return error; repo->cvar_cache[(int)cvar] = *out; diff --git a/src/config_file.c b/src/config_file.c index 15c8de49c..0971aa7b0 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -404,20 +404,12 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val /* * Internal function that actually gets the value in string form */ -static int config_get(const git_config_backend *cfg, const char *name, const git_config_entry **out) +static int config_get(const git_config_backend *cfg, const char *key, const git_config_entry **out) { diskfile_backend *b = (diskfile_backend *)cfg; - char *key; - khiter_t pos; - int error; + khiter_t pos = git_strmap_lookup_index(b->values, key); cvar_t *var; - if ((error = git_config__normalize_name(name, &key)) < 0) - return error; - - pos = git_strmap_lookup_index(b->values, key); - git__free(key); - /* no error message; the config system will write one */ if (!git_strmap_valid_index(b->values, pos)) return GIT_ENOTFOUND; @@ -427,7 +419,6 @@ static int config_get(const git_config_backend *cfg, const char *name, const git var = var->next; *out = var->entry; - return 0; } diff --git a/src/diff.c b/src/diff.c index 4c33a0213..7f2e58c0c 100644 --- a/src/diff.c +++ b/src/diff.c @@ -49,16 +49,29 @@ static git_diff_delta *diff_delta__alloc( return delta; } -static int diff_notify( - const git_diff *diff, - const git_diff_delta *delta, - const char *matched_pathspec) +static int diff_insert_delta( + git_diff *diff, git_diff_delta *delta, const char *matched_pathspec) { - if (!diff->opts.notify_cb) - return 0; + int error = 0; + + if (diff->opts.notify_cb) { + error = diff->opts.notify_cb( + diff, delta, matched_pathspec, diff->opts.notify_payload); + + if (error) { + git__free(delta); + + if (error > 0) /* positive value means to skip this delta */ + return 0; + else /* negative value means to cancel diff */ + return giterr_set_after_callback_function(error, "git_diff"); + } + } + + if ((error = git_vector_insert(&diff->deltas, delta)) < 0) + git__free(delta); - return diff->opts.notify_cb( - diff, delta, matched_pathspec, diff->opts.notify_payload); + return error; } static int diff_delta__from_one( @@ -68,7 +81,6 @@ static int diff_delta__from_one( { git_diff_delta *delta; const char *matched_pathspec; - int notify_res; if ((entry->flags & GIT_IDXENTRY_VALID) != 0) return 0; @@ -111,21 +123,12 @@ static int diff_delta__from_one( !git_oid_iszero(&delta->new_file.oid)) delta->new_file.flags |= GIT_DIFF_FLAG_VALID_OID; - notify_res = diff_notify(diff, delta, matched_pathspec); - - if (notify_res) - git__free(delta); - else if (git_vector_insert(&diff->deltas, delta) < 0) { - git__free(delta); - return -1; - } - - return notify_res < 0 ? GIT_EUSER : 0; + return diff_insert_delta(diff, delta, matched_pathspec); } static int diff_delta__from_two( git_diff *diff, - git_delta_t status, + git_delta_t status, const git_index_entry *old_entry, uint32_t old_mode, const git_index_entry *new_entry, @@ -134,7 +137,6 @@ static int diff_delta__from_two( const char *matched_pathspec) { git_diff_delta *delta; - int notify_res; const char *canonical_path = old_entry->path; if (status == GIT_DELTA_UNMODIFIED && @@ -173,16 +175,7 @@ static int diff_delta__from_two( if (new_oid || !git_oid_iszero(&new_entry->oid)) delta->new_file.flags |= GIT_DIFF_FLAG_VALID_OID; - notify_res = diff_notify(diff, delta, matched_pathspec); - - if (notify_res) - git__free(delta); - else if (git_vector_insert(&diff->deltas, delta) < 0) { - git__free(delta); - return -1; - } - - return notify_res < 0 ? GIT_EUSER : 0; + return diff_insert_delta(diff, delta, matched_pathspec); } static git_diff_delta *diff_delta__last_for_item( @@ -304,26 +297,6 @@ bool git_diff_delta__should_skip( } -static int config_bool(git_config *cfg, const char *name, int defvalue) -{ - int val = defvalue; - - if (git_config_get_bool(&val, cfg, name) < 0) - giterr_clear(); - - return val; -} - -static int config_int(git_config *cfg, const char *name, int defvalue) -{ - int val = defvalue; - - if (git_config_get_int32(&val, cfg, name) < 0) - giterr_clear(); - - return val; -} - static const char *diff_mnemonic_prefix( git_iterator_type_t type, bool left_side) { @@ -422,8 +395,8 @@ static int diff_list_apply_options( diff->opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED; /* load config values that affect diff behavior */ - if (git_repository_config__weakptr(&cfg, repo) < 0) - return -1; + if ((val = git_repository_config__weakptr(&cfg, repo)) < 0) + return val; if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS) && val) diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_HAS_SYMLINKS; @@ -445,7 +418,7 @@ static int diff_list_apply_options( /* If not given explicit `opts`, check `diff.xyz` configs */ if (!opts) { - int context = config_int(cfg, "diff.context", 3); + int context = git_config__get_int_force(cfg, "diff.context", 3); diff->opts.context_lines = context >= 0 ? (uint16_t)context : 3; /* add other defaults here */ @@ -460,12 +433,11 @@ static int diff_list_apply_options( /* if ignore_submodules not explicitly set, check diff config */ if (diff->opts.ignore_submodules <= 0) { - const char *str; + const git_config_entry *entry; + git_config__lookup_entry(&entry, cfg, "diff.ignoresubmodules", true); - if (git_config_get_string(&str , cfg, "diff.ignoreSubmodules") < 0) - giterr_clear(); - else if (str != NULL && - git_submodule_parse_ignore(&diff->opts.ignore_submodules, str) < 0) + if (entry && git_submodule_parse_ignore( + &diff->opts.ignore_submodules, entry->value) < 0) giterr_clear(); } @@ -474,9 +446,9 @@ static int diff_list_apply_options( const char *use_old = DIFF_OLD_PREFIX_DEFAULT; const char *use_new = DIFF_NEW_PREFIX_DEFAULT; - if (config_bool(cfg, "diff.noprefix", 0)) { + if (git_config__get_bool_force(cfg, "diff.noprefix", 0)) use_old = use_new = ""; - } else if (config_bool(cfg, "diff.mnemonicprefix", 0)) { + else if (git_config__get_bool_force(cfg, "diff.mnemonicprefix", 0)) { use_old = diff_mnemonic_prefix(diff->old_src, true); use_new = diff_mnemonic_prefix(diff->new_src, false); } @@ -504,14 +476,7 @@ static int diff_list_apply_options( static void diff_list_free(git_diff *diff) { - git_diff_delta *delta; - unsigned int i; - - git_vector_foreach(&diff->deltas, i, delta) { - git__free(delta); - diff->deltas.contents[i] = NULL; - } - git_vector_free(&diff->deltas); + git_vector_free_deep(&diff->deltas); git_pathspec__vfree(&diff->pathspec); git_pool_clear(&diff->pool); @@ -682,6 +647,7 @@ static int maybe_modified( unsigned int nmode = nitem->mode; bool new_is_workdir = (info->new_iter->type == GIT_ITERATOR_TYPE_WORKDIR); const char *matched_pathspec; + int error = 0; if (!git_pathspec__match( &diff->pathspec, oitem->path, @@ -716,10 +682,9 @@ static int maybe_modified( if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE)) status = GIT_DELTA_TYPECHANGE; else { - if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 || - diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem) < 0) - return -1; - return 0; + if (!(error = diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem))) + error = diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem); + return error; } } @@ -741,8 +706,8 @@ static int maybe_modified( /* TODO: add check against index file st_mtime to avoid racy-git */ if (S_ISGITLINK(nmode)) { - if (maybe_modified_submodule(&status, &noid, diff, info) < 0) - return -1; + if ((error = maybe_modified_submodule(&status, &noid, diff, info)) < 0) + return error; } /* if the stat data looks different, then mark modified - this just @@ -769,9 +734,9 @@ static int maybe_modified( */ if (status == GIT_DELTA_MODIFIED && git_oid_iszero(&nitem->oid)) { if (git_oid_iszero(&noid)) { - if (git_diff__oid_for_file(diff->repo, - nitem->path, nitem->mode, nitem->file_size, &noid) < 0) - return -1; + if ((error = git_diff__oid_for_file(diff->repo, + nitem->path, nitem->mode, nitem->file_size, &noid)) < 0) + return error; } /* if oid matches, then mark unmodified (except submodules, where @@ -926,7 +891,7 @@ static int handle_unmatched_new_item( git_diff_delta *last; /* attempt to insert record for this directory */ - if ((error = diff_delta__from_one(diff, delta_type, nitem)) < 0) + if ((error = diff_delta__from_one(diff, delta_type, nitem)) != 0) return error; /* if delta wasn't created (because of rules), just skip ahead */ @@ -1005,7 +970,7 @@ static int handle_unmatched_new_item( } /* Actually create the record for this item if necessary */ - if ((error = diff_delta__from_one(diff, delta_type, nitem)) < 0) + if ((error = diff_delta__from_one(diff, delta_type, nitem)) != 0) return error; /* If user requested TYPECHANGE records, then check for that instead of @@ -1030,7 +995,7 @@ static int handle_unmatched_old_item( git_diff *diff, diff_in_progress *info) { int error = diff_delta__from_one(diff, GIT_DELTA_DELETED, info->oitem); - if (error < 0) + if (error != 0) return error; /* if we are generating TYPECHANGE records then check for that @@ -1364,7 +1329,7 @@ int git_diff__paired_foreach( int (*cb)(git_diff_delta *h2i, git_diff_delta *i2w, void *payload), void *payload) { - int cmp; + int cmp, error = 0; git_diff_delta *h2i, *i2w; size_t i, j, i_max, j_max; int (*strcomp)(const char *, const char *) = git__strcmp; @@ -1420,18 +1385,17 @@ int git_diff__paired_foreach( strcomp(h2i->new_file.path, i2w->old_file.path); if (cmp < 0) { - if (cb(h2i, NULL, payload)) - return GIT_EUSER; - i++; + i++; i2w = NULL; } else if (cmp > 0) { - if (cb(NULL, i2w, payload)) - return GIT_EUSER; - j++; + j++; h2i = NULL; } else { - if (cb(h2i, i2w, payload)) - return GIT_EUSER; i++; j++; } + + if ((error = cb(h2i, i2w, payload)) != 0) { + giterr_set_after_callback(error); + break; + } } /* restore case-insensitive delta sort */ @@ -1447,5 +1411,5 @@ int git_diff__paired_foreach( git_vector_sort(&idx2wd->deltas); } - return 0; + return error; } diff --git a/src/diff_driver.c b/src/diff_driver.c index bd5a8fbd9..167c0cc5a 100644 --- a/src/diff_driver.c +++ b/src/diff_driver.c @@ -14,6 +14,7 @@ #include "strmap.h" #include "map.h" #include "buf_text.h" +#include "config.h" #include "repository.h" GIT__USE_STRMAP; @@ -130,14 +131,14 @@ static git_diff_driver_registry *git_repository_driver_registry( static int git_diff_driver_load( git_diff_driver **out, git_repository *repo, const char *driver_name) { - int error = 0, bval; + int error = 0; git_diff_driver_registry *reg; git_diff_driver *drv; size_t namelen = strlen(driver_name); khiter_t pos; git_config *cfg; git_buf name = GIT_BUF_INIT; - const char *val; + const git_config_entry *ce; bool found_driver = false; reg = git_repository_driver_registry(repo); @@ -164,23 +165,21 @@ static int git_diff_driver_load( if ((error = git_buf_printf(&name, "diff.%s.binary", driver_name)) < 0) goto done; - if ((error = git_config_get_string(&val, cfg, name.ptr)) < 0) { - if (error != GIT_ENOTFOUND) - goto done; - /* diff.<driver>.binary unspecified, so just continue */ - giterr_clear(); - } else if (git_config_parse_bool(&bval, val) < 0) { - /* TODO: warn that diff.<driver>.binary has invalid value */ - giterr_clear(); - } else if (bval) { + + switch (git_config__get_bool_force(cfg, name.ptr, -1)) { + case true: /* if diff.<driver>.binary is true, just return the binary driver */ *out = &global_drivers[DIFF_DRIVER_BINARY]; goto done; - } else { + case false: /* if diff.<driver>.binary is false, force binary checks off */ /* but still may have custom function context patterns, etc. */ drv->binary_flags = GIT_DIFF_FORCE_TEXT; found_driver = true; + break; + default: + /* diff.<driver>.binary unspecified, so just continue */ + break; } /* TODO: warn if diff.<name>.command or diff.<name>.textconv are set */ @@ -211,16 +210,16 @@ static int git_diff_driver_load( git_buf_truncate(&name, namelen + strlen("diff..")); git_buf_put(&name, "wordregex", strlen("wordregex")); - if ((error = git_config_get_string(&val, cfg, name.ptr)) < 0) { - if (error != GIT_ENOTFOUND) - goto done; - giterr_clear(); /* no diff.<driver>.wordregex, so just continue */ - } else if ((error = regcomp(&drv->word_pattern, val, REG_EXTENDED)) != 0) { - /* TODO: warning about bad regex instead of failure */ - error = giterr_set_regex(&drv->word_pattern, error); + if ((error = git_config__lookup_entry(&ce, cfg, name.ptr, false)) < 0) goto done; - } else { + if (!ce || !ce->value) + /* no diff.<driver>.wordregex, so just continue */; + else if (!(error = regcomp(&drv->word_pattern, ce->value, REG_EXTENDED))) found_driver = true; + else { + /* TODO: warn about bad regex instead of failure */ + error = giterr_set_regex(&drv->word_pattern, error); + goto done; } /* TODO: look up diff.<driver>.algorithm to turn on minimal / patience diff --git a/src/diff_patch.c b/src/diff_patch.c index cc49d68eb..9c2eb885f 100644 --- a/src/diff_patch.c +++ b/src/diff_patch.c @@ -193,21 +193,18 @@ cleanup: return error; } -static int diff_patch_file_callback( +static int diff_patch_invoke_file_callback( git_patch *patch, git_diff_output *output) { - float progress; + float progress = patch->diff ? + ((float)patch->delta_index / patch->diff->deltas.length) : 1.0f; if (!output->file_cb) return 0; - progress = patch->diff ? - ((float)patch->delta_index / patch->diff->deltas.length) : 1.0f; - - if (output->file_cb(patch->delta, progress, output->payload) != 0) - output->error = GIT_EUSER; - - return output->error; + return giterr_set_after_callback_function( + output->file_cb(patch->delta, progress, output->payload), + "git_patch"); } 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; if (output->diff_cb != NULL && - !(error = output->diff_cb(output, patch))) + (error = output->diff_cb(output, patch)) < 0) patch->flags |= GIT_DIFF_PATCH_DIFFED; return error; @@ -272,9 +269,10 @@ int git_diff_foreach( size_t idx; git_patch patch; - if (diff_required(diff, "git_diff_foreach") < 0) - return -1; + if ((error = diff_required(diff, "git_diff_foreach")) < 0) + return error; + memset(&xo, 0, sizeof(xo)); diff_output_init( &xo.output, &diff->opts, file_cb, hunk_cb, data_cb, payload); git_xdiff_init(&xo, &diff->opts); @@ -285,22 +283,18 @@ int git_diff_foreach( if (git_diff_delta__should_skip(&diff->opts, patch.delta)) 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 = diff_patch_invoke_file_callback(&patch, &xo.output))) + error = diff_patch_generate(&patch, &xo.output); - if (!error) - error = diff_patch_generate(&patch, &xo.output); + git_patch_free(&patch); - git_patch_free(&patch); - } - - if (error < 0) + if (error) break; } - if (error == GIT_EUSER) - giterr_clear(); /* don't leave error message set invalidly */ return error; } @@ -332,14 +326,11 @@ static int diff_single_generate(diff_patch_with_delta *pd, git_xdiff_output *xo) !(patch->ofile.opts_flags & GIT_DIFF_INCLUDE_UNMODIFIED)) 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) error = diff_patch_generate(patch, (git_diff_output *)xo); - if (error == GIT_EUSER) - giterr_clear(); /* don't leave error message set invalidly */ - return error; } @@ -424,9 +415,7 @@ int git_diff_blobs( diff_patch_with_delta pd; git_xdiff_output xo; - memset(&pd, 0, sizeof(pd)); memset(&xo, 0, sizeof(xo)); - diff_output_init( &xo.output, opts, file_cb, hunk_cb, data_cb, payload); git_xdiff_init(&xo, opts); @@ -436,6 +425,7 @@ int git_diff_blobs( else if (!new_path && old_path) new_path = old_path; + memset(&pd, 0, sizeof(pd)); error = diff_patch_from_blobs( &pd, &xo, old_blob, old_path, new_blob, new_path, opts); @@ -463,7 +453,6 @@ int git_patch_from_blobs( return -1; memset(&xo, 0, sizeof(xo)); - diff_output_to_patch(&xo.output, &pd->patch); git_xdiff_init(&xo, opts); @@ -536,9 +525,7 @@ int git_diff_blob_to_buffer( diff_patch_with_delta pd; git_xdiff_output xo; - memset(&pd, 0, sizeof(pd)); memset(&xo, 0, sizeof(xo)); - diff_output_init( &xo.output, opts, file_cb, hunk_cb, data_cb, payload); git_xdiff_init(&xo, opts); @@ -548,6 +535,7 @@ int git_diff_blob_to_buffer( else if (!buf_path && old_path) buf_path = old_path; + memset(&pd, 0, sizeof(pd)); error = diff_patch_from_blob_and_buffer( &pd, &xo, old_blob, old_path, buf, buflen, buf_path, opts); @@ -576,7 +564,6 @@ int git_patch_from_blob_and_buffer( return -1; memset(&xo, 0, sizeof(xo)); - diff_output_to_patch(&xo.output, &pd->patch); git_xdiff_init(&xo, opts); @@ -622,17 +609,18 @@ int git_patch_from_diff( if ((error = diff_patch_alloc_from_diff(&patch, diff, idx)) < 0) return error; + memset(&xo, 0, sizeof(xo)); diff_output_to_patch(&xo.output, patch); 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) error = diff_patch_generate(patch, &xo.output); if (!error) { - /* if cumulative diff size is < 0.5 total size, flatten the patch */ - /* unload the file content */ + /* TODO: if cumulative diff size is < 0.5 total size, flatten patch */ + /* TODO: and unload the file content */ } if (error || !patch_ptr) @@ -640,8 +628,6 @@ int git_patch_from_diff( else *patch_ptr = patch; - if (error == GIT_EUSER) - giterr_clear(); /* don't leave error message set invalidly */ return error; } @@ -905,7 +891,7 @@ static int diff_patch_line_cb( GIT_UNUSED(hunk_); 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); GITERR_CHECK_ALLOC(line); diff --git a/src/diff_print.c b/src/diff_print.c index b04b11515..7a70e2b18 100644 --- a/src/diff_print.c +++ b/src/diff_print.c @@ -89,12 +89,6 @@ char git_diff_status_char(git_delta_t status) return code; } -static int callback_error(void) -{ - giterr_clear(); - return GIT_EUSER; -} - static int diff_print_one_name_only( const git_diff_delta *delta, float progress, void *data) { @@ -108,19 +102,16 @@ static int diff_print_one_name_only( return 0; git_buf_clear(out); - - if (git_buf_puts(out, delta->new_file.path) < 0 || - git_buf_putc(out, '\n')) + git_buf_puts(out, delta->new_file.path); + git_buf_putc(out, '\n'); + if (git_buf_oom(out)) return -1; pi->line.origin = GIT_DIFF_LINE_FILE_HDR; pi->line.content = git_buf_cstr(out); pi->line.content_len = git_buf_len(out); - if (pi->print_cb(delta, NULL, &pi->line, pi->payload)) - return callback_error(); - - return 0; + return pi->print_cb(delta, NULL, &pi->line, pi->payload); } static int diff_print_one_name_status( @@ -154,7 +145,6 @@ static int diff_print_one_name_status( git_buf_printf(out, "%c\t%s%c\n", code, delta->old_file.path, old_suffix); else git_buf_printf(out, "%c\t%s\n", code, delta->old_file.path); - if (git_buf_oom(out)) return -1; @@ -162,10 +152,7 @@ static int diff_print_one_name_status( pi->line.content = git_buf_cstr(out); pi->line.content_len = git_buf_len(out); - if (pi->print_cb(delta, NULL, &pi->line, pi->payload)) - return callback_error(); - - return 0; + return pi->print_cb(delta, NULL, &pi->line, pi->payload); } static int diff_print_one_raw( @@ -208,10 +195,7 @@ static int diff_print_one_raw( pi->line.content = git_buf_cstr(out); pi->line.content_len = git_buf_len(out); - if (pi->print_cb(delta, NULL, &pi->line, pi->payload)) - return callback_error(); - - return 0; + return pi->print_cb(delta, NULL, &pi->line, pi->payload); } static int diff_print_oid_range( @@ -238,10 +222,7 @@ static int diff_print_oid_range( git_buf_printf(out, "index %s..%s\n", start_oid, end_oid); } - if (git_buf_oom(out)) - return -1; - - return 0; + return git_buf_oom(out) ? -1 : 0; } static int diff_delta_format_with_paths( @@ -285,8 +266,7 @@ int git_diff_delta__format_file_header( git_buf_printf(out, "diff --git %s%s %s%s\n", oldpfx, delta->old_file.path, newpfx, delta->new_file.path); - if (diff_print_oid_range(out, delta, oid_strlen) < 0) - return -1; + GITERR_CHECK_ERROR(diff_print_oid_range(out, delta, oid_strlen)); if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) diff_delta_format_with_paths( @@ -298,6 +278,7 @@ int git_diff_delta__format_file_header( static int diff_print_patch_file( const git_diff_delta *delta, float progress, void *data) { + int error; diff_print_info *pi = data; const char *oldpfx = pi->diff ? pi->diff->opts.old_prefix : DIFF_OLD_PREFIX_DEFAULT; @@ -313,36 +294,33 @@ static int diff_print_patch_file( (pi->flags & GIT_DIFF_SHOW_UNTRACKED_CONTENT) == 0)) return 0; - if (git_diff_delta__format_file_header( - pi->buf, delta, oldpfx, newpfx, pi->oid_strlen) < 0) - return -1; + if ((error = git_diff_delta__format_file_header( + pi->buf, delta, oldpfx, newpfx, pi->oid_strlen)) < 0) + return error; pi->line.origin = GIT_DIFF_LINE_FILE_HDR; pi->line.content = git_buf_cstr(pi->buf); pi->line.content_len = git_buf_len(pi->buf); - if (pi->print_cb(delta, NULL, &pi->line, pi->payload)) - return callback_error(); + if ((error = pi->print_cb(delta, NULL, &pi->line, pi->payload)) != 0) + return error; if ((delta->flags & GIT_DIFF_FLAG_BINARY) == 0) return 0; git_buf_clear(pi->buf); - if (diff_delta_format_with_paths( + if ((error = diff_delta_format_with_paths( pi->buf, delta, oldpfx, newpfx, - "Binary files %s%s and %s%s differ\n") < 0) - return -1; + "Binary files %s%s and %s%s differ\n")) < 0) + return error; pi->line.origin = GIT_DIFF_LINE_BINARY; pi->line.content = git_buf_cstr(pi->buf); pi->line.content_len = git_buf_len(pi->buf); pi->line.num_lines = 1; - if (pi->print_cb(delta, NULL, &pi->line, pi->payload)) - return callback_error(); - - return 0; + return pi->print_cb(delta, NULL, &pi->line, pi->payload); } static int diff_print_patch_hunk( @@ -359,10 +337,7 @@ static int diff_print_patch_hunk( pi->line.content = h->header; pi->line.content_len = h->header_len; - if (pi->print_cb(d, h, &pi->line, pi->payload)) - return callback_error(); - - return 0; + return pi->print_cb(d, h, &pi->line, pi->payload); } static int diff_print_patch_line( @@ -376,10 +351,7 @@ static int diff_print_patch_line( if (S_ISDIR(delta->new_file.mode)) return 0; - if (pi->print_cb(delta, hunk, line, pi->payload)) - return callback_error(); - - return 0; + return pi->print_cb(delta, hunk, line, pi->payload); } /* print a git_diff to an output callback */ @@ -421,9 +393,14 @@ int git_diff_print( if (!(error = diff_print_info_init( &pi, &buf, diff, format, print_cb, payload))) + { error = git_diff_foreach( diff, print_file, print_hunk, print_line, &pi); + if (error) /* make sure error message is set */ + giterr_set_after_callback_function(error, "git_diff_print"); + } + git_buf_free(&buf); return error; @@ -444,10 +421,15 @@ int git_patch_print( if (!(error = diff_print_info_init( &pi, &temp, git_patch__diff(patch), GIT_DIFF_FORMAT_PATCH, print_cb, payload))) + { error = git_patch__invoke_callbacks( patch, diff_print_patch_file, diff_print_patch_hunk, diff_print_patch_line, &pi); + if (error) /* make sure error message is set */ + giterr_set_after_callback_function(error, "git_patch_print"); + } + git_buf_free(&temp); return error; @@ -478,15 +460,12 @@ int git_patch_to_str( int error; git_buf output = GIT_BUF_INIT; - error = git_patch_print(patch, diff_print_to_buffer_cb, &output); - - /* GIT_EUSER means git_buf_put in print_to_buffer_cb returned -1, - * meaning a memory allocation failure, so just map to -1... - */ - if (error == GIT_EUSER) - error = -1; - - *string = git_buf_detach(&output); + if (!(error = git_patch_print(patch, diff_print_to_buffer_cb, &output))) + *string = git_buf_detach(&output); + else { + git_buf_free(&output); + *string = NULL; + } return error; } diff --git a/src/diff_tform.c b/src/diff_tform.c index 702e43bd3..263a64d12 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -13,6 +13,7 @@ #include "hashsig.h" #include "path.h" #include "fileops.h" +#include "config.h" static git_diff_delta *diff_delta__dup( const git_diff_delta *d, git_pool *pool) @@ -208,9 +209,7 @@ int git_diff_merge(git_diff *onto, const git_diff *from) git_pool_strdup_safe(&onto->pool, onto->opts.new_prefix); } - git_vector_foreach(&onto_new, i, delta) - git__free(delta); - git_vector_free(&onto_new); + git_vector_free_deep(&onto_new); git_pool_clear(&onto_pool); return error; @@ -281,28 +280,22 @@ static int normalize_find_opts( git_repository_config__weakptr(&cfg, diff->repo) < 0) return -1; - if (given) { + if (given) memcpy(opts, given, sizeof(*opts)); - } else { - GIT_INIT_STRUCTURE(opts, GIT_DIFF_FIND_OPTIONS_VERSION); - } if (!given || (given->flags & GIT_DIFF_FIND_ALL) == GIT_DIFF_FIND_BY_CONFIG) { - const char *val = NULL; - - if (git_config_get_string(&val, cfg, "diff.renames") < 0) - giterr_clear(); - else if (val) { - int boolval; - if (!git__parse_bool(&boolval, val) && !boolval) { - /* do nothing */ - } else if (!strcasecmp(val, "copies") || !strcasecmp(val, "copy")) - opts->flags |= (GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES); - else - opts->flags |= GIT_DIFF_FIND_RENAMES; - } + const char *rule = + git_config__get_string_force(cfg, "diff.renames", "true"); + int boolval; + + if (!git__parse_bool(&boolval, rule) && !boolval) + /* don't set FIND_RENAMES if bool value is false */; + else if (!strcasecmp(rule, "copies") || !strcasecmp(rule, "copy")) + opts->flags |= GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES; + else + opts->flags |= GIT_DIFF_FIND_RENAMES; } /* some flags imply others */ @@ -343,14 +336,11 @@ static int normalize_find_opts( #undef USE_DEFAULT if (!opts->rename_limit) { - int32_t limit = 0; - - opts->rename_limit = DEFAULT_RENAME_LIMIT; + opts->rename_limit = git_config__get_int_force( + cfg, "diff.renamelimit", DEFAULT_RENAME_LIMIT); - if (git_config_get_int32(&limit, cfg, "diff.renameLimit") < 0) - giterr_clear(); - else if (limit > 0) - opts->rename_limit = limit; + if (opts->rename_limit <= 0) + opts->rename_limit = DEFAULT_RENAME_LIMIT; } /* assign the internal metric with whitespace flag as payload */ @@ -450,9 +440,7 @@ static int apply_splits_and_deletes( return 0; on_error: - git_vector_foreach(&onto, i, delta) - git__free(delta); - git_vector_free(&onto); + git_vector_free_deep(&onto); return -1; } @@ -824,11 +812,11 @@ int git_diff_find_similar( int error = 0, result; uint16_t similarity; git_diff_delta *src, *tgt; - git_diff_find_options opts; + git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; size_t num_deltas, num_srcs = 0, num_tgts = 0; size_t tried_srcs = 0, tried_tgts = 0; size_t num_rewrites = 0, num_updates = 0, num_bumped = 0; - void **sigcache; /* cache of similarity metric file signatures */ + void **sigcache = NULL; /* cache of similarity metric file signatures */ diff_find_match *tgt2src = NULL; diff_find_match *src2tgt = NULL; diff_find_match *tgt2src_copy = NULL; @@ -838,15 +826,15 @@ int git_diff_find_similar( if ((error = normalize_find_opts(diff, &opts, given_opts)) < 0) return error; - /* No flags set; nothing to do */ - if ((opts.flags & GIT_DIFF_FIND_ALL) == 0) - return 0; - num_deltas = diff->deltas.length; /* TODO: maybe abort if deltas.length > rename_limit ??? */ if (!git__is_uint32(num_deltas)) - return 0; + goto cleanup; + + /* No flags set; nothing to do */ + if ((opts.flags & GIT_DIFF_FIND_ALL) == 0) + goto cleanup; sigcache = git__calloc(num_deltas * 2, sizeof(void *)); GITERR_CHECK_ALLOC(sigcache); @@ -1121,11 +1109,13 @@ cleanup: git__free(src2tgt); git__free(tgt2src_copy); - for (t = 0; t < num_deltas * 2; ++t) { - if (sigcache[t] != NULL) - opts.metric->free_signature(sigcache[t], opts.metric->payload); + if (sigcache) { + for (t = 0; t < num_deltas * 2; ++t) { + if (sigcache[t] != NULL) + opts.metric->free_signature(sigcache[t], opts.metric->payload); + } + git__free(sigcache); } - git__free(sigcache); if (!given_opts || !given_opts->metric) git__free(opts.metric); diff --git a/src/diff_xdiff.c b/src/diff_xdiff.c index e0bc11f7f..e5984f1c9 100644 --- a/src/diff_xdiff.c +++ b/src/diff_xdiff.c @@ -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] @@" */ if (*header != '@') - return -1; + goto fail; if (git_xdiff_scan_int(&header, &hunk->old_start) < 0) - return -1; + goto fail; if (*header == ',') { if (git_xdiff_scan_int(&header, &hunk->old_lines) < 0) - return -1; + goto fail; } else hunk->old_lines = 1; if (git_xdiff_scan_int(&header, &hunk->new_start) < 0) - return -1; + goto fail; if (*header == ',') { if (git_xdiff_scan_int(&header, &hunk->new_lines) < 0) - return -1; + goto fail; } else hunk->new_lines = 1; if (hunk->old_start < 0 || hunk->new_start < 0) - return -1; + goto fail; return 0; + +fail: + giterr_set(GITERR_INVALID, "Malformed hunk header from xdiff"); + return -1; } typedef struct { @@ -122,8 +126,9 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len) info->hunk.header[info->hunk.header_len] = '\0'; if (output->hunk_cb != NULL && - output->hunk_cb(delta, &info->hunk, output->payload)) - output->error = GIT_EUSER; + (output->error = output->hunk_cb( + delta, &info->hunk, output->payload))) + return output->error; info->old_lineno = info->hunk.old_start; info->new_lineno = info->hunk.new_start; @@ -146,10 +151,9 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len) output->error = diff_update_lines( info, &line, bufs[1].ptr, bufs[1].size); - if (!output->error && - output->data_cb != NULL && - output->data_cb(delta, &info->hunk, &line, output->payload)) - output->error = GIT_EUSER; + if (!output->error && output->data_cb != NULL) + output->error = output->data_cb( + delta, &info->hunk, &line, output->payload); } if (len == 3 && !output->error) { @@ -168,10 +172,9 @@ static int git_xdiff_cb(void *priv, mmbuffer_t *bufs, int len) output->error = diff_update_lines( info, &line, bufs[2].ptr, bufs[2].size); - if (!output->error && - output->data_cb != NULL && - output->data_cb(delta, &info->hunk, &line, output->payload)) - output->error = GIT_EUSER; + if (!output->error && output->data_cb != NULL) + output->error = output->data_cb( + delta, &info->hunk, &line, output->payload); } return output->error; @@ -219,11 +222,9 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts) xo->output.diff_cb = git_xdiff; - memset(&xo->config, 0, sizeof(xo->config)); xo->config.ctxlen = opts ? opts->context_lines : 3; xo->config.interhunkctxlen = opts ? opts->interhunk_lines : 0; - memset(&xo->params, 0, sizeof(xo->params)); if (flags & GIT_DIFF_IGNORE_WHITESPACE) xo->params.flags |= XDF_WHITESPACE_FLAGS; if (flags & GIT_DIFF_IGNORE_WHITESPACE_CHANGE) @@ -236,6 +237,5 @@ void git_xdiff_init(git_xdiff_output *xo, const git_diff_options *opts) if (flags & GIT_DIFF_MINIMAL) xo->params.flags |= XDF_NEED_MINIMAL; - memset(&xo->callback, 0, sizeof(xo->callback)); xo->callback.outf = git_xdiff_cb; } diff --git a/src/errors.c b/src/errors.c index d04da4ca9..a0b085923 100644 --- a/src/errors.c +++ b/src/errors.c @@ -23,7 +23,8 @@ static void set_error(int error_class, char *string) { git_error *error = &GIT_GLOBAL->error_t; - git__free(error->message); + if (error->message != string) + git__free(error->message); error->message = string; error->klass = error_class; @@ -103,8 +104,10 @@ int giterr_set_regex(const regex_t *regex, int error_code) void giterr_clear(void) { - set_error(0, NULL); - GIT_GLOBAL->last_error = NULL; + if (GIT_GLOBAL->last_error != NULL) { + set_error(0, NULL); + GIT_GLOBAL->last_error = NULL; + } errno = 0; #ifdef GIT_WIN32 @@ -134,3 +137,39 @@ const git_error *giterr_last(void) { 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 +} diff --git a/src/fetch.c b/src/fetch.c index 276591821..5bf2b93c1 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -104,7 +104,7 @@ cleanup: int git_fetch_negotiate(git_remote *remote) { git_transport *t = remote->transport; - + if (filter_wants(remote) < 0) { giterr_set(GITERR_NET, "Failed to filter the reference list for wants"); return -1; @@ -128,9 +128,9 @@ int git_fetch_download_pack(git_remote *remote) { git_transport *t = remote->transport; - if(!remote->need_pack) + if (!remote->need_pack) return 0; return t->download_pack(t, remote->repo, &remote->stats, - remote->callbacks.transfer_progress, remote->callbacks.payload); + remote->callbacks.transfer_progress, remote->callbacks.payload); } diff --git a/src/fetchhead.c b/src/fetchhead.c index 67089d13d..4435454ef 100644 --- a/src/fetchhead.c +++ b/src/fetchhead.c @@ -260,8 +260,8 @@ int git_repository_fetchhead_foreach(git_repository *repo, while ((line = git__strsep(&buffer, "\n")) != NULL) { ++line_num; - if ((error = fetchhead_ref_parse(&oid, &is_merge, &name, &remote_url, - line, line_num)) < 0) + if ((error = fetchhead_ref_parse( + &oid, &is_merge, &name, &remote_url, line, line_num)) < 0) goto done; if (git_buf_len(&name) > 0) @@ -269,8 +269,9 @@ 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; + error = cb(ref_name, remote_url, &oid, is_merge, payload); + if (error) { + giterr_set_after_callback(error); goto done; } } diff --git a/src/fileops.c b/src/fileops.c index 5763b370b..a60689f3f 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -403,7 +403,6 @@ typedef struct { const char *base; size_t baselen; uint32_t flags; - int error; int depth; } futils__rmdir_data; @@ -447,8 +446,8 @@ static int futils__rm_first_parent(git_buf *path, const char *ceiling) static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path) { + int error = 0; futils__rmdir_data *data = opaque; - int error = data->error; struct stat st; if (data->depth > FUTILS_MAX_DEPTH) @@ -474,13 +473,14 @@ static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path) data->depth++; error = git_path_direach(path, 0, futils__rmdir_recurs_foreach, data); - if (error < 0) - return (error == GIT_EUSER) ? data->error : error; data->depth--; + if (error < 0) + return error; + if (data->depth == 0 && (data->flags & GIT_RMDIR_SKIP_ROOT) != 0) - return data->error; + return error; if ((error = p_rmdir(path->ptr)) < 0) { if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 && @@ -499,28 +499,23 @@ static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path) else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0) error = futils__error_cannot_rmdir(path->ptr, "still present"); - data->error = error; return error; } static int futils__rmdir_empty_parent(void *opaque, git_buf *path) { futils__rmdir_data *data = opaque; - int error; + int error = 0; if (git_buf_len(path) <= data->baselen) - return GIT_ITEROVER; - - error = p_rmdir(git_buf_cstr(path)); + error = GIT_ITEROVER; - if (error) { + else if (p_rmdir(git_buf_cstr(path)) < 0) { int en = errno; if (en == ENOENT || en == ENOTDIR) { - giterr_clear(); - error = 0; + /* do nothing */ } else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) { - giterr_clear(); error = GIT_ITEROVER; } else { error = git_path_set_error(errno, git_buf_cstr(path), "rmdir"); @@ -535,12 +530,13 @@ int git_futils_rmdir_r( { int error; 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 */ if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0) return -1; + memset(&data, 0, sizeof(data)); data.base = base ? base : ""; data.baselen = base ? strlen(base) : 0; data.flags = flags; @@ -548,12 +544,13 @@ int git_futils_rmdir_r( error = futils__rmdir_recurs_foreach(&data, &fullpath); /* 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( &fullpath, base, futils__rmdir_empty_parent, &data); - if (error == GIT_ITEROVER) - error = 0; + if (error == GIT_ITEROVER) { + giterr_clear(); + error = 0; } git_buf_free(&fullpath); @@ -618,6 +615,8 @@ static git_futils_dirs_guess_cb git_futils__dir_guess[GIT_FUTILS_DIR__MAX] = { git_futils_guess_template_dirs, }; +static int git_futils__dirs_shutdown_set = 0; + void git_futils_dirs_global_shutdown(void) { int i; @@ -634,8 +633,6 @@ int git_futils_dirs_global_init(void) for (i = 0; !error && i < GIT_FUTILS_DIR__MAX; i++) error = git_futils_dirs_get(&path, i); - git__on_shutdown(git_futils_dirs_global_shutdown); - return error; } @@ -655,9 +652,16 @@ int git_futils_dirs_get(const git_buf **out, git_futils_dir_t which) GITERR_CHECK_ERROR(git_futils_check_selector(which)); - if (!git_buf_len(&git_futils__dirs[which])) + if (!git_buf_len(&git_futils__dirs[which])) { + /* prepare shutdown if we're going to need it */ + if (!git_futils__dirs_shutdown_set) { + git__on_shutdown(git_futils_dirs_global_shutdown); + git_futils__dirs_shutdown_set = 1; + } + GITERR_CHECK_ERROR( git_futils__dir_guess[which](&git_futils__dirs[which])); + } *out = &git_futils__dirs[which]; return 0; @@ -858,7 +862,6 @@ typedef struct { uint32_t flags; uint32_t mkdir_flags; mode_t dirmode; - int error; } cp_r_info; #define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10) @@ -896,23 +899,21 @@ static int _cp_r_callback(void *ref, git_buf *from) from->ptr[git_path_basename_offset(from)] == '.') return 0; - if (git_buf_joinpath( - &info->to, info->to_root, from->ptr + info->from_prefix) < 0) { - error = -1; - goto exit; - } + if ((error = git_buf_joinpath( + &info->to, info->to_root, from->ptr + info->from_prefix)) < 0) + return error; if (!(error = git_path_lstat(info->to.ptr, &to_st))) exists = true; else if (error != GIT_ENOTFOUND) - goto exit; + return error; else { giterr_clear(); error = 0; } if ((error = git_path_lstat(from->ptr, &from_st)) < 0) - goto exit; + return error; if (S_ISDIR(from_st.st_mode)) { mode_t oldmode = info->dirmode; @@ -926,17 +927,13 @@ static int _cp_r_callback(void *ref, git_buf *from) error = _cp_r_mkdir(info, from); /* 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); - if (error == GIT_EUSER) - error = info->error; - } - if (oldmode != 0) info->dirmode = oldmode; - goto exit; + return error; } if (exists) { @@ -946,8 +943,7 @@ static int _cp_r_callback(void *ref, git_buf *from) if (p_unlink(info->to.ptr) < 0) { giterr_set(GITERR_OS, "Cannot overwrite existing file '%s'", info->to.ptr); - error = -1; - goto exit; + return GIT_EEXISTS; } } @@ -960,7 +956,7 @@ static int _cp_r_callback(void *ref, git_buf *from) /* Make container directory on demand if needed */ if ((info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0 && (error = _cp_r_mkdir(info, from)) < 0) - goto exit; + return error; /* make symlink or regular file */ if (S_ISLNK(from_st.st_mode)) @@ -974,8 +970,6 @@ static int _cp_r_callback(void *ref, git_buf *from) error = git_futils_cp(from->ptr, info->to.ptr, usemode); } -exit: - info->error = error; return error; } @@ -992,11 +986,11 @@ int git_futils_cp_r( if (git_buf_joinpath(&path, from, "") < 0) /* ensure trailing slash */ return -1; + memset(&info, 0, sizeof(info)); info.to_root = to; info.flags = flags; info.dirmode = dirmode; info.from_prefix = path.size; - info.error = 0; git_buf_init(&info.to, 0); /* precalculate mkdir flags */ @@ -1018,9 +1012,6 @@ int git_futils_cp_r( git_buf_free(&path); git_buf_free(&info.to); - if (error == GIT_EUSER) - error = info.error; - return error; } diff --git a/src/filter.c b/src/filter.c index 9f866fe88..ff81eb14e 100644 --- a/src/filter.c +++ b/src/filter.c @@ -69,7 +69,7 @@ static void filter_registry_shutdown(void) return; git_vector_foreach(®->filters, pos, fdef) { - if (fdef->initialized && fdef->filter && fdef->filter->shutdown) { + if (fdef->filter && fdef->filter->shutdown) { fdef->filter->shutdown(fdef->filter); fdef->initialized = false; } diff --git a/src/ignore.c b/src/ignore.c index 27d7c7ec4..c79fe4871 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -74,10 +74,12 @@ 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)) -static int push_one_ignore(void *ref, git_buf *path) +static int push_one_ignore(void *payload, git_buf *path) { - git_ignores *ign = (git_ignores *)ref; - return push_ignore_file(ign->repo, ign, &ign->ign_path, path->ptr, GIT_IGNORE_FILE); + git_ignores *ign = payload; + + return push_ignore_file( + ign->repo, ign, &ign->ign_path, path->ptr, GIT_IGNORE_FILE); } static int get_internal_ignores(git_attr_file **ign, git_repository *repo) diff --git a/src/index.c b/src/index.c index 09e7b2346..bb81f666e 100644 --- a/src/index.c +++ b/src/index.c @@ -2036,11 +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); - git_vector_sort(&entries); - - git_index_clear(index); + if (!error) { + git_vector_sort(&entries); + git_index_clear(index); + git_vector_swap(&entries, &index->entries); + } - git_vector_swap(&entries, &index->entries); git_vector_free(&entries); return error; @@ -2116,8 +2117,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; + giterr_set_after_callback(error); break; } } @@ -2204,11 +2204,8 @@ static int index_apply_to_all( error = 0; continue; } - if (error < 0) { /* return < 0 means abort */ - giterr_clear(); - error = GIT_EUSER; + if (error < 0) /* return < 0 means abort */ break; - } } /* index manipulation may alter entry, so don't depend on it */ @@ -2253,8 +2250,13 @@ int git_index_remove_all( git_index_matched_path_cb cb, void *payload) { - return index_apply_to_all( + int error = index_apply_to_all( index, INDEX_ACTION_REMOVE, pathspec, cb, payload); + + if (error) /* make sure error is set if callback stopped iteration */ + giterr_set_after_callback(error); + + return error; } int git_index_update_all( @@ -2263,6 +2265,11 @@ int git_index_update_all( git_index_matched_path_cb cb, void *payload) { - return index_apply_to_all( + int error = index_apply_to_all( index, INDEX_ACTION_UPDATE, pathspec, cb, payload); + + if (error) /* make sure error is set if callback stopped iteration */ + giterr_set_after_callback(error); + + return error; } diff --git a/src/indexer.c b/src/indexer.c index 852a04120..6132571cc 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -386,12 +386,10 @@ 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; - } - + if (idx->progress_cb) + return giterr_set_after_callback_function( + idx->progress_cb(stats, idx->progress_payload), + "indexer progress"); return 0; } @@ -443,8 +441,8 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran processed = stats->indexed_objects; - if (git_filebuf_write(&idx->pack_file, data, size) < 0) - return -1; + if ((error = git_filebuf_write(&idx->pack_file, data, size)) < 0) + return error; hash_partially(idx, data, (int)size); @@ -452,12 +450,12 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran if (idx->opened_pack) { idx->pack->mwf.size += size; } else { - if (open_pack(&idx->pack, idx->pack_file.path_lock) < 0) - return -1; + if ((error = open_pack(&idx->pack, idx->pack_file.path_lock)) < 0) + return error; idx->opened_pack = 1; mwf = &idx->pack->mwf; - if (git_mwindow_file_register(&idx->pack->mwf) < 0) - return -1; + if ((error = git_mwindow_file_register(&idx->pack->mwf)) < 0) + return error; } if (!idx->parsed_header) { @@ -466,8 +464,8 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran if ((unsigned)idx->pack->mwf.size < sizeof(struct git_pack_header)) return 0; - if (parse_header(&idx->hdr, idx->pack) < 0) - return -1; + if ((error = parse_header(&idx->hdr, idx->pack)) < 0) + return error; idx->parsed_header = 1; idx->nr_objects = ntohl(hdr->hdr_entries); @@ -497,7 +495,7 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran processed = stats->indexed_objects = 0; stats->total_objects = total_objects; - if ((error = do_progress_callback(idx, stats)) < 0) + if ((error = do_progress_callback(idx, stats)) != 0) return error; } @@ -505,6 +503,7 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran /* As the file grows any windows we try to use will be out of date */ git_mwindow_free_all(mwf); + while (processed < idx->nr_objects) { git_packfile_stream *stream = &idx->stream; git_off_t entry_start = idx->off; @@ -522,7 +521,7 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran return 0; } if (error < 0) - return -1; + goto on_error; git_mwindow_close(&w); idx->entry_start = entry_start; @@ -535,7 +534,7 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran return 0; } if (error < 0) - return -1; + goto on_error; idx->have_delta = 1; } else { @@ -544,9 +543,10 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran } idx->have_stream = 1; - if (git_packfile_stream_open(stream, idx->pack, idx->off) < 0) - goto on_error; + error = git_packfile_stream_open(stream, idx->pack, idx->off); + if (error < 0) + goto on_error; } if (idx->have_delta) { @@ -580,7 +580,7 @@ int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_tran } stats->received_objects++; - if ((error = do_progress_callback(idx, stats)) < 0) + if ((error = do_progress_callback(idx, stats)) != 0) goto on_error; } @@ -860,7 +860,7 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) /* Test for this before resolve_deltas(), as it plays with idx->off */ if (idx->off < idx->pack->mwf.size - 20) { - giterr_set(GITERR_INDEXER, "unexpected data at the end of the pack"); + giterr_set(GITERR_INDEXER, "Unexpected data at the end of the pack"); return -1; } @@ -1007,30 +1007,20 @@ on_error: void git_indexer_free(git_indexer *idx) { - khiter_t k; - unsigned int i; - struct entry *e; - struct delta_info *delta; - if (idx == NULL) return; - git_vector_foreach(&idx->objects, i, e) - git__free(e); - git_vector_free(&idx->objects); + git_vector_free_deep(&idx->objects); if (idx->pack) { - for (k = kh_begin(idx->pack->idx_cache); k != kh_end(idx->pack->idx_cache); k++) { - if (kh_exist(idx->pack->idx_cache, k)) - git__free(kh_value(idx->pack->idx_cache, k)); - } + struct git_pack_entry *pentry; + kh_foreach_value( + idx->pack->idx_cache, pentry, { git__free(pentry); }); git_oidmap_free(idx->pack->idx_cache); } - git_vector_foreach(&idx->deltas, i, delta) - git__free(delta); - git_vector_free(&idx->deltas); + git_vector_free_deep(&idx->deltas); git_packfile_free(idx->pack); git_filebuf_cleanup(&idx->pack_file); git__free(idx); diff --git a/src/iterator.c b/src/iterator.c index 8646399ab..0e7d0db85 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -920,12 +920,7 @@ static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi) static void fs_iterator__free_frame(fs_iterator_frame *ff) { - size_t i; - git_path_with_stat *path; - - git_vector_foreach(&ff->entries, i, path) - git__free(path); - git_vector_free(&ff->entries); + git_vector_free_deep(&ff->entries); git__free(ff); } @@ -991,9 +986,8 @@ static int fs_iterator__expand_dir(fs_iterator *fi) fi->base.start, fi->base.end, &ff->entries); if (error < 0) { - git_error last_error = {0}; - - giterr_detach(&last_error); + git_error_state last_error = { 0 }; + giterr_capture(&last_error, error); /* these callbacks may clear the error message */ fs_iterator__free_frame(ff); @@ -1001,12 +995,7 @@ static int fs_iterator__expand_dir(fs_iterator *fi) /* next time return value we skipped to */ fi->base.flags &= ~GIT_ITERATOR_FIRST_ACCESS; - if (last_error.message) { - giterr_set_str(last_error.klass, last_error.message); - free(last_error.message); - } - - return error; + return giterr_restore(&last_error); } if (ff->entries.length == 0) { diff --git a/src/merge.c b/src/merge.c index 00415cbc0..c0be37dd8 100644 --- a/src/merge.c +++ b/src/merge.c @@ -26,6 +26,7 @@ #include "oid.h" #include "index.h" #include "filebuf.h" +#include "config.h" #include "git2/types.h" #include "git2/repository.h" @@ -253,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) { @@ -285,8 +287,8 @@ int git_repository_mergehead_foreach(git_repository *repo, if ((error = git_oid_fromstr(&oid, line)) < 0) goto cleanup; - if (cb(&oid, payload) != 0) { - error = GIT_EUSER; + if ((error = cb(&oid, payload)) != 0) { + giterr_set_after_callback(error); goto cleanup; } @@ -1396,19 +1398,13 @@ static int merge_tree_normalize_opts( } if (!opts->target_limit) { - int32_t limit = 0; - - opts->target_limit = GIT_MERGE_TREE_TARGET_LIMIT; + int limit = git_config__get_int_force(cfg, "merge.renamelimit", 0); - if (git_config_get_int32(&limit, cfg, "merge.renameLimit") < 0) { - giterr_clear(); - - if (git_config_get_int32(&limit, cfg, "diff.renameLimit") < 0) - giterr_clear(); - } + if (!limit) + limit = git_config__get_int_force(cfg, "diff.renamelimit", 0); - if (limit > 0) - opts->target_limit = limit; + opts->target_limit = (limit <= 0) ? + GIT_MERGE_TREE_TARGET_LIMIT : (unsigned int)limit; } /* assign the internal metric with whitespace flag as payload */ @@ -2389,11 +2385,7 @@ done: git_index_set_caps(index_repo, index_repo_caps); git_index_free(index_repo); - - git_vector_foreach(&paths, i, path) - git__free(path); - - git_vector_free(&paths); + git_vector_free_deep(&paths); return error; } diff --git a/src/notes.c b/src/notes.c index beace1b50..795904917 100644 --- a/src/notes.c +++ b/src/notes.c @@ -378,20 +378,11 @@ cleanup: static int note_get_default_ref(const char **out, git_repository *repo) { - int ret; git_config *cfg; + int ret = git_repository_config__weakptr(&cfg, repo); - *out = NULL; - - if (git_repository_config__weakptr(&cfg, repo) < 0) - return -1; - - ret = git_config_get_string(out, cfg, "core.notesRef"); - if (ret == GIT_ENOTFOUND) { - giterr_clear(); - *out = GIT_NOTES_DEFAULT_REF; - return 0; - } + *out = (ret != 0) ? NULL : git_config__get_string_force( + cfg, "core.notesref", GIT_NOTES_DEFAULT_REF); return ret; } @@ -592,8 +583,8 @@ int git_note_foreach( return error; while (!(error = git_note_next(¬e_id, &annotated_id, iter))) { - if (note_cb(¬e_id, &annotated_id, payload)) { - error = GIT_EUSER; + if ((error = note_cb(¬e_id, &annotated_id, payload)) != 0) { + giterr_set_after_callback(error); break; } } diff --git a/src/odb_loose.c b/src/odb_loose.c index ced272b33..fd4ffff1e 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -547,8 +547,7 @@ static int locate_object_short_oid( /* Explore directory to find a unique object matching short_oid */ error = git_path_direach( object_location, 0, fn_locate_object_short_oid, &state); - - if (error && error != GIT_EUSER) + if (error < 0 && error != GIT_EAMBIGUOUS) return error; if (!state.found) @@ -696,7 +695,6 @@ struct foreach_state { size_t dir_len; git_odb_foreach_cb cb; void *data; - int cb_error; }; GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr) @@ -735,12 +733,8 @@ static int foreach_object_dir_cb(void *_state, git_buf *path) if (filename_to_oid(&oid, path->ptr + state->dir_len) < 0) return 0; - if (state->cb(&oid, state->data)) { - state->cb_error = GIT_EUSER; - return -1; - } - - return 0; + return giterr_set_after_callback_function( + state->cb(&oid, state->data), "git_odb_foreach"); } static int foreach_cb(void *_state, git_buf *path) @@ -764,6 +758,8 @@ static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb git_buf_sets(&buf, objects_dir); git_path_to_dir(&buf); + if (git_buf_oom(&buf)) + return -1; memset(&state, 0, sizeof(state)); state.cb = cb; @@ -774,7 +770,7 @@ static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb 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) diff --git a/src/odb_pack.c b/src/odb_pack.c index fd2ca0fd8..903b00d26 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -190,31 +190,39 @@ static int packfile_sort__cb(const void *a_, const void *b_) } - -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 pack_backend *backend = data; struct git_pack_file *pack; + const char *path_str = git_buf_cstr(path); + size_t i, cmp_len = git_buf_len(path); 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 */ + cmp_len -= strlen(".idx"); + for (i = 0; i < backend->packs.length; ++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; } 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; - else if (error < 0) - return error; + } + + if (!error) + error = git_vector_insert(&backend->packs, pack); + + return error; - return git_vector_insert(&backend->packs, pack); } static int pack_entry_find_inner( @@ -314,13 +322,12 @@ static int pack_entry_find_prefix( * 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; - int error; struct stat st; git_buf path = GIT_BUF_INIT; + struct pack_backend *backend = (struct pack_backend *)backend_; if (backend->pack_folder == NULL) return 0; @@ -334,12 +341,9 @@ static int pack_backend__refresh(git_odb_backend *_backend) error = git_path_direach(&path, 0, packfile_load__cb, backend); git_buf_free(&path); - - if (error < 0) - return -1; - git_vector_sort(&backend->packs); - return 0; + + return error; } static int pack_backend__read_header_internal( diff --git a/src/pack-objects.c b/src/pack-objects.c index 2d62507f2..335944c0c 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -205,14 +205,18 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, po = pb->object_list + pb->nr_objects; memset(po, 0x0, sizeof(*po)); - if (git_odb_read_header(&po->size, &po->type, pb->odb, oid) < 0) - return -1; + if ((ret = git_odb_read_header(&po->size, &po->type, pb->odb, oid)) < 0) + return ret; pb->nr_objects++; git_oid_cpy(&po->id, oid); po->hash = name_hash(name); pos = kh_put(oid, pb->object_ix, &po->id, &ret); + if (ret < 0) { + giterr_set_oom(); + return ret; + } assert(ret != 0); kh_value(pb->object_ix, pos) = po; @@ -220,12 +224,17 @@ 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; - } + + ret = pb->progress_cb( + GIT_PACKBUILDER_ADDING_OBJECTS, + pb->nr_objects, 0, pb->progress_cb_payload); + + if (ret) + return giterr_set_after_callback(ret); } } @@ -323,8 +332,10 @@ static int write_object(git_buf *buf, git_packbuilder *pb, git_pobject *po) git_hash_update(&pb->ctx, data, size) < 0) goto on_error; - if (po->delta_data) + if (po->delta_data) { git__free(po->delta_data); + po->delta_data = NULL; + } git_odb_object_free(obj); git_buf_free(&zbuf); @@ -603,6 +614,15 @@ static int write_pack(git_packbuilder *pb, error = cb(entry_oid.id, GIT_OID_RAWSZ, data); done: + /* if callback cancelled writing, we must still free delta_data */ + for ( ; i < pb->nr_objects; ++i) { + po = write_order[i]; + if (po->delta_data) { + git__free(po->delta_data); + po->delta_data = NULL; + } + } + git__free(write_order); git_buf_free(&buf); return error; @@ -1284,21 +1304,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 error; } int git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid *oid) @@ -1318,22 +1339,17 @@ 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 (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_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); 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..23fcf3530 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; @@ -1084,15 +1082,16 @@ int git_pack_foreach_entry( git_vector_foreach(&offsets, i, current) git_vector_insert(&oids, (void*)¤t[4]); } + git_vector_free(&offsets); - p->oids = (git_oid **)oids.contents; + p->oids = (git_oid **)git_vector_detach(NULL, NULL, &oids); } for (i = 0; i < p->num_objects; i++) - if (cb(p->oids[i], data)) - return GIT_EUSER; + if ((error = cb(p->oids[i], data)) != 0) + return giterr_set_after_callback(error); - return 0; + return error; } static int pack_entry_find_offset( diff --git a/src/path.c b/src/path.c index 750dd3ef7..feb273915 100644 --- a/src/path.c +++ b/src/path.c @@ -436,8 +436,12 @@ int git_path_walk_up( while (scan >= stop) { error = cb(data, &iter); iter.ptr[scan] = oldc; - if (error < 0) + + if (error) { + giterr_set_after_callback(error); break; + } + scan = git_buf_rfind_next(&iter, '/'); if (scan >= 0) { scan++; @@ -528,7 +532,9 @@ bool git_path_is_empty_dir(const char *path) if (!git_path_isdir(path)) 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); git_buf_free(&dir); @@ -778,7 +784,7 @@ int git_path_iconv(git_path_iconv_t *ic, char **in, size_t *inlen) return 0; while (1) { - if (git_buf_grow(&ic->buf, wantlen) < 0) + if (git_buf_grow(&ic->buf, wantlen + 1) < 0) return -1; nfc = ic->buf.ptr + ic->buf.size; @@ -867,7 +873,7 @@ int git_path_direach( if ((error = git_path_iconv(&ic, &de_path, &de_len)) < 0) break; #endif - + if ((error = git_buf_put(path, de_path, de_len)) < 0) break; @@ -875,8 +881,8 @@ int git_path_direach( git_buf_truncate(path, wd_len); /* restore path */ - if (error) { - error = GIT_EUSER; + if (error != 0) { + giterr_set_after_callback(error); break; } } diff --git a/src/path.h b/src/path.h index 3daafd265..f26175d15 100644 --- a/src/path.h +++ b/src/path.h @@ -255,9 +255,10 @@ enum { * @param flags Combination of GIT_PATH_DIR flags. * @param callback Callback for each entry. Passed the `payload` and each * successive path inside the directory as a full path. This may - * safely append text to the pathbuf if needed. + * safely append text to the pathbuf if needed. Return non-zero to + * cancel iteration (and return value will be propagated back). * @param payload Passed to callback as first argument. - * @return 0 on success, GIT_EUSER on non-zero callback, or error code + * @return 0 on success or error code from OS error or from callback */ extern int git_path_direach( git_buf *pathbuf, @@ -288,7 +289,7 @@ extern int git_path_cmp( * original input path. * @param callback Function to invoke on each path. Passed the `payload` * and the buffer containing the current path. The path should not - * be modified in any way. + * be modified in any way. Return non-zero to stop iteration. * @param state Passed to fn as the first ath. */ extern int git_path_walk_up( diff --git a/src/pathspec.c b/src/pathspec.c index 1e7e65e90..bad8dacdb 100644 --- a/src/pathspec.c +++ b/src/pathspec.c @@ -102,15 +102,7 @@ int git_pathspec__vinit( /* free data from the pathspec vector */ void git_pathspec__vfree(git_vector *vspec) { - git_attr_fnmatch *match; - unsigned int i; - - git_vector_foreach(vspec, i, match) { - git__free(match); - vspec->contents[i] = NULL; - } - - git_vector_free(vspec); + git_vector_free_deep(vspec); } struct pathspec_match_context { diff --git a/src/pool.c b/src/pool.c index d484769e9..146f118b4 100644 --- a/src/pool.c +++ b/src/pool.c @@ -190,19 +190,18 @@ void *git_pool_malloc(git_pool *pool, uint32_t items) char *git_pool_strndup(git_pool *pool, const char *str, size_t n) { - void *ptr = NULL; + char *ptr = NULL; assert(pool && str && pool->item_size == sizeof(char)); - if (n + 1 == 0) { - giterr_set_oom(); + if ((uint32_t)(n + 1) < n) return NULL; - } if ((ptr = git_pool_malloc(pool, (uint32_t)(n + 1))) != NULL) { memcpy(ptr, str, n); - *(((char *)ptr) + n) = '\0'; + ptr[n] = '\0'; } + pool->has_string_alloc = 1; return ptr; diff --git a/src/posix.c b/src/posix.c index b75109b83..525785f35 100644 --- a/src/posix.c +++ b/src/posix.c @@ -203,4 +203,40 @@ int p_write(git_file fd, const void *buf, size_t cnt) return 0; } +#ifdef NO_MMAP +#include "map.h" + +int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) +{ + GIT_MMAP_VALIDATE(out, len, prot, flags); + + out->data = NULL; + out->len = 0; + + if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) { + giterr_set(GITERR_OS, "Trying to map shared-writeable"); + return -1; + } + + out->data = malloc(len); + GITERR_CHECK_ALLOC(out->data); + + if ((p_lseek(fd, offset, SEEK_SET) < 0) || ((size_t)p_read(fd, out->data, len) != len)) { + giterr_set(GITERR_OS, "mmap emulation failed"); + return -1; + } + + out->len = len; + return 0; +} + +int p_munmap(git_map *map) +{ + assert(map != NULL); + free(map->data); + + return 0; +} + +#endif diff --git a/src/push.c b/src/push.c index 3c9d5bb35..dd77864a5 100644 --- a/src/push.c +++ b/src/push.c @@ -541,10 +541,7 @@ static int queue_objects(git_push *push) error = 0; on_error: - git_vector_foreach(&commits, i, oid) - git__free(oid); - - git_vector_free(&commits); + git_vector_free_deep(&commits); return error; } @@ -662,8 +659,9 @@ int git_push_status_foreach(git_push *push, unsigned int i; git_vector_foreach(&push->status, i, status) { - if (cb(status->ref, status->msg, data) < 0) - return GIT_EUSER; + int error = cb(status->ref, status->msg, data); + if (error) + return giterr_set_after_callback(error); } return 0; diff --git a/src/refdb_fs.c b/src/refdb_fs.c index 62d5c1047..df7cb9d4d 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -264,9 +264,9 @@ done: return error; } -static int _dirent_loose_load(void *data, git_buf *full_path) +static int _dirent_loose_load(void *payload, git_buf *full_path) { - refdb_fs_backend *backend = (refdb_fs_backend *)data; + refdb_fs_backend *backend = payload; const char *file_path; if (git__suffixcmp(full_path->ptr, ".lock") == 0) @@ -305,7 +305,7 @@ static int packed_loadloose(refdb_fs_backend *backend) git_buf_free(&refs_path); - return (error == GIT_EUSER) ? -1 : error; + return error; } static int refdb_fs_backend__exists( diff --git a/src/refs.c b/src/refs.c index 472a79890..4f3a557c6 100644 --- a/src/refs.c +++ b/src/refs.c @@ -471,7 +471,7 @@ int git_reference_rename( if ((error = git_refdb_rename(out, ref->db, ref->name, new_name, force)) < 0) 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 && (error = git_repository_set_head(ref->db->repo, new_name)) < 0) { giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); @@ -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; + while (!(error = git_reference_next(&ref, iter))) { + if ((error = callback(ref, payload)) != 0) { + giterr_set_after_callback(error); + 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; + while (!(error = git_reference_next_name(&refname, iter))) { + if ((error = callback(refname, payload)) != 0) { + giterr_set_after_callback(error); + 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; + while (!(error = git_reference_next_name(&refname, iter))) { + if ((error = callback(refname, payload)) != 0) { + giterr_set_after_callback(error); + break; } } if (error == GIT_ITEROVER) error = 0; -out: git_reference_iterator_free(iter); return error; } @@ -624,7 +621,9 @@ void git_reference_iterator_free(git_reference_iterator *iter) static int cb__reflist_add(const char *ref, void *data) { - return git_vector_insert((git_vector *)data, git__strdup(ref)); + char *name = git__strdup(ref); + GITERR_CHECK_ALLOC(name); + return git_vector_insert((git_vector *)data, name); } int git_reference_list( @@ -647,8 +646,8 @@ int git_reference_list( return -1; } - array->strings = (char **)ref_list.contents; - array->count = ref_list.length; + array->strings = (char **)git_vector_detach(&array->count, NULL, &ref_list); + return 0; } diff --git a/src/remote.c b/src/remote.c index 3d890a5f1..294a8709d 100644 --- a/src/remote.c +++ b/src/remote.c @@ -45,7 +45,7 @@ static int add_refspec(git_remote *remote, const char *string, bool is_fetch) static int download_tags_value(git_remote *remote, git_config *cfg) { - const char *val; + const git_config_entry *ce; git_buf buf = GIT_BUF_INIT; int error; @@ -53,16 +53,14 @@ static int download_tags_value(git_remote *remote, git_config *cfg) if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0) return -1; - error = git_config_get_string(&val, cfg, git_buf_cstr(&buf)); + error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false); git_buf_free(&buf); - if (!error && !strcmp(val, "--no-tags")) - remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE; - else if (!error && !strcmp(val, "--tags")) - remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; - if (error == GIT_ENOTFOUND) { - giterr_clear(); - error = 0; + if (!error && ce && ce->value) { + if (!strcmp(ce->value, "--no-tags")) + remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE; + else if (!strcmp(ce->value, "--tags")) + remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; } return error; @@ -104,12 +102,7 @@ static int get_check_cert(int *out, git_repository *repo) if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) return error; - if ((error = git_config_get_bool(out, cfg, "http.sslVerify")) == 0) - return 0; - else if (error != GIT_ENOTFOUND) - return error; - - giterr_clear(); + *out = git_config__get_bool_force(cfg, "http.sslverify", 1); return 0; } @@ -262,8 +255,7 @@ struct refspec_cb_data { 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 add_refspec(data->remote, entry->value, data->fetch); } @@ -290,9 +282,6 @@ static int get_optional_config( error = 0; } - if (error < 0) - error = -1; - return error; } @@ -303,7 +292,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) const char *val; int error = 0; git_config *config; - struct refspec_cb_data data; + struct refspec_cb_data data = { NULL }; bool optional_setting_found = false, found; assert(out && repo && name); @@ -325,17 +314,15 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) if ((error = get_check_cert(&remote->check_cert, repo)) < 0) goto cleanup; - if ((git_vector_init(&remote->refs, 32, NULL) < 0) || - (git_vector_init(&remote->refspecs, 2, NULL) < 0) || - (git_vector_init(&remote->active_refspecs, 2, NULL) < 0)) { + if (git_vector_init(&remote->refs, 32, NULL) < 0 || + git_vector_init(&remote->refspecs, 2, NULL) < 0 || + git_vector_init(&remote->active_refspecs, 2, NULL) < 0) { error = -1; goto cleanup; } - if (git_buf_printf(&buf, "remote.%s.url", name) < 0) { - error = -1; + if ((error = git_buf_printf(&buf, "remote.%s.url", name)) < 0) goto cleanup; - } if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0) goto cleanup; @@ -370,6 +357,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) data.remote = remote; data.fetch = true; + git_buf_clear(&buf); git_buf_printf(&buf, "remote.%s.fetch", name); @@ -493,7 +481,7 @@ int git_remote_save(const git_remote *remote) } if (error < 0) { git_buf_free(&buf); - return -1; + return error; } } @@ -641,7 +629,7 @@ int git_remote_connect(git_remote *remote, git_direction direction) if (!remote->check_cert) flags |= GIT_TRANSPORTFLAGS_NO_CHECK_CERT; - if ((error = t->connect(t, url, remote->callbacks.credentials, remote->callbacks.payload, direction, flags)) < 0) + if ((error = t->connect(t, url, remote->callbacks.credentials, remote->callbacks.payload, direction, flags)) != 0) goto on_error; remote->transport = t; @@ -667,7 +655,8 @@ int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url) { git_config *cfg; - const char *val; + const git_config_entry *ce; + const char *val = NULL; int error; assert(remote); @@ -684,44 +673,39 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur * to least specific. */ /* remote.<name>.proxy config setting */ - if (remote->name && 0 != *(remote->name)) { + if (remote->name && remote->name[0]) { git_buf buf = GIT_BUF_INIT; if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0) return error; - if ((error = git_config_get_string(&val, cfg, git_buf_cstr(&buf))) == 0 && - val && ('\0' != *val)) { - git_buf_free(&buf); + error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false); + git_buf_free(&buf); - *proxy_url = git__strdup(val); - GITERR_CHECK_ALLOC(*proxy_url); - return 0; - } else if (error != GIT_ENOTFOUND) + if (error < 0) return error; - giterr_clear(); - git_buf_free(&buf); + if (ce && ce->value) { + val = ce->value; + goto found; + } } /* http.proxy config setting */ - if ((error = git_config_get_string(&val, cfg, "http.proxy")) == 0 && - val && ('\0' != *val)) { - *proxy_url = git__strdup(val); - GITERR_CHECK_ALLOC(*proxy_url); - return 0; - } else if (error != GIT_ENOTFOUND) + if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0) return error; - - giterr_clear(); + if (ce && ce->value) { + val = ce->value; + goto found; + } /* HTTP_PROXY / HTTPS_PROXY environment variables */ val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY"); - if (val && ('\0' != *val)) { +found: + if (val && val[0]) { *proxy_url = git__strdup(val); GITERR_CHECK_ALLOC(*proxy_url); - return 0; } return 0; @@ -797,7 +781,7 @@ int git_remote_download(git_remote *remote) git_vector_free(&refs); if (error < 0) - return -1; + return error; if ((error = git_fetch_negotiate(remote)) < 0) return error; @@ -810,10 +794,10 @@ int git_remote_fetch(git_remote *remote) int error; /* Connect and download everything */ - if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH)) < 0) + if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH)) != 0) return error; - if ((error = git_remote_download(remote)) < 0) + if ((error = git_remote_download(remote)) != 0) return error; /* We don't need to be connected anymore */ @@ -1041,7 +1025,6 @@ int git_remote_update_tips(git_remote *remote) int error; size_t i; - if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0) return -1; @@ -1141,40 +1124,28 @@ static int remote_list_cb(const git_config_entry *entry, void *payload) int git_remote_list(git_strarray *remotes_list, git_repository *repo) { - git_config *cfg; - git_vector list; int error; + git_config *cfg; + git_vector list = GIT_VECTOR_INIT; - if (git_repository_config__weakptr(&cfg, repo) < 0) - return -1; + if ((error = git_repository_config__weakptr(&cfg, repo)) < 0) + return error; - if (git_vector_init(&list, 4, git__strcmp_cb) < 0) - return -1; + if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0) + return error; error = git_config_foreach_match( cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list); if (error < 0) { - size_t i; - char *elem; - - git_vector_foreach(&list, i, elem) { - git__free(elem); - } - - git_vector_free(&list); - - /* cb error is converted to GIT_EUSER by git_config_foreach */ - if (error == GIT_EUSER) - error = -1; - + git_vector_free_deep(&list); return error; } git_vector_uniq(&list, git__free); - remotes_list->strings = (char **)list.contents; - remotes_list->count = list.length; + remotes_list->strings = + (char **)git_vector_detach(&remotes_list->count, NULL, &list); return 0; } @@ -1261,8 +1232,7 @@ cleanup: return error; } -struct update_data -{ +struct update_data { git_config *config; const char *old_remote_name; const char *new_remote_name; @@ -1278,9 +1248,7 @@ static int update_config_entries_cb( return 0; return git_config_set_string( - data->config, - entry->name, - data->new_remote_name); + data->config, entry->name, data->new_remote_name); } static int update_branch_remote_config_entry( @@ -1288,20 +1256,17 @@ static int update_branch_remote_config_entry( const char *old_name, const char *new_name) { - git_config *config; - struct update_data data; + int error; + struct update_data data = { NULL }; - if (git_repository_config__weakptr(&config, repo) < 0) - return -1; + if ((error = git_repository_config__weakptr(&data.config, repo)) < 0) + return error; - data.config = config; data.old_remote_name = old_name; data.new_remote_name = new_name; return git_config_foreach_match( - config, - "branch\\..+\\.remote", - update_config_entries_cb, &data); + data.config, "branch\\..+\\.remote", update_config_entries_cb, &data); } static int rename_one_remote_reference( @@ -1309,18 +1274,20 @@ static int rename_one_remote_reference( const char *old_remote_name, const char *new_remote_name) { - int error = -1; + int error; git_buf new_name = GIT_BUF_INIT; - if (git_buf_printf( + error = git_buf_printf( &new_name, GIT_REFS_REMOTES_DIR "%s%s", new_remote_name, - reference->name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name)) < 0) - return -1; + reference->name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name)); - error = git_reference_rename(NULL, reference, git_buf_cstr(&new_name), 0); - git_reference_free(reference); + if (!error) { + error = git_reference_rename( + NULL, reference, git_buf_cstr(&new_name), 0); + git_reference_free(reference); + } git_buf_free(&new_name); return error; @@ -1331,12 +1298,12 @@ static int rename_remote_references( const char *old_name, const char *new_name) { - int error = -1; + int error; git_reference *ref; git_reference_iterator *iter; - 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 (git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR)) { @@ -1344,18 +1311,13 @@ static int rename_remote_references( continue; } - if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0) { - git_reference_iterator_free(iter); - return error; - } + if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0) + break; } git_reference_iterator_free(iter); - if (error == GIT_ITEROVER) - return 0; - - return error; + return (error == GIT_ITEROVER) ? 0 : error; } static int rename_fetch_refspecs( @@ -1368,52 +1330,50 @@ static int rename_fetch_refspecs( git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT; const git_refspec *spec; size_t i; - int error = -1; + int error = 0; - 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) + return error; + + if ((error = git_buf_printf( + &base, "+refs/heads/*:refs/remotes/%s/*", remote->name)) < 0) + return error; 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; - goto cleanup; + if ((error = callback(spec->string, payload)) != 0) { + giterr_set_after_callback(error); + break; } 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) - goto cleanup; + 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; + break; + } - if (git_config_set_string(config, git_buf_cstr(&var), git_buf_cstr(&val)) < 0) - goto cleanup; + if ((error = git_config_set_string( + config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0) + break; } - error = 0; - -cleanup: git_buf_free(&base); git_buf_free(&var); git_buf_free(&val); @@ -1448,11 +1408,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); } @@ -1479,11 +1439,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; } @@ -1655,9 +1617,7 @@ static int copy_refspecs(git_strarray *array, git_remote *remote, unsigned int p return 0; on_error: - git_vector_foreach(&refspecs, i, dup) - git__free(dup); - git_vector_free(&refspecs); + git_vector_free_deep(&refspecs); return -1; } diff --git a/src/repository.c b/src/repository.c index 278c0384e..94f6603aa 100644 --- a/src/repository.c +++ b/src/repository.c @@ -186,39 +186,37 @@ static int load_workdir(git_repository *repo, git_buf *parent_path) { int error; git_config *config; - const char *worktree; - git_buf worktree_buf = GIT_BUF_INIT; + const git_config_entry *ce; + git_buf worktree = GIT_BUF_INIT; if (repo->is_bare) return 0; - if (git_repository_config__weakptr(&config, repo) < 0) - return -1; + if ((error = git_repository_config__weakptr(&config, repo)) < 0) + return error; - error = git_config_get_string(&worktree, config, "core.worktree"); - if (!error && worktree != NULL) { - error = git_path_prettify_dir( - &worktree_buf, worktree, repo->path_repository); - if (error < 0) + if ((error = git_config__lookup_entry( + &ce, config, "core.worktree", false)) < 0) + return error; + + if (ce && ce->value) { + if ((error = git_path_prettify_dir( + &worktree, ce->value, repo->path_repository)) < 0) return error; - repo->workdir = git_buf_detach(&worktree_buf); + + repo->workdir = git_buf_detach(&worktree); } - else if (error != GIT_ENOTFOUND) - return error; + else if (parent_path && git_path_isdir(parent_path->ptr)) + repo->workdir = git_buf_detach(parent_path); else { - giterr_clear(); + if (git_path_dirname_r(&worktree, repo->path_repository) < 0 || + git_path_to_dir(&worktree) < 0) + return -1; - if (parent_path && git_path_isdir(parent_path->ptr)) - repo->workdir = git_buf_detach(parent_path); - else { - git_path_dirname_r(&worktree_buf, repo->path_repository); - git_path_to_dir(&worktree_buf); - repo->workdir = git_buf_detach(&worktree_buf); - } + repo->workdir = git_buf_detach(&worktree); } GITERR_CHECK_ALLOC(repo->workdir); - return 0; } @@ -1610,15 +1608,14 @@ static int at_least_one_cb(const char *refname, void *payload) { GIT_UNUSED(refname); GIT_UNUSED(payload); - - return GIT_EUSER; + return GIT_PASSTHROUGH; } static int repo_contains_no_reference(git_repository *repo) { int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL); - if (error == GIT_EUSER) + if (error == GIT_PASSTHROUGH) return 0; if (!error) diff --git a/src/revwalk.c b/src/revwalk.c index 3dd14b419..c0a053211 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); @@ -173,7 +174,6 @@ struct push_cb_data { 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); } @@ -191,6 +191,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, "?*["); @@ -200,11 +202,8 @@ static int push_glob(git_revwalk *walk, const char *glob, int hide) data.walk = walk; data.hide = hide; - 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); git_buf_free(&buf); return error; diff --git a/src/stash.c b/src/stash.c index 083c2a4cd..eae56966c 100644 --- a/src/stash.c +++ b/src/stash.c @@ -440,7 +440,7 @@ static int is_dirty_cb(const char *path, unsigned int status, void *payload) GIT_UNUSED(status); GIT_UNUSED(payload); - return 1; + return GIT_PASSTHROUGH; } static int ensure_there_are_changes_to_stash( @@ -463,7 +463,7 @@ static int ensure_there_are_changes_to_stash( error = git_status_foreach_ext(repo, &opts, is_dirty_cb, NULL); - if (error == GIT_EUSER) + if (error == GIT_PASSTHROUGH) return 0; if (!error) @@ -582,12 +582,14 @@ int git_stash_foreach( for (i = 0; i < max; i++) { entry = git_reflog_entry_byindex(reflog, i); - if (callback(i, + error = callback(i, git_reflog_entry_message(entry), git_reflog_entry_id_new(entry), - payload)) { - error = GIT_EUSER; - break; + payload); + + if (error) { + giterr_set_after_callback(error); + break; } } diff --git a/src/status.c b/src/status.c index 07fdcb5c3..7a1472d8d 100644 --- a/src/status.c +++ b/src/status.c @@ -314,8 +314,9 @@ int git_status_list_new( goto done; } - if ((error = git_diff__paired_foreach( - status->head2idx, status->idx2wd, status_collect, status)) < 0) + error = git_diff__paired_foreach( + status->head2idx, status->idx2wd, status_collect, status); + if (error < 0) goto done; if (flags & GIT_STATUS_OPT_SORT_CASE_SENSITIVELY) @@ -360,19 +361,13 @@ const git_status_entry *git_status_byindex(git_status_list *status, size_t i) void git_status_list_free(git_status_list *status) { - git_status_entry *status_entry; - size_t i; - if (status == NULL) return; git_diff_free(status->head2idx); git_diff_free(status->idx2wd); - git_vector_foreach(&status->paired, i, status_entry) - git__free(status_entry); - - git_vector_free(&status->paired); + git_vector_free_deep(&status->paired); git__memzero(status, sizeof(*status)); git__free(status); @@ -397,9 +392,8 @@ int git_status_foreach_ext( status_entry->head_to_index->old_file.path : status_entry->index_to_workdir->old_file.path; - if (cb(path, status_entry->status, payload) != 0) { - error = GIT_EUSER; - giterr_clear(); + if ((error = cb(path, status_entry->status, payload)) != 0) { + giterr_set_after_callback(error); break; } } diff --git a/src/submodule.c b/src/submodule.c index 586494fed..f6660a87e 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -168,9 +168,8 @@ int git_submodule_foreach( break; } - if (callback(sm, sm->name, payload)) { - giterr_clear(); - error = GIT_EUSER; + if ((error = callback(sm, sm->name, payload)) != 0) { + giterr_set_after_callback(error); break; } }); @@ -825,17 +824,14 @@ int git_submodule_reload(git_submodule *submodule) assert(submodule); /* refresh index data */ - - if (submodule_update_index(submodule) < 0) - return -1; + if ((error = submodule_update_index(submodule)) < 0) + return error; /* refresh HEAD tree data */ - - if (submodule_update_head(submodule) < 0) - return -1; + if ((error = submodule_update_head(submodule)) < 0) + return error; /* refresh config data */ - mods = open_gitmodules(submodule->repo, false, NULL); if (mods != NULL) { git_buf path = GIT_BUF_INIT; @@ -852,19 +848,17 @@ int git_submodule_reload(git_submodule *submodule) git_buf_free(&path); git_config_file_free(mods); - } - if (error < 0) - return error; + if (error < 0) + return error; + } /* refresh wd data */ - submodule->flags = submodule->flags & ~(GIT_SUBMODULE_STATUS_IN_WD | GIT_SUBMODULE_STATUS__WD_OID_VALID); - error = submodule_load_from_wd_lite(submodule, submodule->path, NULL); - - return error; + return submodule_load_from_wd_lite( + submodule, submodule->path, submodule->repo); } static void submodule_copy_oid_maybe( @@ -1087,15 +1081,14 @@ int git_submodule_parse_update(git_submodule_update_t *out, const char *value) } static int submodule_load_from_config( - const git_config_entry *entry, void *data) + const git_config_entry *entry, void *payload) { - git_repository *repo = data; + git_repository *repo = payload; git_strmap *smcfg = repo->submodules; 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_submodule *sm; - bool is_path; int error = 0; if (git__prefixcmp(key, "submodule.") != 0) @@ -1108,15 +1101,11 @@ static int submodule_load_from_config( return 0; property++; - is_path = (strcasecmp(property, "path") == 0); + path = !strcasecmp(property, "path") ? value : NULL; - if (git_buf_set(&name, namestart, property - namestart - 1) < 0) - return -1; - - if (submodule_get(&sm, repo, name.ptr, is_path ? value : NULL) < 0) { - git_buf_free(&name); - return -1; - } + if ((error = git_buf_set(&name, namestart, property - namestart - 1)) < 0 || + (error = submodule_get(&sm, repo, name.ptr, path)) < 0) + goto done; sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG; @@ -1130,15 +1119,20 @@ static int submodule_load_from_config( if (strcmp(sm->name, name.ptr) != 0) { 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); - if (!sm->path) + if (!sm->path) { error = -1; + goto done; + } } + if (alternate) { void *old_sm = NULL; git_strmap_insert2(smcfg, alternate, sm, old_sm, error); + if (error < 0) + goto done; if (error >= 0) GIT_REFCOUNT_INC(sm); /* inserted under a new key */ @@ -1149,42 +1143,44 @@ 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 * then this should be deleted (at least to match git's behavior) */ - if (is_path) - return 0; + if (path) + goto done; /* copy other properties into submodule entry */ if (strcasecmp(property, "url") == 0) { git__free(sm->url); sm->url = NULL; - if (value != NULL && (sm->url = git__strdup(value)) == NULL) - return -1; + if (value != NULL && (sm->url = git__strdup(value)) == NULL) { + error = -1; + goto done; + } } else if (strcasecmp(property, "update") == 0) { - if (git_submodule_parse_update(&sm->update, value) < 0) - return -1; + if ((error = git_submodule_parse_update(&sm->update, value)) < 0) + goto done; sm->update_default = sm->update; } else if (strcasecmp(property, "fetchRecurseSubmodules") == 0) { - if (git__parse_bool(&sm->fetch_recurse, value) < 0) - return submodule_config_error("fetchRecurseSubmodules", value); + if (git__parse_bool(&sm->fetch_recurse, value) < 0) { + error = submodule_config_error("fetchRecurseSubmodules", value); + goto done; + } } else if (strcasecmp(property, "ignore") == 0) { - if (git_submodule_parse_ignore(&sm->ignore, value) < 0) - return -1; + if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0) + goto done; sm->ignore_default = sm->ignore; } /* ignore other unknown submodule properties */ - return 0; +done: + git_buf_free(&name); + return error; } static int submodule_load_from_wd_lite( @@ -1192,8 +1188,7 @@ static int submodule_load_from_wd_lite( { git_buf path = GIT_BUF_INIT; - GIT_UNUSED(name); - GIT_UNUSED(payload); + GIT_UNUSED(name); GIT_UNUSED(payload); if (git_repository_is_bare(sm->repo)) return 0; @@ -1208,7 +1203,6 @@ static int submodule_load_from_wd_lite( sm->flags |= GIT_SUBMODULE_STATUS_IN_WD; git_buf_free(&path); - return 0; } @@ -1342,7 +1336,6 @@ static int load_submodule_config(git_repository *repo) { int error; git_oid gitmodules_oid; - git_buf path = GIT_BUF_INIT; git_config_backend *mods = NULL; if (repo->submodules) @@ -1370,10 +1363,9 @@ static int load_submodule_config(git_repository *repo) /* add submodule information from .gitmodules */ - if ((mods = open_gitmodules(repo, false, &gitmodules_oid)) != NULL) - error = git_config_file_foreach(mods, submodule_load_from_config, repo); - - if (error != 0) + if ((mods = open_gitmodules(repo, false, &gitmodules_oid)) != NULL && + (error = git_config_file_foreach( + mods, submodule_load_from_config, repo)) < 0) goto cleanup; /* shallow scan submodules in work tree */ @@ -1382,8 +1374,6 @@ static int load_submodule_config(git_repository *repo) error = git_submodule_foreach(repo, submodule_load_from_wd_lite, NULL); cleanup: - git_buf_free(&path); - if (mods != NULL) git_config_file_free(mods); @@ -1468,7 +1458,7 @@ static int submodule_update_config( int error; git_config *config; git_buf key = GIT_BUF_INIT; - const char *old = NULL; + const git_config_entry *ce = NULL; assert(submodule); @@ -1480,14 +1470,16 @@ static int submodule_update_config( if (error < 0) goto cleanup; - if (git_config_get_string(&old, config, key.ptr) < 0) - giterr_clear(); + if ((error = git_config__lookup_entry(&ce, config, key.ptr, false)) < 0) + goto cleanup; - if (!old && only_existing) + if (!ce && only_existing) + goto cleanup; + if (ce && !overwrite) goto cleanup; - if (old && !overwrite) + if (value && ce && ce->value && !strcmp(ce->value, value)) goto cleanup; - if ((!old && !value) || (old && value && strcmp(old, value) == 0)) + if (!value && (!ce || !ce->value)) goto cleanup; if (!value) @@ -418,16 +418,19 @@ typedef struct { 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 ((error = d->cb(ref, &oid, d->cb_data)) != 0) + giterr_set_after_callback_function(error, "git_tag_foreach"); + } - return d->cb(ref, &oid, d->cb_data); + return error; } int git_tag_foreach(git_repository *repo, git_tag_foreach_cb cb, void *cb_data) @@ -455,8 +458,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); + GITERR_CHECK_ALLOC(matched); + + return git_vector_insert(filter->taglist, matched); + } return 0; } @@ -469,20 +478,20 @@ 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); - if (error < 0) { + + if (error < 0) git_vector_free(&taglist); - return -1; - } - tag_names->strings = (char **)taglist.contents; - tag_names->count = taglist.length; + tag_names->strings = + (char **)git_vector_detach(&tag_names->count, NULL, &taglist); + return 0; } 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/http.c b/src/transports/http.c index ace0d97d0..c6aaeb9cf 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -382,9 +382,6 @@ static int on_body_fill_buffer(http_parser *parser, const char *str, size_t len) static void clear_parser_state(http_subtransport *t) { - unsigned i; - char *entry; - http_parser_init(&t->parser, HTTP_RESPONSE); gitno_buffer_setup(&t->socket, &t->parse_buffer, @@ -407,10 +404,7 @@ static void clear_parser_state(http_subtransport *t) git__free(t->location); t->location = NULL; - git_vector_foreach(&t->www_authenticate, i, entry) - git__free(entry); - - git_vector_free(&t->www_authenticate); + git_vector_free_deep(&t->www_authenticate); } static int write_chunk(gitno_socket *socket, const char *buffer, size_t len) diff --git a/src/transports/local.c b/src/transports/local.c index 4502f0202..4635d5dd3 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -43,43 +43,43 @@ typedef struct { static int add_ref(transport_local *t, const char *name) { const char peeled[] = "^{}"; + git_oid head_oid; git_remote_head *head; git_object *obj = NULL, *target = NULL; git_buf buf = GIT_BUF_INIT; int error; - head = git__calloc(1, sizeof(git_remote_head)); - GITERR_CHECK_ALLOC(head); - - head->name = git__strdup(name); - GITERR_CHECK_ALLOC(head->name); - - error = git_reference_name_to_id(&head->oid, t->repo, name); + error = git_reference_name_to_id(&head_oid, t->repo, name); if (error < 0) { - git__free(head->name); - git__free(head); if (!strcmp(name, GIT_HEAD_FILE) && error == GIT_ENOTFOUND) { - /* This is actually okay. Empty repos often have a HEAD that points to - * a nonexistent "refs/heads/master". */ + /* This is actually okay. Empty repos often have a HEAD that + * points to a nonexistent "refs/heads/master". */ giterr_clear(); return 0; } return error; } - if (git_vector_insert(&t->refs, head) < 0) - { + head = git__calloc(1, sizeof(git_remote_head)); + GITERR_CHECK_ALLOC(head); + + head->name = git__strdup(name); + GITERR_CHECK_ALLOC(head->name); + + git_oid_cpy(&head->oid, &head_oid); + + if ((error = git_vector_insert(&t->refs, head)) < 0) { git__free(head->name); git__free(head); - return -1; + return error; } /* If it's not a tag, we don't need to try to peel it */ if (git__prefixcmp(name, GIT_REFS_TAGS_DIR)) return 0; - if (git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJ_ANY) < 0) - return -1; + if ((error = git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJ_ANY)) < 0) + return error; head = NULL; @@ -94,27 +94,24 @@ static int add_ref(transport_local *t, const char *name) /* And if it's a tag, peel it, and add it to the list */ head = git__calloc(1, sizeof(git_remote_head)); GITERR_CHECK_ALLOC(head); + if (git_buf_join(&buf, 0, name, peeled) < 0) return -1; - head->name = git_buf_detach(&buf); - if (git_tag_peel(&target, (git_tag *) obj) < 0) - goto on_error; - - git_oid_cpy(&head->oid, git_object_id(target)); - git_object_free(obj); - git_object_free(target); - - if (git_vector_insert(&t->refs, head) < 0) - return -1; + if (!(error = git_tag_peel(&target, (git_tag *)obj))) { + git_oid_cpy(&head->oid, git_object_id(target)); - return 0; + if ((error = git_vector_insert(&t->refs, head)) < 0) { + git__free(head->name); + git__free(head); + } + } -on_error: git_object_free(obj); git_object_free(target); - return -1; + + return error; } static int store_refs(transport_local *t) @@ -222,7 +219,7 @@ static int local_ls(const git_remote_head ***out, size_t *size, git_transport *t return -1; } - *out = (const git_remote_head **) t->refs.contents; + *out = (const git_remote_head **)t->refs.contents; *size = t->refs.length; return 0; @@ -250,8 +247,9 @@ static int local_negotiate_fetch( git_oid_cpy(&rhead->loid, git_object_id(obj)); else if (error != GIT_ENOTFOUND) return error; + else + giterr_clear(); git_object_free(obj); - giterr_clear(); } return 0; @@ -528,7 +526,7 @@ static int local_download_pack( } } - if ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) < 0) + if ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) != 0) goto cleanup; /* Write the data to the ODB */ @@ -539,7 +537,7 @@ static int local_download_pack( data.progress_payload = progress_payload; data.writepack = writepack; - if ((error = git_packbuilder_foreach(pack, foreach_cb, &data)) < 0) + if ((error = git_packbuilder_foreach(pack, foreach_cb, &data)) != 0) goto cleanup; } error = writepack->commit(writepack, stats); diff --git a/src/transports/smart.c b/src/transports/smart.c index 5242beb65..69eaf9b78 100644 --- a/src/transports/smart.c +++ b/src/transports/smart.c @@ -23,13 +23,13 @@ static int git_smart__recv_cb(gitno_buffer *buf) buf->offset += bytes_read; - if (t->packetsize_cb && !t->cancelled.val) - if (t->packetsize_cb(bytes_read, t->packetsize_payload)) { + if (t->packetsize_cb && !t->cancelled.val) { + error = t->packetsize_cb(bytes_read, t->packetsize_payload); + if (error) { git_atomic_set(&t->cancelled, 1); - - giterr_clear(); return GIT_EUSER; } + } return (int)(buf->offset - old_len); } @@ -342,7 +342,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) t->parent.is_connected = git_smart__is_connected; t->parent.read_flags = git_smart__read_flags; t->parent.cancel = git_smart__cancel; - + t->owner = owner; t->rpc = definition->rpc; @@ -359,7 +359,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param) if (definition->callback(&t->wrapped, &t->parent) < 0) { git__free(t); return -1; - } + } *out = (git_transport *) t; return 0; diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index a4046ee43..dd9b5e0ed 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -45,7 +45,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) error = GIT_EBUFS; if (error < 0 && error != GIT_EBUFS) - return -1; + return error; if (error == GIT_EBUFS) { if ((recvd = gitno_recv(buf)) < 0) @@ -209,12 +209,13 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo) git_strarray refs; unsigned int i; git_reference *ref; + int error; - if (git_reference_list(&refs, repo) < 0) - return -1; + if ((error = git_reference_list(&refs, repo)) < 0) + return error; - if (git_revwalk_new(&walk, repo) < 0) - return -1; + if ((error = git_revwalk_new(&walk, repo)) < 0) + return error; git_revwalk_sorting(walk, GIT_SORT_TIME); @@ -223,13 +224,13 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo) if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR)) continue; - if (git_reference_lookup(&ref, repo, refs.strings[i]) < 0) + if ((error = git_reference_lookup(&ref, repo, refs.strings[i])) < 0) goto on_error; if (git_reference_type(ref) == GIT_REF_SYMBOLIC) continue; - if (git_revwalk_push(walk, git_reference_target(ref)) < 0) + if ((error = git_revwalk_push(walk, git_reference_target(ref))) < 0) goto on_error; git_reference_free(ref); @@ -242,7 +243,7 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo) on_error: git_reference_free(ref); git_strarray_free(&refs); - return -1; + return error; } static int wait_while_ack(gitno_buffer *buf) @@ -503,7 +504,7 @@ int git_smart__download_pack( } if ((error = git_repository_odb__weakptr(&odb, repo)) < 0 || - ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) < 0)) + ((error = git_odb_write_pack(&writepack, odb, progress_cb, progress_payload)) != 0)) goto done; /* @@ -539,11 +540,9 @@ int git_smart__download_pack( if (pkt->type == GIT_PKT_PROGRESS) { if (t->progress_cb) { git_pkt_progress *p = (git_pkt_progress *) pkt; - if (t->progress_cb(p->data, p->len, t->message_cb_payload)) { - giterr_clear(); - error = GIT_EUSER; + error = t->progress_cb(p->data, p->len, t->message_cb_payload); + if (error) goto done; - } } git__free(pkt); } else if (pkt->type == GIT_PKT_DATA) { @@ -551,7 +550,7 @@ int git_smart__download_pack( error = writepack->append(writepack, p->data, p->len, stats); git__free(pkt); - if (error < 0) + if (error != 0) goto done; } else if (pkt->type == GIT_PKT_FLUSH) { /* A flush indicates the end of the packfile */ @@ -564,17 +563,15 @@ int git_smart__download_pack( * Trailing execution of progress_cb, if necessary... * Only the callback through the npp datastructure currently * updates the last_fired_bytes value. It is possible that - * progress has already been reported with the correct + * progress has already been reported with the correct * "received_bytes" value, but until (if?) this is unified * then we will report progress again to be sure that the * correct last received_bytes value is reported. */ if (npp.callback && npp.stats->received_bytes > npp.last_fired_bytes) { - if (npp.callback(npp.stats, npp.payload) < 0) { - giterr_clear(); - error = GIT_EUSER; + error = npp.callback(npp.stats, npp.payload); + if (error != 0) goto done; - } } error = writepack->commit(writepack, stats); diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 673cd0faf..e47e19cca 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -667,9 +667,11 @@ replay: if (allowed_types && (!t->cred || 0 == (t->cred->credtype & allowed_types))) { - if (t->owner->cred_acquire_cb(&t->cred, t->owner->url, t->connection_data.user, allowed_types, - t->owner->cred_acquire_payload) < 0) - return GIT_EUSER; + int error = t->owner->cred_acquire_cb( + &t->cred, t->owner->url, t->connection_data.user, + allowed_types, t->owner->cred_acquire_payload); + if (error < 0) + return error; assert(t->cred); diff --git a/src/tree.c b/src/tree.c index bb59ff82b..4d77ff778 100644 --- a/src/tree.c +++ b/src/tree.c @@ -884,22 +884,22 @@ static int tree_walk( git_vector_foreach(&tree->entries, i, entry) { if (preorder) { error = callback(path->ptr, entry, payload); - if (error > 0) { + if (error < 0) { /* negative value stops iteration */ + giterr_set_after_callback_function(error, "git_tree_walk"); + break; + } + if (error > 0) { /* positive value skips this entry */ error = 0; continue; } - if (error < 0) { - giterr_clear(); - return GIT_EUSER; - } } if (git_tree_entry__is_tree(entry)) { git_tree *subtree; size_t path_len = git_buf_len(path); - if ((error = git_tree_lookup( - &subtree, tree->object.repo, &entry->oid)) < 0) + error = git_tree_lookup(&subtree, tree->object.repo, &entry->oid); + if (error < 0) break; /* append the next entry to the path */ @@ -907,21 +907,24 @@ static int tree_walk( git_buf_putc(path, '/'); if (git_buf_oom(path)) - return -1; + error = -1; + else + error = tree_walk(subtree, callback, path, payload, preorder); - error = tree_walk(subtree, callback, path, payload, preorder); git_tree_free(subtree); - if (error != 0) break; git_buf_truncate(path, path_len); } - if (!preorder && callback(path->ptr, entry, payload) < 0) { - giterr_clear(); - error = GIT_EUSER; - break; + if (!preorder) { + error = callback(path->ptr, entry, payload); + if (error < 0) { /* negative value stops iteration */ + giterr_set_after_callback_function(error, "git_tree_walk"); + break; + } + error = 0; } } diff --git a/src/unix/map.c b/src/unix/map.c index 7de99c99d..e62ab3e76 100644 --- a/src/unix/map.c +++ b/src/unix/map.c @@ -6,7 +6,7 @@ */ #include <git2/common.h> -#ifndef GIT_WIN32 +#if !defined(GIT_WIN32) && !defined(NO_MMAP) #include "map.h" #include <sys/mman.h> diff --git a/src/vector.c b/src/vector.c index 362e7b0c0..050e032a0 100644 --- a/src/vector.c +++ b/src/vector.c @@ -77,6 +77,20 @@ void git_vector_free(git_vector *v) v->_alloc_size = 0; } +void git_vector_free_deep(git_vector *v) +{ + size_t i; + + assert(v); + + for (i = 0; i < v->length; ++i) { + git__free(v->contents[i]); + v->contents[i] = NULL; + } + + git_vector_free(v); +} + int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp) { assert(v); @@ -90,6 +104,22 @@ int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp) return resize_vector(v, max(initial_size, MIN_ALLOCSIZE)); } +void **git_vector_detach(size_t *size, size_t *asize, git_vector *v) +{ + void **data = v->contents; + + if (size) + *size = v->length; + if (asize) + *asize = v->_alloc_size; + + v->_alloc_size = 0; + v->length = 0; + v->contents = NULL; + + return data; +} + int git_vector_insert(git_vector *v, void *element) { assert(v); diff --git a/src/vector.h b/src/vector.h index 279f5c6ee..d318463c6 100644 --- a/src/vector.h +++ b/src/vector.h @@ -23,10 +23,13 @@ typedef struct git_vector { int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp); void git_vector_free(git_vector *v); +void git_vector_free_deep(git_vector *v); /* free each entry and self */ void git_vector_clear(git_vector *v); int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp); void git_vector_swap(git_vector *a, git_vector *b); +void **git_vector_detach(size_t *size, size_t *asize, git_vector *v); + void git_vector_sort(git_vector *v); /** Linear search for matching entry using internal comparison function */ diff --git a/src/win32/map.c b/src/win32/map.c index 44c6c4e2e..902ea3994 100644 --- a/src/win32/map.c +++ b/src/win32/map.c @@ -8,6 +8,7 @@ #include "map.h" #include <errno.h> +#ifndef NO_MMAP static DWORD get_page_size(void) { @@ -112,4 +113,4 @@ int p_munmap(git_map *map) return error; } - +#endif |