summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--src/diff_generate.c26
-rw-r--r--src/integer.h31
-rw-r--r--src/repository.c24
-rw-r--r--src/submodule.c41
-rw-r--r--src/submodule.h18
-rw-r--r--src/transports/winhttp.c75
-rw-r--r--src/util.c14
-rw-r--r--tests/online/badssl.c9
9 files changed, 162 insertions, 78 deletions
diff --git a/README.md b/README.md
index b66d190d7..9bbdeaf3b 100644
--- a/README.md
+++ b/README.md
@@ -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));
}