diff --git a/CMakeLists.txt b/CMakeLists.txt index f4e56e6cf..c79b2637c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -412,7 +412,7 @@ IF (MSVC) # /MTd - Statically link the multithreaded debug version of the CRT # /MDd - Dynamically link the multithreaded debug version of the CRT # /RTC1 - Run time checks - SET(CMAKE_C_FLAGS_DEBUG "/Zi /Od /D_DEBUG /RTC1 ${CRT_FLAG_DEBUG}") + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Zi /Od /D_DEBUG /RTC1 ${CRT_FLAG_DEBUG}") # /DNDEBUG - Disables asserts # /MT - Statically link the multithreaded release version of the CRT @@ -464,7 +464,7 @@ ELSE () ENDIF() IF (WIN32 AND NOT CYGWIN) - SET(CMAKE_C_FLAGS_DEBUG "-D_DEBUG") + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") ENDIF () IF (MINGW) # MinGW always does PIC and complains if we tell it to @@ -608,6 +608,8 @@ IF (SONAME) IF (LIBGIT2_FILENAME) ADD_DEFINITIONS(-DLIBGIT2_FILENAME=\"${LIBGIT2_FILENAME}\") SET_TARGET_PROPERTIES(git2 PROPERTIES OUTPUT_NAME ${LIBGIT2_FILENAME}) + ELSEIF (DEFINED LIBGIT2_PREFIX) + SET_TARGET_PROPERTIES(git2 PROPERTIES PREFIX "${LIBGIT2_PREFIX}") ENDIF() ENDIF() STRING(REPLACE ";" " " LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS}") diff --git a/deps/http-parser/http_parser.c b/deps/http-parser/http_parser.c index 203530254..27bdd2081 100644 --- a/deps/http-parser/http_parser.c +++ b/deps/http-parser/http_parser.c @@ -99,7 +99,7 @@ do { \ FOR##_mark = NULL; \ } \ } while (0) - + /* Run the data callback FOR and consume the current byte */ #define CALLBACK_DATA(FOR) \ CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) @@ -444,6 +444,9 @@ parse_url_char(enum state s, const char ch) return s_req_path; } + /* The schema must start with an alpha character. After that, it may + * consist of digits, '+', '-' or '.', followed by a ':'. + */ if (IS_ALPHA(ch)) { return s_req_schema; } @@ -451,7 +454,7 @@ parse_url_char(enum state s, const char ch) break; case s_req_schema: - if (IS_ALPHA(ch)) { + if (IS_ALPHANUM(ch) || ch == '+' || ch == '-' || ch == '.') { return s; } diff --git a/include/git2/common.h b/include/git2/common.h index 4f43185f8..d7428d811 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -24,10 +24,19 @@ GIT_BEGIN_DECL # include "inttypes.h" GIT_END_DECL -#else +/** This check is needed for importing this file in an iOS/OS X framework throws an error in Xcode otherwise.*/ +#elif !defined(__CLANG_INTTYPES_H) # include #endif +#ifdef DOCURIUM +/* + * This is so clang's doc parser acknowledges comments on functions + * with size_t parameters. + */ +typedef size_t size_t; +#endif + /** Declare a public function exported for application use. */ #if __GNUC__ >= 4 # define GIT_EXTERN(type) extern \ @@ -148,6 +157,7 @@ typedef enum { GIT_OPT_SET_SSL_CERT_LOCATIONS, GIT_OPT_SET_USER_AGENT, GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, + GIT_OPT_SET_SSL_CIPHERS, } git_libgit2_opt_t; /** @@ -259,6 +269,11 @@ typedef enum { * > example, when this is enabled, the parent(s) and tree inputs * > will be validated when creating a new commit. This defaults * > to disabled. + * * opts(GIT_OPT_SET_SSL_CIPHERS, const char *ciphers) + * + * > Set the SSL ciphers use for HTTPS connections. + * > + * > - `ciphers` is the list of ciphers that are eanbled. * * @param option Option key * @param ... value to set the option diff --git a/script/coverity.sh b/script/coverity.sh index 8c826892f..7fe9eb4c7 100755 --- a/script/coverity.sh +++ b/script/coverity.sh @@ -49,10 +49,24 @@ COVERITY_UNSUPPORTED=1 \ # Upload results tar czf libgit2.tgz cov-int SHA=$(git rev-parse --short HEAD) -curl \ + +HTML="$(curl \ + --silent \ + --write-out "\n%{http_code}" \ --form token="$COVERITY_TOKEN" \ --form email=bs@github.com \ --form file=@libgit2.tgz \ --form version="$SHA" \ --form description="Travis build" \ - https://scan.coverity.com/builds?project=libgit2 + https://scan.coverity.com/builds?project=libgit2)" +# Body is everything up to the last line +BODY="$(echo "$HTML" | head -n-1)" +# Status code is the last line +STATUS_CODE="$(echo "$HTML" | tail -n1)" + +echo "${BODY}" + +if [ "${STATUS_CODE}" != "201" ]; then + echo "Received error code ${STATUS_CODE} from Coverity" + exit 1 +fi diff --git a/src/array.h b/src/array.h index 7cd9b7153..490e6be20 100644 --- a/src/array.h +++ b/src/array.h @@ -82,4 +82,44 @@ on_oom: #define git_array_valid_index(a, i) ((i) < (a).size) +#define git_array_foreach(a, i, element) \ + for ((i) = 0; (i) < (a).size && ((element) = &(a).ptr[(i)]); (i)++) + + +GIT_INLINE(int) git_array__search( + size_t *out, + void *array_ptr, + size_t item_size, + size_t array_len, + int (*compare)(const void *, const void *), + const void *key) +{ + size_t lim; + unsigned char *part, *array = array_ptr, *base = array_ptr; + int cmp; + + for (lim = array_len; lim != 0; lim >>= 1) { + part = base + (lim >> 1) * item_size; + cmp = (*compare)(key, part); + + if (cmp == 0) { + base = part; + break; + } + if (cmp > 0) { /* key > p; take right partition */ + base = part + 1 * item_size; + lim--; + } /* else take left partition */ + } + + if (out) + *out = (base - array) / item_size; + + return (cmp == 0) ? 0 : GIT_ENOTFOUND; +} + +#define git_array_search(out, a, cmp, key) \ + git_array__search(out, (a).ptr, sizeof(*(a).ptr), (a).size, \ + (cmp), (key)) + #endif diff --git a/src/blame.c b/src/blame.c index 2daf91591..2c8584ba5 100644 --- a/src/blame.c +++ b/src/blame.c @@ -178,7 +178,7 @@ const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, size_t lineno) return NULL; } -static void normalize_options( +static int normalize_options( git_blame_options *out, const git_blame_options *in, git_repository *repo) @@ -190,7 +190,9 @@ static void normalize_options( /* No newest_commit => HEAD */ if (git_oid_iszero(&out->newest_commit)) { - git_reference_name_to_id(&out->newest_commit, repo, "HEAD"); + if (git_reference_name_to_id(&out->newest_commit, repo, "HEAD") < 0) { + return -1; + } } /* min_line 0 really means 1 */ @@ -204,6 +206,8 @@ static void normalize_options( out->flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES; if (out->flags & GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES) out->flags |= GIT_BLAME_TRACK_COPIES_SAME_FILE; + + return 0; } static git_blame_hunk *split_hunk_in_vector( @@ -362,7 +366,8 @@ int git_blame_file( git_blame *blame = NULL; assert(out && repo && path); - normalize_options(&normOptions, options, repo); + if ((error = normalize_options(&normOptions, options, repo)) < 0) + goto on_error; blame = git_blame__alloc(repo, normOptions, path); GITERR_CHECK_ALLOC(blame); diff --git a/src/blame_git.c b/src/blame_git.c index b8b568285..700207edb 100644 --- a/src/blame_git.c +++ b/src/blame_git.c @@ -525,7 +525,8 @@ static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt) if (sg_origin[i]) continue; - git_commit_parent(&p, origin->commit, i); + if ((error = git_commit_parent(&p, origin->commit, i)) < 0) + goto finish; porigin = find_origin(blame, p, origin); if (!porigin) diff --git a/src/commit.c b/src/commit.c index 685c642aa..5ed9c474d 100644 --- a/src/commit.c +++ b/src/commit.c @@ -676,7 +676,7 @@ int git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_r buf = git_odb_object_data(obj); - while ((h = strchr(buf, '\n')) && h[1] != '\0' && h[1] != '\n') { + while ((h = strchr(buf, '\n')) && h[1] != '\0') { h++; if (git__prefixcmp(buf, field)) { if (git_buf_put(signed_data, buf, h - buf) < 0) diff --git a/src/config_cache.c b/src/config_cache.c index c859ec148..dbea871b9 100644 --- a/src/config_cache.c +++ b/src/config_cache.c @@ -86,7 +86,8 @@ int git_config__cvar(int *out, git_config *config, git_cvar_cached cvar) struct map_data *data = &_cvar_maps[(int)cvar]; git_config_entry *entry; - git_config__lookup_entry(&entry, config, data->cvar_name, false); + if ((error = git_config__lookup_entry(&entry, config, data->cvar_name, false)) < 0) + return error; if (!entry) *out = data->default_value; diff --git a/src/config_file.c b/src/config_file.c index 5f5e309e0..ca4345cc7 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -553,30 +553,15 @@ static int config_set_multivar( git_config_backend *cfg, const char *name, const char *regexp, const char *value) { diskfile_backend *b = (diskfile_backend *)cfg; - refcounted_strmap *map; - git_strmap *values; char *key; regex_t preg; int result; - khiter_t pos; assert(regexp); if ((result = git_config__normalize_name(name, &key)) < 0) return result; - map = refcounted_strmap_take(&b->header); - values = b->header.values->values; - - pos = git_strmap_lookup_index(values, key); - if (!git_strmap_valid_index(values, pos)) { - /* If we don't have it, behave like a normal set */ - result = config_set(cfg, name, value); - refcounted_strmap_free(map); - git__free(key); - return result; - } - result = regcomp(&preg, regexp, REG_EXTENDED); if (result != 0) { giterr_set_regex(&preg, result); @@ -591,7 +576,6 @@ static int config_set_multivar( result = config_refresh(cfg); out: - refcounted_strmap_free(map); git__free(key); regfree(&preg); @@ -1032,6 +1016,11 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con */ first_quote = strchr(line, '"'); + if (first_quote == NULL) { + set_parse_error(reader, 0, "Missing quotation marks in section header"); + return -1; + } + last_quote = strrchr(line, '"'); quoted_len = last_quote - first_quote; @@ -1483,7 +1472,7 @@ static int config_parse( int (*on_section)(struct reader **reader, const char *current_section, const char *line, size_t line_len, void *data), int (*on_variable)(struct reader **reader, const char *current_section, char *var_name, char *var_value, const char *line, size_t line_len, void *data), int (*on_comment)(struct reader **reader, const char *line, size_t line_len, void *data), - int (*on_eof)(struct reader **reader, void *data), + int (*on_eof)(struct reader **reader, const char *current_section, void *data), void *data) { char *current_section = NULL, *var_name, *var_value, *line_start; @@ -1534,7 +1523,7 @@ static int config_parse( } if (on_eof) - result = on_eof(&reader, data); + result = on_eof(&reader, current_section, data); git__free(current_section); return result; @@ -1850,7 +1839,8 @@ static int write_on_comment(struct reader **reader, const char *line, size_t lin return write_line_to(&write_data->buffered_comment, line, line_len); } -static int write_on_eof(struct reader **reader, void *data) +static int write_on_eof( + struct reader **reader, const char *current_section, void *data) { struct write_data *write_data = (struct write_data *)data; int result = 0; @@ -1869,7 +1859,11 @@ static int write_on_eof(struct reader **reader, void *data) * value. */ if ((!write_data->preg || !write_data->preg_replaced) && write_data->value) { - if ((result = write_section(write_data->buf, write_data->section)) == 0) + /* write the section header unless we're already in it */ + if (!current_section || strcmp(current_section, write_data->section)) + result = write_section(write_data->buf, write_data->section); + + if (!result) result = write_value(write_data); } diff --git a/src/describe.c b/src/describe.c index 48f04e858..13ddad5be 100644 --- a/src/describe.c +++ b/src/describe.c @@ -582,7 +582,8 @@ static int describe( best = (struct possible_tag *)git_vector_get(&all_matches, 0); if (gave_up_on) { - git_pqueue_insert(&list, gave_up_on); + if ((error = git_pqueue_insert(&list, gave_up_on)) < 0) + goto cleanup; seen_commits--; } if ((error = finish_depth_computation( diff --git a/src/diff_tform.c b/src/diff_tform.c index 8577f06b8..6a6a62811 100644 --- a/src/diff_tform.c +++ b/src/diff_tform.c @@ -261,7 +261,7 @@ static int normalize_find_opts( if (!given || (given->flags & GIT_DIFF_FIND_ALL) == GIT_DIFF_FIND_BY_CONFIG) { - if (diff->repo) { + if (cfg) { char *rule = git_config__get_string_force(cfg, "diff.renames", "true"); int boolval; @@ -318,8 +318,10 @@ static int normalize_find_opts( #undef USE_DEFAULT if (!opts->rename_limit) { - opts->rename_limit = git_config__get_int_force( - cfg, "diff.renamelimit", DEFAULT_RENAME_LIMIT); + if (cfg) { + opts->rename_limit = git_config__get_int_force( + cfg, "diff.renamelimit", DEFAULT_RENAME_LIMIT); + } if (opts->rename_limit <= 0) opts->rename_limit = DEFAULT_RENAME_LIMIT; diff --git a/src/filebuf.c b/src/filebuf.c index 17efe872e..101d5082a 100644 --- a/src/filebuf.c +++ b/src/filebuf.c @@ -70,6 +70,7 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode) git_file source; char buffer[FILEIO_BUFSIZE]; ssize_t read_bytes; + int error; source = p_open(file->path_original, O_RDONLY); if (source < 0) { @@ -80,7 +81,8 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode) } while ((read_bytes = p_read(source, buffer, sizeof(buffer))) > 0) { - p_write(file->fd, buffer, read_bytes); + if ((error = p_write(file->fd, buffer, read_bytes)) < 0) + break; if (file->compute_digest) git_hash_update(&file->digest, buffer, read_bytes); } @@ -90,6 +92,9 @@ static int lock_file(git_filebuf *file, int flags, mode_t mode) if (read_bytes < 0) { giterr_set(GITERR_OS, "Failed to read file '%s'", file->path_original); return -1; + } else if (error < 0) { + giterr_set(GITERR_OS, "Failed to write file '%s'", file->path_lock); + return -1; } } diff --git a/src/global.c b/src/global.c index 0bfde1e04..adf353d35 100644 --- a/src/global.c +++ b/src/global.c @@ -27,6 +27,7 @@ static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB]; static git_atomic git__n_shutdown_callbacks; static git_atomic git__n_inits; char *git__user_agent; +char *git__ssl_ciphers; void git__on_shutdown(git_global_shutdown_fn callback) { @@ -83,6 +84,7 @@ static void shutdown_common(void) } git__free(git__user_agent); + git__free(git__ssl_ciphers); #if defined(GIT_MSVC_CRTDBG) git_win32__crtdbg_stacktrace_cleanup(); @@ -222,6 +224,20 @@ void git__free_tls_data(void) TlsSetValue(_tls_index, NULL); } +BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved) +{ + /* This is how Windows lets us know our thread is being shut down */ + if (fdwReason == DLL_THREAD_DETACH) { + git__free_tls_data(); + } + + /* + * Windows pays attention to this during library loading. We don't do anything + * so we trivially succeed. + */ + return TRUE; +} + #elif defined(GIT_THREADS) && defined(_POSIX_THREADS) static pthread_key_t _tls_key; diff --git a/src/global.h b/src/global.h index 9fdcee573..219951525 100644 --- a/src/global.h +++ b/src/global.h @@ -36,5 +36,6 @@ extern void git__on_shutdown(git_global_shutdown_fn callback); extern void git__free_tls_data(void); extern const char *git_libgit2__user_agent(void); +extern const char *git_libgit2__ssl_ciphers(void); #endif diff --git a/src/ignore.c b/src/ignore.c index aedc1401e..ac2af4f58 100644 --- a/src/ignore.c +++ b/src/ignore.c @@ -263,10 +263,18 @@ int git_ignore__for_path( goto cleanup; /* given a unrooted path in a non-bare repo, resolve it */ - if (workdir && git_path_root(path) < 0) - error = git_path_find_dir(&ignores->dir, path, workdir); - else + if (workdir && git_path_root(path) < 0) { + git_buf local = GIT_BUF_INIT; + + if ((error = git_path_dirname_r(&local, path)) < 0 || + (error = git_path_resolve_relative(&local, 0)) < 0 || + (error = git_path_to_dir(&local)) < 0 || + (error = git_buf_joinpath(&ignores->dir, workdir, local.ptr)) < 0) + {;} /* Nothing, we just want to stop on the first error */ + git_buf_free(&local); + } else { error = git_buf_joinpath(&ignores->dir, path, ""); + } if (error < 0) goto cleanup; diff --git a/src/index.c b/src/index.c index b97f8091d..63e47965a 100644 --- a/src/index.c +++ b/src/index.c @@ -963,14 +963,20 @@ static int index_entry_reuc_init(git_index_reuc_entry **reuc_out, *reuc_out = reuc = reuc_entry_alloc(path); GITERR_CHECK_ALLOC(reuc); - if ((reuc->mode[0] = ancestor_mode) > 0) + if ((reuc->mode[0] = ancestor_mode) > 0) { + assert(ancestor_oid); git_oid_cpy(&reuc->oid[0], ancestor_oid); + } - if ((reuc->mode[1] = our_mode) > 0) + if ((reuc->mode[1] = our_mode) > 0) { + assert(our_oid); git_oid_cpy(&reuc->oid[1], our_oid); + } - if ((reuc->mode[2] = their_mode) > 0) + if ((reuc->mode[2] = their_mode) > 0) { + assert(their_oid); git_oid_cpy(&reuc->oid[2], their_oid); + } return 0; } @@ -2830,7 +2836,7 @@ static int read_tree_cb( return -1; entry->mode = tentry->attr; - entry->id = tentry->oid; + git_oid_cpy(&entry->id, git_tree_entry_id(tentry)); /* look for corresponding old entry and copy data to new entry */ if (data->old_entries != NULL && diff --git a/src/indexer.c b/src/indexer.c index 9aa092556..a3a866989 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -449,7 +449,7 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size) static int write_at(git_indexer *idx, const void *data, git_off_t offset, size_t size) { git_file fd = idx->pack->mwf.fd; - size_t page_size; + size_t mmap_alignment; size_t page_offset; git_off_t page_start; unsigned char *map_data; @@ -458,11 +458,11 @@ static int write_at(git_indexer *idx, const void *data, git_off_t offset, size_t assert(data && size); - if ((error = git__page_size(&page_size)) < 0) + if ((error = git__mmap_alignment(&mmap_alignment)) < 0) return error; - /* the offset needs to be at the beginning of the a page boundary */ - page_offset = offset % page_size; + /* the offset needs to be at the mmap boundary for the platform */ + page_offset = offset % mmap_alignment; page_start = offset - page_offset; if ((error = p_mmap(&map, page_offset + size, GIT_PROT_WRITE, GIT_MAP_SHARED, fd, page_start)) < 0) @@ -777,7 +777,6 @@ static int fix_thin_pack(git_indexer *idx, git_transfer_progress *stats) curpos = delta->delta_off; error = git_packfile_unpack_header(&size, &type, &idx->pack->mwf, &w, &curpos); - git_mwindow_close(&w); if (error < 0) return error; @@ -914,12 +913,17 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) git_filebuf index_file = {0}; void *packfile_trailer; + if (!idx->parsed_header) { + giterr_set(GITERR_INDEXER, "incomplete pack header"); + return -1; + } + if (git_hash_ctx_init(&ctx) < 0) return -1; /* 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"); + if (idx->off + 20 < idx->pack->mwf.size) { + giterr_set(GITERR_INDEXER, "unexpected data at the end of the pack"); return -1; } diff --git a/src/iterator.c b/src/iterator.c index 024a97573..cb1ea6a87 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -458,7 +458,7 @@ static int tree_iterator__set_next(tree_iterator *ti, tree_iterator_frame *tf) /* try to load trees for items in [current,next) range */ if (!error && git_tree_entry__is_tree(te)) error = git_tree_lookup( - &tf->entries[tf->next]->tree, ti->base.repo, &te->oid); + &tf->entries[tf->next]->tree, ti->base.repo, te->oid); } if (tf->next > tf->current + 1) @@ -603,7 +603,7 @@ static int tree_iterator__update_entry(tree_iterator *ti) te = tf->entries[tf->current]->te; ti->entry.mode = te->attr; - git_oid_cpy(&ti->entry.id, &te->oid); + git_oid_cpy(&ti->entry.id, te->oid); ti->entry.path = tree_iterator__current_filename(ti, te); GITERR_CHECK_ALLOC(ti->entry.path); diff --git a/src/mwindow.c b/src/mwindow.c index 55c8d894b..d3e9be78b 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -296,8 +296,18 @@ static git_mwindow *new_window( */ if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < 0) { - git__free(w); - return NULL; + /* + * The first error might be down to memory fragmentation even if + * we're below our soft limits, so free up what we can and try again. + */ + + while (git_mwindow_close_lru(mwf) == 0) + /* nop */; + + if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < 0) { + git__free(w); + return NULL; + } } ctl->mmap_calls++; diff --git a/src/object.c b/src/object.c index ebf77fb47..1d45f9f1b 100644 --- a/src/object.c +++ b/src/object.c @@ -12,6 +12,7 @@ #include "commit.h" #include "tree.h" #include "blob.h" +#include "oid.h" #include "tag.h" bool git_object__strict_input_validation = true; @@ -166,13 +167,9 @@ int git_object_lookup_prefix( error = git_odb_read(&odb_obj, odb, id); } } else { - git_oid short_oid; + git_oid short_oid = {{ 0 }}; - /* We copy the first len*4 bits from id and fill the remaining with 0s */ - memcpy(short_oid.id, id->id, (len + 1) / 2); - if (len % 2) - short_oid.id[len / 2] &= 0xF0; - memset(short_oid.id + (len + 1) / 2, 0, (GIT_OID_HEXSZ - len) / 2); + git_oid__cpy_prefix(&short_oid, id, len); /* If len < GIT_OID_HEXSZ (a strict short oid was given), we have * 2 options : diff --git a/src/odb.c b/src/odb.c index 1c877c9fc..cb0f70623 100644 --- a/src/odb.c +++ b/src/odb.c @@ -725,7 +725,8 @@ int git_odb_exists_prefix( git_oid_cpy(out, short_id); return 0; } else { - return git_odb__error_notfound("no match for id prefix", short_id); + return git_odb__error_notfound( + "no match for id prefix", short_id, len); } } @@ -740,7 +741,7 @@ int git_odb_exists_prefix( error = odb_exists_prefix_1(out, db, &key, len, true); if (error == GIT_ENOTFOUND) - return git_odb__error_notfound("no match for id prefix", &key); + return git_odb__error_notfound("no match for id prefix", &key, len); return error; } @@ -881,7 +882,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) error = odb_read_1(out, db, id, true); if (error == GIT_ENOTFOUND) - return git_odb__error_notfound("no match for id", id); + return git_odb__error_notfound("no match for id", id, GIT_OID_HEXSZ); return error; } @@ -967,7 +968,7 @@ int git_odb_read_prefix( error = read_prefix_1(out, db, &key, len, true); if (error == GIT_ENOTFOUND) - return git_odb__error_notfound("no match for prefix", &key); + return git_odb__error_notfound("no match for prefix", &key, len); return error; } @@ -1223,12 +1224,14 @@ int git_odb_refresh(struct git_odb *db) return 0; } -int git_odb__error_notfound(const char *message, const git_oid *oid) +int git_odb__error_notfound( + const char *message, const git_oid *oid, size_t oid_len) { if (oid != NULL) { char oid_str[GIT_OID_HEXSZ + 1]; - git_oid_tostr(oid_str, sizeof(oid_str), oid); - giterr_set(GITERR_ODB, "Object not found - %s (%s)", message, oid_str); + git_oid_tostr(oid_str, oid_len, oid); + giterr_set(GITERR_ODB, "Object not found - %s (%.*s)", + message, oid_len, oid_str); } else giterr_set(GITERR_ODB, "Object not found - %s", message); diff --git a/src/odb.h b/src/odb.h index 281bd3a4d..31a9fd1b9 100644 --- a/src/odb.h +++ b/src/odb.h @@ -82,7 +82,8 @@ int git_odb__hashlink(git_oid *out, const char *path); /* * Generate a GIT_ENOTFOUND error for the ODB. */ -int git_odb__error_notfound(const char *message, const git_oid *oid); +int git_odb__error_notfound( + const char *message, const git_oid *oid, size_t oid_len); /* * Generate a GIT_EAMBIGUOUS error for the ODB. diff --git a/src/odb_loose.c b/src/odb_loose.c index 730c4b1e1..9d9bffd21 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -547,7 +547,8 @@ static int locate_object_short_oid( /* Check that directory exists */ if (git_path_isdir(object_location->ptr) == false) - return git_odb__error_notfound("no matching loose object for prefix", short_oid); + return git_odb__error_notfound("no matching loose object for prefix", + short_oid, len); state.dir_len = git_buf_len(object_location); state.short_oid_len = len; @@ -560,7 +561,8 @@ static int locate_object_short_oid( return error; if (!state.found) - return git_odb__error_notfound("no matching loose object for prefix", short_oid); + return git_odb__error_notfound("no matching loose object for prefix", + short_oid, len); if (state.found > 1) return git_odb__error_ambiguous("multiple matches in loose objects"); @@ -613,9 +615,10 @@ static int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_ raw.len = 0; raw.type = GIT_OBJ_BAD; - if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) - error = git_odb__error_notfound("no matching loose object", oid); - else if ((error = read_header_loose(&raw, &object_path)) == 0) { + if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) { + error = git_odb__error_notfound("no matching loose object", + oid, GIT_OID_HEXSZ); + } else if ((error = read_header_loose(&raw, &object_path)) == 0) { *len_p = raw.len; *type_p = raw.type; } @@ -633,9 +636,10 @@ static int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p assert(backend && oid); - if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) - error = git_odb__error_notfound("no matching loose object", oid); - else if ((error = read_loose(&raw, &object_path)) == 0) { + if (locate_object(&object_path, (loose_backend *)backend, oid) < 0) { + error = git_odb__error_notfound("no matching loose object", + oid, GIT_OID_HEXSZ); + } else if ((error = read_loose(&raw, &object_path)) == 0) { *buffer_p = raw.data; *len_p = raw.len; *type_p = raw.type; diff --git a/src/odb_pack.c b/src/odb_pack.c index 77d2c75b9..5a57864ad 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -264,7 +264,8 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen if (!pack_entry_find_inner(e, backend, oid, last_found)) return 0; - return git_odb__error_notfound("failed to find pack entry", oid); + return git_odb__error_notfound( + "failed to find pack entry", oid, GIT_OID_HEXSZ); } static int pack_entry_find_prefix( @@ -309,7 +310,8 @@ static int pack_entry_find_prefix( } if (!found) - return git_odb__error_notfound("no matching pack entry for prefix", short_oid); + return git_odb__error_notfound("no matching pack entry for prefix", + short_oid, len); else return 0; } @@ -333,7 +335,7 @@ static int pack_backend__refresh(git_odb_backend *backend_) return 0; if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode)) - return git_odb__error_notfound("failed to refresh packfiles", NULL); + return git_odb__error_notfound("failed to refresh packfiles", NULL, 0); git_buf_sets(&path, backend->pack_folder); diff --git a/src/oid.h b/src/oid.h index aa1f0bfdc..922a2a347 100644 --- a/src/oid.h +++ b/src/oid.h @@ -44,4 +44,13 @@ GIT_INLINE(int) git_oid__cmp(const git_oid *a, const git_oid *b) return git_oid__hashcmp(a->id, b->id); } +GIT_INLINE(void) git_oid__cpy_prefix( + git_oid *out, const git_oid *id, size_t len) +{ + memcpy(&out->id, id->id, (len + 1) / 2); + + if (len & 1) + out->id[len / 2] &= 0xF0; +} + #endif diff --git a/src/openssl_stream.c b/src/openssl_stream.c index 97736b714..a65f5586e 100644 --- a/src/openssl_stream.c +++ b/src/openssl_stream.c @@ -34,6 +34,8 @@ SSL_CTX *git__ssl_ctx; +#define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA" + #ifdef GIT_THREADS static git_mutex *openssl_locks; @@ -85,6 +87,7 @@ int git_openssl_stream_global_init(void) { #ifdef GIT_OPENSSL long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + const char *ciphers = git_libgit2__ssl_ciphers(); /* Older OpenSSL and MacOS OpenSSL doesn't have this */ #ifdef SSL_OP_NO_COMPRESSION @@ -108,6 +111,16 @@ int git_openssl_stream_global_init(void) git__ssl_ctx = NULL; return -1; } + + if (!ciphers) { + ciphers = GIT_SSL_DEFAULT_CIPHERS; + } + + if(!SSL_CTX_set_cipher_list(git__ssl_ctx, ciphers)) { + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + return -1; + } #endif git__on_shutdown(shutdown_ssl); diff --git a/src/pack-objects.c b/src/pack-objects.c index 46fe8f3db..11e13f7d4 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -848,8 +848,10 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg, git_packbuilder__cache_unlock(pb); - if (overflow) + if (overflow) { + git__free(delta_buf); return -1; + } trg_object->delta_data = git__realloc(delta_buf, delta_size); GITERR_CHECK_ALLOC(trg_object->delta_data); diff --git a/src/pack.c b/src/pack.c index 52c652178..e7003e66d 100644 --- a/src/pack.c +++ b/src/pack.c @@ -494,7 +494,6 @@ int git_packfile_resolve_header( int error; error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos); - git_mwindow_close(&w_curs); if (error < 0) return error; @@ -517,7 +516,6 @@ int git_packfile_resolve_header( while (type == GIT_OBJ_OFS_DELTA || type == GIT_OBJ_REF_DELTA) { curpos = base_offset; error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos); - git_mwindow_close(&w_curs); if (error < 0) return error; if (type != GIT_OBJ_OFS_DELTA && type != GIT_OBJ_REF_DELTA) @@ -585,7 +583,6 @@ static int pack_dependency_chain(git_dependency_chain *chain_out, elem->base_key = obj_offset; error = git_packfile_unpack_header(&size, &type, &p->mwf, &w_curs, &curpos); - git_mwindow_close(&w_curs); if (error < 0) goto on_error; @@ -1018,7 +1015,7 @@ static int packfile_open(struct git_pack_file *p) unsigned char *idx_sha1; if (p->index_version == -1 && pack_index_open(p) < 0) - return git_odb__error_notfound("failed to open packfile", NULL); + return git_odb__error_notfound("failed to open packfile", NULL, 0); /* if mwf opened by another thread, return now */ if (git_mutex_lock(&p->lock) < 0) @@ -1099,7 +1096,7 @@ int git_packfile__name(char **out, const char *path) path_len = strlen(path); if (path_len < strlen(".idx")) - return git_odb__error_notfound("invalid packfile path", NULL); + return git_odb__error_notfound("invalid packfile path", NULL, 0); if (git_buf_printf(&buf, "%.*s.pack", (int)(path_len - strlen(".idx")), path) < 0) return -1; @@ -1117,7 +1114,7 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) *pack_out = NULL; if (path_len < strlen(".idx")) - return git_odb__error_notfound("invalid packfile path", NULL); + return git_odb__error_notfound("invalid packfile path", NULL, 0); GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(*p), path_len); GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2); @@ -1143,7 +1140,7 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path) if (p_stat(p->pack_name, &st) < 0 || !S_ISREG(st.st_mode)) { git__free(p); - return git_odb__error_notfound("packfile not found", NULL); + return git_odb__error_notfound("packfile not found", NULL, 0); } /* ok, it looks sane as far as we can check without @@ -1344,7 +1341,7 @@ static int pack_entry_find_offset( } if (!found) - return git_odb__error_notfound("failed to find offset for pack entry", short_oid); + return git_odb__error_notfound("failed to find offset for pack entry", short_oid, len); if (found > 1) return git_odb__error_ambiguous("found multiple offsets for pack entry"); diff --git a/src/posix.c b/src/posix.c index c7201ba14..b3f1a1cd3 100644 --- a/src/posix.c +++ b/src/posix.c @@ -224,6 +224,13 @@ int git__page_size(size_t *page_size) return 0; } +int git__mmap_alignment(size_t *alignment) +{ + /* dummy; here we don't need any alignment anyway */ + *alignment = 4096; + return 0; +} + int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) { diff --git a/src/posix.h b/src/posix.h index 8785a4c99..f204751cf 100644 --- a/src/posix.h +++ b/src/posix.h @@ -109,6 +109,7 @@ extern int p_getcwd(char *buffer_out, size_t size); extern int p_rename(const char *from, const char *to); extern int git__page_size(size_t *page_size); +extern int git__mmap_alignment(size_t *page_size); /** * Platform-dependent methods diff --git a/src/push.c b/src/push.c index 3c9fa2f1b..0747259c8 100644 --- a/src/push.c +++ b/src/push.c @@ -374,9 +374,9 @@ static int enqueue_object( case GIT_OBJ_COMMIT: return 0; case GIT_OBJ_TREE: - return git_packbuilder_insert_tree(pb, &entry->oid); + return git_packbuilder_insert_tree(pb, entry->oid); default: - return git_packbuilder_insert(pb, &entry->oid, entry->filename); + return git_packbuilder_insert(pb, entry->oid, entry->filename); } } @@ -396,7 +396,7 @@ static int queue_differences( const git_tree_entry *d_entry = git_tree_entry_byindex(delta, j); int cmp = 0; - if (!git_oid__cmp(&b_entry->oid, &d_entry->oid)) + if (!git_oid__cmp(b_entry->oid, d_entry->oid)) goto loop; cmp = strcmp(b_entry->filename, d_entry->filename); @@ -407,15 +407,15 @@ static int queue_differences( git_tree_entry__is_tree(b_entry) && git_tree_entry__is_tree(d_entry)) { /* Add the right-hand entry */ - if ((error = git_packbuilder_insert(pb, &d_entry->oid, + if ((error = git_packbuilder_insert(pb, d_entry->oid, d_entry->filename)) < 0) goto on_error; /* Acquire the subtrees and recurse */ if ((error = git_tree_lookup(&b_child, - git_tree_owner(base), &b_entry->oid)) < 0 || + git_tree_owner(base), b_entry->oid)) < 0 || (error = git_tree_lookup(&d_child, - git_tree_owner(delta), &d_entry->oid)) < 0 || + git_tree_owner(delta), d_entry->oid)) < 0 || (error = queue_differences(b_child, d_child, pb)) < 0) goto on_error; diff --git a/src/refdb_fs.c b/src/refdb_fs.c index f6ed7201a..f978038e6 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -962,6 +962,7 @@ static int packed_write(refdb_fs_backend *backend) for (i = 0; i < git_sortedcache_entrycount(refcache); ++i) { struct packref *ref = git_sortedcache_entry(refcache, i); + assert(ref); if (packed_find_peel(backend, ref) < 0) goto fail; diff --git a/src/refs.c b/src/refs.c index a15e31b53..26c80021f 100644 --- a/src/refs.c +++ b/src/refs.c @@ -289,6 +289,9 @@ cleanup: "Could not use '%s' as valid reference name", git_buf_cstr(&name)); } + if (error == GIT_ENOTFOUND) + giterr_set(GITERR_REFERENCE, "no reference found for shorthand '%s'", refname); + git_buf_free(&name); git_buf_free(&refnamebuf); return error; diff --git a/src/settings.c b/src/settings.c index 88602bad0..0da19ea03 100644 --- a/src/settings.c +++ b/src/settings.c @@ -71,12 +71,18 @@ static int config_level_to_sysdir(int config_level) } extern char *git__user_agent; +extern char *git__ssl_ciphers; const char *git_libgit2__user_agent() { return git__user_agent; } +const char *git_libgit2__ssl_ciphers() +{ + return git__ssl_ciphers; +} + int git_libgit2_opts(int key, ...) { int error = 0; @@ -169,7 +175,7 @@ int git_libgit2_opts(int key, ...) } } #else - giterr_set(GITERR_NET, "Cannot set certificate locations: OpenSSL is not enabled"); + giterr_set(GITERR_NET, "cannot set certificate locations: OpenSSL is not enabled"); error = -1; #endif break; @@ -187,6 +193,22 @@ int git_libgit2_opts(int key, ...) git_object__strict_input_validation = (va_arg(ap, int) != 0); break; + case GIT_OPT_SET_SSL_CIPHERS: +#ifdef GIT_OPENSSL + { + git__free(git__ssl_ciphers); + git__ssl_ciphers = git__strdup(va_arg(ap, const char *)); + if (!git__ssl_ciphers) { + giterr_set_oom(); + error = -1; + } + } +#else + giterr_set(GITERR_NET, "cannot set custom ciphers: OpenSSL is not enabled"); + error = -1; +#endif + break; + default: giterr_set(GITERR_INVALID, "invalid option key"); error = -1; diff --git a/src/submodule.c b/src/submodule.c index 38db41529..c903cf939 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -80,7 +80,8 @@ static kh_inline int str_equal_no_trailing_slash(const char *a, const char *b) if (blen > 0 && b[blen - 1] == '/') blen--; - return (alen == blen && strncmp(a, b, alen) == 0); + return (alen == 0 && blen == 0) || + (alen == blen && strncmp(a, b, alen) == 0); } __KHASH_IMPL( @@ -1416,7 +1417,7 @@ static int submodule_update_head(git_submodule *submodule) git_tree_entry_bypath(&te, head, submodule->path) < 0) giterr_clear(); else - submodule_update_from_head_data(submodule, te->attr, &te->oid); + submodule_update_from_head_data(submodule, te->attr, git_tree_entry_id(te)); git_tree_entry_free(te); git_tree_free(head); diff --git a/src/transport.c b/src/transport.c index 5c65c7c06..327052fa3 100644 --- a/src/transport.c +++ b/src/transport.c @@ -35,6 +35,8 @@ static transport_definition transports[] = { { "file://", git_transport_local, NULL }, #ifdef GIT_SSH { "ssh://", git_transport_smart, &ssh_subtransport_definition }, + { "ssh+git://", git_transport_smart, &ssh_subtransport_definition }, + { "git+ssh://", git_transport_smart, &ssh_subtransport_definition }, #endif { NULL, 0, 0 } }; diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index 6363378ec..02e1ecf74 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -721,18 +721,39 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt) return 0; } -static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt) +static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, git_buf *data_pkt_buf) { git_pkt *pkt; - const char *line = data_pkt->data, *line_end; - size_t line_len = data_pkt->len; + const char *line, *line_end; + size_t line_len; int error; + int reading_from_buf = data_pkt_buf->size > 0; + + if (reading_from_buf) { + /* We had an existing partial packet, so add the new + * packet to the buffer and parse the whole thing */ + git_buf_put(data_pkt_buf, data_pkt->data, data_pkt->len); + line = data_pkt_buf->ptr; + line_len = data_pkt_buf->size; + } + else { + line = data_pkt->data; + line_len = data_pkt->len; + } while (line_len > 0) { error = git_pkt_parse_line(&pkt, line, &line_end, line_len); - if (error < 0) - return error; + if (error == GIT_EBUFS) { + /* Buffer the data when the inner packet is split + * across multiple sideband packets */ + if (!reading_from_buf) + git_buf_put(data_pkt_buf, line, line_len); + error = 0; + goto done; + } + else if (error < 0) + goto done; /* Advance in the buffer */ line_len -= (line_end - line); @@ -743,10 +764,15 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt) git_pkt_free(pkt); if (error < 0 && error != GIT_ITEROVER) - return error; + goto done; } - return 0; + error = 0; + +done: + if (reading_from_buf) + git_buf_consume(data_pkt_buf, line_end); + return error; } static int parse_report(transport_smart *transport, git_push *push) @@ -755,6 +781,7 @@ static int parse_report(transport_smart *transport, git_push *push) const char *line_end = NULL; gitno_buffer *buf = &transport->buffer; int error, recvd; + git_buf data_pkt_buf = GIT_BUF_INIT; for (;;) { if (buf->offset > 0) @@ -763,16 +790,21 @@ static int parse_report(transport_smart *transport, git_push *push) else error = GIT_EBUFS; - if (error < 0 && error != GIT_EBUFS) - return -1; + if (error < 0 && error != GIT_EBUFS) { + error = -1; + goto done; + } if (error == GIT_EBUFS) { - if ((recvd = gitno_recv(buf)) < 0) - return recvd; + if ((recvd = gitno_recv(buf)) < 0) { + error = recvd; + goto done; + } if (recvd == 0) { giterr_set(GITERR_NET, "early EOF"); - return GIT_EEOF; + error = GIT_EEOF; + goto done; } continue; } @@ -784,7 +816,7 @@ static int parse_report(transport_smart *transport, git_push *push) switch (pkt->type) { case GIT_PKT_DATA: /* This is a sideband packet which contains other packets */ - error = add_push_report_sideband_pkt(push, (git_pkt_data *)pkt); + error = add_push_report_sideband_pkt(push, (git_pkt_data *)pkt, &data_pkt_buf); break; case GIT_PKT_ERR: giterr_set(GITERR_NET, "report-status: Error reported: %s", @@ -805,12 +837,24 @@ static int parse_report(transport_smart *transport, git_push *push) git_pkt_free(pkt); /* add_push_report_pkt returns GIT_ITEROVER when it receives a flush */ - if (error == GIT_ITEROVER) - return 0; + if (error == GIT_ITEROVER) { + error = 0; + if (data_pkt_buf.size > 0) { + /* If there was data remaining in the pack data buffer, + * then the server sent a partial pkt-line */ + giterr_set(GITERR_NET, "Incomplete pack data pkt-line"); + error = GIT_ERROR; + } + goto done; + } - if (error < 0) - return error; + if (error < 0) { + goto done; + } } +done: + git_buf_free(&data_pkt_buf); + return error; } static int add_ref_from_push_spec(git_vector *refs, push_spec *push_spec) diff --git a/src/transports/ssh.c b/src/transports/ssh.c index 35739abe3..cfd573665 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -21,7 +21,8 @@ #define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) -static const char prefix_ssh[] = "ssh://"; +static const char *ssh_prefixes[] = { "ssh://", "ssh+git://", "git+ssh://" }; + static const char cmd_uploadpack[] = "git-upload-pack"; static const char cmd_receivepack[] = "git-receive-pack"; @@ -63,17 +64,24 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url) { char *repo; int len; + size_t i; - if (!git__prefixcmp(url, prefix_ssh)) { - url = url + strlen(prefix_ssh); - repo = strchr(url, '/'); - if (repo && repo[1] == '~') - ++repo; - } else { - repo = strchr(url, ':'); - if (repo) repo++; + for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) { + const char *p = ssh_prefixes[i]; + + if (!git__prefixcmp(url, p)) { + url = url + strlen(p); + repo = strchr(url, '/'); + if (repo && repo[1] == '~') + ++repo; + + goto done; + } } + repo = strchr(url, ':'); + if (repo) repo++; +done: if (!repo) { giterr_set(GITERR_NET, "Malformed git protocol URL"); return -1; @@ -500,6 +508,7 @@ static int _git_ssh_setup_conn( char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL; const char *default_port="22"; int auth_methods, error = 0; + size_t i; ssh_stream *s; git_cred *cred = NULL; LIBSSH2_SESSION* session=NULL; @@ -515,16 +524,22 @@ static int _git_ssh_setup_conn( s->session = NULL; s->channel = NULL; - if (!git__prefixcmp(url, prefix_ssh)) { - if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port)) < 0) - goto done; - } else { - if ((error = git_ssh_extract_url_parts(&host, &user, url)) < 0) - goto done; - port = git__strdup(default_port); - GITERR_CHECK_ALLOC(port); - } + for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) { + const char *p = ssh_prefixes[i]; + if (!git__prefixcmp(url, p)) { + if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port)) < 0) + goto done; + + goto post_extract; + } + } + if ((error = git_ssh_extract_url_parts(&host, &user, url)) < 0) + goto done; + port = git__strdup(default_port); + GITERR_CHECK_ALLOC(port); + +post_extract: if ((error = git_socket_stream_new(&s->io, host, port)) < 0 || (error = git_stream_connect(s->io)) < 0) goto done; diff --git a/src/tree.c b/src/tree.c index 48b9f121d..6ce460c6d 100644 --- a/src/tree.c +++ b/src/tree.c @@ -85,9 +85,10 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2) } /** - * Allocate either from the pool or from the system allocator + * Allocate a new self-contained entry, with enough space after it to + * store the filename and the id. */ -static git_tree_entry *alloc_entry_base(git_pool *pool, const char *filename, size_t filename_len) +static git_tree_entry *alloc_entry(const char *filename, size_t filename_len, const git_oid *id) { git_tree_entry *entry = NULL; size_t tree_len; @@ -95,44 +96,32 @@ static git_tree_entry *alloc_entry_base(git_pool *pool, const char *filename, si TREE_ENTRY_CHECK_NAMELEN(filename_len); if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) || - GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1)) + GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) || + GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, GIT_OID_RAWSZ)) return NULL; - entry = pool ? git_pool_malloc(pool, tree_len) : - git__malloc(tree_len); + entry = git__calloc(1, tree_len); if (!entry) return NULL; - memset(entry, 0x0, sizeof(git_tree_entry)); - memcpy(entry->filename, filename, filename_len); - entry->filename[filename_len] = 0; + { + char *filename_ptr; + void *id_ptr; + + filename_ptr = ((char *) entry) + sizeof(git_tree_entry); + memcpy(filename_ptr, filename, filename_len); + entry->filename = filename_ptr; + + id_ptr = filename_ptr + filename_len + 1; + git_oid_cpy(id_ptr, id); + entry->oid = id_ptr; + } + entry->filename_len = (uint16_t)filename_len; return entry; } -/** - * Allocate a tree entry, using the poolin the tree which owns - * it. This is useful when reading trees, so we don't allocate a ton - * of small strings but can use the pool. - */ -static git_tree_entry *alloc_entry_pooled(git_pool *pool, const char *filename, size_t filename_len) -{ - git_tree_entry *entry = NULL; - - if (!(entry = alloc_entry_base(pool, filename, filename_len))) - return NULL; - - entry->pooled = true; - - return entry; -} - -static git_tree_entry *alloc_entry(const char *filename) -{ - return alloc_entry_base(NULL, filename, strlen(filename)); -} - struct tree_key_search { const char *filename; uint16_t filename_len; @@ -174,7 +163,10 @@ static int homing_search_cmp(const void *key, const void *array_member) * around the area for our target file. */ static int tree_key_search( - size_t *at_pos, git_vector *entries, const char *filename, size_t filename_len) + size_t *at_pos, + const git_tree *tree, + const char *filename, + size_t filename_len) { struct tree_key_search ksearch; const git_tree_entry *entry; @@ -187,13 +179,15 @@ static int tree_key_search( /* Initial homing search; find an entry on the tree with * the same prefix as the filename we're looking for */ - if (git_vector_bsearch2(&homing, entries, &homing_search_cmp, &ksearch) < 0) + + if (git_array_search(&homing, + tree->entries, &homing_search_cmp, &ksearch) < 0) return GIT_ENOTFOUND; /* just a signal error; not passed back to user */ /* We found a common prefix. Look forward as long as * there are entries that share the common prefix */ - for (i = homing; i < entries->length; ++i) { - entry = entries->contents[i]; + for (i = homing; i < tree->entries.size; ++i) { + entry = git_array_get(tree->entries, i); if (homing_search_cmp(&ksearch, entry) < 0) break; @@ -213,7 +207,7 @@ static int tree_key_search( i = homing - 1; do { - entry = entries->contents[i]; + entry = git_array_get(tree->entries, i); if (homing_search_cmp(&ksearch, entry) > 0) break; @@ -234,7 +228,7 @@ static int tree_key_search( void git_tree_entry_free(git_tree_entry *entry) { - if (entry == NULL || entry->pooled) + if (entry == NULL) return; git__free(entry); @@ -242,36 +236,26 @@ void git_tree_entry_free(git_tree_entry *entry) int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source) { - size_t total_size; - git_tree_entry *copy; + git_tree_entry *cpy; assert(source); - GITERR_CHECK_ALLOC_ADD(&total_size, sizeof(git_tree_entry), source->filename_len); - GITERR_CHECK_ALLOC_ADD(&total_size, total_size, 1); + cpy = alloc_entry(source->filename, source->filename_len, source->oid); + if (cpy == NULL) + return -1; - copy = git__malloc(total_size); - GITERR_CHECK_ALLOC(copy); + cpy->attr = source->attr; - memcpy(copy, source, total_size); - - copy->pooled = 0; - - *dest = copy; + *dest = cpy; return 0; } void git_tree__free(void *_tree) { git_tree *tree = _tree; - size_t i; - git_tree_entry *e; - git_vector_foreach(&tree->entries, i, e) - git_tree_entry_free(e); - - git_vector_free(&tree->entries); - git_pool_clear(&tree->pool); + git_odb_object_free(tree->odb_obj); + git_array_clear(tree->entries); git__free(tree); } @@ -294,7 +278,7 @@ const char *git_tree_entry_name(const git_tree_entry *entry) const git_oid *git_tree_entry_id(const git_tree_entry *entry) { assert(entry); - return &entry->oid; + return entry->oid; } git_otype git_tree_entry_type(const git_tree_entry *entry) @@ -315,7 +299,7 @@ int git_tree_entry_to_object( const git_tree_entry *entry) { assert(entry && object_out); - return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY); + return git_object_lookup(object_out, repo, entry->oid, GIT_OBJ_ANY); } static const git_tree_entry *entry_fromname( @@ -323,13 +307,10 @@ static const git_tree_entry *entry_fromname( { size_t idx; - /* be safe when we cast away constness - i.e. don't trigger a sort */ - assert(git_vector_is_sorted(&tree->entries)); - - if (tree_key_search(&idx, (git_vector *)&tree->entries, name, name_len) < 0) + if (tree_key_search(&idx, tree, name, name_len) < 0) return NULL; - return git_vector_get(&tree->entries, idx); + return git_array_get(tree->entries, idx); } const git_tree_entry *git_tree_entry_byname( @@ -344,7 +325,7 @@ const git_tree_entry *git_tree_entry_byindex( const git_tree *tree, size_t idx) { assert(tree); - return git_vector_get(&tree->entries, idx); + return git_array_get(tree->entries, idx); } const git_tree_entry *git_tree_entry_byid( @@ -355,8 +336,8 @@ const git_tree_entry *git_tree_entry_byid( assert(tree); - git_vector_foreach(&tree->entries, i, e) { - if (memcmp(&e->oid.id, &id->id, sizeof(id->id)) == 0) + git_array_foreach(tree->entries, i, e) { + if (memcmp(&e->oid->id, &id->id, sizeof(id->id)) == 0) return e; } @@ -365,7 +346,6 @@ const git_tree_entry *git_tree_entry_byid( int git_tree__prefix_position(const git_tree *tree, const char *path) { - const git_vector *entries = &tree->entries; struct tree_key_search ksearch; size_t at_pos, path_len; @@ -378,21 +358,20 @@ int git_tree__prefix_position(const git_tree *tree, const char *path) ksearch.filename = path; ksearch.filename_len = (uint16_t)path_len; - /* be safe when we cast away constness - i.e. don't trigger a sort */ - assert(git_vector_is_sorted(&tree->entries)); - /* Find tree entry with appropriate prefix */ - git_vector_bsearch2( - &at_pos, (git_vector *)entries, &homing_search_cmp, &ksearch); + git_array_search( + &at_pos, tree->entries, &homing_search_cmp, &ksearch); - for (; at_pos < entries->length; ++at_pos) { - const git_tree_entry *entry = entries->contents[at_pos]; + for (; at_pos < tree->entries.size; ++at_pos) { + const git_tree_entry *entry = git_array_get(tree->entries, at_pos); if (homing_search_cmp(&ksearch, entry) < 0) break; } for (; at_pos > 0; --at_pos) { - const git_tree_entry *entry = entries->contents[at_pos - 1]; + const git_tree_entry *entry = + git_array_get(tree->entries, at_pos - 1); + if (homing_search_cmp(&ksearch, entry) > 0) break; } @@ -403,7 +382,7 @@ int git_tree__prefix_position(const git_tree *tree, const char *path) size_t git_tree_entrycount(const git_tree *tree) { assert(tree); - return tree->entries.length; + return tree->entries.size; } unsigned int git_treebuilder_entrycount(git_treebuilder *bld) @@ -444,13 +423,18 @@ static int parse_mode(unsigned int *modep, const char *buffer, const char **buff int git_tree__parse(void *_tree, git_odb_object *odb_obj) { git_tree *tree = _tree; - const char *buffer = git_odb_object_data(odb_obj); - const char *buffer_end = buffer + git_odb_object_size(odb_obj); + const char *buffer; + const char *buffer_end; - git_pool_init(&tree->pool, 1); - if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < 0) + if (git_odb_object_dup(&tree->odb_obj, odb_obj) < 0) return -1; + buffer = git_odb_object_data(tree->odb_obj); + buffer_end = buffer + git_odb_object_size(tree->odb_obj); + + git_array_init_to_size(tree->entries, DEFAULT_TREE_SIZE); + GITERR_CHECK_ARRAY(tree->entries); + while (buffer < buffer_end) { git_tree_entry *entry; size_t filename_len; @@ -464,27 +448,21 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj) return tree_error("Failed to parse tree. Object is corrupted", NULL); filename_len = nul - buffer; - /** Allocate the entry and store it in the entries vector */ + /* Allocate the entry */ { - entry = alloc_entry_pooled(&tree->pool, buffer, filename_len); + entry = git_array_alloc(tree->entries); GITERR_CHECK_ALLOC(entry); - if (git_vector_insert(&tree->entries, entry) < 0) - return -1; - entry->attr = attr; + entry->filename_len = filename_len; + entry->filename = buffer; + entry->oid = (git_oid *) ((char *) buffer + filename_len + 1); } - /* Advance to the ID just after the path */ buffer += filename_len + 1; - - git_oid_fromraw(&entry->oid, (const unsigned char *)buffer); buffer += GIT_OID_RAWSZ; } - /* The tree is sorted by definition. Bad inputs give bad outputs */ - tree->entries.flags |= GIT_VECTOR_SORTED; - return 0; } @@ -517,10 +495,9 @@ static int append_entry( if (!valid_entry_name(bld->repo, filename)) return tree_error("Failed to insert entry. Invalid name for a tree entry", filename); - entry = alloc_entry(filename); + entry = alloc_entry(filename, strlen(filename), id); GITERR_CHECK_ALLOC(entry); - git_oid_cpy(&entry->oid, id); entry->attr = (uint16_t)filemode; git_strmap_insert(bld->map, entry->filename, entry, error); @@ -709,10 +686,10 @@ int git_treebuilder_new( if (source != NULL) { git_tree_entry *entry_src; - git_vector_foreach(&source->entries, i, entry_src) { + git_array_foreach(source->entries, i, entry_src) { if (append_entry( bld, entry_src->filename, - &entry_src->oid, + entry_src->oid, entry_src->attr) < 0) goto on_error; } @@ -764,8 +741,9 @@ int git_treebuilder_insert( pos = git_strmap_lookup_index(bld->map, filename); if (git_strmap_valid_index(bld->map, pos)) { entry = git_strmap_value_at(bld->map, pos); + git_oid_cpy((git_oid *) entry->oid, id); } else { - entry = alloc_entry(filename); + entry = alloc_entry(filename, strlen(filename), id); GITERR_CHECK_ALLOC(entry); git_strmap_insert(bld->map, entry->filename, entry, error); @@ -777,7 +755,6 @@ int git_treebuilder_insert( } } - git_oid_cpy(&entry->oid, id); entry->attr = filemode; if (entry_out) @@ -848,19 +825,20 @@ int git_treebuilder_write(git_oid *oid, git_treebuilder *bld) git_buf_printf(&tree, "%o ", entry->attr); git_buf_put(&tree, entry->filename, entry->filename_len + 1); - git_buf_put(&tree, (char *)entry->oid.id, GIT_OID_RAWSZ); + git_buf_put(&tree, (char *)entry->oid->id, GIT_OID_RAWSZ); if (git_buf_oom(&tree)) error = -1; } - git_vector_free(&entries); if (!error && !(error = git_repository_odb__weakptr(&odb, bld->repo))) error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE); git_buf_free(&tree); + git_vector_free(&entries); + return error; } @@ -960,7 +938,7 @@ int git_tree_entry_bypath( return git_tree_entry_dup(entry_out, entry); } - if (git_tree_lookup(&subtree, root->object.repo, &entry->oid) < 0) + if (git_tree_lookup(&subtree, root->object.repo, entry->oid) < 0) return -1; error = git_tree_entry_bypath( @@ -984,7 +962,7 @@ static int tree_walk( size_t i; const git_tree_entry *entry; - git_vector_foreach(&tree->entries, i, entry) { + git_array_foreach(tree->entries, i, entry) { if (preorder) { error = callback(path->ptr, entry, payload); if (error < 0) { /* negative value stops iteration */ @@ -1001,7 +979,7 @@ static int tree_walk( git_tree *subtree; size_t path_len = git_buf_len(path); - error = git_tree_lookup(&subtree, tree->object.repo, &entry->oid); + error = git_tree_lookup(&subtree, tree->object.repo, entry->oid); if (error < 0) break; diff --git a/src/tree.h b/src/tree.h index 914d788c8..5e7a66e04 100644 --- a/src/tree.h +++ b/src/tree.h @@ -17,15 +17,14 @@ struct git_tree_entry { uint16_t attr; uint16_t filename_len; - git_oid oid; - bool pooled; - char filename[GIT_FLEX_ARRAY]; + const git_oid *oid; + const char *filename; }; struct git_tree { git_object object; - git_vector entries; - git_pool pool; + git_odb_object *odb_obj; + git_array_t(git_tree_entry) entries; }; struct git_treebuilder { diff --git a/src/unix/map.c b/src/unix/map.c index 72abb3418..c55ad1aa7 100644 --- a/src/unix/map.c +++ b/src/unix/map.c @@ -24,6 +24,11 @@ int git__page_size(size_t *page_size) return 0; } +int git__mmap_alignment(size_t *alignment) +{ + return git__page_size(alignment); +} + int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) { int mprot = PROT_READ; diff --git a/src/win32/map.c b/src/win32/map.c index a99c30f7e..03a3646a6 100644 --- a/src/win32/map.c +++ b/src/win32/map.c @@ -17,22 +17,41 @@ static DWORD get_page_size(void) if (!page_size) { GetSystemInfo(&sys); - page_size = sys.dwAllocationGranularity; + page_size = sys.dwPageSize; } return page_size; } +static DWORD get_allocation_granularity(void) +{ + static DWORD granularity; + SYSTEM_INFO sys; + + if (!granularity) { + GetSystemInfo(&sys); + granularity = sys.dwAllocationGranularity; + } + + return granularity; +} + int git__page_size(size_t *page_size) { *page_size = get_page_size(); return 0; } +int git__mmap_alignment(size_t *page_size) +{ + *page_size = get_allocation_granularity(); + return 0; +} + int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) { HANDLE fh = (HANDLE)_get_osfhandle(fd); - DWORD page_size = get_page_size(); + DWORD alignment = get_allocation_granularity(); DWORD fmap_prot = 0; DWORD view_prot = 0; DWORD off_low = 0; @@ -62,12 +81,12 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs if (prot & GIT_PROT_READ) view_prot |= FILE_MAP_READ; - page_start = (offset / page_size) * page_size; + page_start = (offset / alignment) * alignment; page_offset = offset - page_start; - if (page_offset != 0) { /* offset must be multiple of page size */ + if (page_offset != 0) { /* offset must be multiple of the allocation granularity */ errno = EINVAL; - giterr_set(GITERR_OS, "Failed to mmap. Offset must be multiple of page size"); + giterr_set(GITERR_OS, "Failed to mmap. Offset must be multiple of allocation granularity"); return -1; } diff --git a/src/xdiff/xprepare.c b/src/xdiff/xprepare.c index 63a22c630..13b55aba7 100644 --- a/src/xdiff/xprepare.c +++ b/src/xdiff/xprepare.c @@ -301,10 +301,11 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdl_free_ctx(&xe->xdf2); xdl_free_ctx(&xe->xdf1); + xdl_free_classifier(&cf); return -1; } - if (!(xpp->flags & XDF_HISTOGRAM_DIFF)) + if (XDF_DIFF_ALG(xpp->flags) != XDF_HISTOGRAM_DIFF) xdl_free_classifier(&cf); return 0; diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c index 27fed2539..91bf984a1 100644 --- a/tests/attr/ignore.c +++ b/tests/attr/ignore.c @@ -252,3 +252,16 @@ void test_attr_ignore__dont_ignore_files_for_folder(void) if (cl_repo_get_bool(g_repo, "core.ignorecase")) assert_is_ignored(false, "dir/TeSt"); } + +void test_attr_ignore__symlink_to_outside(void) +{ +#ifdef GIT_WIN32 + cl_skip(); +#endif + + cl_git_rewritefile("attr/.gitignore", "symlink\n"); + cl_git_mkfile("target", "target"); + cl_git_pass(p_symlink("../target", "attr/symlink")); + assert_is_ignored(true, "symlink"); + assert_is_ignored(true, "lala/../symlink"); +} diff --git a/tests/commit/parse.c b/tests/commit/parse.c index 838cfb467..297fccc6b 100644 --- a/tests/commit/parse.c +++ b/tests/commit/parse.c @@ -498,6 +498,21 @@ committer Ben Burkert 1358451456 -0800\n\ \n\ a simple commit which works\n"; + const char *oneline_signature = "tree 51832e6397b30309c8bcad9c55fa6ae67778f378\n\ +parent a1b6decaaac768b5e01e1b5dbf5b2cc081bed1eb\n\ +author Some User 1454537944 -0700\n\ +committer Some User 1454537944 -0700\n\ +gpgsig bad\n\ +\n\ +corrupt signature\n"; + + const char *oneline_data = "tree 51832e6397b30309c8bcad9c55fa6ae67778f378\n\ +parent a1b6decaaac768b5e01e1b5dbf5b2cc081bed1eb\n\ +author Some User 1454537944 -0700\n\ +committer Some User 1454537944 -0700\n\ +\n\ +corrupt signature\n"; + cl_git_pass(git_repository_odb__weakptr(&odb, g_repo)); cl_git_pass(git_odb_write(&commit_id, odb, passing_commit_cases[4], strlen(passing_commit_cases[4]), GIT_OBJ_COMMIT)); @@ -523,6 +538,15 @@ a simple commit which works\n"; cl_git_fail_with(GIT_ENOTFOUND, git_commit_extract_signature(&signature, &signed_data, g_repo, &commit_id, NULL)); cl_assert_equal_i(GITERR_OBJECT, giterr_last()->klass); + /* Parse the commit with a single-line signature */ + git_buf_clear(&signature); + git_buf_clear(&signed_data); + cl_git_pass(git_odb_write(&commit_id, odb, oneline_signature, strlen(oneline_signature), GIT_OBJ_COMMIT)); + cl_git_pass(git_commit_extract_signature(&signature, &signed_data, g_repo, &commit_id, NULL)); + cl_assert_equal_s("bad", signature.ptr); + cl_assert_equal_s(oneline_data, signed_data.ptr); + + git_buf_free(&signature); git_buf_free(&signed_data); diff --git a/tests/config/multivar.c b/tests/config/multivar.c index 015008992..d1b8c4cda 100644 --- a/tests/config/multivar.c +++ b/tests/config/multivar.c @@ -163,7 +163,7 @@ void test_config_multivar__add_new(void) cl_git_pass(git_config_open_ondisk(&cfg, "config/config11")); - cl_git_pass(git_config_set_multivar(cfg, var, "", "variable")); + cl_git_pass(git_config_set_multivar(cfg, var, "$^", "variable")); n = 0; cl_git_pass(git_config_get_multivar_foreach(cfg, var, NULL, cb, &n)); cl_assert_equal_i(n, 1); diff --git a/tests/config/write.c b/tests/config/write.c index e634aa326..56ef2e9fb 100644 --- a/tests/config/write.c +++ b/tests/config/write.c @@ -695,3 +695,30 @@ void test_config_write__locking(void) git_config_free(cfg); } + +void test_config_write__repeated(void) +{ + const char *filename = "config-repeated"; + git_config *cfg; + git_buf result = GIT_BUF_INIT; + const char *expected = "[sample \"prefix\"]\n\ +\tsetting1 = someValue1\n\ +\tsetting2 = someValue2\n\ +\tsetting3 = someValue3\n\ +\tsetting4 = someValue4\n\ +"; + cl_git_pass(git_config_open_ondisk(&cfg, filename)); + cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting1", "someValue1")); + cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting2", "someValue2")); + cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting3", "someValue3")); + cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting4", "someValue4")); + git_config_free(cfg); + + cl_git_pass(git_config_open_ondisk(&cfg, filename)); + + cl_git_pass(git_futils_readbuffer(&result, filename)); + cl_assert_equal_s(expected, result.ptr); + git_buf_free(&result); + + git_config_free(cfg); +} diff --git a/tests/core/array.c b/tests/core/array.c new file mode 100644 index 000000000..8e626a506 --- /dev/null +++ b/tests/core/array.c @@ -0,0 +1,57 @@ +#include "clar_libgit2.h" +#include "array.h" + +static int int_lookup(const void *k, const void *a) +{ + const int *one = (const int *)k; + int *two = (int *)a; + + return *one - *two; +} + +#define expect_pos(k, n, ret) \ + key = (k); \ + cl_assert_equal_i((ret), \ + git_array_search(&p, integers, int_lookup, &key)); \ + cl_assert_equal_i((n), p); + +void test_core_array__bsearch2(void) +{ + git_array_t(int) integers = GIT_ARRAY_INIT; + int *i, key; + size_t p; + + i = git_array_alloc(integers); *i = 2; + i = git_array_alloc(integers); *i = 3; + i = git_array_alloc(integers); *i = 5; + i = git_array_alloc(integers); *i = 7; + i = git_array_alloc(integers); *i = 7; + i = git_array_alloc(integers); *i = 8; + i = git_array_alloc(integers); *i = 13; + i = git_array_alloc(integers); *i = 21; + i = git_array_alloc(integers); *i = 25; + i = git_array_alloc(integers); *i = 42; + i = git_array_alloc(integers); *i = 69; + i = git_array_alloc(integers); *i = 121; + i = git_array_alloc(integers); *i = 256; + i = git_array_alloc(integers); *i = 512; + i = git_array_alloc(integers); *i = 513; + i = git_array_alloc(integers); *i = 514; + i = git_array_alloc(integers); *i = 516; + i = git_array_alloc(integers); *i = 516; + i = git_array_alloc(integers); *i = 517; + + /* value to search for, expected position, return code */ + expect_pos(3, 1, GIT_OK); + expect_pos(2, 0, GIT_OK); + expect_pos(1, 0, GIT_ENOTFOUND); + expect_pos(25, 8, GIT_OK); + expect_pos(26, 9, GIT_ENOTFOUND); + expect_pos(42, 9, GIT_OK); + expect_pos(50, 10, GIT_ENOTFOUND); + expect_pos(68, 10, GIT_ENOTFOUND); + expect_pos(256, 12, GIT_OK); + + git_array_clear(integers); +} + diff --git a/tests/core/stream.c b/tests/core/stream.c index ace6a05da..0cbf44230 100644 --- a/tests/core/stream.c +++ b/tests/core/stream.c @@ -33,8 +33,12 @@ void test_core_stream__register_tls(void) cl_git_pass(git_stream_register_tls(NULL)); error = git_tls_stream_new(&stream, "localhost", "443"); - /* We don't have arbitrary TLS stream support on Windows */ -#if GIT_WIN32 + /* We don't have arbitrary TLS stream support on Windows + * or when openssl support is disabled (except on OSX + * with Security framework). + */ +#if defined(GIT_WIN32) || \ + (!defined(GIT_SECURE_TRANSPORT) && !defined(GIT_OPENSSL)) cl_git_fail_with(-1, error); #else cl_git_pass(error); diff --git a/tests/diff/iterator.c b/tests/diff/iterator.c index 8417e8ed4..25a23eda7 100644 --- a/tests/diff/iterator.c +++ b/tests/diff/iterator.c @@ -268,7 +268,7 @@ static void check_tree_entry( cl_git_pass(git_iterator_current_tree_entry(&te, i)); cl_assert(te); - cl_assert(git_oid_streq(&te->oid, oid) == 0); + cl_assert(git_oid_streq(te->oid, oid) == 0); cl_git_pass(git_iterator_current(&ie, i)); cl_git_pass(git_buf_sets(&path, ie->path)); diff --git a/tests/index/racy.c b/tests/index/racy.c index 68aa46007..1768f5efd 100644 --- a/tests/index/racy.c +++ b/tests/index/racy.c @@ -105,8 +105,8 @@ static void setup_race(void) { git_buf path = GIT_BUF_INIT; git_index *index; - const git_index_entry *entry; - int i, found_race = 0; + git_index_entry *entry; + struct stat st; /* Make sure we do have a timestamp */ cl_git_pass(git_repository_index__weakptr(&index, g_repo)); @@ -114,27 +114,20 @@ static void setup_race(void) cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "A")); - /* Make sure writing the file, adding and rewriting happen in the same second */ - for (i = 0; i < 10; i++) { - struct stat st; - cl_git_mkfile(path.ptr, "A"); + cl_git_mkfile(path.ptr, "A"); + cl_git_pass(git_index_add_bypath(index, "A")); - cl_git_pass(git_index_add_bypath(index, "A")); - cl_git_mkfile(path.ptr, "B"); - cl_git_pass(git_index_write(index)); + cl_git_mkfile(path.ptr, "B"); + cl_git_pass(git_index_write(index)); - cl_git_mkfile(path.ptr, ""); + cl_git_mkfile(path.ptr, ""); - cl_git_pass(p_stat(path.ptr, &st)); - cl_assert(entry = git_index_get_bypath(index, "A", 0)); - if (entry->mtime.seconds == (int32_t) st.st_mtime) { - found_race = 1; - break; - } - } + cl_git_pass(p_stat(path.ptr, &st)); + cl_assert(entry = (git_index_entry *)git_index_get_bypath(index, "A", 0)); - if (!found_race) - cl_fail("failed to find race after 10 attempts"); + /* force a race */ + entry->mtime.seconds = st.st_mtime; + entry->mtime.nanoseconds = st.st_mtime_nsec; git_buf_free(&path); } diff --git a/tests/object/tree/attributes.c b/tests/object/tree/attributes.c index 413514c48..8654dfa31 100644 --- a/tests/object/tree/attributes.c +++ b/tests/object/tree/attributes.c @@ -82,6 +82,7 @@ void test_object_tree_attributes__normalize_attributes_when_creating_a_tree_from cl_git_pass(git_treebuilder_new(&builder, repo, tree)); entry = git_treebuilder_get(builder, "old_mode.txt"); + cl_assert(entry != NULL); cl_assert_equal_i( GIT_FILEMODE_BLOB, git_tree_entry_filemode(entry)); @@ -92,6 +93,7 @@ void test_object_tree_attributes__normalize_attributes_when_creating_a_tree_from cl_git_pass(git_tree_lookup(&tree, repo, &tid2)); entry = git_tree_entry_byname(tree, "old_mode.txt"); + cl_assert(entry != NULL); cl_assert_equal_i( GIT_FILEMODE_BLOB, git_tree_entry_filemode(entry)); diff --git a/tests/online/badssl.c b/tests/online/badssl.c index 12badbda3..66b090df4 100644 --- a/tests/online/badssl.c +++ b/tests/online/badssl.c @@ -36,3 +36,11 @@ void test_online_badssl__self_signed(void) cl_git_fail_with(GIT_ECERTIFICATE, git_clone(&g_repo, "https://self-signed.badssl.com/fake.git", "./fake", NULL)); } + +void test_online_badssl__old_cipher(void) +{ + if (!g_has_ssl) + cl_skip(); + + cl_git_fail(git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", NULL)); +} diff --git a/tests/refs/create.c b/tests/refs/create.c index b96d0c90a..6d5a5f1f6 100644 --- a/tests/refs/create.c +++ b/tests/refs/create.c @@ -19,7 +19,7 @@ void test_refs_create__cleanup(void) { cl_git_sandbox_cleanup(); - cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 0)); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1)); } void test_refs_create__symbolic(void) @@ -122,7 +122,7 @@ void test_refs_create__oid(void) } /* Can by default create a reference that targets at an unknown id */ -void test_refs_create__oid_unknown_succeeds_by_default(void) +void test_refs_create__oid_unknown_succeeds_without_strict(void) { git_reference *new_reference, *looked_up_ref; git_oid id; @@ -131,6 +131,8 @@ void test_refs_create__oid_unknown_succeeds_by_default(void) git_oid_fromstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644"); + cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 0)); + /* Create and write the new object id reference */ cl_git_pass(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL)); git_reference_free(new_reference); @@ -141,7 +143,7 @@ void test_refs_create__oid_unknown_succeeds_by_default(void) } /* Strict object enforcement enforces valid object id */ -void test_refs_create__oid_unknown_fails_strict_mode(void) +void test_refs_create__oid_unknown_fails_by_default(void) { git_reference *new_reference, *looked_up_ref; git_oid id; @@ -150,8 +152,6 @@ void test_refs_create__oid_unknown_fails_strict_mode(void) git_oid_fromstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644"); - cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1)); - /* Create and write the new object id reference */ cl_git_fail(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL)); diff --git a/tests/refs/lookup.c b/tests/refs/lookup.c index d076e491f..456d0d2a8 100644 --- a/tests/refs/lookup.c +++ b/tests/refs/lookup.c @@ -58,3 +58,11 @@ void test_refs_lookup__namespace(void) error = git_reference_lookup(&ref, g_repo, "refs/heads/"); cl_assert_equal_i(error, GIT_EINVALIDSPEC); } + +void test_refs_lookup__dwim_notfound(void) +{ + git_reference *ref; + + cl_git_fail_with(GIT_ENOTFOUND, git_reference_dwim(&ref, g_repo, "idontexist")); + cl_assert_equal_s("no reference found for shorthand 'idontexist'", giterr_last()->message); +} diff --git a/tests/repo/iterator.c b/tests/repo/iterator.c index c18e24a4f..6b5795b9c 100644 --- a/tests/repo/iterator.c +++ b/tests/repo/iterator.c @@ -1020,6 +1020,11 @@ void test_repo_iterator__unreadable_dir(void) if (!cl_is_chmod_supported()) return; +#ifndef GIT_WIN32 + if (geteuid() == 0) + cl_skip(); +#endif + g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_must_pass(p_mkdir("empty_standard_repo/r", 0777)); diff --git a/tests/reset/hard.c b/tests/reset/hard.c index 0c0af914c..e461f8093 100644 --- a/tests/reset/hard.c +++ b/tests/reset/hard.c @@ -122,9 +122,9 @@ static void unmerged_index_init(git_index *index, int entries) int write_theirs = 4; git_oid ancestor, ours, theirs; - git_oid_fromstr(&ancestor, "6bb0d9f700543ba3d318ba7075fc3bd696b4287b"); - git_oid_fromstr(&ours, "b19a1e93bec1317dc6097229e12afaffbfa74dc2"); - git_oid_fromstr(&theirs, "950b81b7eee953d050aa05a641f8e056c85dd1bd"); + git_oid_fromstr(&ancestor, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a"); + git_oid_fromstr(&ours, "32504b727382542f9f089e24fddac5e78533e96c"); + git_oid_fromstr(&theirs, "061d42a44cacde5726057b67558821d95db96f19"); cl_git_rewritefile("status/conflicting_file", "conflicting file\n"); diff --git a/tests/status/worktree.c b/tests/status/worktree.c index fc4afc6be..5d3b4d55e 100644 --- a/tests/status/worktree.c +++ b/tests/status/worktree.c @@ -657,7 +657,7 @@ void test_status_worktree__conflict_has_no_oid(void) entry.mode = 0100644; entry.path = "modified_file"; - git_oid_fromstr(&entry.id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + git_oid_fromstr(&entry.id, "452e4244b5d083ddf0460acf1ecc74db9dcfa11a"); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_conflict_add(index, &entry, &entry, &entry)); @@ -1006,6 +1006,9 @@ void test_status_worktree__unreadable(void) git_status_options opts = GIT_STATUS_OPTIONS_INIT; status_entry_counts counts = {0}; + if (geteuid() == 0) + cl_skip(); + /* Create directory with no read permission */ cl_git_pass(git_futils_mkdir_r("empty_standard_repo/no_permission", 0777)); cl_git_mkfile("empty_standard_repo/no_permission/foo", "dummy"); diff --git a/tests/transport/register.c b/tests/transport/register.c index ea917d5d3..97aae6b20 100644 --- a/tests/transport/register.c +++ b/tests/transport/register.c @@ -40,15 +40,23 @@ void test_transport_register__custom_transport_error_remove_non_existing(void) void test_transport_register__custom_transport_ssh(void) { + const char *urls[] = { + "ssh://somehost:somepath", + "ssh+git://somehost:somepath", + "git+ssh://somehost:somepath", + "git@somehost:somepath", + }; git_transport *transport; + unsigned i; + for (i = 0; i < ARRAY_SIZE(urls); i++) { #ifndef GIT_SSH - cl_git_fail_with(git_transport_new(&transport, NULL, "ssh://somehost:somepath"), -1); - cl_git_fail_with(git_transport_new(&transport, NULL, "git@somehost:somepath"), -1); + cl_git_fail_with(git_transport_new(&transport, NULL, urls[i]), -1); #else - cl_git_pass(git_transport_new(&transport, NULL, "git@somehost:somepath")); - transport->free(transport); + cl_git_pass(git_transport_new(&transport, NULL, urls[i])); + transport->free(transport); #endif + } cl_git_pass(git_transport_register("ssh", dummy_transport, NULL)); @@ -58,11 +66,12 @@ void test_transport_register__custom_transport_ssh(void) cl_git_pass(git_transport_unregister("ssh")); + for (i = 0; i < ARRAY_SIZE(urls); i++) { #ifndef GIT_SSH - cl_git_fail_with(git_transport_new(&transport, NULL, "ssh://somehost:somepath"), -1); - cl_git_fail_with(git_transport_new(&transport, NULL, "git@somehost:somepath"), -1); + cl_git_fail_with(git_transport_new(&transport, NULL, urls[i]), -1); #else - cl_git_pass(git_transport_new(&transport, NULL, "git@somehost:somepath")); - transport->free(transport); + cl_git_pass(git_transport_new(&transport, NULL, urls[i])); + transport->free(transport); #endif + } }