Unverified Commit 2bd9b6b6 by Patrick Steinhardt Committed by GitHub

Merge pull request #4835 from pks-t/pks/v0.26.7

Security release v0.26.7
parents e98d0a37 9102156c
v0.26.7
-------
This is a security release fixing the following list of issues:
- Submodule URLs and paths with a leading "-" are now ignored.
This is due to the recently discovered CVE-2018-17456, which
can lead to arbitrary code execution in upstream git. While
libgit2 itself is not vulnerable, it can be used to inject
options in an implementation which performs a recursive clone
by executing an external command.
- When running repack while doing repo writes,
`packfile_load__cb()` could see some temporary files in the
directory that were bigger than the usual, and makes `memcmp`
overflow on the `p->pack_name` string. This issue was reported
and fixed by bisho.
- The configuration file parser used unbounded recursion to parse
multiline variables, which could lead to a stack overflow. The
issue was reported by the oss-fuzz project, issue 10048 and
fixed by Nelson Elhage.
- The fix to the unbounded recursion introduced a memory leak in
the config parser. While this leak was never in a public
release, the oss-fuzz project reported this as issue 10127. The
fix was implemented by Nelson Elhage and Patrick Steinhardt.
- When parsing "ok" packets received via the smart protocol, our
parsing code did not correctly verify the bounds of the
packets, which could result in a heap-buffer overflow. The
issue was reported by the oss-fuzz project, issue 9749 and
fixed by Patrick Steinhardt.
- The parsing code for the smart protocol has been tightened in
general, fixing heap-buffer overflows when parsing the packet
type as well as for "ACK" and "unpack" packets. The issue was
discovered and fixed by Patrick Steinhardt.
- Fixed potential integer overflows on platforms with 16 bit
integers when parsing packets for the smart protocol. The issue
was discovered and fixed by Patrick Steinhardt.
- Fixed potential NULL pointer dereference when parsing
configuration files which have "include.path" statements
without a value.
v0.26.6 v0.26.6
------- -------
......
...@@ -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.6" #define LIBGIT2_VERSION "0.26.7"
#define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MAJOR 0
#define LIBGIT2_VER_MINOR 26 #define LIBGIT2_VER_MINOR 26
#define LIBGIT2_VER_REVISION 6 #define LIBGIT2_VER_REVISION 7
#define LIBGIT2_VER_PATCH 0 #define LIBGIT2_VER_PATCH 0
#define LIBGIT2_SOVERSION 26 #define LIBGIT2_SOVERSION 26
......
...@@ -1347,48 +1347,50 @@ done: ...@@ -1347,48 +1347,50 @@ done:
static int parse_multiline_variable(struct reader *reader, git_buf *value, int in_quotes) static int parse_multiline_variable(struct reader *reader, git_buf *value, int in_quotes)
{ {
char *line = NULL, *proc_line = NULL;
int quote_count; int quote_count;
bool multiline; bool multiline = true;
while (multiline) {
char *line = NULL, *proc_line = NULL;
int error;
/* Check that the next line exists */
line = reader_readline(reader, false);
GITERR_CHECK_ALLOC(line);
/*
* We've reached the end of the file, there is no continuation.
* (this is not an error).
*/
if (line[0] == '\0') {
error = 0;
goto out;
}
/* Check that the next line exists */ /* If it was just a comment, pretend it didn't exist */
line = reader_readline(reader, false); quote_count = strip_comments(line, !!in_quotes);
if (line == NULL) if (line[0] == '\0')
return -1; goto next;
/* We've reached the end of the file, there is no continuation. if ((error = unescape_line(&proc_line, &multiline,
* (this is not an error). line, in_quotes)) < 0)
*/ goto out;
if (line[0] == '\0') {
git__free(line);
return 0;
}
quote_count = strip_comments(line, !!in_quotes); /* Add this line to the multiline var */
if ((error = git_buf_puts(value, proc_line)) < 0)
goto out;
/* If it was just a comment, pretend it didn't exist */ next:
if (line[0] == '\0') {
git__free(line); git__free(line);
return parse_multiline_variable(reader, value, quote_count); git__free(proc_line);
/* TODO: unbounded recursion. This **could** be exploitable */ in_quotes = quote_count;
} continue;
if (unescape_line(&proc_line, &multiline, line, in_quotes) < 0) { out:
git__free(line); git__free(line);
return -1; git__free(proc_line);
return error;
} }
/* add this line to the multiline var */
git_buf_puts(value, proc_line);
git__free(line);
git__free(proc_line);
/*
* If we need to continue reading the next line, let's just
* keep putting stuff in the buffer
*/
if (multiline)
return parse_multiline_variable(reader, value, quote_count);
return 0; return 0;
} }
...@@ -1596,7 +1598,7 @@ static int read_on_variable( ...@@ -1596,7 +1598,7 @@ static int read_on_variable(
result = 0; result = 0;
/* Add or append the new config option */ /* Add or append the new config option */
if (!git__strcmp(var->entry->name, "include.path")) { if (!git__strcmp(var->entry->name, "include.path") && var->entry->value) {
struct reader *r; struct reader *r;
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
char *dir; char *dir;
......
...@@ -209,7 +209,7 @@ static int packfile_load__cb(void *data, git_buf *path) ...@@ -209,7 +209,7 @@ static int packfile_load__cb(void *data, git_buf *path)
for (i = 0; i < backend->packs.length; ++i) { for (i = 0; i < backend->packs.length; ++i) {
struct git_pack_file *p = git_vector_get(&backend->packs, i); struct git_pack_file *p = git_vector_get(&backend->packs, i);
if (memcmp(p->pack_name, path_str, cmp_len) == 0) if (strncmp(p->pack_name, path_str, cmp_len) == 0)
return 0; return 0;
} }
......
...@@ -1792,6 +1792,14 @@ static int get_value(const char **out, git_config *cfg, git_buf *buf, const char ...@@ -1792,6 +1792,14 @@ static int get_value(const char **out, git_config *cfg, git_buf *buf, const char
return error; return error;
} }
static bool looks_like_command_line_option(const char *s)
{
if (s && s[0] == '-')
return true;
return false;
}
static int submodule_read_config(git_submodule *sm, git_config *cfg) static int submodule_read_config(git_submodule *sm, git_config *cfg)
{ {
git_buf key = GIT_BUF_INIT; git_buf key = GIT_BUF_INIT;
...@@ -1805,24 +1813,31 @@ static int submodule_read_config(git_submodule *sm, git_config *cfg) ...@@ -1805,24 +1813,31 @@ static int submodule_read_config(git_submodule *sm, git_config *cfg)
if ((error = get_value(&value, cfg, &key, sm->name, "path")) == 0) { if ((error = get_value(&value, cfg, &key, sm->name, "path")) == 0) {
in_config = 1; in_config = 1;
/* We would warn here if we had that API */
if (!looks_like_command_line_option(value)) {
/* /*
* TODO: if case insensitive filesystem, then the following strcmp * TODO: if case insensitive filesystem, then the following strcmp
* should be strcasecmp * should be strcasecmp
*/ */
if (strcmp(sm->name, value) != 0) { if (strcmp(sm->name, value) != 0) {
if (sm->path != sm->name) if (sm->path != sm->name)
git__free(sm->path); git__free(sm->path);
sm->path = git__strdup(value); sm->path = git__strdup(value);
GITERR_CHECK_ALLOC(sm->path); GITERR_CHECK_ALLOC(sm->path);
}
} }
} else if (error != GIT_ENOTFOUND) { } else if (error != GIT_ENOTFOUND) {
goto cleanup; goto cleanup;
} }
if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) { if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) {
in_config = 1; /* We would warn here if we had that API */
sm->url = git__strdup(value); if (!looks_like_command_line_option(value)) {
GITERR_CHECK_ALLOC(sm->url); in_config = 1;
sm->url = git__strdup(value);
GITERR_CHECK_ALLOC(sm->url);
}
} else if (error != GIT_ENOTFOUND) { } else if (error != GIT_ENOTFOUND) {
goto cleanup; goto cleanup;
} }
......
...@@ -28,14 +28,14 @@ ...@@ -28,14 +28,14 @@
extern bool git_smart__ofs_delta_enabled; extern bool git_smart__ofs_delta_enabled;
enum git_pkt_type { typedef enum {
GIT_PKT_CMD, GIT_PKT_CMD,
GIT_PKT_FLUSH, GIT_PKT_FLUSH,
GIT_PKT_REF, GIT_PKT_REF,
GIT_PKT_HAVE, GIT_PKT_HAVE,
GIT_PKT_ACK, GIT_PKT_ACK,
GIT_PKT_NAK, GIT_PKT_NAK,
GIT_PKT_PACK, GIT_PKT_PACK__UNUSED,
GIT_PKT_COMMENT, GIT_PKT_COMMENT,
GIT_PKT_ERR, GIT_PKT_ERR,
GIT_PKT_DATA, GIT_PKT_DATA,
...@@ -43,7 +43,7 @@ enum git_pkt_type { ...@@ -43,7 +43,7 @@ enum git_pkt_type {
GIT_PKT_OK, GIT_PKT_OK,
GIT_PKT_NG, GIT_PKT_NG,
GIT_PKT_UNPACK, GIT_PKT_UNPACK,
}; } git_pkt_type;
/* Used for multi_ack and mutli_ack_detailed */ /* Used for multi_ack and mutli_ack_detailed */
enum git_ack_status { enum git_ack_status {
...@@ -55,11 +55,11 @@ enum git_ack_status { ...@@ -55,11 +55,11 @@ enum git_ack_status {
/* This would be a flush pkt */ /* This would be a flush pkt */
typedef struct { typedef struct {
enum git_pkt_type type; git_pkt_type type;
} git_pkt; } git_pkt;
struct git_pkt_cmd { struct git_pkt_cmd {
enum git_pkt_type type; git_pkt_type type;
char *cmd; char *cmd;
char *path; char *path;
char *host; char *host;
...@@ -67,50 +67,50 @@ struct git_pkt_cmd { ...@@ -67,50 +67,50 @@ struct git_pkt_cmd {
/* This is a pkt-line with some info in it */ /* This is a pkt-line with some info in it */
typedef struct { typedef struct {
enum git_pkt_type type; git_pkt_type type;
git_remote_head head; git_remote_head head;
char *capabilities; char *capabilities;
} git_pkt_ref; } git_pkt_ref;
/* Useful later */ /* Useful later */
typedef struct { typedef struct {
enum git_pkt_type type; git_pkt_type type;
git_oid oid; git_oid oid;
enum git_ack_status status; enum git_ack_status status;
} git_pkt_ack; } git_pkt_ack;
typedef struct { typedef struct {
enum git_pkt_type type; git_pkt_type type;
char comment[GIT_FLEX_ARRAY]; char comment[GIT_FLEX_ARRAY];
} git_pkt_comment; } git_pkt_comment;
typedef struct { typedef struct {
enum git_pkt_type type; git_pkt_type type;
int len; size_t len;
char data[GIT_FLEX_ARRAY]; char data[GIT_FLEX_ARRAY];
} git_pkt_data; } git_pkt_data;
typedef git_pkt_data git_pkt_progress; typedef git_pkt_data git_pkt_progress;
typedef struct { typedef struct {
enum git_pkt_type type; git_pkt_type type;
int len; size_t len;
char error[GIT_FLEX_ARRAY]; char error[GIT_FLEX_ARRAY];
} git_pkt_err; } git_pkt_err;
typedef struct { typedef struct {
enum git_pkt_type type; git_pkt_type type;
char *ref; char *ref;
} git_pkt_ok; } git_pkt_ok;
typedef struct { typedef struct {
enum git_pkt_type type; git_pkt_type type;
char *ref; char *ref;
char *msg; char *msg;
} git_pkt_ng; } git_pkt_ng;
typedef struct { typedef struct {
enum git_pkt_type type; git_pkt_type type;
int unpack_ok; int unpack_ok;
} git_pkt_unpack; } git_pkt_unpack;
...@@ -184,7 +184,7 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream ...@@ -184,7 +184,7 @@ int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream
int git_smart__update_heads(transport_smart *t, git_vector *symrefs); int git_smart__update_heads(transport_smart *t, git_vector *symrefs);
/* smart_pkt.c */ /* smart_pkt.c */
int git_pkt_parse_line(git_pkt **head, const char *line, const char **out, size_t len); int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, size_t linelen);
int git_pkt_buffer_flush(git_buf *buf); int git_pkt_buffer_flush(git_buf *buf);
int git_pkt_send_flush(GIT_SOCKET s); int git_pkt_send_flush(GIT_SOCKET s);
int git_pkt_buffer_done(git_buf *buf); int git_pkt_buffer_done(git_buf *buf);
......
...@@ -41,7 +41,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) ...@@ -41,7 +41,7 @@ int git_smart__store_refs(transport_smart *t, int flushes)
do { do {
if (buf->offset > 0) if (buf->offset > 0)
error = git_pkt_parse_line(&pkt, buf->data, &line_end, buf->offset); error = git_pkt_parse_line(&pkt, &line_end, buf->data, buf->offset);
else else
error = GIT_EBUFS; error = GIT_EBUFS;
...@@ -206,15 +206,15 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec ...@@ -206,15 +206,15 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec
return 0; return 0;
} }
static int recv_pkt(git_pkt **out, gitno_buffer *buf) static int recv_pkt(git_pkt **out, git_pkt_type *pkt_type, gitno_buffer *buf)
{ {
const char *ptr = buf->data, *line_end = ptr; const char *ptr = buf->data, *line_end = ptr;
git_pkt *pkt = NULL; git_pkt *pkt = NULL;
int pkt_type, error = 0, ret; int error = 0, ret;
do { do {
if (buf->offset > 0) if (buf->offset > 0)
error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset); error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset);
else else
error = GIT_EBUFS; error = GIT_EBUFS;
...@@ -233,13 +233,14 @@ static int recv_pkt(git_pkt **out, gitno_buffer *buf) ...@@ -233,13 +233,14 @@ static int recv_pkt(git_pkt **out, gitno_buffer *buf)
} while (error); } while (error);
gitno_consume(buf, line_end); gitno_consume(buf, line_end);
pkt_type = pkt->type; if (pkt_type)
*pkt_type = pkt->type;
if (out != NULL) if (out != NULL)
*out = pkt; *out = pkt;
else else
git__free(pkt); git__free(pkt);
return pkt_type; return error;
} }
static int store_common(transport_smart *t) static int store_common(transport_smart *t)
...@@ -249,7 +250,7 @@ static int store_common(transport_smart *t) ...@@ -249,7 +250,7 @@ static int store_common(transport_smart *t)
int error; int error;
do { do {
if ((error = recv_pkt(&pkt, buf)) < 0) if ((error = recv_pkt(&pkt, NULL, buf)) < 0)
return error; return error;
if (pkt->type == GIT_PKT_ACK) { if (pkt->type == GIT_PKT_ACK) {
...@@ -317,7 +318,7 @@ static int wait_while_ack(gitno_buffer *buf) ...@@ -317,7 +318,7 @@ static int wait_while_ack(gitno_buffer *buf)
while (1) { while (1) {
git__free(pkt); git__free(pkt);
if ((error = recv_pkt((git_pkt **)&pkt, buf)) < 0) if ((error = recv_pkt((git_pkt **)&pkt, NULL, buf)) < 0)
return error; return error;
if (pkt->type == GIT_PKT_NAK) if (pkt->type == GIT_PKT_NAK)
...@@ -342,7 +343,8 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -342,7 +343,8 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
gitno_buffer *buf = &t->buffer; gitno_buffer *buf = &t->buffer;
git_buf data = GIT_BUF_INIT; git_buf data = GIT_BUF_INIT;
git_revwalk *walk = NULL; git_revwalk *walk = NULL;
int error = -1, pkt_type; int error = -1;
git_pkt_type pkt_type;
unsigned int i; unsigned int i;
git_oid oid; git_oid oid;
...@@ -392,16 +394,13 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -392,16 +394,13 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
if ((error = store_common(t)) < 0) if ((error = store_common(t)) < 0)
goto on_error; goto on_error;
} else { } else {
pkt_type = recv_pkt(NULL, buf); error = recv_pkt(NULL, &pkt_type, buf);
if (error < 0) {
if (pkt_type == GIT_PKT_ACK) { goto on_error;
} else if (pkt_type == GIT_PKT_ACK) {
break; break;
} else if (pkt_type == GIT_PKT_NAK) { } else if (pkt_type == GIT_PKT_NAK) {
continue; continue;
} else if (pkt_type < 0) {
/* recv_pkt returned an error */
error = pkt_type;
goto on_error;
} else { } else {
giterr_set(GITERR_NET, "Unexpected pkt type"); giterr_set(GITERR_NET, "Unexpected pkt type");
error = -1; error = -1;
...@@ -467,10 +466,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -467,10 +466,10 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
/* Now let's eat up whatever the server gives us */ /* Now let's eat up whatever the server gives us */
if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) { if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) {
pkt_type = recv_pkt(NULL, buf); error = recv_pkt(NULL, &pkt_type, buf);
if (pkt_type < 0) { if (error < 0) {
return pkt_type; return error;
} else if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) { } else if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) {
giterr_set(GITERR_NET, "Unexpected pkt type"); giterr_set(GITERR_NET, "Unexpected pkt type");
return -1; return -1;
...@@ -591,7 +590,7 @@ int git_smart__download_pack( ...@@ -591,7 +590,7 @@ int git_smart__download_pack(
goto done; goto done;
} }
if ((error = recv_pkt(&pkt, buf)) >= 0) { if ((error = recv_pkt(&pkt, NULL, buf)) >= 0) {
/* Check cancellation after network call */ /* Check cancellation after network call */
if (t->cancelled.val) { if (t->cancelled.val) {
giterr_clear(); giterr_clear();
...@@ -749,7 +748,7 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, ...@@ -749,7 +748,7 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt,
} }
while (line_len > 0) { while (line_len > 0) {
error = git_pkt_parse_line(&pkt, line, &line_end, line_len); error = git_pkt_parse_line(&pkt, &line_end, line, line_len);
if (error == GIT_EBUFS) { if (error == GIT_EBUFS) {
/* Buffer the data when the inner packet is split /* Buffer the data when the inner packet is split
...@@ -792,8 +791,8 @@ static int parse_report(transport_smart *transport, git_push *push) ...@@ -792,8 +791,8 @@ static int parse_report(transport_smart *transport, git_push *push)
for (;;) { for (;;) {
if (buf->offset > 0) if (buf->offset > 0)
error = git_pkt_parse_line(&pkt, buf->data, error = git_pkt_parse_line(&pkt, &line_end,
&line_end, buf->offset); buf->data, buf->offset);
else else
error = GIT_EBUFS; error = GIT_EBUFS;
......
...@@ -250,35 +250,47 @@ void git__strtolower(char *str) ...@@ -250,35 +250,47 @@ void git__strtolower(char *str)
git__strntolower(str, strlen(str)); git__strntolower(str, strlen(str));
} }
int git__prefixcmp(const char *str, const char *prefix) GIT_INLINE(int) prefixcmp(const char *str, size_t str_n, const char *prefix, bool icase)
{ {
for (;;) { int s, p;
unsigned char p = *(prefix++), s;
while (str_n--) {
s = (unsigned char)*str++;
p = (unsigned char)*prefix++;
if (icase) {
s = git__tolower(s);
p = git__tolower(p);
}
if (!p) if (!p)
return 0; return 0;
if ((s = *(str++)) != p)
if (s != p)
return s - p; return s - p;
} }
return (0 - *prefix);
} }
int git__prefixcmp_icase(const char *str, const char *prefix) int git__prefixcmp(const char *str, const char *prefix)
{ {
return strncasecmp(str, prefix, strlen(prefix)); return prefixcmp(str, SIZE_MAX, prefix, false);
} }
int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix) int git__prefixncmp(const char *str, size_t str_n, const char *prefix)
{ {
int s, p; return prefixcmp(str, str_n, prefix, false);
}
while(str_n--) {
s = (unsigned char)git__tolower(*str++);
p = (unsigned char)git__tolower(*prefix++);
if (s != p) int git__prefixcmp_icase(const char *str, const char *prefix)
return s - p; {
} return prefixcmp(str, SIZE_MAX, prefix, true);
}
return (0 - *prefix); int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix)
{
return prefixcmp(str, str_n, prefix, true);
} }
int git__suffixcmp(const char *str, const char *suffix) int git__suffixcmp(const char *str, const char *suffix)
......
...@@ -254,6 +254,7 @@ GIT_INLINE(void) git__free(void *ptr) ...@@ -254,6 +254,7 @@ GIT_INLINE(void) git__free(void *ptr)
extern int git__prefixcmp(const char *str, const char *prefix); extern int git__prefixcmp(const char *str, const char *prefix);
extern int git__prefixcmp_icase(const char *str, const char *prefix); extern int git__prefixcmp_icase(const char *str, const char *prefix);
extern int git__prefixncmp(const char *str, size_t str_n, const char *prefix);
extern int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix); extern int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix);
extern int git__suffixcmp(const char *str, const char *suffix); extern int git__suffixcmp(const char *str, const char *suffix);
......
...@@ -32,6 +32,7 @@ void test_config_include__absolute(void) ...@@ -32,6 +32,7 @@ void test_config_include__absolute(void)
git_buf_free(&buf); git_buf_free(&buf);
git_config_free(cfg); git_config_free(cfg);
cl_git_pass(p_unlink("config-include-absolute"));
} }
void test_config_include__homedir(void) void test_config_include__homedir(void)
...@@ -51,6 +52,8 @@ void test_config_include__homedir(void) ...@@ -51,6 +52,8 @@ void test_config_include__homedir(void)
git_config_free(cfg); git_config_free(cfg);
cl_sandbox_set_search_path_defaults(); cl_sandbox_set_search_path_defaults();
cl_git_pass(p_unlink("config-include-homedir"));
} }
/* We need to pretend that the variables were defined where the file was included */ /* We need to pretend that the variables were defined where the file was included */
...@@ -75,6 +78,8 @@ void test_config_include__ordering(void) ...@@ -75,6 +78,8 @@ void test_config_include__ordering(void)
git_buf_free(&buf); git_buf_free(&buf);
git_config_free(cfg); git_config_free(cfg);
cl_git_pass(p_unlink("included"));
cl_git_pass(p_unlink("including"));
} }
/* We need to pretend that the variables were defined where the file was included */ /* We need to pretend that the variables were defined where the file was included */
...@@ -87,8 +92,23 @@ void test_config_include__depth(void) ...@@ -87,8 +92,23 @@ void test_config_include__depth(void)
cl_git_fail(git_config_open_ondisk(&cfg, "a")); cl_git_fail(git_config_open_ondisk(&cfg, "a"));
p_unlink("a"); cl_git_pass(p_unlink("a"));
p_unlink("b"); cl_git_pass(p_unlink("b"));
}
void test_config_include__empty_path_sanely_handled(void)
{
git_config *cfg;
git_buf buf = GIT_BUF_INIT;
cl_git_mkfile("a", "[include]\npath");
cl_git_pass(git_config_open_ondisk(&cfg, "a"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "include.path"));
cl_assert_equal_s("", git_buf_cstr(&buf));
git_buf_free(&buf);
git_config_free(cfg);
cl_git_pass(p_unlink("a"));
} }
void test_config_include__missing(void) void test_config_include__missing(void)
...@@ -106,6 +126,7 @@ void test_config_include__missing(void) ...@@ -106,6 +126,7 @@ void test_config_include__missing(void)
git_buf_free(&buf); git_buf_free(&buf);
git_config_free(cfg); git_config_free(cfg);
cl_git_pass(p_unlink("including"));
} }
void test_config_include__missing_homedir(void) void test_config_include__missing_homedir(void)
...@@ -126,6 +147,7 @@ void test_config_include__missing_homedir(void) ...@@ -126,6 +147,7 @@ void test_config_include__missing_homedir(void)
git_config_free(cfg); git_config_free(cfg);
cl_sandbox_set_search_path_defaults(); cl_sandbox_set_search_path_defaults();
cl_git_pass(p_unlink("including"));
} }
#define replicate10(s) s s s s s s s s s s #define replicate10(s) s s s s s s s s s s
...@@ -150,4 +172,8 @@ void test_config_include__depth2(void) ...@@ -150,4 +172,8 @@ void test_config_include__depth2(void)
git_buf_free(&buf); git_buf_free(&buf);
git_config_free(cfg); git_config_free(cfg);
cl_git_pass(p_unlink("top-level"));
cl_git_pass(p_unlink("middle"));
cl_git_pass(p_unlink("bottom"));
} }
...@@ -40,6 +40,48 @@ void test_core_string__2(void) ...@@ -40,6 +40,48 @@ void test_core_string__2(void)
cl_assert(git__strcasesort_cmp("fooBar", "foobar") < 0); cl_assert(git__strcasesort_cmp("fooBar", "foobar") < 0);
} }
/* compare prefixes with len */
void test_core_string__prefixncmp(void)
{
cl_assert(git__prefixncmp("", 0, "") == 0);
cl_assert(git__prefixncmp("a", 1, "") == 0);
cl_assert(git__prefixncmp("", 0, "a") < 0);
cl_assert(git__prefixncmp("a", 1, "b") < 0);
cl_assert(git__prefixncmp("b", 1, "a") > 0);
cl_assert(git__prefixncmp("ab", 2, "a") == 0);
cl_assert(git__prefixncmp("ab", 1, "a") == 0);
cl_assert(git__prefixncmp("ab", 2, "ac") < 0);
cl_assert(git__prefixncmp("a", 1, "ac") < 0);
cl_assert(git__prefixncmp("ab", 1, "ac") < 0);
cl_assert(git__prefixncmp("ab", 2, "aa") > 0);
cl_assert(git__prefixncmp("ab", 1, "aa") < 0);
}
/* compare prefixes with len */
void test_core_string__prefixncmp_icase(void)
{
cl_assert(git__prefixncmp_icase("", 0, "") == 0);
cl_assert(git__prefixncmp_icase("a", 1, "") == 0);
cl_assert(git__prefixncmp_icase("", 0, "a") < 0);
cl_assert(git__prefixncmp_icase("a", 1, "b") < 0);
cl_assert(git__prefixncmp_icase("A", 1, "b") < 0);
cl_assert(git__prefixncmp_icase("a", 1, "B") < 0);
cl_assert(git__prefixncmp_icase("b", 1, "a") > 0);
cl_assert(git__prefixncmp_icase("B", 1, "a") > 0);
cl_assert(git__prefixncmp_icase("b", 1, "A") > 0);
cl_assert(git__prefixncmp_icase("ab", 2, "a") == 0);
cl_assert(git__prefixncmp_icase("Ab", 2, "a") == 0);
cl_assert(git__prefixncmp_icase("ab", 2, "A") == 0);
cl_assert(git__prefixncmp_icase("ab", 1, "a") == 0);
cl_assert(git__prefixncmp_icase("ab", 2, "ac") < 0);
cl_assert(git__prefixncmp_icase("Ab", 2, "ac") < 0);
cl_assert(git__prefixncmp_icase("ab", 2, "Ac") < 0);
cl_assert(git__prefixncmp_icase("a", 1, "ac") < 0);
cl_assert(git__prefixncmp_icase("ab", 1, "ac") < 0);
cl_assert(git__prefixncmp_icase("ab", 2, "aa") > 0);
cl_assert(git__prefixncmp_icase("ab", 1, "aa") < 0);
}
void test_core_string__strcmp(void) void test_core_string__strcmp(void)
{ {
cl_assert(git__strcmp("", "") == 0); cl_assert(git__strcmp("", "") == 0);
......
#include "clar_libgit2.h"
#include "posix.h"
#include "path.h"
#include "submodule_helpers.h"
#include "fileops.h"
#include "repository.h"
static git_repository *g_repo = NULL;
void test_submodule_inject_option__initialize(void)
{
g_repo = setup_fixture_submodule_simple();
}
void test_submodule_inject_option__cleanup(void)
{
cl_git_sandbox_cleanup();
}
static int find_naughty(git_submodule *sm, const char *name, void *payload)
{
int *foundit = (int *) payload;
GIT_UNUSED(sm);
if (!git__strcmp("naughty", name))
*foundit = true;
return 0;
}
void test_submodule_inject_option__url(void)
{
int foundit;
git_submodule *sm;
git_buf buf = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&buf, git_repository_workdir(g_repo), ".gitmodules"));
cl_git_rewritefile(buf.ptr,
"[submodule \"naughty\"]\n"
" path = testrepo\n"
" url = -u./payload\n");
git_buf_free(&buf);
/* We do want to find it, but with the appropriate field empty */
foundit = 0;
cl_git_pass(git_submodule_foreach(g_repo, find_naughty, &foundit));
cl_assert_equal_i(1, foundit);
cl_git_pass(git_submodule_lookup(&sm, g_repo, "naughty"));
cl_assert_equal_s("testrepo", git_submodule_path(sm));
cl_assert_equal_p(NULL, git_submodule_url(sm));
git_submodule_free(sm);
}
void test_submodule_inject_option__path(void)
{
int foundit;
git_submodule *sm;
git_buf buf = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&buf, git_repository_workdir(g_repo), ".gitmodules"));
cl_git_rewritefile(buf.ptr,
"[submodule \"naughty\"]\n"
" path = --something\n"
" url = blah.git\n");
git_buf_free(&buf);
/* We do want to find it, but with the appropriate field empty */
foundit = 0;
cl_git_pass(git_submodule_foreach(g_repo, find_naughty, &foundit));
cl_assert_equal_i(1, foundit);
cl_git_pass(git_submodule_lookup(&sm, g_repo, "naughty"));
cl_assert_equal_s("naughty", git_submodule_path(sm));
cl_assert_equal_s("blah.git", git_submodule_url(sm));
git_submodule_free(sm);
}
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