summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAxel Rasmussen <axelrasmussen@google.com>2015-10-01 18:01:32 -0700
committerAxel Rasmussen <axelrasmussen@google.com>2015-10-01 18:01:32 -0700
commitc7b17fb5cd1adac57c4300e95cef8c7064b0601a (patch)
treeb1a1bcd6e1d88f1cd48b7fdb414d6444c28eb896
parent28cdb3153c8c6d651c5b2afcf315a2d188e9fde9 (diff)
parenta99f33e9b05504ea5eccd9c9210cd4a9e8d11695 (diff)
downloadlibgit2-c7b17fb5cd1adac57c4300e95cef8c7064b0601a.tar.gz
Merge branch 'master' into nsec_fix_next
-rw-r--r--CMakeLists.txt16
-rw-r--r--examples/network/ls-remote.c2
-rw-r--r--include/git2/remote.h13
-rw-r--r--include/git2/sys/odb_backend.h4
-rw-r--r--include/git2/sys/refdb_backend.h4
-rw-r--r--include/git2/sys/transport.h5
-rw-r--r--src/diff_print.c2
-rw-r--r--src/odb.c3
-rw-r--r--src/openssl_stream.c7
-rw-r--r--src/push.c3
-rw-r--r--src/push.h1
-rw-r--r--src/refdb.c8
-rw-r--r--src/remote.c32
-rw-r--r--src/repository.c24
-rw-r--r--src/submodule.c37
-rw-r--r--src/transports/http.c6
-rw-r--r--src/transports/smart.c81
-rw-r--r--src/transports/smart.h1
-rw-r--r--src/transports/winhttp.c18
-rw-r--r--src/unix/posix.h15
-rw-r--r--src/util.c21
-rw-r--r--src/win32/path_w32.c23
-rw-r--r--tests/core/mkdir.c2
-rw-r--r--tests/diff/binary.c21
-rw-r--r--tests/index/rename.c5
-rw-r--r--tests/network/remote/defaultbranch.c6
-rw-r--r--tests/network/remote/local.c8
-rw-r--r--tests/network/remote/remotes.c6
-rw-r--r--tests/odb/sorting.c1
-rw-r--r--tests/online/badssl.c27
-rw-r--r--tests/online/clone.c27
-rw-r--r--tests/online/fetch.c12
-rw-r--r--tests/online/push.c2
-rw-r--r--tests/repo/reservedname.c24
-rw-r--r--tests/resources/sub.git/HEAD1
-rw-r--r--tests/resources/sub.git/config8
-rw-r--r--tests/resources/sub.git/indexbin0 -> 405 bytes
-rw-r--r--tests/resources/sub.git/logs/HEAD1
-rw-r--r--tests/resources/sub.git/logs/refs/heads/master1
-rw-r--r--tests/resources/sub.git/objects/10/ddd6d257e01349d514541981aeecea6b2e741dbin0 -> 22 bytes
-rw-r--r--tests/resources/sub.git/objects/17/6a458f94e0ea5272ce67c36bf30b6be9caf623bin0 -> 28 bytes
-rw-r--r--tests/resources/sub.git/objects/94/c7d78d85c933d1d95b56bc2de01833ba8559fbbin0 -> 132 bytes
-rw-r--r--tests/resources/sub.git/objects/b7/a59b3f4ea13b985f8a1e0d3757d5cd3331add8bin0 -> 139 bytes
-rw-r--r--tests/resources/sub.git/objects/d0/ee23c41b28746d7e822511d7838bce784ae773bin0 -> 54 bytes
-rw-r--r--tests/resources/sub.git/refs/heads/master1
-rw-r--r--tests/resources/super/.gitted/COMMIT_EDITMSG1
-rw-r--r--tests/resources/super/.gitted/HEAD1
-rw-r--r--tests/resources/super/.gitted/config10
-rw-r--r--tests/resources/super/.gitted/indexbin0 -> 217 bytes
-rw-r--r--tests/resources/super/.gitted/objects/51/589c218bf77a8da9e9d8dbc097d76a742726c4bin0 -> 90 bytes
-rw-r--r--tests/resources/super/.gitted/objects/79/d0d58ca6aa1688a073d280169908454cad5b91bin0 -> 132 bytes
-rw-r--r--tests/resources/super/.gitted/objects/d7/57768b570a83e80d02edcc1032db14573e5034bin0 -> 87 bytes
-rw-r--r--tests/resources/super/.gitted/refs/heads/master1
-rw-r--r--tests/resources/super/gitmodules3
-rw-r--r--tests/submodule/submodule_helpers.c16
-rw-r--r--tests/submodule/submodule_helpers.h1
-rw-r--r--tests/win32/longpath.c60
57 files changed, 488 insertions, 84 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0c9c356c8..f15a6e623 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,7 @@ CMAKE_POLICY(SET CMP0015 NEW)
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
INCLUDE(CheckLibraryExists)
+INCLUDE(CheckFunctionExists)
INCLUDE(CheckStructHasMember)
INCLUDE(AddCFlagIfSupported)
INCLUDE(FindPkgConfig)
@@ -476,6 +477,21 @@ ELSE ()
ENDIF ()
ENDIF()
+CHECK_FUNCTION_EXISTS(futimens HAVE_FUTIMENS)
+IF (HAVE_FUTIMENS)
+ ADD_DEFINITIONS(-DHAVE_FUTIMENS)
+ENDIF ()
+
+CHECK_FUNCTION_EXISTS(qsort_r HAVE_QSORT_R)
+IF (HAVE_QSORT_R)
+ ADD_DEFINITIONS(-DHAVE_QSORT_R)
+ENDIF ()
+
+CHECK_FUNCTION_EXISTS(qsort_s HAVE_QSORT_S)
+IF (HAVE_QSORT_S)
+ ADD_DEFINITIONS(-DHAVE_QSORT_S)
+ENDIF ()
+
IF( NOT CMAKE_CONFIGURATION_TYPES )
# Build Debug by default
IF (NOT CMAKE_BUILD_TYPE)
diff --git a/examples/network/ls-remote.c b/examples/network/ls-remote.c
index 21026562f..c9da79f5f 100644
--- a/examples/network/ls-remote.c
+++ b/examples/network/ls-remote.c
@@ -26,7 +26,7 @@ static int use_remote(git_repository *repo, char *name)
*/
callbacks.credentials = cred_acquire_cb;
- error = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks);
+ error = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, NULL);
if (error < 0)
goto cleanup;
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 444fe5276..c42d96710 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -241,9 +241,10 @@ GIT_EXTERN(const git_refspec *)git_remote_get_refspec(const git_remote *remote,
* @param direction GIT_DIRECTION_FETCH if you want to fetch or
* GIT_DIRECTION_PUSH if you want to push
* @param callbacks the callbacks to use for this connection
+ * @param custom_headers extra HTTP headers to use in this connection
* @return 0 or an error code
*/
-GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks);
+GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_strarray *custom_headers);
/**
* Get the remote repository's reference advertisement list
@@ -546,6 +547,11 @@ typedef struct {
* The default is to auto-follow tags.
*/
git_remote_autotag_option_t download_tags;
+
+ /**
+ * Extra headers for this fetch operation
+ */
+ git_strarray custom_headers;
} git_fetch_options;
#define GIT_FETCH_OPTIONS_VERSION 1
@@ -585,6 +591,11 @@ typedef struct {
* Callbacks to use for this push operation
*/
git_remote_callbacks callbacks;
+
+ /**
+ * Extra headers for this push operation
+ */
+ git_strarray custom_headers;
} git_push_options;
#define GIT_PUSH_OPTIONS_VERSION 1
diff --git a/include/git2/sys/odb_backend.h b/include/git2/sys/odb_backend.h
index fe102ff3c..e423a9236 100644
--- a/include/git2/sys/odb_backend.h
+++ b/include/git2/sys/odb_backend.h
@@ -83,6 +83,10 @@ struct git_odb_backend {
git_odb_writepack **, git_odb_backend *, git_odb *odb,
git_transfer_progress_cb progress_cb, void *progress_payload);
+ /**
+ * Frees any resources held by the odb (including the `git_odb_backend`
+ * itself). An odb backend implementation must provide this function.
+ */
void (* free)(git_odb_backend *);
};
diff --git a/include/git2/sys/refdb_backend.h b/include/git2/sys/refdb_backend.h
index 01fce8009..5129ad84a 100644
--- a/include/git2/sys/refdb_backend.h
+++ b/include/git2/sys/refdb_backend.h
@@ -130,8 +130,8 @@ struct git_refdb_backend {
int (*ensure_log)(git_refdb_backend *backend, const char *refname);
/**
- * Frees any resources held by the refdb. A refdb implementation may
- * provide this function; if it is not provided, nothing will be done.
+ * Frees any resources held by the refdb (including the `git_refdb_backend`
+ * itself). A refdb backend implementation must provide this function.
*/
void (*free)(git_refdb_backend *backend);
diff --git a/include/git2/sys/transport.h b/include/git2/sys/transport.h
index 4a75b0832..ca8617f3f 100644
--- a/include/git2/sys/transport.h
+++ b/include/git2/sys/transport.h
@@ -40,6 +40,11 @@ struct git_transport {
git_transport_certificate_check_cb certificate_check_cb,
void *payload);
+ /* Set custom headers for HTTP requests */
+ int (*set_custom_headers)(
+ git_transport *transport,
+ const git_strarray *custom_headers);
+
/* Connect the transport to the remote repository, using the given
* direction. */
int (*connect)(
diff --git a/src/diff_print.c b/src/diff_print.c
index d406a441a..bc2d6fab0 100644
--- a/src/diff_print.c
+++ b/src/diff_print.c
@@ -358,6 +358,7 @@ static int format_binary(
scan += chunk_len;
pi->line.num_lines++;
}
+ git_buf_putc(pi->buf, '\n');
return 0;
}
@@ -416,7 +417,6 @@ static int diff_print_patch_file_binary(
if ((error = format_binary(pi, binary->new_file.type, binary->new_file.data,
binary->new_file.datalen, binary->new_file.inflatedlen)) < 0 ||
- (error = git_buf_putc(pi->buf, '\n')) < 0 ||
(error = format_binary(pi, binary->old_file.type, binary->old_file.data,
binary->old_file.datalen, binary->old_file.inflatedlen)) < 0) {
diff --git a/src/odb.c b/src/odb.c
index b2d635109..2b2c35fe8 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -600,8 +600,7 @@ static void odb_free(git_odb *db)
backend_internal *internal = git_vector_get(&db->backends, i);
git_odb_backend *backend = internal->backend;
- if (backend->free) backend->free(backend);
- else git__free(backend);
+ backend->free(backend);
git__free(internal);
}
diff --git a/src/openssl_stream.c b/src/openssl_stream.c
index 8ff53d4b1..54dd761ca 100644
--- a/src/openssl_stream.c
+++ b/src/openssl_stream.c
@@ -302,6 +302,7 @@ cert_fail_name:
typedef struct {
git_stream parent;
git_stream *io;
+ bool connected;
char *host;
SSL *ssl;
git_cert_x509 cert_info;
@@ -318,6 +319,8 @@ int openssl_connect(git_stream *stream)
if ((ret = git_stream_connect(st->io)) < 0)
return ret;
+ st->connected = true;
+
bio = BIO_new(&git_stream_bio_method);
GITERR_CHECK_ALLOC(bio);
bio->ptr = st->io;
@@ -406,9 +409,11 @@ int openssl_close(git_stream *stream)
openssl_stream *st = (openssl_stream *) stream;
int ret;
- if ((ret = ssl_teardown(st->ssl)) < 0)
+ if (st->connected && (ret = ssl_teardown(st->ssl)) < 0)
return -1;
+ st->connected = false;
+
return git_stream_close(st->io);
}
diff --git a/src/push.c b/src/push.c
index a0d8a0550..3c9fa2f1b 100644
--- a/src/push.c
+++ b/src/push.c
@@ -73,6 +73,7 @@ int git_push_set_options(git_push *push, const git_push_options *opts)
GITERR_CHECK_VERSION(opts, GIT_PUSH_OPTIONS_VERSION, "git_push_options");
push->pb_parallelism = opts->pb_parallelism;
+ push->custom_headers = &opts->custom_headers;
return 0;
}
@@ -638,7 +639,7 @@ int git_push_finish(git_push *push, const git_remote_callbacks *callbacks)
int error;
if (!git_remote_connected(push->remote) &&
- (error = git_remote_connect(push->remote, GIT_DIRECTION_PUSH, callbacks)) < 0)
+ (error = git_remote_connect(push->remote, GIT_DIRECTION_PUSH, callbacks, push->custom_headers)) < 0)
return error;
if ((error = filter_refs(push->remote)) < 0 ||
diff --git a/src/push.h b/src/push.h
index a847ee0d0..e32ad2f4d 100644
--- a/src/push.h
+++ b/src/push.h
@@ -38,6 +38,7 @@ struct git_push {
/* options */
unsigned pb_parallelism;
+ const git_strarray *custom_headers;
};
/**
diff --git a/src/refdb.c b/src/refdb.c
index 16fb519a6..debba1276 100644
--- a/src/refdb.c
+++ b/src/refdb.c
@@ -61,12 +61,8 @@ int git_refdb_open(git_refdb **out, git_repository *repo)
static void refdb_free_backend(git_refdb *db)
{
- if (db->backend) {
- if (db->backend->free)
- db->backend->free(db->backend);
- else
- git__free(db->backend);
- }
+ if (db->backend)
+ db->backend->free(db->backend);
}
int git_refdb_set_backend(git_refdb *db, git_refdb_backend *backend)
diff --git a/src/remote.c b/src/remote.c
index 7404bf49f..2f8ffcb37 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -687,7 +687,15 @@ int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs)
cbs->certificate_check, cbs->payload);
}
-int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks)
+static int set_transport_custom_headers(git_transport *t, const git_strarray *custom_headers)
+{
+ if (!t->set_custom_headers)
+ return 0;
+
+ return t->set_custom_headers(t, custom_headers);
+}
+
+int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_strarray *custom_headers)
{
git_transport *t;
const char *url;
@@ -726,6 +734,9 @@ int git_remote_connect(git_remote *remote, git_direction direction, const git_re
if (!t && (error = git_transport_new(&t, remote, url)) < 0)
return error;
+ if ((error = set_transport_custom_headers(t, custom_headers)) != 0)
+ goto on_error;
+
if ((error = set_transport_callbacks(t, callbacks)) < 0 ||
(error = t->connect(t, url, credentials, payload, direction, flags)) != 0)
goto on_error;
@@ -884,16 +895,18 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const
size_t i;
git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT;
const git_remote_callbacks *cbs = NULL;
+ const git_strarray *custom_headers = NULL;
assert(remote);
if (opts) {
GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
cbs = &opts->callbacks;
+ custom_headers = &opts->custom_headers;
}
if (!git_remote_connected(remote) &&
- (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) < 0)
+ (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, custom_headers)) < 0)
goto on_error;
if (ls_to_vector(&refs, remote) < 0)
@@ -957,16 +970,18 @@ int git_remote_fetch(
bool prune = false;
git_buf reflog_msg_buf = GIT_BUF_INIT;
const git_remote_callbacks *cbs = NULL;
+ const git_strarray *custom_headers = NULL;
if (opts) {
GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
cbs = &opts->callbacks;
+ custom_headers = &opts->custom_headers;
update_fetchhead = opts->update_fetchhead;
tagopt = opts->download_tags;
}
/* Connect and download everything */
- if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) != 0)
+ if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, custom_headers)) != 0)
return error;
error = git_remote_download(remote, refspecs, opts);
@@ -2377,14 +2392,17 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
git_push *push;
git_refspec *spec;
const git_remote_callbacks *cbs = NULL;
+ const git_strarray *custom_headers = NULL;
assert(remote);
- if (opts)
+ if (opts) {
cbs = &opts->callbacks;
+ custom_headers = &opts->custom_headers;
+ }
if (!git_remote_connected(remote) &&
- (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
+ (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, custom_headers)) < 0)
goto cleanup;
free_refspecs(&remote->active_refspecs);
@@ -2433,15 +2451,17 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_
{
int error;
const git_remote_callbacks *cbs = NULL;
+ const git_strarray *custom_headers = NULL;
if (opts) {
GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
cbs = &opts->callbacks;
+ custom_headers = &opts->custom_headers;
}
assert(remote && refspecs);
- if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
+ if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, custom_headers)) < 0)
return error;
if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
diff --git a/src/repository.c b/src/repository.c
index d0bf7dc79..77145cfc8 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -908,12 +908,28 @@ bool git_repository__reserved_names(
buf->size = git_repository__reserved_names_win32[i].size;
}
- /* Try to add any repo-specific reserved names */
+ /* Try to add any repo-specific reserved names - the gitlink file
+ * within a submodule or the repository (if the repository directory
+ * is beneath the workdir). These are typically `.git`, but should
+ * be protected in case they are not. Note, repo and workdir paths
+ * are always prettified to end in `/`, so a prefixcmp is safe.
+ */
if (!repo->is_bare) {
- const char *reserved_path = repo->path_gitlink ?
- repo->path_gitlink : repo->path_repository;
+ int (*prefixcmp)(const char *, const char *);
+ int error, ignorecase;
- if (reserved_names_add8dot3(repo, reserved_path) < 0)
+ error = git_repository__cvar(
+ &ignorecase, repo, GIT_CVAR_IGNORECASE);
+ prefixcmp = (error || ignorecase) ? git__prefixcmp_icase :
+ git__prefixcmp;
+
+ if (repo->path_gitlink &&
+ reserved_names_add8dot3(repo, repo->path_gitlink) < 0)
+ goto on_error;
+
+ if (repo->path_repository &&
+ prefixcmp(repo->path_repository, repo->workdir) == 0 &&
+ reserved_names_add8dot3(repo, repo->path_repository) < 0)
goto on_error;
}
}
diff --git a/src/submodule.c b/src/submodule.c
index 1d73dc24e..3fd338843 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -170,7 +170,7 @@ static int name_from_path(git_buf *out, git_config *cfg, const char *path)
git_buf_clear(out);
git_buf_put(out, fdot + 1, ldot - fdot - 1);
- return 0;
+ goto cleanup;
}
if (error == GIT_ITEROVER) {
@@ -178,6 +178,8 @@ static int name_from_path(git_buf *out, git_config *cfg, const char *path)
error = GIT_ENOTFOUND;
}
+cleanup:
+ git_config_iterator_free(iter);
return error;
}
@@ -227,6 +229,7 @@ int git_submodule_lookup(
if (error < 0) {
git_submodule_free(sm);
+ git_buf_free(&path);
return error;
}
@@ -1697,11 +1700,13 @@ static int submodule_read_config(git_submodule *sm, git_config *cfg)
* should be strcasecmp
*/
if (strcmp(sm->name, value) != 0) {
+ if (sm->path != sm->name)
+ git__free(sm->path);
sm->path = git__strdup(value);
GITERR_CHECK_ALLOC(sm->path);
}
} else if (error != GIT_ENOTFOUND) {
- return error;
+ goto cleanup;
}
if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) {
@@ -1709,7 +1714,7 @@ static int submodule_read_config(git_submodule *sm, git_config *cfg)
sm->url = git__strdup(value);
GITERR_CHECK_ALLOC(sm->url);
} else if (error != GIT_ENOTFOUND) {
- return error;
+ goto cleanup;
}
if ((error = get_value(&value, cfg, &key, sm->name, "branch")) == 0) {
@@ -1717,40 +1722,44 @@ static int submodule_read_config(git_submodule *sm, git_config *cfg)
sm->branch = git__strdup(value);
GITERR_CHECK_ALLOC(sm->branch);
} else if (error != GIT_ENOTFOUND) {
- return error;
+ goto cleanup;
}
if ((error = get_value(&value, cfg, &key, sm->name, "update")) == 0) {
in_config = 1;
if ((error = git_submodule_parse_update(&sm->update, value)) < 0)
- return error;
+ goto cleanup;
sm->update_default = sm->update;
} else if (error != GIT_ENOTFOUND) {
- return error;
+ goto cleanup;
}
if ((error = get_value(&value, cfg, &key, sm->name, "fetchRecurseSubmodules")) == 0) {
in_config = 1;
if ((error = git_submodule_parse_recurse(&sm->fetch_recurse, value)) < 0)
- return error;
+ goto cleanup;
sm->fetch_recurse_default = sm->fetch_recurse;
} else if (error != GIT_ENOTFOUND) {
- return error;
+ goto cleanup;
}
if ((error = get_value(&value, cfg, &key, sm->name, "ignore")) == 0) {
in_config = 1;
if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0)
- return error;
+ goto cleanup;
sm->ignore_default = sm->ignore;
} else if (error != GIT_ENOTFOUND) {
- return error;
+ goto cleanup;
}
if (in_config)
sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;
- return 0;
+ error = 0;
+
+cleanup:
+ git_buf_free(&key);
+ return error;
}
static int submodule_load_each(const git_config_entry *entry, void *payload)
@@ -1784,8 +1793,10 @@ static int submodule_load_each(const git_config_entry *entry, void *payload)
* already inserted, we've already loaded it, so we skip.
*/
pos = git_strmap_lookup_index(map, name.ptr);
- if (git_strmap_valid_index(map, pos))
- return 0;
+ if (git_strmap_valid_index(map, pos)) {
+ error = 0;
+ goto done;
+ }
if ((error = submodule_alloc(&sm, data->repo, name.ptr)) < 0)
goto done;
diff --git a/src/transports/http.c b/src/transports/http.c
index 87f3ee816..e5f2b9f28 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -193,6 +193,7 @@ static int gen_request(
{
http_subtransport *t = OWNING_SUBTRANSPORT(s);
const char *path = t->connection_data.path ? t->connection_data.path : "/";
+ size_t i;
git_buf_printf(buf, "%s %s%s HTTP/1.1\r\n", s->verb, path, s->service_url);
@@ -210,6 +211,11 @@ static int gen_request(
} else
git_buf_puts(buf, "Accept: */*\r\n");
+ for (i = 0; i < t->owner->custom_headers.count; i++) {
+ if (t->owner->custom_headers.strings[i])
+ git_buf_printf(buf, "%s\r\n", t->owner->custom_headers.strings[i]);
+ }
+
/* Apply credentials to the request */
if (apply_credentials(buf, t) < 0)
return -1;
diff --git a/src/transports/smart.c b/src/transports/smart.c
index 31a2dec7b..b0611c35e 100644
--- a/src/transports/smart.c
+++ b/src/transports/smart.c
@@ -66,6 +66,84 @@ static int git_smart__set_callbacks(
return 0;
}
+static int http_header_name_length(const char *http_header)
+{
+ const char *colon = strchr(http_header, ':');
+ if (!colon)
+ return 0;
+ return colon - http_header;
+}
+
+static bool is_malformed_http_header(const char *http_header)
+{
+ const char *c;
+ int name_len;
+
+ // Disallow \r and \n
+ c = strchr(http_header, '\r');
+ if (c)
+ return true;
+ c = strchr(http_header, '\n');
+ if (c)
+ return true;
+
+ // Require a header name followed by :
+ name_len = http_header_name_length(http_header);
+ if (name_len < 1)
+ return true;
+
+ return false;
+}
+
+static char *forbidden_custom_headers[] = {
+ "User-Agent",
+ "Host",
+ "Accept",
+ "Content-Type",
+ "Transfer-Encoding",
+ "Content-Length",
+};
+
+static bool is_forbidden_custom_header(const char *custom_header)
+{
+ unsigned long i;
+ int name_len = http_header_name_length(custom_header);
+
+ // Disallow headers that we set
+ for (i = 0; i < ARRAY_SIZE(forbidden_custom_headers); i++)
+ if (strncmp(forbidden_custom_headers[i], custom_header, name_len) == 0)
+ return true;
+
+ return false;
+}
+
+static int git_smart__set_custom_headers(
+ git_transport *transport,
+ const git_strarray *custom_headers)
+{
+ transport_smart *t = (transport_smart *)transport;
+ size_t i;
+
+ if (t->custom_headers.count)
+ git_strarray_free(&t->custom_headers);
+
+ if (!custom_headers)
+ return 0;
+
+ for (i = 0; i < custom_headers->count; i++) {
+ if (is_malformed_http_header(custom_headers->strings[i])) {
+ giterr_set(GITERR_INVALID, "custom HTTP header '%s' is malformed", custom_headers->strings[i]);
+ return -1;
+ }
+ if (is_forbidden_custom_header(custom_headers->strings[i])) {
+ giterr_set(GITERR_INVALID, "custom HTTP header '%s' is already set by libgit2", custom_headers->strings[i]);
+ return -1;
+ }
+ }
+
+ return git_strarray_copy(&t->custom_headers, custom_headers);
+}
+
int git_smart__update_heads(transport_smart *t, git_vector *symrefs)
{
size_t i;
@@ -362,6 +440,8 @@ static void git_smart__free(git_transport *transport)
git_vector_free(refs);
+ git_strarray_free(&t->custom_headers);
+
git__free(t);
}
@@ -399,6 +479,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
t->parent.version = GIT_TRANSPORT_VERSION;
t->parent.set_callbacks = git_smart__set_callbacks;
+ t->parent.set_custom_headers = git_smart__set_custom_headers;
t->parent.connect = git_smart__connect;
t->parent.close = git_smart__close;
t->parent.free = git_smart__free;
diff --git a/src/transports/smart.h b/src/transports/smart.h
index 4c728c7cc..800466adf 100644
--- a/src/transports/smart.h
+++ b/src/transports/smart.h
@@ -139,6 +139,7 @@ typedef struct {
git_transport_message_cb error_cb;
git_transport_certificate_check_cb certificate_check_cb;
void *message_cb_payload;
+ git_strarray custom_headers;
git_smart_subtransport *wrapped;
git_smart_subtransport_stream *current_stream;
transport_smart_caps caps;
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index 0c43c4b0b..b364e906e 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -277,6 +277,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
unsigned long disable_redirects = WINHTTP_DISABLE_REDIRECTS;
int default_timeout = TIMEOUT_INFINITE;
int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
+ int i;
/* Prepare URL */
git_buf_printf(&buf, "%s%s", t->connection_data.path, s->service_url);
@@ -409,6 +410,23 @@ static int winhttp_stream_connect(winhttp_stream *s)
}
}
+ for (i = 0; i < t->owner->custom_headers.count; i++) {
+ if (t->owner->custom_headers.strings[i]) {
+ git_buf_clear(&buf);
+ git_buf_puts(&buf, t->owner->custom_headers.strings[i]);
+ if (git__utf8_to_16(ct, MAX_CONTENT_TYPE_LEN, git_buf_cstr(&buf)) < 0) {
+ giterr_set(GITERR_OS, "Failed to convert custom header to wide characters");
+ goto on_error;
+ }
+
+ if (!WinHttpAddRequestHeaders(s->request, ct, (ULONG)-1L,
+ WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) {
+ giterr_set(GITERR_OS, "Failed to add a header to the request");
+ goto on_error;
+ }
+ }
+ }
+
/* If requested, disable certificate validation */
if (t->connection_data.use_ssl) {
int flags;
diff --git a/src/unix/posix.h b/src/unix/posix.h
index 777350990..6633689bc 100644
--- a/src/unix/posix.h
+++ b/src/unix/posix.h
@@ -22,7 +22,6 @@ typedef int GIT_SOCKET;
#define p_stat(p,b) stat(p, b)
#define p_utimes(f, t) utimes(f, t)
-#define p_futimes(f, t) futimes(f, t)
#define p_readlink(a, b, c) readlink(a, b, c)
#define p_symlink(o,n) symlink(o, n)
@@ -53,4 +52,18 @@ extern char *p_realpath(const char *, char *);
#define p_localtime_r(c, r) localtime_r(c, r)
#define p_gmtime_r(c, r) gmtime_r(c, r)
+#ifdef HAVE_FUTIMENS
+GIT_INLINE(int) p_futimes(int f, const struct timeval t[2])
+{
+ struct timespec s[2];
+ s[0].tv_sec = t[0].tv_sec;
+ s[0].tv_nsec = t[0].tv_usec * 1000;
+ s[1].tv_sec = t[1].tv_sec;
+ s[1].tv_nsec = t[1].tv_usec * 1000;
+ return futimens(f, s);
+}
+#else
+# define p_futimes futimes
+#endif
+
#endif
diff --git a/src/util.c b/src/util.c
index b3929bca2..9e67f4347 100644
--- a/src/util.c
+++ b/src/util.c
@@ -611,7 +611,7 @@ size_t git__unescape(char *str)
return (pos - str);
}
-#if defined(GIT_WIN32) || defined(BSD)
+#if defined(HAVE_QSORT_S) || (defined(HAVE_QSORT_R) && defined(BSD))
typedef struct {
git__sort_r_cmp cmp;
void *payload;
@@ -628,21 +628,16 @@ static int GIT_STDLIB_CALL git__qsort_r_glue_cmp(
void git__qsort_r(
void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload)
{
-#if defined(__MINGW32__) || defined(AMIGA) || \
- defined(__OpenBSD__) || defined(__NetBSD__) || \
- defined(__gnu_hurd__) || defined(__ANDROID_API__) || \
- defined(__sun) || defined(__CYGWIN__) || \
- (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8) || \
- (defined(_MSC_VER) && _MSC_VER < 1500)
- git__insertsort_r(els, nel, elsize, NULL, cmp, payload);
-#elif defined(GIT_WIN32)
- git__qsort_r_glue glue = { cmp, payload };
- qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue);
-#elif defined(BSD)
+#if defined(HAVE_QSORT_R) && defined(BSD)
git__qsort_r_glue glue = { cmp, payload };
qsort_r(els, nel, elsize, &glue, git__qsort_r_glue_cmp);
-#else
+#elif defined(HAVE_QSORT_R) && defined(__GLIBC__)
qsort_r(els, nel, elsize, cmp, payload);
+#elif defined(HAVE_QSORT_S)
+ git__qsort_r_glue glue = { cmp, payload };
+ qsort_s(els, nel, elsize, git__qsort_r_glue_cmp, &glue);
+#else
+ git__insertsort_r(els, nel, elsize, NULL, cmp, payload);
#endif
}
diff --git a/src/win32/path_w32.c b/src/win32/path_w32.c
index 118e8bcc5..40b95c33b 100644
--- a/src/win32/path_w32.c
+++ b/src/win32/path_w32.c
@@ -198,13 +198,13 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
/* See if this is an absolute path (beginning with a drive letter) */
if (path__is_absolute(src)) {
if (git__utf8_to_16(dest, MAX_PATH, src) < 0)
- return -1;
+ goto on_error;
}
/* File-prefixed NT-style paths beginning with \\?\ */
else if (path__is_nt_namespace(src)) {
/* Skip the NT prefix, the destination already contains it */
if (git__utf8_to_16(dest, MAX_PATH, src + PATH__NT_NAMESPACE_LEN) < 0)
- return -1;
+ goto on_error;
}
/* UNC paths */
else if (path__is_unc(src)) {
@@ -213,36 +213,43 @@ int git_win32_path_from_utf8(git_win32_path out, const char *src)
/* Skip the leading "\\" */
if (git__utf8_to_16(dest, MAX_PATH - 2, src + 2) < 0)
- return -1;
+ goto on_error;
}
/* Absolute paths omitting the drive letter */
else if (src[0] == '\\' || src[0] == '/') {
if (path__cwd(dest, MAX_PATH) < 0)
- return -1;
+ goto on_error;
if (!path__is_absolute(dest)) {
errno = ENOENT;
- return -1;
+ goto on_error;
}
/* Skip the drive letter specification ("C:") */
if (git__utf8_to_16(dest + 2, MAX_PATH - 2, src) < 0)
- return -1;
+ goto on_error;
}
/* Relative paths */
else {
int cwd_len;
if ((cwd_len = git_win32_path__cwd(dest, MAX_PATH)) < 0)
- return -1;
+ goto on_error;
dest[cwd_len++] = L'\\';
if (git__utf8_to_16(dest + cwd_len, MAX_PATH - cwd_len, src) < 0)
- return -1;
+ goto on_error;
}
return git_win32_path_canonicalize(out);
+
+on_error:
+ /* set windows error code so we can use its error message */
+ if (errno == ENAMETOOLONG)
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+
+ return -1;
}
int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src)
diff --git a/tests/core/mkdir.c b/tests/core/mkdir.c
index 5e6a06002..96c972396 100644
--- a/tests/core/mkdir.c
+++ b/tests/core/mkdir.c
@@ -48,6 +48,8 @@ void test_core_mkdir__absolute(void)
cl_assert(!git_path_isdir(path.ptr));
cl_git_fail(git_futils_mkdir(path.ptr, 0755, 0));
cl_assert(!git_path_isdir(path.ptr));
+
+ git_buf_free(&path);
}
void test_core_mkdir__basic(void)
diff --git a/tests/diff/binary.c b/tests/diff/binary.c
index 5298e9ebb..173a5994e 100644
--- a/tests/diff/binary.c
+++ b/tests/diff/binary.c
@@ -96,7 +96,8 @@ void test_diff_binary__add(void)
"Kc${Nk-~s>u4FC%O\n"
"\n" \
"literal 0\n" \
- "Hc$@<O00001\n";
+ "Hc$@<O00001\n" \
+ "\n";
opts.flags = GIT_DIFF_SHOW_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ;
@@ -136,7 +137,8 @@ void test_diff_binary__modify(void)
"Mc${NkU}WL~000&M4gdfE\n" \
"\n" \
"literal 3\n" \
- "Kc${Nk-~s>u4FC%O\n";
+ "Kc${Nk-~s>u4FC%O\n" \
+ "\n";
opts.flags = GIT_DIFF_SHOW_BINARY;
@@ -177,7 +179,8 @@ void test_diff_binary__delete(void)
"Hc$@<O00001\n" \
"\n" \
"literal 3\n" \
- "Kc${Nk-~s>u4FC%O\n";
+ "Kc${Nk-~s>u4FC%O\n" \
+ "\n";
opts.flags = GIT_DIFF_SHOW_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ;
@@ -208,7 +211,8 @@ void test_diff_binary__delta(void)
"delta 198\n" \
"zc$}LmI8{(0BqLQJI6p64AwNwaIJGP_Pr*5}Br~;mqJ$<Jl;sX*mF<MGCYv&*L7AHu\n" \
"zGA1*^gt?gYVN82wTbPO_W)+x<&1+cP;HrPHR>PQ;Y(X&QMK*C5^Br3bjG4d=XI^5@\n" \
- "JfH567LIF3FM2!Fd\n";
+ "JfH567LIF3FM2!Fd\n" \
+ "\n";
opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ;
@@ -249,7 +253,8 @@ void test_diff_binary__delta_append(void)
"nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \
"\n" \
"delta 7\n" \
- "Oc%18D`@*{63ljhg(E~C7\n";
+ "Oc%18D`@*{63ljhg(E~C7\n" \
+ "\n";
opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ;
@@ -314,7 +319,8 @@ void test_diff_binary__index_to_workdir(void)
"nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \
"\n" \
"delta 7\n" \
- "Oc%18D`@*{63ljhg(E~C7\n";
+ "Oc%18D`@*{63ljhg(E~C7\n" \
+ "\n";
opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ;
@@ -379,7 +385,8 @@ void test_diff_binary__print_patch_from_diff(void)
"nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \
"\n" \
"delta 7\n" \
- "Oc%18D`@*{63ljhg(E~C7\n";
+ "Oc%18D`@*{63ljhg(E~C7\n" \
+ "\n";
opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
opts.id_abbrev = GIT_OID_HEXSZ;
diff --git a/tests/index/rename.c b/tests/index/rename.c
index ebaa9b740..86eaf0053 100644
--- a/tests/index/rename.c
+++ b/tests/index/rename.c
@@ -77,5 +77,10 @@ void test_index_rename__casechanging(void)
cl_assert_equal_i(1, git_index_entrycount(index));
else
cl_assert_equal_i(2, git_index_entrycount(index));
+
+ git_index_free(index);
+ git_repository_free(repo);
+
+ cl_fixture_cleanup("rename");
}
diff --git a/tests/network/remote/defaultbranch.c b/tests/network/remote/defaultbranch.c
index e83755ef6..5edd79fb8 100644
--- a/tests/network/remote/defaultbranch.c
+++ b/tests/network/remote/defaultbranch.c
@@ -26,7 +26,7 @@ static void assert_default_branch(const char *should)
{
git_buf name = GIT_BUF_INIT;
- cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL));
+ cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL, NULL));
cl_git_pass(git_remote_default_branch(&name, g_remote));
cl_assert_equal_s(should, name.ptr);
git_buf_free(&name);
@@ -57,7 +57,7 @@ void test_network_remote_defaultbranch__no_default_branch(void)
git_buf buf = GIT_BUF_INIT;
cl_git_pass(git_remote_create(&remote_b, g_repo_b, "self", git_repository_path(g_repo_b)));
- cl_git_pass(git_remote_connect(remote_b, GIT_DIRECTION_FETCH, NULL));
+ cl_git_pass(git_remote_connect(remote_b, GIT_DIRECTION_FETCH, NULL, NULL));
cl_git_pass(git_remote_ls(&heads, &len, remote_b));
cl_assert_equal_i(0, len);
@@ -80,7 +80,7 @@ void test_network_remote_defaultbranch__detached_sharing_nonbranch_id(void)
cl_git_pass(git_reference_create(&ref, g_repo_a, "refs/foo/bar", &id, 1, NULL));
git_reference_free(ref);
- cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL));
+ cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL, NULL));
cl_git_fail_with(GIT_ENOTFOUND, git_remote_default_branch(&buf, g_remote));
cl_git_pass(git_clone(&cloned_repo, git_repository_path(g_repo_a), "./local-detached", NULL));
diff --git a/tests/network/remote/local.c b/tests/network/remote/local.c
index 5d726c958..4d990ab71 100644
--- a/tests/network/remote/local.c
+++ b/tests/network/remote/local.c
@@ -40,7 +40,7 @@ static void connect_to_local_repository(const char *local_repository)
git_buf_sets(&file_path_buf, cl_git_path_url(local_repository));
cl_git_pass(git_remote_create_anonymous(&remote, repo, git_buf_cstr(&file_path_buf)));
- cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL));
}
void test_network_remote_local__connected(void)
@@ -214,7 +214,7 @@ void test_network_remote_local__push_to_bare_remote(void)
/* Connect to the bare repo */
cl_git_pass(git_remote_create_anonymous(&localremote, repo, "./localbare.git"));
- cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL));
+ cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, NULL));
/* Try to push */
cl_git_pass(git_remote_upload(localremote, &push_array, NULL));
@@ -253,7 +253,7 @@ void test_network_remote_local__push_to_bare_remote_with_file_url(void)
/* Connect to the bare repo */
cl_git_pass(git_remote_create_anonymous(&localremote, repo, url));
- cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL));
+ cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, NULL));
/* Try to push */
cl_git_pass(git_remote_upload(localremote, &push_array, NULL));
@@ -290,7 +290,7 @@ void test_network_remote_local__push_to_non_bare_remote(void)
/* Connect to the bare repo */
cl_git_pass(git_remote_create_anonymous(&localremote, repo, "./localnonbare"));
- cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL));
+ cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, NULL));
/* Try to push */
cl_git_fail_with(GIT_EBAREREPO, git_remote_upload(localremote, &push_array, NULL));
diff --git a/tests/network/remote/remotes.c b/tests/network/remote/remotes.c
index 2fa21d460..46abc6d33 100644
--- a/tests/network/remote/remotes.c
+++ b/tests/network/remote/remotes.c
@@ -93,7 +93,7 @@ void test_network_remote_remotes__error_when_no_push_available(void)
cl_git_pass(git_remote_create_anonymous(&r, _repo, cl_fixture("testrepo.git")));
callbacks.transport = git_transport_local;
- cl_git_pass(git_remote_connect(r, GIT_DIRECTION_PUSH, &callbacks));
+ cl_git_pass(git_remote_connect(r, GIT_DIRECTION_PUSH, &callbacks, NULL));
/* Make sure that push is really not available */
r->transport->push = NULL;
@@ -359,7 +359,7 @@ void test_network_remote_remotes__can_load_with_an_empty_url(void)
cl_assert(remote->url == NULL);
cl_assert(remote->pushurl == NULL);
- cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL));
+ cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL));
cl_assert(giterr_last() != NULL);
cl_assert(giterr_last()->klass == GITERR_INVALID);
@@ -376,7 +376,7 @@ void test_network_remote_remotes__can_load_with_only_an_empty_pushurl(void)
cl_assert(remote->url == NULL);
cl_assert(remote->pushurl == NULL);
- cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL));
+ cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL));
git_remote_free(remote);
}
diff --git a/tests/odb/sorting.c b/tests/odb/sorting.c
index 147a160c8..d24c49c69 100644
--- a/tests/odb/sorting.c
+++ b/tests/odb/sorting.c
@@ -14,6 +14,7 @@ static git_odb_backend *new_backend(size_t position)
if (b == NULL)
return NULL;
+ b->base.free = (void (*)(git_odb_backend *)) git__free;
b->base.version = GIT_ODB_BACKEND_VERSION;
b->position = position;
return (git_odb_backend *)b;
diff --git a/tests/online/badssl.c b/tests/online/badssl.c
new file mode 100644
index 000000000..850468320
--- /dev/null
+++ b/tests/online/badssl.c
@@ -0,0 +1,27 @@
+#include "clar_libgit2.h"
+
+#include "git2/clone.h"
+
+static git_repository *g_repo;
+
+#if defined(GIT_OPENSSL) || defined(GIT_WINHTTP) || defined(GIT_SECURE_TRANSPORT)
+
+void test_online_badssl__expired(void)
+{
+ cl_git_fail_with(GIT_ECERTIFICATE,
+ git_clone(&g_repo, "https://expired.badssl.com/fake.git", "./fake", NULL));
+}
+
+void test_online_badssl__wrong_host(void)
+{
+ cl_git_fail_with(GIT_ECERTIFICATE,
+ git_clone(&g_repo, "https://wrong.host.badssl.com/fake.git", "./fake", NULL));
+}
+
+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));
+}
+
+#endif
diff --git a/tests/online/clone.c b/tests/online/clone.c
index 225b3abe2..b84be405c 100644
--- a/tests/online/clone.c
+++ b/tests/online/clone.c
@@ -213,6 +213,33 @@ void test_online_clone__custom_remote_callbacks(void)
cl_assert(callcount > 0);
}
+void test_online_clone__custom_headers(void)
+{
+ char *empty_header = "";
+ char *unnamed_header = "this is a header about nothing";
+ char *newlines = "X-Custom: almost OK\n";
+ char *conflict = "Accept: defined-by-git";
+ char *ok = "X-Custom: this should be ok";
+
+ g_options.fetch_opts.custom_headers.count = 1;
+
+ g_options.fetch_opts.custom_headers.strings = &empty_header;
+ cl_git_fail(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options));
+
+ g_options.fetch_opts.custom_headers.strings = &unnamed_header;
+ cl_git_fail(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options));
+
+ g_options.fetch_opts.custom_headers.strings = &newlines;
+ cl_git_fail(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options));
+
+ g_options.fetch_opts.custom_headers.strings = &conflict;
+ cl_git_fail(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options));
+
+ /* Finally, we got it right! */
+ g_options.fetch_opts.custom_headers.strings = &ok;
+ cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options));
+}
+
static int cred_failure_cb(
git_cred **cred,
const char *url,
diff --git a/tests/online/fetch.c b/tests/online/fetch.c
index 72e7c24e3..c12df069f 100644
--- a/tests/online/fetch.c
+++ b/tests/online/fetch.c
@@ -81,11 +81,11 @@ void test_online_fetch__fetch_twice(void)
{
git_remote *remote;
cl_git_pass(git_remote_create(&remote, _repo, "test", "git://github.com/libgit2/TestGitRepository.git"));
- cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL));
cl_git_pass(git_remote_download(remote, NULL, NULL));
git_remote_disconnect(remote);
- git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL);
+ git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL);
cl_git_pass(git_remote_download(remote, NULL, NULL));
git_remote_disconnect(remote);
@@ -117,7 +117,7 @@ void test_online_fetch__doesnt_retrieve_a_pack_when_the_repository_is_up_to_date
cl_git_pass(git_repository_open(&_repository, "./fetch/lg2"));
cl_git_pass(git_remote_lookup(&remote, _repository, "origin"));
- cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL));
cl_assert_equal_i(false, invoked);
@@ -155,7 +155,7 @@ void test_online_fetch__can_cancel(void)
options.callbacks.transfer_progress = cancel_at_half;
options.callbacks.payload = &bytes_received;
- cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL));
cl_git_fail_with(git_remote_download(remote, NULL, &options), -4321);
git_remote_disconnect(remote);
git_remote_free(remote);
@@ -169,7 +169,7 @@ void test_online_fetch__ls_disconnected(void)
cl_git_pass(git_remote_create(&remote, _repo, "test",
"http://github.com/libgit2/TestGitRepository.git"));
- cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL));
cl_git_pass(git_remote_ls(&refs, &refs_len_before, remote));
git_remote_disconnect(remote);
cl_git_pass(git_remote_ls(&refs, &refs_len_after, remote));
@@ -187,7 +187,7 @@ void test_online_fetch__remote_symrefs(void)
cl_git_pass(git_remote_create(&remote, _repo, "test",
"http://github.com/libgit2/TestGitRepository.git"));
- cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL));
+ cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL));
git_remote_disconnect(remote);
cl_git_pass(git_remote_ls(&refs, &refs_len, remote));
diff --git a/tests/online/push.c b/tests/online/push.c
index 4d2b1d310..77c437622 100644
--- a/tests/online/push.c
+++ b/tests/online/push.c
@@ -372,7 +372,7 @@ void test_online_push__initialize(void)
record_callbacks_data_clear(&_record_cbs_data);
- cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH, &_record_cbs));
+ cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH, &_record_cbs, NULL));
/* Clean up previously pushed branches. Fails if receive.denyDeletes is
* set on the remote. Also, on Git 1.7.0 and newer, you must run
diff --git a/tests/repo/reservedname.c b/tests/repo/reservedname.c
index faea0cc2b..2a5b38239 100644
--- a/tests/repo/reservedname.c
+++ b/tests/repo/reservedname.c
@@ -106,3 +106,27 @@ void test_repo_reservedname__submodule_pointer(void)
git_repository_free(sub_repo);
#endif
}
+
+/* Like the `submodule_pointer` test (above), this ensures that we do not
+ * follow the gitlink to the submodule's repository location and treat that
+ * as a reserved name. This tests at an initial submodule update, where the
+ * submodule repo is being created.
+ */
+void test_repo_reservedname__submodule_pointer_during_create(void)
+{
+ git_repository *repo;
+ git_submodule *sm;
+ git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
+ git_buf url = GIT_BUF_INIT;
+
+ repo = setup_fixture_super();
+
+ cl_git_pass(git_buf_joinpath(&url, clar_sandbox_path(), "sub.git"));
+ cl_repo_set_string(repo, "submodule.sub.url", url.ptr);
+
+ cl_git_pass(git_submodule_lookup(&sm, repo, "sub"));
+ cl_git_pass(git_submodule_update(sm, 1, &update_options));
+
+ git_submodule_free(sm);
+ git_buf_free(&url);
+}
diff --git a/tests/resources/sub.git/HEAD b/tests/resources/sub.git/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests/resources/sub.git/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/sub.git/config b/tests/resources/sub.git/config
new file mode 100644
index 000000000..78387c50b
--- /dev/null
+++ b/tests/resources/sub.git/config
@@ -0,0 +1,8 @@
+[core]
+ repositoryformatversion = 0
+ filemode = false
+ bare = false
+ logallrefupdates = true
+ symlinks = false
+ ignorecase = true
+ hideDotFiles = dotGitOnly
diff --git a/tests/resources/sub.git/index b/tests/resources/sub.git/index
new file mode 100644
index 000000000..54be69e33
--- /dev/null
+++ b/tests/resources/sub.git/index
Binary files differ
diff --git a/tests/resources/sub.git/logs/HEAD b/tests/resources/sub.git/logs/HEAD
new file mode 100644
index 000000000..f636268f6
--- /dev/null
+++ b/tests/resources/sub.git/logs/HEAD
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 b7a59b3f4ea13b985f8a1e0d3757d5cd3331add8 Edward Thomson <ethomson@microsoft.com> 1442522322 -0400 commit (initial): Initial revision
diff --git a/tests/resources/sub.git/logs/refs/heads/master b/tests/resources/sub.git/logs/refs/heads/master
new file mode 100644
index 000000000..f636268f6
--- /dev/null
+++ b/tests/resources/sub.git/logs/refs/heads/master
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 b7a59b3f4ea13b985f8a1e0d3757d5cd3331add8 Edward Thomson <ethomson@microsoft.com> 1442522322 -0400 commit (initial): Initial revision
diff --git a/tests/resources/sub.git/objects/10/ddd6d257e01349d514541981aeecea6b2e741d b/tests/resources/sub.git/objects/10/ddd6d257e01349d514541981aeecea6b2e741d
new file mode 100644
index 000000000..a095b3fb8
--- /dev/null
+++ b/tests/resources/sub.git/objects/10/ddd6d257e01349d514541981aeecea6b2e741d
Binary files differ
diff --git a/tests/resources/sub.git/objects/17/6a458f94e0ea5272ce67c36bf30b6be9caf623 b/tests/resources/sub.git/objects/17/6a458f94e0ea5272ce67c36bf30b6be9caf623
new file mode 100644
index 000000000..ef8316670
--- /dev/null
+++ b/tests/resources/sub.git/objects/17/6a458f94e0ea5272ce67c36bf30b6be9caf623
Binary files differ
diff --git a/tests/resources/sub.git/objects/94/c7d78d85c933d1d95b56bc2de01833ba8559fb b/tests/resources/sub.git/objects/94/c7d78d85c933d1d95b56bc2de01833ba8559fb
new file mode 100644
index 000000000..9adc11d71
--- /dev/null
+++ b/tests/resources/sub.git/objects/94/c7d78d85c933d1d95b56bc2de01833ba8559fb
Binary files differ
diff --git a/tests/resources/sub.git/objects/b7/a59b3f4ea13b985f8a1e0d3757d5cd3331add8 b/tests/resources/sub.git/objects/b7/a59b3f4ea13b985f8a1e0d3757d5cd3331add8
new file mode 100644
index 000000000..221b55de7
--- /dev/null
+++ b/tests/resources/sub.git/objects/b7/a59b3f4ea13b985f8a1e0d3757d5cd3331add8
Binary files differ
diff --git a/tests/resources/sub.git/objects/d0/ee23c41b28746d7e822511d7838bce784ae773 b/tests/resources/sub.git/objects/d0/ee23c41b28746d7e822511d7838bce784ae773
new file mode 100644
index 000000000..d9bb9c84d
--- /dev/null
+++ b/tests/resources/sub.git/objects/d0/ee23c41b28746d7e822511d7838bce784ae773
Binary files differ
diff --git a/tests/resources/sub.git/refs/heads/master b/tests/resources/sub.git/refs/heads/master
new file mode 100644
index 000000000..0e4d6e2a7
--- /dev/null
+++ b/tests/resources/sub.git/refs/heads/master
@@ -0,0 +1 @@
+b7a59b3f4ea13b985f8a1e0d3757d5cd3331add8
diff --git a/tests/resources/super/.gitted/COMMIT_EDITMSG b/tests/resources/super/.gitted/COMMIT_EDITMSG
new file mode 100644
index 000000000..e2d6b8987
--- /dev/null
+++ b/tests/resources/super/.gitted/COMMIT_EDITMSG
@@ -0,0 +1 @@
+submodule
diff --git a/tests/resources/super/.gitted/HEAD b/tests/resources/super/.gitted/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/tests/resources/super/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/super/.gitted/config b/tests/resources/super/.gitted/config
new file mode 100644
index 000000000..06a8b7790
--- /dev/null
+++ b/tests/resources/super/.gitted/config
@@ -0,0 +1,10 @@
+[core]
+ repositoryformatversion = 0
+ filemode = false
+ bare = false
+ logallrefupdates = true
+ symlinks = false
+ ignorecase = true
+ hideDotFiles = dotGitOnly
+[submodule "sub"]
+ url = ../sub.git
diff --git a/tests/resources/super/.gitted/index b/tests/resources/super/.gitted/index
new file mode 100644
index 000000000..cc2ffffb9
--- /dev/null
+++ b/tests/resources/super/.gitted/index
Binary files differ
diff --git a/tests/resources/super/.gitted/objects/51/589c218bf77a8da9e9d8dbc097d76a742726c4 b/tests/resources/super/.gitted/objects/51/589c218bf77a8da9e9d8dbc097d76a742726c4
new file mode 100644
index 000000000..727d3a696
--- /dev/null
+++ b/tests/resources/super/.gitted/objects/51/589c218bf77a8da9e9d8dbc097d76a742726c4
Binary files differ
diff --git a/tests/resources/super/.gitted/objects/79/d0d58ca6aa1688a073d280169908454cad5b91 b/tests/resources/super/.gitted/objects/79/d0d58ca6aa1688a073d280169908454cad5b91
new file mode 100644
index 000000000..7fd889d5f
--- /dev/null
+++ b/tests/resources/super/.gitted/objects/79/d0d58ca6aa1688a073d280169908454cad5b91
Binary files differ
diff --git a/tests/resources/super/.gitted/objects/d7/57768b570a83e80d02edcc1032db14573e5034 b/tests/resources/super/.gitted/objects/d7/57768b570a83e80d02edcc1032db14573e5034
new file mode 100644
index 000000000..f26c68c54
--- /dev/null
+++ b/tests/resources/super/.gitted/objects/d7/57768b570a83e80d02edcc1032db14573e5034
Binary files differ
diff --git a/tests/resources/super/.gitted/refs/heads/master b/tests/resources/super/.gitted/refs/heads/master
new file mode 100644
index 000000000..663a9dcd9
--- /dev/null
+++ b/tests/resources/super/.gitted/refs/heads/master
@@ -0,0 +1 @@
+79d0d58ca6aa1688a073d280169908454cad5b91
diff --git a/tests/resources/super/gitmodules b/tests/resources/super/gitmodules
new file mode 100644
index 000000000..a3d8f7f5a
--- /dev/null
+++ b/tests/resources/super/gitmodules
@@ -0,0 +1,3 @@
+[submodule "sub"]
+ path = sub
+ url = ../sub.git
diff --git a/tests/submodule/submodule_helpers.c b/tests/submodule/submodule_helpers.c
index 1dc687231..cde69d92d 100644
--- a/tests/submodule/submodule_helpers.c
+++ b/tests/submodule/submodule_helpers.c
@@ -126,6 +126,22 @@ git_repository *setup_fixture_submod2(void)
return repo;
}
+git_repository *setup_fixture_super(void)
+{
+ git_repository *repo = cl_git_sandbox_init("super");
+
+ cl_fixture_sandbox("sub.git");
+ p_mkdir("super/sub", 0777);
+
+ rewrite_gitmodules(git_repository_workdir(repo));
+
+ cl_set_cleanup(cleanup_fixture_submodules, "sub.git");
+
+ cl_git_pass(git_repository_reinit_filesystem(repo, 1));
+
+ return repo;
+}
+
git_repository *setup_fixture_submodule_simple(void)
{
git_repository *repo = cl_git_sandbox_init("submodule_simple");
diff --git a/tests/submodule/submodule_helpers.h b/tests/submodule/submodule_helpers.h
index 1493f245f..1191ab35b 100644
--- a/tests/submodule/submodule_helpers.h
+++ b/tests/submodule/submodule_helpers.h
@@ -4,6 +4,7 @@ extern void rewrite_gitmodules(const char *workdir);
extern git_repository *setup_fixture_submodules(void);
extern git_repository *setup_fixture_submod2(void);
extern git_repository *setup_fixture_submodule_simple(void);
+extern git_repository *setup_fixture_super(void);
extern unsigned int get_submodule_status(git_repository *, const char *);
diff --git a/tests/win32/longpath.c b/tests/win32/longpath.c
new file mode 100644
index 000000000..6de7d389a
--- /dev/null
+++ b/tests/win32/longpath.c
@@ -0,0 +1,60 @@
+#include "clar_libgit2.h"
+
+#include "git2/clone.h"
+#include "clone.h"
+#include "buffer.h"
+#include "fileops.h"
+
+static git_buf path = GIT_BUF_INIT;
+
+void test_win32_longpath__initialize(void)
+{
+#ifdef GIT_WIN32
+ const char *base = clar_sandbox_path();
+ size_t base_len = strlen(base);
+ size_t remain = MAX_PATH - base_len;
+ size_t i;
+
+ git_buf_clear(&path);
+ git_buf_puts(&path, base);
+ git_buf_putc(&path, '/');
+
+ cl_assert(remain < (MAX_PATH - 5));
+
+ for (i = 0; i < (remain - 5); i++)
+ git_buf_putc(&path, 'a');
+#endif
+}
+
+void test_win32_longpath__cleanup(void)
+{
+ git_buf_free(&path);
+}
+
+#ifdef GIT_WIN32
+void assert_name_too_long(void)
+{
+ const git_error *err;
+ size_t expected_len, actual_len;
+ const char *expected_msg;
+
+ err = giterr_last();
+ actual_len = strlen(err->message);
+
+ expected_msg = git_win32_get_error_message(ERROR_FILENAME_EXCED_RANGE);
+ expected_len = strlen(expected_msg);
+
+ /* check the suffix */
+ cl_assert_equal_s(expected_msg, err->message + (actual_len - expected_len));
+}
+#endif
+
+void test_win32_longpath__errmsg_on_checkout(void)
+{
+#ifdef GIT_WIN32
+ git_repository *repo;
+
+ cl_git_fail(git_clone(&repo, cl_fixture("testrepo.git"), path.ptr, NULL));
+ assert_name_too_long();
+#endif
+}