Unverified Commit b55bb43d by Patrick Steinhardt Committed by GitHub

Merge pull request #4475 from pks-t/pks/v0.26.1-backports

v0.26.3 backports
parents dd2d5381 bb00842f
v0.26.3
-------
This is a bugfix release. It includes the following non-exclusive list of
improvements, which have been backported from the master branch:
* Fix cloning of the libgit2 project with `git clone --recursive` by removing an
invalid submodule from our testing data.
* Fix endianness of the port in `p_getaddrinfo()`.
* Fix handling of negative gitignore rules with wildcards.
* Fix handling of case-insensitive negative gitignore rules.
* Fix resolving references to a tag if the reference is stored with its fully
resolved OID in the packed-refs file.
* Fix checkout not treating worktree files as modified when only their mode has
changed.
* Fix rename detection with `GIT_DIFF_FIND_RENAMES_FROM_REWRITES`.
* Enable Windows 7 and earlier to use TLS 1.2.
v0.26.2 v0.26.2
------- -------
......
...@@ -437,10 +437,12 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME; ...@@ -437,10 +437,12 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME;
#define WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE 0x00000040 #define WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE 0x00000040
#define WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR 0x80000000 #define WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR 0x80000000
#define WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 0x00000008 #define WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 0x00000008
#define WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 0x00000020 #define WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 0x00000020
#define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 0x00000080 #define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 0x00000080
#define WINHTTP_FLAG_SECURE_PROTOCOL_ALL (WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 | WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1) #define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 0x00000200
#define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 0x00000800
#define WINHTTP_FLAG_SECURE_PROTOCOL_ALL (WINHTTP_FLAG_SECURE_PROTOCOL_SSL2 | WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1)
#define WINHTTP_AUTH_SCHEME_BASIC 0x00000001 #define WINHTTP_AUTH_SCHEME_BASIC 0x00000001
#define WINHTTP_AUTH_SCHEME_NTLM 0x00000002 #define WINHTTP_AUTH_SCHEME_NTLM 0x00000002
......
...@@ -62,5 +62,6 @@ ...@@ -62,5 +62,6 @@
#include "git2/tree.h" #include "git2/tree.h"
#include "git2/types.h" #include "git2/types.h"
#include "git2/version.h" #include "git2/version.h"
#include "git2/worktree.h"
#endif #endif
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "git2/types.h" #include "git2/types.h"
#include "git2/oid.h" #include "git2/oid.h"
#include "git2/odb.h" #include "git2/odb.h"
#include "git2/buffer.h"
/** /**
* @file git2/sys/mempack.h * @file git2/sys/mempack.h
...@@ -38,10 +39,10 @@ GIT_BEGIN_DECL ...@@ -38,10 +39,10 @@ GIT_BEGIN_DECL
* Subsequent reads will also be served from the in-memory store * Subsequent reads will also be served from the in-memory store
* to ensure consistency, until the memory store is dumped. * to ensure consistency, until the memory store is dumped.
* *
* @param out Poiter where to store the ODB backend * @param out Pointer where to store the ODB backend
* @return 0 on success; error code otherwise * @return 0 on success; error code otherwise
*/ */
int git_mempack_new(git_odb_backend **out); GIT_EXTERN(int) git_mempack_new(git_odb_backend **out);
/** /**
* Dump all the queued in-memory writes to a packfile. * Dump all the queued in-memory writes to a packfile.
...@@ -64,7 +65,7 @@ int git_mempack_new(git_odb_backend **out); ...@@ -64,7 +65,7 @@ int git_mempack_new(git_odb_backend **out);
* @param backend The mempack backend * @param backend The mempack backend
* @return 0 on success; error code otherwise * @return 0 on success; error code otherwise
*/ */
int git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backend); GIT_EXTERN(int) git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backend);
/** /**
* Reset the memory packer by clearing all the queued objects. * Reset the memory packer by clearing all the queued objects.
...@@ -78,7 +79,7 @@ int git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backe ...@@ -78,7 +79,7 @@ int git_mempack_dump(git_buf *pack, git_repository *repo, git_odb_backend *backe
* *
* @param backend The mempack backend * @param backend The mempack backend
*/ */
void git_mempack_reset(git_odb_backend *backend); GIT_EXTERN(void) git_mempack_reset(git_odb_backend *backend);
GIT_END_DECL GIT_END_DECL
......
...@@ -7,10 +7,10 @@ ...@@ -7,10 +7,10 @@
#ifndef INCLUDE_git_version_h__ #ifndef INCLUDE_git_version_h__
#define INCLUDE_git_version_h__ #define INCLUDE_git_version_h__
#define LIBGIT2_VERSION "0.26.2" #define LIBGIT2_VERSION "0.26.3"
#define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MAJOR 0
#define LIBGIT2_VER_MINOR 26 #define LIBGIT2_VER_MINOR 26
#define LIBGIT2_VER_REVISION 2 #define LIBGIT2_VER_REVISION 3
#define LIBGIT2_VER_PATCH 0 #define LIBGIT2_VER_PATCH 0
#define LIBGIT2_SOVERSION 26 #define LIBGIT2_SOVERSION 26
......
...@@ -159,6 +159,19 @@ GIT_INLINE(bool) is_workdir_base_or_new( ...@@ -159,6 +159,19 @@ GIT_INLINE(bool) is_workdir_base_or_new(
git_oid__cmp(&newitem->id, workdir_id) == 0); git_oid__cmp(&newitem->id, workdir_id) == 0);
} }
GIT_INLINE(bool) is_file_mode_changed(git_filemode_t a, git_filemode_t b)
{
#ifdef GIT_WIN32
/*
* On Win32 we do not support the executable bit; the file will
* always be 0100644 on disk, don't bother doing a test.
*/
return false;
#else
return (S_ISREG(a) && S_ISREG(b) && a != b);
#endif
}
static bool checkout_is_workdir_modified( static bool checkout_is_workdir_modified(
checkout_data *data, checkout_data *data,
const git_diff_file *baseitem, const git_diff_file *baseitem,
...@@ -192,16 +205,23 @@ static bool checkout_is_workdir_modified( ...@@ -192,16 +205,23 @@ static bool checkout_is_workdir_modified(
return rval; return rval;
} }
/* Look at the cache to decide if the workdir is modified. If not, /*
* we can simply compare the oid in the cache to the baseitem instead * Look at the cache to decide if the workdir is modified: if the
* of hashing the file. If so, we allow the checkout to proceed if the * cache contents match the workdir contents, then we do not need
* oid is identical (ie, the staged item is what we're trying to check * to examine the working directory directly, instead we can
* out.) * examine the cache to see if _it_ has been modified. This allows
* us to avoid touching the disk.
*/ */
if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) { ie = git_index_get_bypath(data->index, wditem->path, 0);
if (git_index_time_eq(&wditem->mtime, &ie->mtime) &&
wditem->file_size == ie->file_size) if (ie != NULL &&
return !is_workdir_base_or_new(&ie->id, baseitem, newitem); git_index_time_eq(&wditem->mtime, &ie->mtime) &&
wditem->file_size == ie->file_size &&
!is_file_mode_changed(wditem->mode, ie->mode)) {
/* The workdir is modified iff the index entry is modified */
return !is_workdir_base_or_new(&ie->id, baseitem, newitem) ||
is_file_mode_changed(baseitem->mode, ie->mode);
} }
/* depending on where base is coming from, we may or may not know /* depending on where base is coming from, we may or may not know
...@@ -214,6 +234,9 @@ static bool checkout_is_workdir_modified( ...@@ -214,6 +234,9 @@ static bool checkout_is_workdir_modified(
if (S_ISDIR(wditem->mode)) if (S_ISDIR(wditem->mode))
return false; return false;
if (is_file_mode_changed(baseitem->mode, wditem->mode))
return true;
if (git_diff__oid_for_entry(&oid, data->diff, wditem, wditem->mode, NULL) < 0) if (git_diff__oid_for_entry(&oid, data->diff, wditem, wditem->mode, NULL) < 0)
return false; return false;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "stream.h" #include "stream.h"
#include "git2/transport.h" #include "git2/transport.h"
#include "buffer.h" #include "buffer.h"
#include "global.h"
#include "vector.h" #include "vector.h"
#include "proxy.h" #include "proxy.h"
...@@ -36,6 +37,18 @@ typedef struct { ...@@ -36,6 +37,18 @@ typedef struct {
git_cred *proxy_cred; git_cred *proxy_cred;
} curl_stream; } curl_stream;
int git_curl_stream_global_init(void)
{
if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
giterr_set(GITERR_NET, "could not initialize curl");
return -1;
}
/* `curl_global_cleanup` is provided by libcurl */
git__on_shutdown(curl_global_cleanup);
return 0;
}
static int seterr_curl(curl_stream *s) static int seterr_curl(curl_stream *s)
{ {
giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error); giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error);
...@@ -193,6 +206,7 @@ static int curls_set_proxy(git_stream *stream, const git_proxy_options *proxy_op ...@@ -193,6 +206,7 @@ static int curls_set_proxy(git_stream *stream, const git_proxy_options *proxy_op
CURLcode res; CURLcode res;
curl_stream *s = (curl_stream *) stream; curl_stream *s = (curl_stream *) stream;
git_proxy_options_clear(&s->proxy);
if ((error = git_proxy_options_dup(&s->proxy, proxy_opts)) < 0) if ((error = git_proxy_options_dup(&s->proxy, proxy_opts)) < 0)
return error; return error;
...@@ -293,6 +307,8 @@ static void curls_free(git_stream *stream) ...@@ -293,6 +307,8 @@ static void curls_free(git_stream *stream)
curls_close(stream); curls_close(stream);
git_strarray_free(&s->cert_info_strings); git_strarray_free(&s->cert_info_strings);
git_proxy_options_clear(&s->proxy);
git_cred_free(s->proxy_cred);
git__free(s); git__free(s);
} }
...@@ -348,6 +364,11 @@ int git_curl_stream_new(git_stream **out, const char *host, const char *port) ...@@ -348,6 +364,11 @@ int git_curl_stream_new(git_stream **out, const char *host, const char *port)
#include "stream.h" #include "stream.h"
int git_curl_stream_global_init(void)
{
return 0;
}
int git_curl_stream_new(git_stream **out, const char *host, const char *port) int git_curl_stream_new(git_stream **out, const char *host, const char *port)
{ {
GIT_UNUSED(out); GIT_UNUSED(out);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "git2/sys/stream.h" #include "git2/sys/stream.h"
extern int git_curl_stream_global_init(void);
extern int git_curl_stream_new(git_stream **out, const char *host, const char *port); extern int git_curl_stream_new(git_stream **out, const char *host, const char *port);
#endif #endif
...@@ -12,13 +12,6 @@ ...@@ -12,13 +12,6 @@
#include "commit.h" #include "commit.h"
#include "index.h" #include "index.h"
#define DIFF_FLAG_IS_SET(DIFF,FLAG) \
(((DIFF)->opts.flags & (FLAG)) != 0)
#define DIFF_FLAG_ISNT_SET(DIFF,FLAG) \
(((DIFF)->opts.flags & (FLAG)) == 0)
#define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->opts.flags = \
(VAL) ? ((DIFF)->opts.flags | (FLAG)) : ((DIFF)->opts.flags & ~(VAL))
GIT_INLINE(const char *) diff_delta__path(const git_diff_delta *delta) GIT_INLINE(const char *) diff_delta__path(const git_diff_delta *delta)
{ {
const char *str = delta->old_file.path; const char *str = delta->old_file.path;
......
...@@ -138,7 +138,6 @@ int git_diff_file_content__init_from_src( ...@@ -138,7 +138,6 @@ int git_diff_file_content__init_from_src(
memset(fc, 0, sizeof(*fc)); memset(fc, 0, sizeof(*fc));
fc->repo = repo; fc->repo = repo;
fc->file = as_file; fc->file = as_file;
fc->blob = src->blob;
if (!src->blob && !src->buf) { if (!src->blob && !src->buf) {
fc->flags |= GIT_DIFF_FLAG__NO_DATA; fc->flags |= GIT_DIFF_FLAG__NO_DATA;
...@@ -148,12 +147,15 @@ int git_diff_file_content__init_from_src( ...@@ -148,12 +147,15 @@ int git_diff_file_content__init_from_src(
fc->file->mode = GIT_FILEMODE_BLOB; fc->file->mode = GIT_FILEMODE_BLOB;
if (src->blob) { if (src->blob) {
git_blob_dup((git_blob **)&fc->blob, (git_blob *) src->blob);
fc->file->size = git_blob_rawsize(src->blob); fc->file->size = git_blob_rawsize(src->blob);
git_oid_cpy(&fc->file->id, git_blob_id(src->blob)); git_oid_cpy(&fc->file->id, git_blob_id(src->blob));
fc->file->id_abbrev = GIT_OID_HEXSZ; fc->file->id_abbrev = GIT_OID_HEXSZ;
fc->map.len = (size_t)fc->file->size; fc->map.len = (size_t)fc->file->size;
fc->map.data = (char *)git_blob_rawcontent(src->blob); fc->map.data = (char *)git_blob_rawcontent(src->blob);
fc->flags |= GIT_DIFF_FLAG__FREE_BLOB;
} else { } else {
fc->file->size = src->buflen; fc->file->size = src->buflen;
git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJ_BLOB); git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJ_BLOB);
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
(((DIFF)->base.opts.flags & (FLAG)) == 0) (((DIFF)->base.opts.flags & (FLAG)) == 0)
#define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->base.opts.flags = \ #define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->base.opts.flags = \
(VAL) ? ((DIFF)->base.opts.flags | (FLAG)) : \ (VAL) ? ((DIFF)->base.opts.flags | (FLAG)) : \
((DIFF)->base.opts.flags & ~(VAL)) ((DIFF)->base.opts.flags & ~(FLAG))
typedef struct { typedef struct {
struct git_diff base; struct git_diff base;
......
...@@ -685,8 +685,10 @@ static bool is_rename_target( ...@@ -685,8 +685,10 @@ static bool is_rename_target(
break; break;
} }
if (FLAG_SET(opts, GIT_DIFF_FIND_RENAMES_FROM_REWRITES) && if (FLAG_SET(opts, GIT_DIFF_FIND_RENAMES_FROM_REWRITES) &&
delta->similarity < opts->rename_from_rewrite_threshold) delta->similarity < opts->rename_from_rewrite_threshold) {
delta->flags |= GIT_DIFF_FLAG__TO_SPLIT;
break; break;
}
return false; return false;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "sysdir.h" #include "sysdir.h"
#include "filter.h" #include "filter.h"
#include "merge_driver.h" #include "merge_driver.h"
#include "curl_stream.h"
#include "openssl_stream.h" #include "openssl_stream.h"
#include "thread-utils.h" #include "thread-utils.h"
#include "git2/global.h" #include "git2/global.h"
...@@ -22,7 +23,7 @@ ...@@ -22,7 +23,7 @@
git_mutex git__mwindow_mutex; git_mutex git__mwindow_mutex;
#define MAX_SHUTDOWN_CB 9 #define MAX_SHUTDOWN_CB 10
static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB]; static git_global_shutdown_fn git__shutdown_callbacks[MAX_SHUTDOWN_CB];
static git_atomic git__n_shutdown_callbacks; static git_atomic git__n_shutdown_callbacks;
...@@ -62,7 +63,8 @@ static int init_common(void) ...@@ -62,7 +63,8 @@ static int init_common(void)
(ret = git_filter_global_init()) == 0 && (ret = git_filter_global_init()) == 0 &&
(ret = git_merge_driver_global_init()) == 0 && (ret = git_merge_driver_global_init()) == 0 &&
(ret = git_transport_ssh_global_init()) == 0 && (ret = git_transport_ssh_global_init()) == 0 &&
(ret = git_openssl_stream_global_init()) == 0) (ret = git_openssl_stream_global_init()) == 0 &&
(ret = git_curl_stream_global_init()) == 0)
ret = git_mwindow_global_init(); ret = git_mwindow_global_init();
GIT_MEMORY_BARRIER; GIT_MEMORY_BARRIER;
......
...@@ -23,21 +23,36 @@ struct git_hash_ctx { ...@@ -23,21 +23,36 @@ struct git_hash_ctx {
GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx) GIT_INLINE(int) git_hash_init(git_hash_ctx *ctx)
{ {
assert(ctx); assert(ctx);
SHA1_Init(&ctx->c);
if (SHA1_Init(&ctx->c) != 1) {
giterr_set(GITERR_SHA1, "hash_openssl: failed to initialize hash context");
return -1;
}
return 0; return 0;
} }
GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len) GIT_INLINE(int) git_hash_update(git_hash_ctx *ctx, const void *data, size_t len)
{ {
assert(ctx); assert(ctx);
SHA1_Update(&ctx->c, data, len);
if (SHA1_Update(&ctx->c, data, len) != 1) {
giterr_set(GITERR_SHA1, "hash_openssl: failed to update hash");
return -1;
}
return 0; return 0;
} }
GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx) GIT_INLINE(int) git_hash_final(git_oid *out, git_hash_ctx *ctx)
{ {
assert(ctx); assert(ctx);
SHA1_Final(out->id, &ctx->c);
if (SHA1_Final(out->id, &ctx->c) != 1) {
giterr_set(GITERR_SHA1, "hash_openssl: failed to finalize hash");
return -1;
}
return 0; return 0;
} }
......
...@@ -40,38 +40,42 @@ ...@@ -40,38 +40,42 @@
*/ */
static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg) static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg)
{ {
int (*cmp)(const char *, const char *, size_t);
git_attr_fnmatch *longer, *shorter; git_attr_fnmatch *longer, *shorter;
char *p; char *p;
if ((rule->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0 if ((rule->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0
&& (neg->flags & GIT_ATTR_FNMATCH_NEGATIVE) != 0) { || (neg->flags & GIT_ATTR_FNMATCH_NEGATIVE) == 0)
return false;
/* If lengths match we need to have an exact match */
if (rule->length == neg->length) { if (neg->flags & GIT_ATTR_FNMATCH_ICASE)
return strcmp(rule->pattern, neg->pattern) == 0; cmp = git__strncasecmp;
} else if (rule->length < neg->length) { else
shorter = rule; cmp = git__strncmp;
longer = neg;
} else { /* If lengths match we need to have an exact match */
shorter = neg; if (rule->length == neg->length) {
longer = rule; return cmp(rule->pattern, neg->pattern, rule->length) == 0;
} } else if (rule->length < neg->length) {
shorter = rule;
/* Otherwise, we need to check if the shorter longer = neg;
* rule is a basename only (that is, it contains } else {
* no path separator) and, if so, if it shorter = neg;
* matches the tail of the longer rule */ longer = rule;
p = longer->pattern + longer->length - shorter->length; }
if (p[-1] != '/') /* Otherwise, we need to check if the shorter
return false; * rule is a basename only (that is, it contains
if (memchr(shorter->pattern, '/', shorter->length) != NULL) * no path separator) and, if so, if it
return false; * matches the tail of the longer rule */
p = longer->pattern + longer->length - shorter->length;
return memcmp(p, shorter->pattern, shorter->length) == 0; if (p[-1] != '/')
} return false;
if (memchr(shorter->pattern, '/', shorter->length) != NULL)
return false;
return false; return cmp(p, shorter->pattern, shorter->length) == 0;
} }
/** /**
...@@ -89,7 +93,7 @@ static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg) ...@@ -89,7 +93,7 @@ static int does_negate_pattern(git_attr_fnmatch *rule, git_attr_fnmatch *neg)
*/ */
static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match) static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match)
{ {
int error = 0; int error = 0, fnflags;
size_t i; size_t i;
git_attr_fnmatch *rule; git_attr_fnmatch *rule;
char *path; char *path;
...@@ -97,6 +101,10 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match ...@@ -97,6 +101,10 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
*out = 0; *out = 0;
fnflags = FNM_PATHNAME;
if (match->flags & GIT_ATTR_FNMATCH_ICASE)
fnflags |= FNM_IGNORECASE;
/* path of the file relative to the workdir, so we match the rules in subdirs */ /* path of the file relative to the workdir, so we match the rules in subdirs */
if (match->containing_dir) { if (match->containing_dir) {
git_buf_puts(&buf, match->containing_dir); git_buf_puts(&buf, match->containing_dir);
...@@ -117,12 +125,12 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match ...@@ -117,12 +125,12 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
continue; continue;
} }
/* /*
* When dealing with a directory, we add '/<star>' so * When dealing with a directory, we add '/<star>' so
* p_fnmatch() honours FNM_PATHNAME. Checking for LEADINGDIR * p_fnmatch() honours FNM_PATHNAME. Checking for LEADINGDIR
* alone isn't enough as that's also set for nagations, so we * alone isn't enough as that's also set for nagations, so we
* need to check that NEGATIVE is off. * need to check that NEGATIVE is off.
*/ */
git_buf_clear(&buf); git_buf_clear(&buf);
if (rule->containing_dir) { if (rule->containing_dir) {
git_buf_puts(&buf, rule->containing_dir); git_buf_puts(&buf, rule->containing_dir);
...@@ -136,7 +144,7 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match ...@@ -136,7 +144,7 @@ static int does_negate_rule(int *out, git_vector *rules, git_attr_fnmatch *match
if (error < 0) if (error < 0)
goto out; goto out;
if ((error = p_fnmatch(git_buf_cstr(&buf), path, FNM_PATHNAME)) < 0) { if ((error = p_fnmatch(git_buf_cstr(&buf), path, fnflags)) < 0) {
giterr_set(GITERR_INVALID, "error matching pattern"); giterr_set(GITERR_INVALID, "error matching pattern");
goto out; goto out;
} }
...@@ -197,10 +205,26 @@ static int parse_ignore_file( ...@@ -197,10 +205,26 @@ static int parse_ignore_file(
if (ignore_case) if (ignore_case)
match->flags |= GIT_ATTR_FNMATCH_ICASE; match->flags |= GIT_ATTR_FNMATCH_ICASE;
while (match->length > 0) {
if (match->pattern[match->length - 1] == ' ' ||
match->pattern[match->length - 1] == '\t') {
match->pattern[match->length - 1] = 0;
match->length --;
} else {
break;
}
}
scan = git__next_line(scan); scan = git__next_line(scan);
/* if a negative match doesn't actually do anything, throw it away */ /*
if (match->flags & GIT_ATTR_FNMATCH_NEGATIVE) * If a negative match doesn't actually do anything,
* throw it away. As we cannot always verify whether a
* rule containing wildcards negates another rule, we
* do not optimize away these rules, though.
* */
if (match->flags & GIT_ATTR_FNMATCH_NEGATIVE
&& !(match->flags & GIT_ATTR_FNMATCH_HASWILD))
error = does_negate_rule(&valid_rule, &attrs->rules, match); error = does_negate_rule(&valid_rule, &attrs->rules, match);
if (!error && valid_rule) if (!error && valid_rule)
......
...@@ -843,6 +843,7 @@ static int fix_thin_pack(git_indexer *idx, git_transfer_progress *stats) ...@@ -843,6 +843,7 @@ static int fix_thin_pack(git_indexer *idx, git_transfer_progress *stats)
static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats) static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
{ {
unsigned int i; unsigned int i;
int error;
struct delta_info *delta; struct delta_info *delta;
int progressed = 0, non_null = 0, progress_cb_result; int progressed = 0, non_null = 0, progress_cb_result;
...@@ -857,8 +858,13 @@ static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats) ...@@ -857,8 +858,13 @@ static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
non_null = 1; non_null = 1;
idx->off = delta->delta_off; idx->off = delta->delta_off;
if (git_packfile_unpack(&obj, idx->pack, &idx->off) < 0) if ((error = git_packfile_unpack(&obj, idx->pack, &idx->off)) < 0) {
continue; if (error == GIT_PASSTHROUGH) {
/* We have not seen the base object, we'll try again later. */
continue;
}
return -1;
}
if (hash_and_save(idx, &obj, delta->delta_off) < 0) if (hash_and_save(idx, &obj, delta->delta_off) < 0)
continue; continue;
...@@ -950,6 +956,10 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats) ...@@ -950,6 +956,10 @@ int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats)
giterr_set(GITERR_INDEXER, "unexpected data at the end of the pack"); giterr_set(GITERR_INDEXER, "unexpected data at the end of the pack");
return -1; return -1;
} }
if (idx->off + 20 > idx->pack->mwf.size) {
giterr_set(GITERR_INDEXER, "missing trailer at the end of the pack");
return -1;
}
packfile_trailer = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ, &left); packfile_trailer = git_mwindow_open(&idx->pack->mwf, &w, idx->pack->mwf.size - GIT_OID_RAWSZ, GIT_OID_RAWSZ, &left);
if (packfile_trailer == NULL) { if (packfile_trailer == NULL) {
...@@ -1118,6 +1128,9 @@ void git_indexer_free(git_indexer *idx) ...@@ -1118,6 +1128,9 @@ void git_indexer_free(git_indexer *idx)
if (idx == NULL) if (idx == NULL)
return; return;
if (idx->have_stream)
git_packfile_stream_free(&idx->stream);
git_vector_free_deep(&idx->objects); git_vector_free_deep(&idx->objects);
if (idx->pack->idx_cache) { if (idx->pack->idx_cache) {
......
...@@ -2141,7 +2141,7 @@ static int compute_base( ...@@ -2141,7 +2141,7 @@ static int compute_base(
git_oidarray bases = {0}; git_oidarray bases = {0};
git_annotated_commit *base = NULL, *other = NULL, *new_base = NULL; git_annotated_commit *base = NULL, *other = NULL, *new_base = NULL;
git_merge_options opts = GIT_MERGE_OPTIONS_INIT; git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
size_t i; size_t i, base_count;
int error; int error;
*out = NULL; *out = NULL;
...@@ -2149,17 +2149,27 @@ static int compute_base( ...@@ -2149,17 +2149,27 @@ static int compute_base(
if (given_opts) if (given_opts)
memcpy(&opts, given_opts, sizeof(git_merge_options)); memcpy(&opts, given_opts, sizeof(git_merge_options));
if ((error = insert_head_ids(&head_ids, one)) < 0 || /* With more than two commits, merge_bases_many finds the base of
(error = insert_head_ids(&head_ids, two)) < 0) * the first commit and a hypothetical merge of the others. Since
* "one" may itself be a virtual commit, which insert_head_ids
* substitutes multiple ancestors for, it needs to be added
* after "two" which is always a single real commit.
*/
if ((error = insert_head_ids(&head_ids, two)) < 0 ||
(error = insert_head_ids(&head_ids, one)) < 0 ||
(error = git_merge_bases_many(&bases, repo,
head_ids.size, head_ids.ptr)) < 0)
goto done; goto done;
if ((error = git_merge_bases_many(&bases, repo, base_count = (opts.flags & GIT_MERGE_NO_RECURSIVE) ? 0 : bases.count;
head_ids.size, head_ids.ptr)) < 0 ||
(error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0 || if (base_count)
(opts.flags & GIT_MERGE_NO_RECURSIVE)) git_oidarray__reverse(&bases);
if ((error = git_annotated_commit_lookup(&base, repo, &bases.ids[0])) < 0)
goto done; goto done;
for (i = 1; i < bases.count; i++) { for (i = 1; i < base_count; i++) {
recursion_level++; recursion_level++;
if (opts.recursion_limit && recursion_level > opts.recursion_limit) if (opts.recursion_limit && recursion_level > opts.recursion_limit)
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "common.h" #include "common.h"
#include "git2/object.h" #include "git2/object.h"
#include "git2/sys/odb_backend.h" #include "git2/sys/odb_backend.h"
#include "git2/sys/mempack.h"
#include "fileops.h" #include "fileops.h"
#include "hash.h" #include "hash.h"
#include "odb.h" #include "odb.h"
......
...@@ -19,3 +19,15 @@ void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array) ...@@ -19,3 +19,15 @@ void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array)
arr->count = array->size; arr->count = array->size;
arr->ids = array->ptr; arr->ids = array->ptr;
} }
void git_oidarray__reverse(git_oidarray *arr)
{
size_t i;
git_oid tmp;
for (i = 0; i < arr->count / 2; i++) {
git_oid_cpy(&tmp, &arr->ids[i]);
git_oid_cpy(&arr->ids[i], &arr->ids[(arr->count-1)-i]);
git_oid_cpy(&arr->ids[(arr->count-1)-i], &tmp);
}
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
typedef git_array_t(git_oid) git_array_oid_t; typedef git_array_t(git_oid) git_array_oid_t;
extern void git_oidarray__reverse(git_oidarray *arr);
extern void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array); extern void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array);
#endif #endif
...@@ -149,11 +149,20 @@ int git_openssl_stream_global_init(void) ...@@ -149,11 +149,20 @@ int git_openssl_stream_global_init(void)
return 0; return 0;
} }
#if defined(GIT_THREADS)
static void threadid_cb(CRYPTO_THREADID *threadid)
{
CRYPTO_THREADID_set_numeric(threadid, git_thread_currentid());
}
#endif
int git_openssl_set_locking(void) int git_openssl_set_locking(void)
{ {
#if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L #if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
int num_locks, i; int num_locks, i;
CRYPTO_THREADID_set_callback(threadid_cb);
num_locks = CRYPTO_num_locks(); num_locks = CRYPTO_num_locks();
openssl_locks = git__calloc(num_locks, sizeof(git_mutex)); openssl_locks = git__calloc(num_locks, sizeof(git_mutex));
GITERR_CHECK_ALLOC(openssl_locks); GITERR_CHECK_ALLOC(openssl_locks);
...@@ -272,8 +281,9 @@ static int ssl_set_error(SSL *ssl, int error) ...@@ -272,8 +281,9 @@ static int ssl_set_error(SSL *ssl, int error)
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
e = ERR_get_error(); e = ERR_get_error();
if (e > 0) { if (e > 0) {
giterr_set(GITERR_NET, "SSL error: %s", char errmsg[256];
ERR_error_string(e, NULL)); ERR_error_string_n(e, errmsg, sizeof(errmsg));
giterr_set(GITERR_NET, "SSL error: %s", errmsg);
break; break;
} else if (error < 0) { } else if (error < 0) {
giterr_set(GITERR_OS, "SSL error: syscall failure"); giterr_set(GITERR_OS, "SSL error: syscall failure");
...@@ -283,10 +293,13 @@ static int ssl_set_error(SSL *ssl, int error) ...@@ -283,10 +293,13 @@ static int ssl_set_error(SSL *ssl, int error)
return GIT_EEOF; return GIT_EEOF;
break; break;
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
{
char errmsg[256];
e = ERR_get_error(); e = ERR_get_error();
giterr_set(GITERR_NET, "SSL error: %s", ERR_error_string_n(e, errmsg, sizeof(errmsg));
ERR_error_string(e, NULL)); giterr_set(GITERR_NET, "SSL error: %s", errmsg);
break; break;
}
case SSL_ERROR_NONE: case SSL_ERROR_NONE:
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
default: default:
......
...@@ -716,8 +716,11 @@ int git_packfile_unpack( ...@@ -716,8 +716,11 @@ int git_packfile_unpack(
error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, elem->size, elem->type); error = packfile_unpack_compressed(&delta, p, &w_curs, &curpos, elem->size, elem->type);
git_mwindow_close(&w_curs); git_mwindow_close(&w_curs);
if (error < 0) if (error < 0) {
/* We have transferred ownership of the data to the cache. */
obj->data = NULL;
break; break;
}
/* the current object becomes the new base, on which we apply the delta */ /* the current object becomes the new base, on which we apply the delta */
base = *obj; base = *obj;
...@@ -934,19 +937,19 @@ git_off_t get_delta_base( ...@@ -934,19 +937,19 @@ git_off_t get_delta_base(
if (type == GIT_OBJ_OFS_DELTA) { if (type == GIT_OBJ_OFS_DELTA) {
unsigned used = 0; unsigned used = 0;
unsigned char c = base_info[used++]; unsigned char c = base_info[used++];
base_offset = c & 127; size_t unsigned_base_offset = c & 127;
while (c & 128) { while (c & 128) {
if (left <= used) if (left <= used)
return GIT_EBUFS; return GIT_EBUFS;
base_offset += 1; unsigned_base_offset += 1;
if (!base_offset || MSB(base_offset, 7)) if (!unsigned_base_offset || MSB(unsigned_base_offset, 7))
return 0; /* overflow */ return 0; /* overflow */
c = base_info[used++]; c = base_info[used++];
base_offset = (base_offset << 7) + (c & 127); unsigned_base_offset = (unsigned_base_offset << 7) + (c & 127);
} }
base_offset = delta_obj_offset - base_offset; if (unsigned_base_offset == 0 || (size_t)delta_obj_offset <= unsigned_base_offset)
if (base_offset <= 0 || base_offset >= delta_obj_offset)
return 0; /* out of bound */ return 0; /* out of bound */
base_offset = delta_obj_offset - unsigned_base_offset;
*curpos += used; *curpos += used;
} else if (type == GIT_OBJ_REF_DELTA) { } else if (type == GIT_OBJ_REF_DELTA) {
/* If we have the cooperative cache, search in it first */ /* If we have the cooperative cache, search in it first */
......
...@@ -40,7 +40,7 @@ int p_getaddrinfo( ...@@ -40,7 +40,7 @@ int p_getaddrinfo(
if (ainfo->ai_servent) if (ainfo->ai_servent)
ainfo->ai_port = ainfo->ai_servent->s_port; ainfo->ai_port = ainfo->ai_servent->s_port;
else else
ainfo->ai_port = atol(port); ainfo->ai_port = htons(atol(port));
memcpy(&ainfo->ai_addr_in.sin_addr, memcpy(&ainfo->ai_addr_in.sin_addr,
ainfo->ai_hostent->h_addr_list[0], ainfo->ai_hostent->h_addr_list[0],
......
...@@ -59,6 +59,9 @@ ...@@ -59,6 +59,9 @@
#ifndef O_CLOEXEC #ifndef O_CLOEXEC
#define O_CLOEXEC 0 #define O_CLOEXEC 0
#endif #endif
#ifndef SOCK_CLOEXEC
#define SOCK_CLOEXEC 0
#endif
/* access() mode parameter #defines */ /* access() mode parameter #defines */
#ifndef F_OK #ifndef F_OK
......
...@@ -30,3 +30,9 @@ int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src) ...@@ -30,3 +30,9 @@ int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src)
return 0; return 0;
} }
void git_proxy_options_clear(git_proxy_options *opts)
{
git__free((char *) opts->url);
opts->url = NULL;
}
...@@ -10,5 +10,6 @@ ...@@ -10,5 +10,6 @@
#include "git2/proxy.h" #include "git2/proxy.h"
extern int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src); extern int git_proxy_options_dup(git_proxy_options *tgt, const git_proxy_options *src);
extern void git_proxy_options_clear(git_proxy_options *opts);
#endif #endif
\ No newline at end of file
...@@ -178,6 +178,9 @@ int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks) ...@@ -178,6 +178,9 @@ int git_push_update_tips(git_push *push, const git_remote_callbacks *callbacks)
if (!fetch_spec) if (!fetch_spec)
continue; continue;
/* Clear the buffer which can be dirty from previous iteration */
git_buf_clear(&remote_ref_name);
if ((error = git_refspec_transform(&remote_ref_name, fetch_spec, status->ref)) < 0) if ((error = git_refspec_transform(&remote_ref_name, fetch_spec, status->ref)) < 0)
goto on_error; goto on_error;
......
...@@ -1359,7 +1359,13 @@ int git_reference_peel( ...@@ -1359,7 +1359,13 @@ int git_reference_peel(
return peel_error(error, ref, "Cannot resolve reference"); return peel_error(error, ref, "Cannot resolve reference");
} }
if (!git_oid_iszero(&resolved->peel)) { /*
* If we try to peel an object to a tag, we cannot use
* the fully peeled object, as that will always resolve
* to a commit. So we only want to use the peeled value
* if it is not zero and the target is not a tag.
*/
if (target_type != GIT_OBJ_TAG && !git_oid_iszero(&resolved->peel)) {
error = git_object_lookup(&target, error = git_object_lookup(&target,
git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY); git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY);
} else { } else {
......
...@@ -1235,7 +1235,7 @@ static int reserved_names_add8dot3(git_repository *repo, const char *path) ...@@ -1235,7 +1235,7 @@ static int reserved_names_add8dot3(git_repository *repo, const char *path)
name_len = strlen(name); name_len = strlen(name);
if ((name_len == def_len && memcmp(name, def, def_len) == 0) || if ((name_len == def_len && memcmp(name, def, def_len) == 0) ||
(name_len == def_dot_git_len && memcmp(name, def_dot_git, def_dot_git_len) == 0)) { (name_len == def_dot_git_len && memcmp(name, def_dot_git, def_dot_git_len) == 0)) {
git__free(name); git__free(name);
return 0; return 0;
...@@ -1784,7 +1784,13 @@ static int repo_init_structure( ...@@ -1784,7 +1784,13 @@ static int repo_init_structure(
default_template = true; default_template = true;
} }
if (tdir) { /*
* If tdir was the empty string, treat it like tdir was a path to an
* empty directory (so, don't do any copying). This is the behavior
* that git(1) exhibits, although it doesn't seem to be officially
* documented.
*/
if (tdir && git__strcmp(tdir, "") != 0) {
uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS | uint32_t cpflags = GIT_CPDIR_COPY_SYMLINKS |
GIT_CPDIR_SIMPLE_TO_MODE | GIT_CPDIR_SIMPLE_TO_MODE |
GIT_CPDIR_COPY_DOTFILES; GIT_CPDIR_COPY_DOTFILES;
...@@ -2762,7 +2768,7 @@ int git_repository__cleanup_files( ...@@ -2762,7 +2768,7 @@ int git_repository__cleanup_files(
error = git_futils_rmdir_r(path, NULL, error = git_futils_rmdir_r(path, NULL,
GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS); GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS);
} }
git_buf_clear(&buf); git_buf_clear(&buf);
} }
......
...@@ -232,7 +232,7 @@ int sha1_position(const void *table, ...@@ -232,7 +232,7 @@ int sha1_position(const void *table,
{ {
const unsigned char *base = table; const unsigned char *base = table;
do { while (lo < hi) {
unsigned mi = (lo + hi) / 2; unsigned mi = (lo + hi) / 2;
int cmp = git_oid__hashcmp(base + mi * stride, key); int cmp = git_oid__hashcmp(base + mi * stride, key);
...@@ -243,7 +243,7 @@ int sha1_position(const void *table, ...@@ -243,7 +243,7 @@ int sha1_position(const void *table,
hi = mi; hi = mi;
else else
lo = mi+1; lo = mi+1;
} while (lo < hi); }
return -((int)lo)-1; return -((int)lo)-1;
} }
...@@ -231,6 +231,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out, ...@@ -231,6 +231,7 @@ int git_signature__parse(git_signature *sig, const char **buffer_out,
if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0) { if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0) {
git__free(sig->name); git__free(sig->name);
git__free(sig->email); git__free(sig->email);
sig->name = sig->email = NULL;
return signature_error("invalid Unix timestamp"); return signature_error("invalid Unix timestamp");
} }
......
...@@ -104,7 +104,7 @@ int socket_connect(git_stream *stream) ...@@ -104,7 +104,7 @@ int socket_connect(git_stream *stream)
} }
for (p = info; p != NULL; p = p->ai_next) { for (p = info; p != NULL; p = p->ai_next) {
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); s = socket(p->ai_family, p->ai_socktype | SOCK_CLOEXEC, p->ai_protocol);
if (s == INVALID_SOCKET) if (s == INVALID_SOCKET)
continue; continue;
......
...@@ -81,8 +81,10 @@ static int stransport_connect(git_stream *stream) ...@@ -81,8 +81,10 @@ static int stransport_connect(git_stream *stream)
} }
if (sec_res == kSecTrustResultDeny || sec_res == kSecTrustResultRecoverableTrustFailure || if (sec_res == kSecTrustResultDeny || sec_res == kSecTrustResultRecoverableTrustFailure ||
sec_res == kSecTrustResultFatalTrustFailure) sec_res == kSecTrustResultFatalTrustFailure) {
giterr_set(GITERR_SSL, "untrusted connection error");
return GIT_ECERTIFICATE; return GIT_ECERTIFICATE;
}
return 0; return 0;
......
...@@ -270,7 +270,7 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo) ...@@ -270,7 +270,7 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
git_revwalk *walk = NULL; git_revwalk *walk = NULL;
git_strarray refs; git_strarray refs;
unsigned int i; unsigned int i;
git_reference *ref; git_reference *ref = NULL;
int error; int error;
if ((error = git_reference_list(&refs, repo)) < 0) if ((error = git_reference_list(&refs, repo)) < 0)
...@@ -282,6 +282,9 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo) ...@@ -282,6 +282,9 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
git_revwalk_sorting(walk, GIT_SORT_TIME); git_revwalk_sorting(walk, GIT_SORT_TIME);
for (i = 0; i < refs.count; ++i) { for (i = 0; i < refs.count; ++i) {
git_reference_free(ref);
ref = NULL;
/* No tags */ /* No tags */
if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR)) if (!git__prefixcmp(refs.strings[i], GIT_REFS_TAGS_DIR))
continue; continue;
...@@ -294,16 +297,13 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo) ...@@ -294,16 +297,13 @@ static int fetch_setup_walk(git_revwalk **out, git_repository *repo)
if ((error = git_revwalk_push(walk, git_reference_target(ref))) < 0) if ((error = git_revwalk_push(walk, git_reference_target(ref))) < 0)
goto on_error; goto on_error;
git_reference_free(ref);
} }
git_strarray_free(&refs);
*out = walk; *out = walk;
return 0;
on_error: on_error:
git_revwalk_free(walk); if (error)
git_revwalk_free(walk);
git_reference_free(ref); git_reference_free(ref);
git_strarray_free(&refs); git_strarray_free(&refs);
return error; return error;
......
...@@ -37,6 +37,14 @@ ...@@ -37,6 +37,14 @@
#define WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH 0 #define WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH 0
#endif #endif
#ifndef WINHTTP_FLAG_SECURE_PROTOCOL_TLS_1_1
# define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 0x00000200
#endif
#ifndef WINHTTP_FLAG_SECURE_PROTOCOL_TLS_1_2
# define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 0x00000800
#endif
static const char *prefix_https = "https://"; static const char *prefix_https = "https://";
static const char *upload_pack_service = "upload-pack"; static const char *upload_pack_service = "upload-pack";
static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack"; static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack";
...@@ -747,6 +755,10 @@ static int winhttp_connect( ...@@ -747,6 +755,10 @@ static int winhttp_connect(
int error = -1; int error = -1;
int default_timeout = TIMEOUT_INFINITE; int default_timeout = TIMEOUT_INFINITE;
int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT; int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
DWORD protocols =
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 |
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_1 |
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;
t->session = NULL; t->session = NULL;
t->connection = NULL; t->connection = NULL;
...@@ -788,6 +800,16 @@ static int winhttp_connect( ...@@ -788,6 +800,16 @@ static int winhttp_connect(
goto on_error; goto on_error;
} }
/*
* Do a best-effort attempt to enable TLS 1.2 but allow this to
* fail; if TLS 1.2 support is not available for some reason,
* ignore the failure (it will keep the default protocols).
*/
WinHttpSetOption(t->session,
WINHTTP_OPTION_SECURE_PROTOCOLS,
&protocols,
sizeof(protocols));
if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) { if (!WinHttpSetTimeouts(t->session, default_timeout, default_connect_timeout, default_timeout, default_timeout)) {
giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP"); giterr_set(GITERR_OS, "failed to set timeouts for WinHTTP");
goto on_error; goto on_error;
......
...@@ -51,6 +51,16 @@ void test_attr_ignore__allow_root(void) ...@@ -51,6 +51,16 @@ void test_attr_ignore__allow_root(void)
assert_is_ignored(false, "NewFolder/NewFolder/File.txt"); assert_is_ignored(false, "NewFolder/NewFolder/File.txt");
} }
void test_attr_ignore__ignore_space(void)
{
cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder \n/NewFolder/NewFolder");
assert_is_ignored(false, "File.txt");
assert_is_ignored(true, "NewFolder");
assert_is_ignored(true, "NewFolder/NewFolder");
assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
}
void test_attr_ignore__ignore_root(void) void test_attr_ignore__ignore_root(void)
{ {
cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder\n/NewFolder/NewFolder"); cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder\n/NewFolder/NewFolder");
...@@ -303,3 +313,46 @@ void test_attr_ignore__test(void) ...@@ -303,3 +313,46 @@ void test_attr_ignore__test(void)
assert_is_ignored(true, "dist/foo.o"); assert_is_ignored(true, "dist/foo.o");
assert_is_ignored(true, "bin/foo"); assert_is_ignored(true, "bin/foo");
} }
void test_attr_ignore__unignore_dir_succeeds(void)
{
cl_git_rewritefile("attr/.gitignore",
"*.c\n"
"!src/*.c\n");
assert_is_ignored(false, "src/foo.c");
assert_is_ignored(true, "src/foo/foo.c");
}
void test_attr_ignore__case_insensitive_unignores_previous_rule(void)
{
git_config *cfg;
cl_git_rewritefile("attr/.gitignore",
"/case\n"
"!/Case/\n");
cl_git_pass(git_repository_config(&cfg, g_repo));
cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", true));
cl_must_pass(p_mkdir("attr/case", 0755));
cl_git_mkfile("attr/case/file", "content");
assert_is_ignored(false, "case/file");
}
void test_attr_ignore__case_sensitive_unignore_does_nothing(void)
{
git_config *cfg;
cl_git_rewritefile("attr/.gitignore",
"/case\n"
"!/Case/\n");
cl_git_pass(git_repository_config(&cfg, g_repo));
cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", false));
cl_must_pass(p_mkdir("attr/case", 0755));
cl_git_mkfile("attr/case/file", "content");
assert_is_ignored(true, "case/file");
}
...@@ -136,3 +136,48 @@ void test_checkout_head__do_remove_tracked_subdir(void) ...@@ -136,3 +136,48 @@ void test_checkout_head__do_remove_tracked_subdir(void)
cl_assert(!git_path_isfile("testrepo/subdir/tracked-file")); cl_assert(!git_path_isfile("testrepo/subdir/tracked-file"));
cl_assert(git_path_isfile("testrepo/subdir/untracked-file")); cl_assert(git_path_isfile("testrepo/subdir/untracked-file"));
} }
void test_checkout_head__typechange_workdir(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
git_object *target;
struct stat st;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_git_pass(git_revparse_single(&target, g_repo, "HEAD"));
cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
cl_must_pass(p_chmod("testrepo/new.txt", 0755));
cl_git_pass(git_checkout_head(g_repo, &opts));
cl_git_pass(p_stat("testrepo/new.txt", &st));
cl_assert(!GIT_PERMS_IS_EXEC(st.st_mode));
git_object_free(target);
}
void test_checkout_head__typechange_index_and_workdir(void)
{
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
git_object *target;
git_index *index;
struct stat st;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
cl_git_pass(git_revparse_single(&target, g_repo, "HEAD"));
cl_git_pass(git_reset(g_repo, target, GIT_RESET_HARD, NULL));
cl_must_pass(p_chmod("testrepo/new.txt", 0755));
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_index_add_bypath(index, "new.txt"));
cl_git_pass(git_index_write(index));
cl_git_pass(git_checkout_head(g_repo, &opts));
cl_git_pass(p_stat("testrepo/new.txt", &st));
cl_assert(!GIT_PERMS_IS_EXEC(st.st_mode));
git_object_free(target);
git_index_free(index);
}
...@@ -1514,6 +1514,51 @@ void test_checkout_tree__baseline_is_empty_when_no_index(void) ...@@ -1514,6 +1514,51 @@ void test_checkout_tree__baseline_is_empty_when_no_index(void)
git_reference_free(head); git_reference_free(head);
} }
void test_checkout_tree__mode_change_is_force_updated(void)
{
git_index *index;
git_reference *head;
git_object *obj;
git_status_list *status;
if (!cl_is_chmod_supported())
clar__skip();
assert_on_branch(g_repo, "master");
cl_git_pass(git_repository_index(&index, g_repo));
cl_git_pass(git_repository_head(&head, g_repo));
cl_git_pass(git_reference_peel(&obj, head, GIT_OBJ_COMMIT));
cl_git_pass(git_reset(g_repo, obj, GIT_RESET_HARD, NULL));
cl_git_pass(git_status_list_new(&status, g_repo, NULL));
cl_assert_equal_i(0, git_status_list_entrycount(status));
git_status_list_free(status);
/* update the mode on-disk */
cl_must_pass(p_chmod("testrepo/README", 0755));
cl_git_pass(git_checkout_tree(g_repo, obj, &g_opts));
cl_git_pass(git_status_list_new(&status, g_repo, NULL));
cl_assert_equal_i(0, git_status_list_entrycount(status));
git_status_list_free(status);
/* update the mode on-disk and in the index */
cl_must_pass(p_chmod("testrepo/README", 0755));
cl_must_pass(git_index_add_bypath(index, "README"));
cl_git_pass(git_checkout_tree(g_repo, obj, &g_opts));
cl_git_pass(git_status_list_new(&status, g_repo, NULL));
cl_assert_equal_i(0, git_status_list_entrycount(status));
git_status_list_free(status);
git_object_free(obj);
git_reference_free(head);
git_index_free(index);
}
void test_checkout_tree__nullopts(void) void test_checkout_tree__nullopts(void)
{ {
cl_git_pass(git_checkout_tree(g_repo, NULL, NULL)); cl_git_pass(git_checkout_tree(g_repo, NULL, NULL));
......
#include "clar_libgit2.h" #include "clar_libgit2.h"
#include "diff_helpers.h" #include "diff_helpers.h"
#define BLOB_DIFF \
"diff --git a/file b/file\n" \
"index 45141a7..4d713dc 100644\n" \
"--- a/file\n" \
"+++ b/file\n" \
"@@ -1 +1,6 @@\n" \
" Hello from the root\n" \
"+\n" \
"+Some additional lines\n" \
"+\n" \
"+Down here below\n" \
"+\n"
static git_repository *g_repo = NULL; static git_repository *g_repo = NULL;
static diff_expects expected; static diff_expects expected;
static git_diff_options opts; static git_diff_options opts;
...@@ -65,6 +78,32 @@ static void assert_one_modified( ...@@ -65,6 +78,32 @@ static void assert_one_modified(
cl_assert_equal_i(dels, exp->line_dels); cl_assert_equal_i(dels, exp->line_dels);
} }
void test_diff_blob__patch_with_freed_blobs(void)
{
git_oid a_oid, b_oid;
git_blob *a, *b;
git_patch *p;
git_buf buf = GIT_BUF_INIT;
/* tests/resources/attr/root_test1 */
cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));
/* tests/resources/attr/root_test2 */
cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8));
cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4));
cl_git_pass(git_patch_from_blobs(&p, a, NULL, b, NULL, NULL));
git_blob_free(a);
git_blob_free(b);
cl_git_pass(git_patch_to_buf(&buf, p));
cl_assert_equal_s(buf.ptr, BLOB_DIFF);
git_patch_free(p);
git_buf_free(&buf);
}
void test_diff_blob__can_compare_text_blobs(void) void test_diff_blob__can_compare_text_blobs(void)
{ {
git_blob *a, *b, *c; git_blob *a, *b, *c;
......
...@@ -70,22 +70,22 @@ ...@@ -70,22 +70,22 @@
"This is a mighty fine recipe!\n" \ "This is a mighty fine recipe!\n" \
">>>>>>> branchF-2\n" ">>>>>>> branchF-2\n"
#define CONFLICTING_RECURSIVE_H1_TO_H2_WITH_DIFF3 \ #define CONFLICTING_RECURSIVE_H2_TO_H1_WITH_DIFF3 \
"VEAL SOUP.\n" \ "VEAL SOUP.\n" \
"\n" \ "\n" \
"<<<<<<< HEAD\n" \ "<<<<<<< HEAD\n" \
"put into a pot three quarts of water, three onions cut small, one\n" \ "Put Into A Pot Three Quarts of Water, Three Onions Cut Small, One\n" \
"||||||| merged common ancestors\n" \ "||||||| merged common ancestors\n" \
"<<<<<<< Temporary merge branch 1\n" \ "<<<<<<< Temporary merge branch 1\n" \
"Put into a pot three quarts of water, THREE ONIONS CUT SMALL, one\n" \ "PUT INTO A POT three quarts of water, three onions cut small, one\n" \
"||||||| merged common ancestors\n" \ "||||||| merged common ancestors\n" \
"Put into a pot three quarts of water, three onions cut small, one\n" \ "Put into a pot three quarts of water, three onions cut small, one\n" \
"=======\n" \ "=======\n" \
"PUT INTO A POT three quarts of water, three onions cut small, one\n" \ "Put into a pot three quarts of water, THREE ONIONS CUT SMALL, one\n" \
">>>>>>> Temporary merge branch 2\n" \ ">>>>>>> Temporary merge branch 2\n" \
"=======\n" \ "=======\n" \
"Put Into A Pot Three Quarts of Water, Three Onions Cut Small, One\n" \ "put into a pot three quarts of water, three onions cut small, one\n" \
">>>>>>> branchH-2\n" \ ">>>>>>> branchH-1\n" \
"spoonful of black pepper pounded, and two of salt, with two or three\n" \ "spoonful of black pepper pounded, and two of salt, with two or three\n" \
"slices of lean ham; let it boil steadily two hours; skim it\n" \ "slices of lean ham; let it boil steadily two hours; skim it\n" \
"occasionally, then put into it a shin of veal, let it boil two hours\n" \ "occasionally, then put into it a shin of veal, let it boil two hours\n" \
......
...@@ -312,7 +312,7 @@ void test_merge_trees_recursive__conflicting_merge_base(void) ...@@ -312,7 +312,7 @@ void test_merge_trees_recursive__conflicting_merge_base(void)
{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
{ 0100644, "3a66812fed1e03ea4a6a7ee28d8a57aec1ca6537", 1, "veal.txt" }, { 0100644, "a13c307108cd1ac9d10a23bd2e8072c298570592", 1, "veal.txt" },
{ 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 2, "veal.txt" }, { 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 2, "veal.txt" },
{ 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 3, "veal.txt" }, { 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 3, "veal.txt" },
}; };
...@@ -339,14 +339,14 @@ void test_merge_trees_recursive__conflicting_merge_base_with_diff3(void) ...@@ -339,14 +339,14 @@ void test_merge_trees_recursive__conflicting_merge_base_with_diff3(void)
{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
{ 0100644, "cd17a91513f3aee9e44114d1ede67932dd41d2fc", 1, "veal.txt" }, { 0100644, "43b17b0ba58cbf2ffd3a048c1d4c7bbbcb0b987e", 1, "veal.txt" },
{ 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 2, "veal.txt" }, { 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 2, "veal.txt" },
{ 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 3, "veal.txt" }, { 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 3, "veal.txt" },
}; };
opts.file_flags |= GIT_MERGE_FILE_STYLE_DIFF3; opts.file_flags |= GIT_MERGE_FILE_STYLE_DIFF3;
cl_git_pass(merge_commits_from_branches(&index, repo, "branchH-1", "branchH-2", &opts)); cl_git_pass(merge_commits_from_branches(&index, repo, "branchH-2", "branchH-1", &opts));
cl_assert(merge_test_index(index, merge_index_entries, 8)); cl_assert(merge_test_index(index, merge_index_entries, 8));
...@@ -392,19 +392,67 @@ void test_merge_trees_recursive__recursionlimit(void) ...@@ -392,19 +392,67 @@ void test_merge_trees_recursive__recursionlimit(void)
{ 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" }, { 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" },
{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" }, { 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
{ 0100644, "ce7e553c6feb6e5f3bd67e3c3be04182fe3094b4", 1, "gravy.txt" }, { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
{ 0100644, "d8dd349b78f19a4ebe3357bacb8138f00bf5ed41", 2, "gravy.txt" },
{ 0100644, "e50fbbd701458757bdfe9815f58ed717c588d1b5", 3, "gravy.txt" },
{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
{ 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" }, { 0100644, "59bdc2a0bfc74c6d4f911e04bab6aa081efe40d1", 1, "veal.txt" },
{ 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 2, "veal.txt" },
{ 0100644, "68a2e1ee61a23a4728fe6b35580fbbbf729df370", 3, "veal.txt" },
}; };
opts.recursion_limit = 1; opts.recursion_limit = 1;
cl_git_pass(merge_commits_from_branches(&index, repo, "branchE-1", "branchE-2", &opts)); cl_git_pass(merge_commits_from_branches(&index, repo, "branchC-1", "branchC-2", &opts));
cl_assert(merge_test_index(index, merge_index_entries, 8)); cl_assert(merge_test_index(index, merge_index_entries, 8));
git_index_free(index); git_index_free(index);
} }
/* There are multiple levels of criss-cross merges. This ensures
* that the virtual merge base parents are compared in the same
* order as git. If the base parents are created in the order as
* git does, then the file `targetfile.txt` is automerged. If not,
* `targetfile.txt` will be in conflict due to the virtual merge
* base.
*/
void test_merge_trees_recursive__merge_base_for_virtual_commit(void)
{
git_index *index;
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
struct merge_index_entry merge_index_entries[] = {
{ 0100644, "1bde1883de4977ea3e664b315da951d1f614c3b1", 0, "targetfile.txt" },
{ 0100644, "f66647f02d6779e119bd435fe2908867c64c265f", 1, "version.txt" },
{ 0100644, "358efd6f589384fa8baf92234db9c7899a53916e", 2, "version.txt" },
{ 0100644, "a664873b1c0b9a1ed300f8644dde536fdaa3a34f", 3, "version.txt" },
};
cl_git_pass(merge_commits_from_branches(&index, repo, "branchJ-1", "branchJ-2", &opts));
cl_assert(merge_test_index(index, merge_index_entries, 4));
git_index_free(index);
}
/* This test is the same as above, but the graph is constructed such
* that the 1st-recursion merge bases of the two heads are
* in a different order.
*/
void test_merge_trees_recursive__merge_base_for_virtual_commit_2(void)
{
git_index *index;
git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
struct merge_index_entry merge_index_entries[] = {
{ 0100644, "4a06b258fed8a4d15967ec4253ae7366b70f727d", 0, "targetfile.txt" },
{ 0100644, "16c5a7810777e1181709833cfe6931949259f802", 1, "version.txt" },
{ 0100644, "f0856993e005c0d8ed2dc7cdc222cc1d89fb3c77", 2, "version.txt" },
{ 0100644, "2cba583804a4a6fad1baf97c959be447238d1489", 3, "version.txt" },
};
cl_git_pass(merge_commits_from_branches(&index, repo, "branchK-1", "branchK-2", &opts));
cl_assert(merge_test_index(index, merge_index_entries, 4));
git_index_free(index);
}
...@@ -62,22 +62,22 @@ void test_merge_workdir_recursive__conflicting_merge_base_with_diff3(void) ...@@ -62,22 +62,22 @@ void test_merge_workdir_recursive__conflicting_merge_base_with_diff3(void)
{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" }, { 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" }, { 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" }, { 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
{ 0100644, "cd17a91513f3aee9e44114d1ede67932dd41d2fc", 1, "veal.txt" }, { 0100644, "43b17b0ba58cbf2ffd3a048c1d4c7bbbcb0b987e", 1, "veal.txt" },
{ 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 2, "veal.txt" }, { 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 2, "veal.txt" },
{ 0100644, "37a5054a9f9b4628e3924c5cb8f2147c6e2a3efc", 3, "veal.txt" }, { 0100644, "d604c75019c282144bdbbf3fd3462ba74b240efc", 3, "veal.txt" },
}; };
opts.file_flags |= GIT_MERGE_FILE_STYLE_DIFF3; opts.file_flags |= GIT_MERGE_FILE_STYLE_DIFF3;
checkout_opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3; checkout_opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3;
cl_git_pass(merge_branches(repo, GIT_REFS_HEADS_DIR "branchH-1", GIT_REFS_HEADS_DIR "branchH-2", &opts, &checkout_opts)); cl_git_pass(merge_branches(repo, GIT_REFS_HEADS_DIR "branchH-2", GIT_REFS_HEADS_DIR "branchH-1", &opts, &checkout_opts));
cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_repository_index(&index, repo));
cl_assert(merge_test_index(index, merge_index_entries, 8)); cl_assert(merge_test_index(index, merge_index_entries, 8));
cl_git_pass(git_futils_readbuffer(&conflicting_buf, "merge-recursive/veal.txt")); cl_git_pass(git_futils_readbuffer(&conflicting_buf, "merge-recursive/veal.txt"));
cl_assert_equal_s(CONFLICTING_RECURSIVE_H1_TO_H2_WITH_DIFF3, conflicting_buf.ptr); cl_assert_equal_s(CONFLICTING_RECURSIVE_H2_TO_H1_WITH_DIFF3, conflicting_buf.ptr);
git_index_free(index); git_index_free(index);
git_buf_free(&conflicting_buf); git_buf_free(&conflicting_buf);
......
...@@ -495,6 +495,7 @@ static void test_inserting_submodule(void) ...@@ -495,6 +495,7 @@ static void test_inserting_submodule(void)
git_treebuilder *bld; git_treebuilder *bld;
git_oid sm_id; git_oid sm_id;
cl_git_pass(git_oid_fromstr(&sm_id, "da39a3ee5e6b4b0d3255bfef95601890afd80709"));
cl_git_pass(git_treebuilder_new(&bld, g_repo, NULL)); cl_git_pass(git_treebuilder_new(&bld, g_repo, NULL));
cl_git_pass(git_treebuilder_insert(NULL, bld, "sm", &sm_id, GIT_FILEMODE_COMMIT)); cl_git_pass(git_treebuilder_insert(NULL, bld, "sm", &sm_id, GIT_FILEMODE_COMMIT));
git_treebuilder_free(bld); git_treebuilder_free(bld);
......
...@@ -40,6 +40,40 @@ static const unsigned char thin_pack[] = { ...@@ -40,6 +40,40 @@ static const unsigned char thin_pack[] = {
}; };
static const unsigned int thin_pack_len = 78; static const unsigned int thin_pack_len = 78;
/*
* Packfile with one object. It references an object which is not in the
* packfile and has a corrupt length (states the deltified stream is 1 byte
* long, where it is actually 6).
*/
static const unsigned char corrupt_thin_pack[] = {
0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01,
0x71, 0xe6, 0x8f, 0xe8, 0x12, 0x9b, 0x54, 0x6b, 0x10, 0x1a, 0xee, 0x95,
0x10, 0xc5, 0x32, 0x8e, 0x7f, 0x21, 0xca, 0x1d, 0x18, 0x78, 0x9c, 0x63,
0x62, 0x66, 0x4e, 0xcb, 0xcf, 0x07, 0x00, 0x02, 0xac, 0x01, 0x4d, 0x07,
0x67, 0x03, 0xc5, 0x40, 0x99, 0x49, 0xb1, 0x3b, 0x7d, 0xae, 0x9b, 0x0e,
0xdd, 0xde, 0xc6, 0x76, 0x43, 0x24, 0x64
};
static const unsigned int corrupt_thin_pack_len = 67;
/*
* Packfile with a missing trailer.
*/
static const unsigned char missing_trailer_pack[] = {
0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x50, 0xf4, 0x3b,
};
static const unsigned int missing_trailer_pack_len = 12;
/*
* Packfile that causes the packfile stream to open in a way in which it leaks
* the stream reader.
*/
static const unsigned char leaky_pack[] = {
0x50, 0x41, 0x43, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03,
0xf4, 0xbd, 0x51, 0x51, 0x51, 0x51, 0x51, 0x72, 0x65, 0x41, 0x4b, 0x63,
0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0xbd, 0x41, 0x4b
};
static const unsigned int leaky_pack_len = 33;
static const unsigned char base_obj[] = { 07, 076 }; static const unsigned char base_obj[] = { 07, 076 };
static const unsigned int base_obj_len = 2; static const unsigned int base_obj_len = 2;
...@@ -60,6 +94,38 @@ void test_pack_indexer__out_of_order(void) ...@@ -60,6 +94,38 @@ void test_pack_indexer__out_of_order(void)
git_indexer_free(idx); git_indexer_free(idx);
} }
void test_pack_indexer__missing_trailer(void)
{
git_indexer *idx = 0;
git_transfer_progress stats = { 0 };
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL));
cl_git_pass(git_indexer_append(
idx, missing_trailer_pack, missing_trailer_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
cl_assert(giterr_last() != NULL);
cl_assert_equal_i(giterr_last()->klass, GITERR_INDEXER);
git_indexer_free(idx);
}
void test_pack_indexer__leaky(void)
{
git_indexer *idx = 0;
git_transfer_progress stats = { 0 };
cl_git_pass(git_indexer_new(&idx, ".", 0, NULL, NULL, NULL));
cl_git_pass(git_indexer_append(
idx, leaky_pack, leaky_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
cl_assert(giterr_last() != NULL);
cl_assert_equal_i(giterr_last()->klass, GITERR_INDEXER);
git_indexer_free(idx);
}
void test_pack_indexer__fix_thin(void) void test_pack_indexer__fix_thin(void)
{ {
git_indexer *idx = NULL; git_indexer *idx = NULL;
...@@ -126,6 +192,35 @@ void test_pack_indexer__fix_thin(void) ...@@ -126,6 +192,35 @@ void test_pack_indexer__fix_thin(void)
} }
} }
void test_pack_indexer__corrupt_length(void)
{
git_indexer *idx = NULL;
git_transfer_progress stats = { 0 };
git_repository *repo;
git_odb *odb;
git_oid id, should_id;
cl_git_pass(git_repository_init(&repo, "thin.git", true));
cl_git_pass(git_repository_odb(&odb, repo));
/* Store the missing base into your ODB so the indexer can fix the pack */
cl_git_pass(git_odb_write(&id, odb, base_obj, base_obj_len, GIT_OBJ_BLOB));
git_oid_fromstr(&should_id, "e68fe8129b546b101aee9510c5328e7f21ca1d18");
cl_assert_equal_oid(&should_id, &id);
cl_git_pass(git_indexer_new(&idx, ".", 0, odb, NULL, NULL));
cl_git_pass(git_indexer_append(
idx, corrupt_thin_pack, corrupt_thin_pack_len, &stats));
cl_git_fail(git_indexer_commit(idx, &stats));
cl_assert(giterr_last() != NULL);
cl_assert_equal_i(giterr_last()->klass, GITERR_ZLIB);
git_indexer_free(idx);
git_odb_free(odb);
git_repository_free(repo);
}
static int find_tmp_file_recurs(void *opaque, git_buf *path) static int find_tmp_file_recurs(void *opaque, git_buf *path)
{ {
int error = 0; int error = 0;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "git2/rebase.h" #include "git2/rebase.h"
#include "posix.h" #include "posix.h"
#include "signature.h" #include "signature.h"
#include "../submodule/submodule_helpers.h"
#include <fcntl.h> #include <fcntl.h>
...@@ -12,9 +13,44 @@ static git_signature *signature; ...@@ -12,9 +13,44 @@ static git_signature *signature;
// Fixture setup and teardown // Fixture setup and teardown
void test_rebase_submodule__initialize(void) void test_rebase_submodule__initialize(void)
{ {
git_index *index;
git_oid tree_oid, commit_id;
git_tree *tree;
git_commit *parent;
git_object *obj;
git_reference *master_ref;
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
repo = cl_git_sandbox_init("rebase-submodule"); repo = cl_git_sandbox_init("rebase-submodule");
cl_git_pass(git_signature_new(&signature, cl_git_pass(git_signature_new(&signature,
"Rebaser", "rebaser@rebaser.rb", 1405694510, 0)); "Rebaser", "rebaser@rebaser.rb", 1405694510, 0));
rewrite_gitmodules(git_repository_workdir(repo));
git_submodule_set_url(repo, "my-submodule", git_repository_path(repo));
/* We have to commit the rewritten .gitmodules file */
git_repository_index(&index, repo);
git_index_add_bypath(index, ".gitmodules");
git_index_write_tree(&tree_oid, index);
git_index_free(index);
cl_git_pass(git_tree_lookup(&tree, repo, &tree_oid));
git_repository_head(&master_ref, repo);
cl_git_pass(git_commit_lookup(&parent, repo, git_reference_target(master_ref)));
cl_git_pass(git_commit_create_v(&commit_id, repo, git_reference_name(master_ref), signature, signature, NULL, "Fixup .gitmodules", tree, 1, parent));
/* And a final reset, for good measure */
git_object_lookup(&obj, repo, &commit_id, GIT_OBJ_COMMIT);
cl_git_pass(git_reset(repo, obj, GIT_RESET_HARD, &opts));
git_object_free(obj);
git_commit_free(parent);
git_reference_free(master_ref);
git_tree_free(tree);
} }
void test_rebase_submodule__cleanup(void) void test_rebase_submodule__cleanup(void)
...@@ -31,7 +67,6 @@ void test_rebase_submodule__init_untracked(void) ...@@ -31,7 +67,6 @@ void test_rebase_submodule__init_untracked(void)
git_buf untracked_path = GIT_BUF_INIT; git_buf untracked_path = GIT_BUF_INIT;
FILE *fp; FILE *fp;
git_submodule *submodule; git_submodule *submodule;
git_config *config;
cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus")); cl_git_pass(git_reference_lookup(&branch_ref, repo, "refs/heads/asparagus"));
cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master")); cl_git_pass(git_reference_lookup(&upstream_ref, repo, "refs/heads/master"));
...@@ -39,12 +74,6 @@ void test_rebase_submodule__init_untracked(void) ...@@ -39,12 +74,6 @@ void test_rebase_submodule__init_untracked(void)
cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref)); cl_git_pass(git_annotated_commit_from_ref(&branch_head, repo, branch_ref));
cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref)); cl_git_pass(git_annotated_commit_from_ref(&upstream_head, repo, upstream_ref));
git_repository_config(&config, repo);
cl_git_pass(git_config_set_string(config, "submodule.my-submodule.url", git_repository_path(repo)));
git_config_free(config);
cl_git_pass(git_submodule_lookup(&submodule, repo, "my-submodule")); cl_git_pass(git_submodule_lookup(&submodule, repo, "my-submodule"));
cl_git_pass(git_submodule_update(submodule, 1, NULL)); cl_git_pass(git_submodule_update(submodule, 1, NULL));
......
...@@ -117,3 +117,15 @@ void test_refs_peel__can_peel_fully_peeled_packed_refs(void) ...@@ -117,3 +117,15 @@ void test_refs_peel__can_peel_fully_peeled_packed_refs(void)
"0df1a5865c8abfc09f1f2182e6a31be550e99f07", "0df1a5865c8abfc09f1f2182e6a31be550e99f07",
GIT_OBJ_COMMIT); GIT_OBJ_COMMIT);
} }
void test_refs_peel__can_peel_fully_peeled_tag_to_tag(void)
{
assert_peel_generic(g_peel_repo,
"refs/tags/tag-inside-tags", GIT_OBJ_TAG,
"c2596aa0151888587ec5c0187f261e63412d9e11",
GIT_OBJ_TAG);
assert_peel_generic(g_peel_repo,
"refs/foo/tag-outside-tags", GIT_OBJ_TAG,
"c2596aa0151888587ec5c0187f261e63412d9e11",
GIT_OBJ_TAG);
}
...@@ -320,6 +320,17 @@ void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void) ...@@ -320,6 +320,17 @@ void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void)
assert_config_entry_on_init_bytype("core.logallrefupdates", true, false); assert_config_entry_on_init_bytype("core.logallrefupdates", true, false);
} }
void test_repo_init__empty_template_path(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
opts.template_path = "";
cl_git_pass(git_futils_mkdir("foo", 0755, 0));
cl_git_pass(git_repository_init_ext(&_repo, "foo", &opts));
cleanup_repository("foo");
}
void test_repo_init__extended_0(void) void test_repo_init__extended_0(void)
{ {
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
......
my-submodule @ efad0b11
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment