diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | src/diff_generate.c | 26 | ||||
-rw-r--r-- | src/integer.h | 31 | ||||
-rw-r--r-- | src/repository.c | 24 | ||||
-rw-r--r-- | src/submodule.c | 41 | ||||
-rw-r--r-- | src/submodule.h | 18 | ||||
-rw-r--r-- | src/transports/winhttp.c | 75 | ||||
-rw-r--r-- | src/util.c | 14 | ||||
-rw-r--r-- | tests/online/badssl.c | 9 |
9 files changed, 162 insertions, 78 deletions
@@ -4,8 +4,8 @@ libgit2 - the Git linkable library | Build Status | | | ------------ | - | | **master** branch CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush) | +| **v1.1 branch** CI builds | [![CI Build](https://github.com/libgit2/libgit2/workflows/CI%20Build/badge.svg?branch=maint%2Fv1.1&event=push)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22CI+Build%22+event%3Apush+branch%3Amaint%2Fv1.1) | | **v1.0 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v1.0)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v1.0) | -| **v0.28 branch** CI builds | [![Azure Pipelines Build Status](https://dev.azure.com/libgit2/libgit2/_apis/build/status/libgit2?branchName=maint/v0.28)](https://dev.azure.com/libgit2/libgit2/_build/latest?definitionId=7&branchName=maint/v0.28) | | **Nightly** builds | [![Nightly Build](https://github.com/libgit2/libgit2/workflows/Nightly%20Build/badge.svg)](https://github.com/libgit2/libgit2/actions?query=workflow%3A%22Nightly+Build%22) [![Coverity Scan Status](https://scan.coverity.com/projects/639/badge.svg)](https://scan.coverity.com/projects/639) | `libgit2` is a portable, pure C implementation of the Git core methods diff --git a/src/diff_generate.c b/src/diff_generate.c index 745e5ae1b..f05ae3713 100644 --- a/src/diff_generate.c +++ b/src/diff_generate.c @@ -680,6 +680,8 @@ typedef struct { git_iterator *new_iter; const git_index_entry *oitem; const git_index_entry *nitem; + git_strmap *submodule_cache; + bool submodule_cache_initialized; } diff_in_progress; #define MODE_BITS_MASK 0000777 @@ -694,6 +696,7 @@ static int maybe_modified_submodule( git_submodule *sub; unsigned int sm_status = 0; git_submodule_ignore_t ign = diff->base.opts.ignore_submodules; + git_strmap *submodule_cache = NULL; *status = GIT_DELTA_UNMODIFIED; @@ -701,8 +704,23 @@ static int maybe_modified_submodule( ign == GIT_SUBMODULE_IGNORE_ALL) return 0; - if ((error = git_submodule_lookup( - &sub, diff->base.repo, info->nitem->path)) < 0) { + if (diff->base.repo->submodule_cache != NULL) { + submodule_cache = diff->base.repo->submodule_cache; + } else { + if (!info->submodule_cache_initialized) { + info->submodule_cache_initialized = true; + /* + * Try to cache the submodule information to avoid having to parse it for + * every submodule. It is okay if it fails, the cache will still be NULL + * and the submodules will be attempted to be looked up individually. + */ + git_submodule_cache_init(&info->submodule_cache, diff->base.repo); + } + submodule_cache = info->submodule_cache; + } + + if ((error = git_submodule__lookup_with_cache( + &sub, diff->base.repo, info->nitem->path, submodule_cache)) < 0) { /* GIT_EEXISTS means dir with .git in it was found - ignore it */ if (error == GIT_EEXISTS) { @@ -1192,7 +1210,7 @@ int git_diff__from_iterators( const git_diff_options *opts) { git_diff_generated *diff; - diff_in_progress info; + diff_in_progress info = {0}; int error = 0; *out = NULL; @@ -1260,6 +1278,8 @@ cleanup: *out = &diff->base; else git_diff_free(&diff->base); + if (info.submodule_cache) + git_submodule_cache_free(info.submodule_cache); return error; } diff --git a/src/integer.h b/src/integer.h index 067c0be1f..026a1fac0 100644 --- a/src/integer.h +++ b/src/integer.h @@ -77,6 +77,11 @@ GIT_INLINE(int) git__is_int(long long p) # define git__sub_int_overflow(out, one, two) \ __builtin_ssub_overflow(one, two, out) +# define git__add_int64_overflow(out, one, two) \ + __builtin_add_overflow(one, two, out) +# define git__multiply_int64_overflow(out, one, two) \ + __builtin_mul_overflow(one, two, out) + /* Use Microsoft's safe integer handling functions where available */ #elif defined(_MSC_VER) @@ -87,11 +92,17 @@ GIT_INLINE(int) git__is_int(long long p) (SizeTAdd(one, two, out) != S_OK) # define git__multiply_sizet_overflow(out, one, two) \ (SizeTMult(one, two, out) != S_OK) + #define git__add_int_overflow(out, one, two) \ (IntAdd(one, two, out) != S_OK) #define git__sub_int_overflow(out, one, two) \ (IntSub(one, two, out) != S_OK) +#define git__add_int64_overflow(out, one, two) \ + (LongLongAdd(one, two, out) != S_OK) +#define git__multiply_int64_overflow(out, one, two) \ + (LongLongMult(one, two, out) != S_OK) + #else /** @@ -136,6 +147,26 @@ GIT_INLINE(bool) git__sub_int_overflow(int *out, int one, int two) return false; } +GIT_INLINE(bool) git__add_int64_overflow(int64_t *out, int64_t one, int64_t two) +{ + if ((two > 0 && one > (INT64_MAX - two)) || + (two < 0 && one < (INT64_MIN - two))) + return true; + *out = one + two; + return false; +} + +GIT_INLINE(bool) git__multiply_int64_overflow(int64_t *out, int64_t one, int64_t two) +{ + if ((one == -1 && two == INT_MIN) || + (two == -1 && one == INT_MIN) || + (one && INT64_MAX / one < two) || + (one && INT64_MIN / one > two)) + return true; + *out = one * two; + return false; +} + #endif #endif diff --git a/src/repository.c b/src/repository.c index 3b6bcbe86..948413d17 100644 --- a/src/repository.c +++ b/src/repository.c @@ -3055,30 +3055,16 @@ int git_repository_set_ident(git_repository *repo, const char *name, const char int git_repository_submodule_cache_all(git_repository *repo) { - int error; - GIT_ASSERT_ARG(repo); - - if ((error = git_strmap_new(&repo->submodule_cache))) - return error; - - error = git_submodule__map(repo, repo->submodule_cache); - return error; + return git_submodule_cache_init(&repo->submodule_cache, repo); } int git_repository_submodule_cache_clear(git_repository *repo) { - git_submodule *sm; - + int error = 0; GIT_ASSERT_ARG(repo); - if (repo->submodule_cache == NULL) { - return 0; - } - git_strmap_foreach_value(repo->submodule_cache, sm, { - git_submodule_free(sm); - }); - git_strmap_free(repo->submodule_cache); - repo->submodule_cache = 0; - return 0; + error = git_submodule_cache_free(repo->submodule_cache); + repo->submodule_cache = NULL; + return error; } diff --git a/src/submodule.c b/src/submodule.c index 0c901fa6f..50bde2c63 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -249,11 +249,48 @@ out: return error; } +int git_submodule_cache_init(git_strmap **out, git_repository *repo) +{ + int error = 0; + git_strmap *cache = NULL; + GIT_ASSERT_ARG(out); + GIT_ASSERT_ARG(repo); + if ((error = git_strmap_new(&cache)) < 0) + return error; + if ((error = git_submodule__map(repo, cache)) < 0) { + git_submodule_cache_free(cache); + return error; + } + *out = cache; + return error; +} + +int git_submodule_cache_free(git_strmap *cache) +{ + git_submodule *sm = NULL; + if (cache == NULL) + return 0; + git_strmap_foreach_value(cache, sm, { + git_submodule_free(sm); + }); + git_strmap_free(cache); + return 0; +} + int git_submodule_lookup( git_submodule **out, /* NULL if user only wants to test existence */ git_repository *repo, const char *name) /* trailing slash is allowed */ { + return git_submodule__lookup_with_cache(out, repo, name, repo->submodule_cache); +} + +int git_submodule__lookup_with_cache( + git_submodule **out, /* NULL if user only wants to test existence */ + git_repository *repo, + const char *name, /* trailing slash is allowed */ + git_strmap *cache) +{ int error; unsigned int location; git_submodule *sm; @@ -266,8 +303,8 @@ int git_submodule_lookup( return -1; } - if (repo->submodule_cache != NULL) { - if ((sm = git_strmap_get(repo->submodule_cache, name)) != NULL) { + if (cache != NULL) { + if ((sm = git_strmap_get(cache, name)) != NULL) { if (out) { *out = sm; GIT_REFCOUNT_INC(*out); diff --git a/src/submodule.h b/src/submodule.h index 57d95c3fc..b01ff68a2 100644 --- a/src/submodule.h +++ b/src/submodule.h @@ -101,12 +101,6 @@ struct git_submodule { git_oid wd_oid; }; -/* Force revalidation of submodule data cache (alloc as needed) */ -extern int git_submodule_cache_refresh(git_repository *repo); - -/* Release all submodules */ -extern void git_submodule_cache_free(git_repository *repo); - /* Additional flags on top of public GIT_SUBMODULE_STATUS values */ enum { GIT_SUBMODULE_STATUS__WD_SCANNED = (1u << 20), @@ -122,9 +116,15 @@ enum { #define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \ ((S) & ~(0xFFFFFFFFu << 20)) -/* Internal lookup does not attempt to refresh cached data */ -extern int git_submodule__lookup( - git_submodule **out, git_repository *repo, const char *path); +/* Initialize an external submodule cache for the provided repo. */ +extern int git_submodule_cache_init(git_strmap **out, git_repository *repo); + +/* Release the resources of the submodule cache. */ +extern int git_submodule_cache_free(git_strmap *cache); + +/* Submodule lookup with an explicit cache */ +extern int git_submodule__lookup_with_cache( + git_submodule **out, git_repository *repo, const char *path, git_strmap *cache); /* Internal status fn returns status and optionally the various OIDs */ extern int git_submodule__status( diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c index 2b77ec9a7..c82c788ae 100644 --- a/src/transports/winhttp.c +++ b/src/transports/winhttp.c @@ -874,42 +874,65 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked) static int send_request(winhttp_stream *s, size_t len, bool chunked) { - int request_failed = 0, cert_valid = 1, error = 0; - DWORD ignore_flags; + int request_failed = 1, error, attempts = 0; + DWORD ignore_flags, send_request_error; git_error_clear(); - if ((error = do_send_request(s, len, chunked)) < 0) { - if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) { - git_error_set(GIT_ERROR_OS, "failed to send request"); - return -1; + + while (request_failed && attempts++ < 3) { + int cert_valid = 1; + int client_cert_requested = 0; + request_failed = 0; + if ((error = do_send_request(s, len, chunked)) < 0) { + send_request_error = GetLastError(); + request_failed = 1; + switch (send_request_error) { + case ERROR_WINHTTP_SECURE_FAILURE: + cert_valid = 0; + break; + case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED: + client_cert_requested = 1; + break; + default: + git_error_set(GIT_ERROR_OS, "failed to send request"); + return -1; + } } - request_failed = 1; - cert_valid = 0; - } + if (!request_failed || !cert_valid) { + git_error_clear(); + if ((error = certificate_check(s, cert_valid)) < 0) { + if (!git_error_last()) + git_error_set(GIT_ERROR_OS, "user cancelled certificate check"); - git_error_clear(); - if ((error = certificate_check(s, cert_valid)) < 0) { - if (!git_error_last()) - git_error_set(GIT_ERROR_OS, "user cancelled certificate check"); - - return error; - } + return error; + } + } - /* if neither the request nor the certificate check returned errors, we're done */ - if (!request_failed) - return 0; + /* if neither the request nor the certificate check returned errors, we're done */ + if (!request_failed) + return 0; - ignore_flags = no_check_cert_flags; + if (!cert_valid) { + ignore_flags = no_check_cert_flags; + if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) { + git_error_set(GIT_ERROR_OS, "failed to set security options"); + return -1; + } + } - if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) { - git_error_set(GIT_ERROR_OS, "failed to set security options"); - return -1; + if (client_cert_requested) { + /* + * Client certificates are not supported, explicitly tell the server that + * (it's possible a client certificate was requested but is not required) + */ + if (!WinHttpSetOption(s->request, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0)) { + git_error_set(GIT_ERROR_OS, "failed to set client cert context"); + return -1; + } + } } - if ((error = do_send_request(s, len, chunked)) < 0) - git_error_set(GIT_ERROR_OS, "failed to send request with unchecked certificate"); - return error; } diff --git a/src/util.c b/src/util.c index 87ccf32af..af825e4d2 100644 --- a/src/util.c +++ b/src/util.c @@ -34,8 +34,8 @@ int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const char **endptr, int base) { const char *p; - int64_t n, nn; - int c, ovfl, v, neg, ndig; + int64_t n, nn, v; + int c, ovfl, neg, ndig; p = nptr; neg = 0; @@ -110,19 +110,11 @@ int git__strntol64(int64_t *result, const char *nptr, size_t nptr_len, const cha if (v >= base) break; v = neg ? -v : v; - if (n > INT64_MAX / base || n < INT64_MIN / base) { + if (git__multiply_int64_overflow(&nn, n, base) || git__add_int64_overflow(&n, nn, v)) { ovfl = 1; /* Keep on iterating until the end of this number */ continue; } - nn = n * base; - if ((v > 0 && nn > INT64_MAX - v) || - (v < 0 && nn < INT64_MIN - v)) { - ovfl = 1; - /* Keep on iterating until the end of this number */ - continue; - } - n = nn + v; } Return: diff --git a/tests/online/badssl.c b/tests/online/badssl.c index 6524fcd8e..6735e9cdb 100644 --- a/tests/online/badssl.c +++ b/tests/online/badssl.c @@ -67,14 +67,9 @@ void test_online_badssl__old_cipher(void) git_clone_options opts = GIT_CLONE_OPTIONS_INIT; opts.fetch_opts.callbacks.certificate_check = cert_check_assert_invalid; - /* FIXME: we don't actually reject RC4 anywhere, figure out what to tweak */ - cl_skip(); - if (!g_has_ssl) cl_skip(); - cl_git_fail_with(GIT_ECERTIFICATE, - git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", NULL)); - cl_git_fail_with(GIT_ECERTIFICATE, - git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", &opts)); + cl_git_fail(git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", NULL)); + cl_git_fail(git_clone(&g_repo, "https://rc4.badssl.com/fake.git", "./fake", &opts)); } |