diff options
author | Patrick Steinhardt <ps@pks.im> | 2018-10-26 16:27:21 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-26 16:27:21 +0300 |
commit | f23dc5b29f1394928a940d7ec447f4bfd53dad1f (patch) | |
tree | 66c5748613d81b10a76a3a3c0f929694dc82de94 | |
parent | 68e55c3a65c4a3fc5d6991a60214d7f1bfc62427 (diff) | |
parent | a0c286b5bea67d17016c8a4efc0f73f591c3738b (diff) |
Merge pull request #4846 from pks-t/pks/v0.27.6
Bugix release v0.27.7
29 files changed, 457 insertions, 66 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 38db317e7..f7e72d343 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,48 @@ +v0.27.7 +------- + +This is a bugfix release with the following changes or improvements: + +- Our continuous integration environment has switched from Travis and + AppVeyor to Azure Pipelines CI. + +- Fix adding worktrees for bare repositories. + +- Fix parsed patches not computing the old respectively new line + numbers correctly. + +- Fix parsing configuration variables which do not have a section. + +- Fix a zero-byte allocation when trying to detect file renames and + copies of a diff without any hunks. + +- Fix a zero-byte allocation when trying to resize or duplicate + vectors. + +- Fix return value when trying to unlock worktrees which aren't + locked. + +- Fix returning an unitialized error code when preparing a revision + walk without any pushed commits. + +- Fix return value of `git_remote_lookup` when lookup of + "remote.$remote.tagopt" fails. + +- Fix the revision walk always labelling commits as interesting due + to a mishandling of the commit date. + +- Fix the packbuilder inserting uninteresting blobs when adding a + tree containing references to such blobs. + +- Ignore unsupported authentication schemes in HTTP transport. + +- Improve performane of `git_remote_prune`. + +- Fix detection of whether `qsort_r` has a BSD or GNU function + signature. + +- Fix detection of iconv if it is provided by libc. + v0.27.6 ------- diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c1590271..83898c570 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ INCLUDE(CheckLibraryExists) INCLUDE(CheckFunctionExists) INCLUDE(CheckSymbolExists) INCLUDE(CheckStructHasMember) +INCLUDE(CheckPrototypeDefinition) # Added in CMake 3.0 INCLUDE(AddCFlagIfSupported) INCLUDE(FindPkgLibraries) INCLUDE(FindThreads) @@ -224,6 +225,9 @@ ELSE () ENABLE_WARNINGS(shift-count-overflow) DISABLE_WARNINGS(unused-const-variable) DISABLE_WARNINGS(unused-function) + ENABLE_WARNINGS(format) + ENABLE_WARNINGS(format-security) + ENABLE_WARNINGS(int-conversion) IF (APPLE) # Apple deprecated OpenSSL DISABLE_WARNINGS(deprecated-declarations) diff --git a/cmake/Modules/CheckPrototypeDefinition.c.in b/cmake/Modules/CheckPrototypeDefinition.c.in new file mode 100644 index 000000000..a97344ac3 --- /dev/null +++ b/cmake/Modules/CheckPrototypeDefinition.c.in @@ -0,0 +1,29 @@ +@CHECK_PROTOTYPE_DEFINITION_HEADER@ + +static void cmakeRequireSymbol(int dummy, ...) { + (void) dummy; +} + +static void checkSymbol(void) { +#ifndef @CHECK_PROTOTYPE_DEFINITION_SYMBOL@ + cmakeRequireSymbol(0, &@CHECK_PROTOTYPE_DEFINITION_SYMBOL@); +#endif +} + +@CHECK_PROTOTYPE_DEFINITION_PROTO@ { + return @CHECK_PROTOTYPE_DEFINITION_RETURN@; +} + +#ifdef __CLASSIC_C__ +int main() { + int ac; + char*av[]; +#else +int main(int ac, char *av[]) { +#endif + checkSymbol(); + if (ac > 1000) { + return *av[0]; + } + return 0; +} diff --git a/cmake/Modules/CheckPrototypeDefinition.cmake b/cmake/Modules/CheckPrototypeDefinition.cmake new file mode 100644 index 000000000..244b9b53b --- /dev/null +++ b/cmake/Modules/CheckPrototypeDefinition.cmake @@ -0,0 +1,96 @@ +# - Check if the protoype we expect is correct. +# check_prototype_definition(FUNCTION PROTOTYPE RETURN HEADER VARIABLE) +# FUNCTION - The name of the function (used to check if prototype exists) +# PROTOTYPE- The prototype to check. +# RETURN - The return value of the function. +# HEADER - The header files required. +# VARIABLE - The variable to store the result. +# Example: +# check_prototype_definition(getpwent_r +# "struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)" +# "NULL" +# "unistd.h;pwd.h" +# SOLARIS_GETPWENT_R) +# The following variables may be set before calling this macro to +# modify the way the check is run: +# +# CMAKE_REQUIRED_FLAGS = string of compile command line flags +# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) +# CMAKE_REQUIRED_INCLUDES = list of include directories +# CMAKE_REQUIRED_LIBRARIES = list of libraries to link + +#============================================================================= +# Copyright 2005-2009 Kitware, Inc. +# Copyright 2010-2011 Andreas Schneider <asn@cryptomilk.org> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) +# + +get_filename_component(__check_proto_def_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) + +function(CHECK_PROTOTYPE_DEFINITION _FUNCTION _PROTOTYPE _RETURN _HEADER _VARIABLE) + + if ("${_VARIABLE}" MATCHES "^${_VARIABLE}$") + set(CHECK_PROTOTYPE_DEFINITION_CONTENT "/* */\n") + + set(CHECK_PROTOTYPE_DEFINITION_FLAGS ${CMAKE_REQUIRED_FLAGS}) + if (CMAKE_REQUIRED_LIBRARIES) + set(CHECK_PROTOTYPE_DEFINITION_LIBS + "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}") + else(CMAKE_REQUIRED_LIBRARIES) + set(CHECK_PROTOTYPE_DEFINITION_LIBS) + endif(CMAKE_REQUIRED_LIBRARIES) + if (CMAKE_REQUIRED_INCLUDES) + set(CMAKE_SYMBOL_EXISTS_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + else(CMAKE_REQUIRED_INCLUDES) + set(CMAKE_SYMBOL_EXISTS_INCLUDES) + endif(CMAKE_REQUIRED_INCLUDES) + + foreach(_FILE ${_HEADER}) + set(CHECK_PROTOTYPE_DEFINITION_HEADER + "${CHECK_PROTOTYPE_DEFINITION_HEADER}#include <${_FILE}>\n") + endforeach(_FILE) + + set(CHECK_PROTOTYPE_DEFINITION_SYMBOL ${_FUNCTION}) + set(CHECK_PROTOTYPE_DEFINITION_PROTO ${_PROTOTYPE}) + set(CHECK_PROTOTYPE_DEFINITION_RETURN ${_RETURN}) + + configure_file("${__check_proto_def_dir}/CheckPrototypeDefinition.c.in" + "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c" @ONLY) + + file(READ ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c _SOURCE) + + try_compile(${_VARIABLE} + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckPrototypeDefinition.c + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${CHECK_PROTOTYPE_DEFINITION_FLAGS} + "${CHECK_PROTOTYPE_DEFINITION_LIBS}" + "${CMAKE_SYMBOL_EXISTS_INCLUDES}" + OUTPUT_VARIABLE OUTPUT) + + if (${_VARIABLE}) + set(${_VARIABLE} 1 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}") + message(STATUS "Checking prototype ${_FUNCTION} for ${_VARIABLE} - True") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} passed with the following output:\n" + "${OUTPUT}\n\n") + else (${_VARIABLE}) + message(STATUS "Checking prototype ${_FUNCTION} for ${_VARIABLE} - False") + set(${_VARIABLE} 0 CACHE INTERNAL "Have correct prototype for ${_FUNCTION}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the prototype ${_FUNCTION} exists for ${_VARIABLE} failed with the following output:\n" + "${OUTPUT}\n\n${_SOURCE}\n\n") + endif (${_VARIABLE}) + endif("${_VARIABLE}" MATCHES "^${_VARIABLE}$") + +endfunction(CHECK_PROTOTYPE_DEFINITION) diff --git a/cmake/Modules/FindIconv.cmake b/cmake/Modules/FindIconv.cmake index 95414bda6..3c66cdad4 100644 --- a/cmake/Modules/FindIconv.cmake +++ b/cmake/Modules/FindIconv.cmake @@ -12,14 +12,19 @@ IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) ENDIF() FIND_PATH(ICONV_INCLUDE_DIR iconv.h) +CHECK_FUNCTION_EXISTS(iconv_open libc_has_iconv) FIND_LIBRARY(iconv_lib NAMES iconv libiconv libiconv-2 c) -IF(ICONV_INCLUDE_DIR AND iconv_lib) - SET(ICONV_FOUND TRUE) -ENDIF() - -IF(ICONV_FOUND) - # split iconv into -L and -l linker options, so we can set them for pkg-config +IF(ICONV_INCLUDE_DIR AND libc_has_iconv) + SET(ICONV_FOUND TRUE) + SET(ICONV_LIBRARIES "") + IF(NOT ICONV_FIND_QUIETLY) + MESSAGE(STATUS "Found Iconv: provided by libc") + ENDIF(NOT ICONV_FIND_QUIETLY) +ELSEIF(ICONV_INCLUDE_DIR AND iconv_lib) + SET(ICONV_FOUND TRUE) + # split iconv into -L and -l linker options, so we can + # set them for pkg-config GET_FILENAME_COMPONENT(iconv_path ${iconv_lib} PATH) GET_FILENAME_COMPONENT(iconv_name ${iconv_lib} NAME_WE) STRING(REGEX REPLACE "^lib" "" iconv_name ${iconv_name}) diff --git a/include/git2/version.h b/include/git2/version.h index 8dd6a5e22..964e4a58b 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,10 +7,10 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.27.6" +#define LIBGIT2_VERSION "0.27.7" #define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MINOR 27 -#define LIBGIT2_VER_REVISION 6 +#define LIBGIT2_VER_REVISION 7 #define LIBGIT2_VER_PATCH 0 #define LIBGIT2_SOVERSION 27 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4cfb2d311..2080933f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,10 +57,19 @@ IF (HAVE_FUTIMENS) SET(GIT_USE_FUTIMENS 1) ENDIF () -CHECK_FUNCTION_EXISTS(qsort_r HAVE_QSORT_R) -IF (HAVE_QSORT_R) - ADD_DEFINITIONS(-DHAVE_QSORT_R) -ENDIF () +CHECK_PROTOTYPE_DEFINITION(qsort_r + "void qsort_r(void *base, size_t nmemb, size_t size, void *thunk, int (*compar)(void *, const void *, const void *))" + "" "stdlib.h" HAVE_QSORT_R_BSD) +IF (HAVE_QSORT_R_BSD) + ADD_DEFINITIONS(-DHAVE_QSORT_R_BSD) +ENDIF() + +CHECK_PROTOTYPE_DEFINITION(qsort_r + "void qsort_r(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *arg)" + "" "stdlib.h" HAVE_QSORT_R_GNU) +IF (HAVE_QSORT_R_GNU) + ADD_DEFINITIONS(-DHAVE_QSORT_R_GNU) +ENDIF() CHECK_FUNCTION_EXISTS(qsort_s HAVE_QSORT_S) IF (HAVE_QSORT_S) diff --git a/src/config_file.c b/src/config_file.c index 0f4eb0e28..0c05fb515 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -1075,8 +1075,16 @@ static int read_on_variable( GIT_UNUSED(line); GIT_UNUSED(line_len); + if (current_section) { + /* TODO: Once warnings lang, we should likely warn + * here. Git appears to warn in most cases if it sees + * un-namespaced config options. + */ + git_buf_puts(&buf, current_section); + git_buf_putc(&buf, '.'); + } git__strtolower(var_name); - git_buf_printf(&buf, "%s.%s", current_section, var_name); + git_buf_puts(&buf, var_name); git__free(var_name); if (git_buf_oom(&buf)) { diff --git a/src/diff_tform.c b/src/diff_tform.c index bc664dd05..a9706e002 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -822,7 +822,7 @@ int git_diff_find_similar( num_deltas = diff->deltas.length; /* TODO: maybe abort if deltas.length > rename_limit ??? */ - if (!git__is_uint32(num_deltas)) + if (!num_deltas || !git__is_uint32(num_deltas)) goto cleanup; /* No flags set; nothing to do */ diff --git a/src/index.c b/src/index.c index 7a8bb2c6f..2b47e4dc3 100644 --- a/src/index.c +++ b/src/index.c @@ -1774,7 +1774,8 @@ int git_index_conflict_add(git_index *index, if (entries[i] && !valid_filemode(entries[i]->mode)) { giterr_set(GITERR_INDEX, "invalid filemode for stage %d entry", i + 1); - return -1; + ret = -1; + goto on_error; } } @@ -3509,7 +3510,7 @@ int git_index_snapshot_new(git_vector *snap, git_index *index) error = git_vector_dup(snap, &index->entries, index->entries._cmp); if (error < 0) - git_index_free(index); + git_index_snapshot_release(snap, index); return error; } diff --git a/src/pack-objects.c b/src/pack-objects.c index e9245143c..355b9e1e0 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -1666,7 +1666,7 @@ int insert_tree(git_packbuilder *pb, git_tree *tree) break; case GIT_OBJ_BLOB: - if ((error = retrieve_object(&obj, pb, git_tree_id(tree))) < 0) + if ((error = retrieve_object(&obj, pb, entry_id)) < 0) return error; if (obj->uninteresting) continue; diff --git a/src/parse.c b/src/parse.c index 6b8902c35..b04fda36b 100644 --- a/src/parse.c +++ b/src/parse.c @@ -8,12 +8,14 @@ int git_parse_ctx_init(git_parse_ctx *ctx, const char *content, size_t content_len) { - if (content_len) + if (content && content_len) { ctx->content = content; - else - ctx->content = NULL; + ctx->content_len = content_len; + } else { + ctx->content = ""; + ctx->content_len = 0; + } - ctx->content_len = content_len; ctx->remain = ctx->content; ctx->remain_len = ctx->content_len; ctx->line = ctx->remain; @@ -26,6 +28,7 @@ int git_parse_ctx_init(git_parse_ctx *ctx, const char *content, size_t content_l void git_parse_ctx_clear(git_parse_ctx *ctx) { memset(ctx, 0, sizeof(*ctx)); + ctx->content = ""; } void git_parse_advance_line(git_parse_ctx *ctx) diff --git a/src/patch_parse.c b/src/patch_parse.c index acdd45e82..e02c87cf3 100644 --- a/src/patch_parse.c +++ b/src/patch_parse.c @@ -563,6 +563,8 @@ static int parse_hunk_body( char c; int origin; int prefix = 1; + int old_lineno = hunk->hunk.old_start + (hunk->hunk.old_lines - oldlines); + int new_lineno = hunk->hunk.new_start + (hunk->hunk.new_lines - newlines); if (ctx->parse_ctx.line_len == 0 || ctx->parse_ctx.line[ctx->parse_ctx.line_len - 1] != '\n') { error = git_parse_err("invalid patch instruction at line %"PRIuZ, @@ -586,11 +588,13 @@ static int parse_hunk_body( case '-': origin = GIT_DIFF_LINE_DELETION; oldlines--; + new_lineno = -1; break; case '+': origin = GIT_DIFF_LINE_ADDITION; newlines--; + old_lineno = -1; break; default: @@ -607,6 +611,9 @@ static int parse_hunk_body( line->content_len = ctx->parse_ctx.line_len - prefix; line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len; line->origin = origin; + line->num_lines = 1; + line->old_lineno = old_lineno; + line->new_lineno = new_lineno; hunk->line_count++; } diff --git a/src/remote.c b/src/remote.c index d8a6b991d..2078dd3e7 100644 --- a/src/remote.c +++ b/src/remote.c @@ -428,7 +428,7 @@ static int get_optional_config( int git_remote_lookup(git_remote **out, git_repository *repo, const char *name) { - git_remote *remote; + git_remote *remote = NULL; git_buf buf = GIT_BUF_INIT; const char *val; int error = 0; @@ -510,7 +510,7 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name) if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0) goto cleanup; - if (download_tags_value(remote, config) < 0) + if ((error = download_tags_value(remote, config)) < 0) goto cleanup; if ((error = lookup_remote_prune_config(remote, config, name)) < 0) @@ -1234,7 +1234,7 @@ int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks) goto cleanup; key.name = (char *) git_buf_cstr(&buf); - error = git_vector_search(&pos, &remote_refs, &key); + error = git_vector_bsearch(&pos, &remote_refs, &key); git_buf_free(&buf); if (error < 0 && error != GIT_ENOTFOUND) diff --git a/src/repository.c b/src/repository.c index 90b778e03..3c8987990 100644 --- a/src/repository.c +++ b/src/repository.c @@ -268,11 +268,15 @@ static int load_config_data(git_repository *repo, const git_config *config) { int is_bare; + int err = git_config_get_bool(&is_bare, config, "core.bare"); + if (err < 0 && err != GIT_ENOTFOUND) + return err; + /* Try to figure out if it's bare, default to non-bare if it's not set */ - if (git_config_get_bool(&is_bare, config, "core.bare") < 0) - repo->is_bare = 0; + if (err != GIT_ENOTFOUND) + repo->is_bare = is_bare && !repo->is_worktree; else - repo->is_bare = is_bare; + repo->is_bare = 0; return 0; } diff --git a/src/revwalk.c b/src/revwalk.c index eb228a522..f11dc0630 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -384,10 +384,16 @@ static int still_interesting(git_commit_list *list, int64_t time, int slop) if (!list) return 0; + /* + * If the destination list has commits with an earlier date than our + * source, we want to reset the slop counter as we're not done. + */ + if (time <= list->item->time) + return SLOP; + for (; list; list = list->next) { /* - * If the destination list has commits with an earlier date than - * our source or if it still contains interesting commits we + * If the destination list still contains interesting commits we * want to continue looking. */ if (!list->item->uninteresting || list->item->time > time) @@ -401,7 +407,7 @@ static int still_interesting(git_commit_list *list, int64_t time, int slop) static int limit_list(git_commit_list **out, git_revwalk *walk, git_commit_list *commits) { int error, slop = SLOP; - int64_t time = ~0ll; + int64_t time = INT64_MAX; git_commit_list *list = commits; git_commit_list *newlist = NULL; git_commit_list **p = &newlist; @@ -522,7 +528,7 @@ cleanup: static int prepare_walk(git_revwalk *walk) { - int error; + int error = 0; git_commit_list *list, *commits = NULL; git_commit_list_node *next; diff --git a/src/transports/http.c b/src/transports/http.c index e051c8a35..22b8bb864 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -188,6 +188,9 @@ static int apply_credentials(git_buf *buf, http_subtransport *t) if (auth_context_match(&context, t, credtype_match, &cred->credtype) < 0) return -1; + if (!context) + return 0; + return context->next_token(buf, context, cred); } diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 4a1eb0490..c3c18a80a 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -846,23 +846,27 @@ on_error: static int do_send_request(winhttp_stream *s, size_t len, int ignore_length) { - if (ignore_length) { - if (!WinHttpSendRequest(s->request, - WINHTTP_NO_ADDITIONAL_HEADERS, 0, - WINHTTP_NO_REQUEST_DATA, 0, - WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, 0)) { - return -1; - } - } else { - if (!WinHttpSendRequest(s->request, - WINHTTP_NO_ADDITIONAL_HEADERS, 0, - WINHTTP_NO_REQUEST_DATA, 0, - len, 0)) { - return -1; + int attempts; + bool success; + + for (attempts = 0; attempts < 5; attempts++) { + if (ignore_length) { + success = WinHttpSendRequest(s->request, + WINHTTP_NO_ADDITIONAL_HEADERS, 0, + WINHTTP_NO_REQUEST_DATA, 0, + WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, 0); + } else { + success = WinHttpSendRequest(s->request, + WINHTTP_NO_ADDITIONAL_HEADERS, 0, + WINHTTP_NO_REQUEST_DATA, 0, + len, 0); } + + if (success || GetLastError() != SEC_E_BUFFER_TOO_SMALL) + break; } - return 0; + return success ? 0 : -1; } static int send_request(winhttp_stream *s, size_t len, int ignore_length) diff --git a/src/tree.c b/src/tree.c index 12622975a..a014ce807 100644 --- a/src/tree.c +++ b/src/tree.c @@ -490,15 +490,16 @@ static int append_entry( git_treebuilder *bld, const char *filename, const git_oid *id, - git_filemode_t filemode) + git_filemode_t filemode, + bool validate) { git_tree_entry *entry; int error = 0; - if (!valid_entry_name(bld->repo, filename)) + if (validate && !valid_entry_name(bld->repo, filename)) return tree_error("failed to insert entry: invalid name for a tree entry", filename); - if (git_oid_iszero(id)) + if (validate && git_oid_iszero(id)) return tree_error("failed to insert entry: invalid null OID for a tree entry", filename); entry = alloc_entry(filename, strlen(filename), id); @@ -596,12 +597,12 @@ static int write_tree( last_comp = subdir; } - error = append_entry(bld, last_comp, &sub_oid, S_IFDIR); + error = append_entry(bld, last_comp, &sub_oid, S_IFDIR, true); git__free(subdir); if (error < 0) goto on_error; } else { - error = append_entry(bld, filename, &entry->id, entry->mode); + error = append_entry(bld, filename, &entry->id, entry->mode, true); if (error < 0) goto on_error; } @@ -699,7 +700,8 @@ int git_treebuilder_new( if (append_entry( bld, entry_src->filename, entry_src->oid, - entry_src->attr) < 0) + entry_src->attr, + false) < 0) goto on_error; } } diff --git a/src/util.c b/src/util.c index 48cac852e..911921857 100644 --- a/src/util.c +++ b/src/util.c @@ -690,7 +690,7 @@ size_t git__unescape(char *str) return (pos - str); } -#if defined(HAVE_QSORT_S) || (defined(HAVE_QSORT_R) && defined(BSD)) +#if defined(HAVE_QSORT_S) || defined(HAVE_QSORT_R_BSD) typedef struct { git__sort_r_cmp cmp; void *payload; @@ -707,10 +707,10 @@ static int GIT_STDLIB_CALL git__qsort_r_glue_cmp( void git__qsort_r( void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload) { -#if defined(HAVE_QSORT_R) && defined(BSD) +#if defined(HAVE_QSORT_R_BSD) git__qsort_r_glue glue = { cmp, payload }; qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp); -#elif defined(HAVE_QSORT_R) && defined(__GLIBC__) +#elif defined(HAVE_QSORT_R_GNU) qsort_r(els, nel, elsize, cmp, payload); #elif defined(HAVE_QSORT_S) git__qsort_r_glue glue = { cmp, payload }; diff --git a/src/vector.c b/src/vector.c index b12fa942d..98aa7bb2f 100644 --- a/src/vector.c +++ b/src/vector.c @@ -32,6 +32,9 @@ GIT_INLINE(int) resize_vector(git_vector *v, size_t new_size) { void *new_contents; + if (new_size == 0) + return 0; + new_contents = git__reallocarray(v->contents, new_size, sizeof(void *)); GITERR_CHECK_ALLOC(new_contents); @@ -50,22 +53,24 @@ int git_vector_size_hint(git_vector *v, size_t size_hint) int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp) { - size_t bytes; - assert(v && src); - GITERR_CHECK_ALLOC_MULTIPLY(&bytes, src->length, sizeof(void *)); - - v->_alloc_size = src->length; + v->_alloc_size = 0; + v->contents = NULL; v->_cmp = cmp ? cmp : src->_cmp; v->length = src->length; v->flags = src->flags; if (cmp != src->_cmp) git_vector_set_sorted(v, 0); - v->contents = git__malloc(bytes); - GITERR_CHECK_ALLOC(v->contents); - memcpy(v->contents, src->contents, bytes); + if (src->length) { + size_t bytes; + GITERR_CHECK_ALLOC_MULTIPLY(&bytes, src->length, sizeof(void *)); + v->contents = git__malloc(bytes); + GITERR_CHECK_ALLOC(v->contents); + v->_alloc_size = src->length; + memcpy(v->contents, src->contents, bytes); + } return 0; } diff --git a/src/worktree.c b/src/worktree.c index 91527663e..4acf61b8b 100644 --- a/src/worktree.c +++ b/src/worktree.c @@ -139,7 +139,7 @@ static int open_worktree_dir(git_worktree **out, const char *parent, const char if ((wt->name = git__strdup(name)) == NULL || (wt->commondir_path = git_worktree__read_link(dir, "commondir")) == NULL || (wt->gitlink_path = git_worktree__read_link(dir, "gitdir")) == NULL - || (wt->parent_path = git__strdup(parent)) == NULL) { + || (parent && (wt->parent_path = git__strdup(parent)) == NULL)) { error = -1; goto out; } @@ -417,7 +417,7 @@ int git_worktree_unlock(git_worktree *wt) assert(wt); if (!git_worktree_is_locked(NULL, wt)) - return 0; + return 1; if (git_buf_joinpath(&path, wt->gitdir_path, "locked") < 0) return -1; diff --git a/tests/config/read.c b/tests/config/read.c index a34455a0c..646567134 100644 --- a/tests/config/read.c +++ b/tests/config/read.c @@ -748,3 +748,36 @@ void test_config_read__bom(void) git_config_free(cfg); git_buf_free(&buf); } + +static int read_nosection_cb(const git_config_entry *entry, void *payload) { + int *seen = (int*)payload; + if (strcmp(entry->name, "key") == 0) { + (*seen)++; + } + return 0; +} + +/* This would ideally issue a warning, if we had a way to do so. */ +void test_config_read__nosection(void) +{ + git_config *cfg; + git_buf buf = GIT_BUF_INIT; + int seen = 0; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config-nosection"))); + + /* + * Given a key with no section, we do not allow reading it, + * but we do include it in an iteration over the config + * store. This appears to match how git's own APIs (and + * git-config(1)) behave. + */ + + cl_git_fail_with(git_config_get_string_buf(&buf, cfg, "key"), GIT_EINVALIDSPEC); + + cl_git_pass(git_config_foreach(cfg, read_nosection_cb, &seen)); + cl_assert_equal_i(seen, 1); + + git_buf_free(&buf); + git_config_free(cfg); +} diff --git a/tests/core/vector.c b/tests/core/vector.c index c2e5d3f34..91452404c 100644 --- a/tests/core/vector.c +++ b/tests/core/vector.c @@ -407,3 +407,22 @@ void test_core_vector__reverse(void) git_vector_free(&v); } + +void test_core_vector__dup_empty_vector(void) +{ + git_vector v = GIT_VECTOR_INIT; + git_vector dup = GIT_VECTOR_INIT; + int dummy; + + cl_assert_equal_i(0, v.length); + + cl_git_pass(git_vector_dup(&dup, &v, v._cmp)); + cl_assert_equal_i(0, dup._alloc_size); + cl_assert_equal_i(0, dup.length); + + cl_git_pass(git_vector_insert(&dup, &dummy)); + cl_assert_equal_i(8, dup._alloc_size); + cl_assert_equal_i(1, dup.length); + + git_vector_free(&dup); +} diff --git a/tests/diff/parse.c b/tests/diff/parse.c index dc2ceefec..74816f570 100644 --- a/tests/diff/parse.c +++ b/tests/diff/parse.c @@ -288,3 +288,74 @@ void test_diff_parse__patch_roundtrip_succeeds(void) git_buf_free(&patchbuf); git_buf_free(&diffbuf); } + +#define cl_assert_equal_i_src(i1,i2,file,line) clar__assert_equal(file,line,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2)) + +static void cl_git_assert_lineinfo_(int old_lineno, int new_lineno, int num_lines, git_patch *patch, size_t hunk_idx, size_t line_idx, const char *file, int lineno) +{ + const git_diff_line *line; + + cl_git_expect(git_patch_get_line_in_hunk(&line, patch, hunk_idx, line_idx), 0, file, lineno); + cl_assert_equal_i_src(old_lineno, line->old_lineno, file, lineno); + cl_assert_equal_i_src(new_lineno, line->new_lineno, file, lineno); + cl_assert_equal_i_src(num_lines, line->num_lines, file, lineno); +} + +#define cl_git_assert_lineinfo(old, new, num, p, h, l) \ + cl_git_assert_lineinfo_(old,new,num,p,h,l,__FILE__,__LINE__) + + +void test_diff_parse__issue4672(void) +{ + const char *text = "diff --git a/a b/a\n" + "index 7f129fd..af431f2 100644\n" + "--- a/a\n" + "+++ b/a\n" + "@@ -3 +3 @@\n" + "-a contents 2\n" + "+a contents\n"; + + git_diff *diff; + git_patch *patch; + const git_diff_hunk *hunk; + size_t n, l = 0; + + cl_git_pass(git_diff_from_buffer(&diff, text, strlen(text))); + cl_git_pass(git_patch_from_diff(&patch, diff, 0)); + cl_git_pass(git_patch_get_hunk(&hunk, &n, patch, 0)); + + cl_git_assert_lineinfo(3, -1, 1, patch, 0, l++); + cl_git_assert_lineinfo(-1, 3, 1, patch, 0, l++); + + cl_assert_equal_i(n, l); + + git_patch_free(patch); + git_diff_free(diff); +} + +void test_diff_parse__lineinfo(void) +{ + const char *text = PATCH_ORIGINAL_TO_CHANGE_MIDDLE; + git_diff *diff; + git_patch *patch; + const git_diff_hunk *hunk; + size_t n, l = 0; + + cl_git_pass(git_diff_from_buffer(&diff, text, strlen(text))); + cl_git_pass(git_patch_from_diff(&patch, diff, 0)); + cl_git_pass(git_patch_get_hunk(&hunk, &n, patch, 0)); + + cl_git_assert_lineinfo(3, 3, 1, patch, 0, l++); + cl_git_assert_lineinfo(4, 4, 1, patch, 0, l++); + cl_git_assert_lineinfo(5, 5, 1, patch, 0, l++); + cl_git_assert_lineinfo(6, -1, 1, patch, 0, l++); + cl_git_assert_lineinfo(-1, 6, 1, patch, 0, l++); + cl_git_assert_lineinfo(7, 7, 1, patch, 0, l++); + cl_git_assert_lineinfo(8, 8, 1, patch, 0, l++); + cl_git_assert_lineinfo(9, 9, 1, patch, 0, l++); + + cl_assert_equal_i(n, l); + + git_patch_free(patch); + git_diff_free(diff); +} diff --git a/tests/object/tree/update.c b/tests/object/tree/update.c index b76e8612a..41b50f3e9 100644 --- a/tests/object/tree/update.c +++ b/tests/object/tree/update.c @@ -284,3 +284,19 @@ void test_object_tree_update__add_conflict2(void) cl_git_fail(git_tree_create_updated(&tree_updater_id, g_repo, NULL, 2, updates)); } + +void test_object_tree_update__remove_invalid_submodule(void) +{ + git_tree *baseline; + git_oid updated_tree_id, baseline_id; + git_tree_update updates[] = { + {GIT_TREE_UPDATE_REMOVE, {{0}}, GIT_FILEMODE_BLOB, "submodule"}, + }; + + /* This tree contains a submodule with an all-zero commit for a submodule named 'submodule' */ + cl_git_pass(git_oid_fromstr(&baseline_id, "396c7f1adb7925f51ba13a75f48252f44c5a14a2")); + cl_git_pass(git_tree_lookup(&baseline, g_repo, &baseline_id)); + cl_git_pass(git_tree_create_updated(&updated_tree_id, g_repo, baseline, 1, updates)); + + git_tree_free(baseline); +} diff --git a/tests/resources/config/config-nosection b/tests/resources/config/config-nosection new file mode 100644 index 000000000..dd2ee0857 --- /dev/null +++ b/tests/resources/config/config-nosection @@ -0,0 +1 @@ +key = value diff --git a/tests/resources/testrepo2/.gitted/objects/39/6c7f1adb7925f51ba13a75f48252f44c5a14a2 b/tests/resources/testrepo2/.gitted/objects/39/6c7f1adb7925f51ba13a75f48252f44c5a14a2 Binary files differnew file mode 100644 index 000000000..667704b32 --- /dev/null +++ b/tests/resources/testrepo2/.gitted/objects/39/6c7f1adb7925f51ba13a75f48252f44c5a14a2 diff --git a/tests/worktree/worktree.c b/tests/worktree/worktree.c index 4ac3b8bba..9026a7f83 100644 --- a/tests/worktree/worktree.c +++ b/tests/worktree/worktree.c @@ -228,6 +228,26 @@ void test_worktree_worktree__init(void) git_repository_free(repo); } +void test_worktree_worktree__add_from_bare(void) +{ + git_worktree *wt; + git_repository *repo, *wtrepo; + + repo = cl_git_sandbox_init("short_tag.git"); + + cl_assert_equal_i(1, git_repository_is_bare(repo)); + cl_assert_equal_i(0, git_repository_is_worktree(repo)); + + cl_git_pass(git_worktree_add(&wt, repo, "worktree-frombare", "worktree-frombare", NULL)); + cl_git_pass(git_repository_open(&wtrepo, "worktree-frombare")); + cl_assert_equal_i(0, git_repository_is_bare(wtrepo)); + cl_assert_equal_i(1, git_repository_is_worktree(wtrepo)); + + git_worktree_free(wt); + git_repository_free(repo); + git_repository_free(wtrepo); +} + void test_worktree_worktree__add_locked(void) { git_worktree *wt; @@ -435,7 +455,7 @@ void test_worktree_worktree__unlock_unlocked_worktree(void) cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); cl_assert(!git_worktree_is_locked(NULL, wt)); - cl_assert(git_worktree_unlock(wt) == 0); + cl_assert_equal_i(1, git_worktree_unlock(wt)); cl_assert(!wt->locked); git_worktree_free(wt); @@ -448,7 +468,7 @@ void test_worktree_worktree__unlock_locked_worktree(void) cl_git_pass(git_worktree_lookup(&wt, fixture.repo, "testrepo-worktree")); cl_git_pass(git_worktree_lock(wt, NULL)); cl_assert(git_worktree_is_locked(NULL, wt)); - cl_git_pass(git_worktree_unlock(wt)); + cl_assert_equal_i(0, git_worktree_unlock(wt)); cl_assert(!wt->locked); git_worktree_free(wt); |