diff options
-rw-r--r-- | CMakeLists.txt | 8 | ||||
-rw-r--r-- | include/git2/checkout.h | 2 | ||||
-rw-r--r-- | include/git2/config.h | 22 | ||||
-rw-r--r-- | include/git2/transport.h | 55 | ||||
-rw-r--r-- | src/config_file.c | 5 | ||||
-rw-r--r-- | src/pack-objects.c | 2 | ||||
-rw-r--r-- | src/submodule.c | 31 | ||||
-rw-r--r-- | src/transports/http.c | 5 | ||||
-rw-r--r-- | src/transports/smart.h | 6 | ||||
-rw-r--r-- | src/transports/smart_pkt.c | 218 | ||||
-rw-r--r-- | src/transports/smart_protocol.c | 10 | ||||
-rw-r--r-- | tests/config/include.c | 42 | ||||
-rw-r--r-- | tests/core/vector.c | 4 | ||||
-rw-r--r-- | tests/submodule/inject_option.c | 80 | ||||
-rw-r--r-- | tests/transports/smart/packet.c | 340 |
15 files changed, 684 insertions, 146 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c3f3e4081..7165cca6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,12 +14,15 @@ PROJECT(libgit2 C) CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11) CMAKE_POLICY(SET CMP0015 NEW) -IF (POLICY CMP0051) +IF(POLICY CMP0051) CMAKE_POLICY(SET CMP0051 NEW) ENDIF() -IF (POLICY CMP0042) +IF(POLICY CMP0042) CMAKE_POLICY(SET CMP0042 NEW) ENDIF() +IF(POLICY CMP0054) + CMAKE_POLICY(SET CMP0054 NEW) +ENDIF() # Add find modules to the path SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${libgit2_SOURCE_DIR}/cmake/Modules/") @@ -230,6 +233,7 @@ ELSE () DISABLE_WARNINGS(unused-function) ENABLE_WARNINGS(format) ENABLE_WARNINGS(format-security) + ENABLE_WARNINGS(int-conversion) IF (APPLE) # Apple deprecated OpenSSL DISABLE_WARNINGS(deprecated-declarations) diff --git a/include/git2/checkout.h b/include/git2/checkout.h index 7ba0df871..485bae63f 100644 --- a/include/git2/checkout.h +++ b/include/git2/checkout.h @@ -67,7 +67,7 @@ GIT_BEGIN_DECL * To emulate `git checkout -f`, use `GIT_CHECKOUT_FORCE`. * * - * There are some additional flags to modified the behavior of checkout: + * There are some additional flags to modify the behavior of checkout: * * - GIT_CHECKOUT_ALLOW_CONFLICTS makes SAFE mode apply safe file updates * even if there are conflicts (instead of cancelling the checkout). diff --git a/include/git2/config.h b/include/git2/config.h index 7bcca7da2..f32f7af7f 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -75,7 +75,17 @@ typedef struct git_config_entry { */ GIT_EXTERN(void) git_config_entry_free(git_config_entry *); -typedef int (*git_config_foreach_cb)(const git_config_entry *, void *); +/** + * A config enumeration callback + * + * @param entry the entry currently being enumerated + * @param payload a user-specified pointer + */ +typedef int (*git_config_foreach_cb)(const git_config_entry *entry, void *payload); + +/** + * An opaque structure for a configuration iterator + */ typedef struct git_config_iterator git_config_iterator; /** @@ -252,7 +262,7 @@ GIT_EXTERN(int) git_config_open_level( * Open the global/XDG configuration file according to git's rules * * Git allows you to store your global configuration at - * `$HOME/.config` or `$XDG_CONFIG_HOME/git/config`. For backwards + * `$HOME/.gitconfig` or `$XDG_CONFIG_HOME/git/config`. For backwards * compatability, the XDG file shouldn't be used unless the use has * created it explicitly. With this function you'll open the correct * one to write to. @@ -581,7 +591,7 @@ GIT_EXTERN(int) git_config_iterator_glob_new(git_config_iterator **out, const gi /** * Perform an operation on each config variable matching a regular expression. * - * This behaviors like `git_config_foreach` with an additional filter of a + * This behaves like `git_config_foreach` with an additional filter of a * regular expression that filters which config keys are passed to the * callback. * @@ -711,11 +721,11 @@ GIT_EXTERN(int) git_config_parse_int64(int64_t *out, const char *value); GIT_EXTERN(int) git_config_parse_path(git_buf *out, const char *value); /** - * Perform an operation on each config variable in given config backend + * Perform an operation on each config variable in a given config backend, * matching a regular expression. * - * This behaviors like `git_config_foreach_match` except instead of all config - * entries it just enumerates through the given backend entry. + * This behaves like `git_config_foreach_match` except that only config + * entries from the given backend entry are enumerated. * * The regular expression is applied case-sensitively on the normalized form of * the variable name: the section and variable parts are lower-cased. The diff --git a/include/git2/transport.h b/include/git2/transport.h index 0c371bf4b..92642514e 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -77,44 +77,73 @@ typedef struct { *** Begin interface for credentials acquisition *** */ -/** Authentication type requested */ +/** + * Supported credential types + * + * This represents the various types of authentication methods supported by + * the library. + */ typedef enum { - /* git_cred_userpass_plaintext */ + /** + * A vanilla user/password request + * @see git_cred_userpass_plaintext_new + */ GIT_CREDTYPE_USERPASS_PLAINTEXT = (1u << 0), - /* git_cred_ssh_key */ + /** + * An SSH key-based authentication request + * @see git_cred_ssh_key_new + */ GIT_CREDTYPE_SSH_KEY = (1u << 1), - /* git_cred_ssh_custom */ + /** + * An SSH key-based authentication request, with a custom signature + * @see git_cred_ssh_custom_new + */ GIT_CREDTYPE_SSH_CUSTOM = (1u << 2), - /* git_cred_default */ + /** + * An NTLM/Negotiate-based authentication request. + * @see git_cred_default + */ GIT_CREDTYPE_DEFAULT = (1u << 3), - /* git_cred_ssh_interactive */ + /** + * An SSH interactive authentication request + * @see git_cred_ssh_interactive_new + */ GIT_CREDTYPE_SSH_INTERACTIVE = (1u << 4), /** - * Username-only information + * Username-only authentication request * - * If the SSH transport does not know which username to use, - * it will ask via this credential type. + * Used as a pre-authentication step if the underlying transport + * (eg. SSH, with no username in its URL) does not know which username + * to use. + * + * @see git_cred_username_new */ GIT_CREDTYPE_USERNAME = (1u << 5), /** - * Credentials read from memory. + * An SSH key-based authentication request + * + * Allows credentials to be read from memory instead of files. + * Note that because of differences in crypto backend support, it might + * not be functional. * - * Only available for libssh2+OpenSSL for now. + * @see git_cred_ssh_key_memory_new */ GIT_CREDTYPE_SSH_MEMORY = (1u << 6), } git_credtype_t; -/* The base structure for all credential types */ typedef struct git_cred git_cred; +/** + * The base structure for all credential types + */ struct git_cred { - git_credtype_t credtype; + git_credtype_t credtype; /**< A type of credential */ void (*free)(git_cred *cred); }; diff --git a/src/config_file.c b/src/config_file.c index e8740d35f..57db97d8b 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -664,6 +664,9 @@ static int parse_include(git_config_parser *reader, char *dir; int result; + if (!file) + return 0; + if ((result = git_path_dirname_r(&path, reader->file->path)) < 0) return result; @@ -765,7 +768,7 @@ static int parse_conditional_include(git_config_parser *reader, size_t i; int error = 0, matches; - if (!parse_data->repo) + if (!parse_data->repo || !file) return 0; condition = git__substrdup(section + strlen("includeIf."), diff --git a/src/pack-objects.c b/src/pack-objects.c index 2b786df33..58eaac616 100644 --- a/src/pack-objects.c +++ b/src/pack-objects.c @@ -1676,7 +1676,7 @@ int insert_tree(git_packbuilder *pb, git_tree *tree) break; case GIT_OBJ_BLOB: - if ((error = retrieve_object(&obj, pb, git_tree_id(tree))) < 0) + if ((error = retrieve_object(&obj, pb, entry_id)) < 0) return error; if (obj->uninteresting) continue; diff --git a/src/submodule.c b/src/submodule.c index 9231f08b1..825e85a52 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -1865,6 +1865,14 @@ static int get_value(const char **out, git_config *cfg, git_buf *buf, const char 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) { git_buf key = GIT_BUF_INIT; @@ -1878,24 +1886,31 @@ static int submodule_read_config(git_submodule *sm, git_config *cfg) if ((error = get_value(&value, cfg, &key, sm->name, "path")) == 0) { 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 * should be strcasecmp */ - if (strcmp(sm->name, value) != 0) { - if (sm->path != sm->name) - git__free(sm->path); - sm->path = git__strdup(value); - GITERR_CHECK_ALLOC(sm->path); + if (strcmp(sm->name, value) != 0) { + if (sm->path != sm->name) + git__free(sm->path); + sm->path = git__strdup(value); + GITERR_CHECK_ALLOC(sm->path); + } + } } else if (error != GIT_ENOTFOUND) { goto cleanup; } if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) { - in_config = 1; - sm->url = git__strdup(value); - GITERR_CHECK_ALLOC(sm->url); + /* We would warn here if we had that API */ + if (!looks_like_command_line_option(value)) { + in_config = 1; + sm->url = git__strdup(value); + GITERR_CHECK_ALLOC(sm->url); + } } else if (error != GIT_ENOTFOUND) { goto cleanup; } diff --git a/src/transports/http.c b/src/transports/http.c index bc3ab18e2..df0d342b9 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -142,7 +142,7 @@ static int auth_context_match( } if (!scheme) - return -1; + return 0; /* See if authentication has already started for this scheme */ git_vector_foreach(&t->auth_contexts, i, c) { @@ -188,6 +188,9 @@ static int apply_credentials(git_buf *buf, http_subtransport *t) if (auth_context_match(&context, t, credtype_match, &cred->credtype) < 0) return -1; + if (!context) + return 0; + return context->next_token(buf, context, cred); } diff --git a/src/transports/smart.h b/src/transports/smart.h index 057d7e6e0..abf80286b 100644 --- a/src/transports/smart.h +++ b/src/transports/smart.h @@ -90,7 +90,7 @@ typedef struct { typedef struct { git_pkt_type type; - int len; + size_t len; char data[GIT_FLEX_ARRAY]; } git_pkt_data; @@ -98,7 +98,7 @@ typedef git_pkt_data git_pkt_progress; typedef struct { git_pkt_type type; - int len; + size_t len; char error[GIT_FLEX_ARRAY]; } git_pkt_err; @@ -188,7 +188,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); /* 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_send_flush(GIT_SOCKET s); int git_pkt_buffer_done(git_buf *buf); diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c index 00798c396..6a404efe4 100644 --- a/src/transports/smart_pkt.c +++ b/src/transports/smart_pkt.c @@ -43,34 +43,43 @@ static int flush_pkt(git_pkt **out) static int ack_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_ack *pkt; - GIT_UNUSED(line); - GIT_UNUSED(len); pkt = git__calloc(1, sizeof(git_pkt_ack)); GITERR_CHECK_ALLOC(pkt); - pkt->type = GIT_PKT_ACK; - line += 3; - len -= 3; - if (len >= GIT_OID_HEXSZ) { - git_oid_fromstr(&pkt->oid, line + 1); - line += GIT_OID_HEXSZ + 1; - len -= GIT_OID_HEXSZ + 1; - } + if (git__prefixncmp(line, len, "ACK ")) + goto out_err; + line += 4; + len -= 4; + + if (len < GIT_OID_HEXSZ || git_oid_fromstr(&pkt->oid, line) < 0) + goto out_err; + line += GIT_OID_HEXSZ; + len -= GIT_OID_HEXSZ; + + if (len && line[0] == ' ') { + line++; + len--; - if (len >= 7) { - if (!git__prefixcmp(line + 1, "continue")) + if (!git__prefixncmp(line, len, "continue")) pkt->status = GIT_ACK_CONTINUE; - if (!git__prefixcmp(line + 1, "common")) + else if (!git__prefixncmp(line, len, "common")) pkt->status = GIT_ACK_COMMON; - if (!git__prefixcmp(line + 1, "ready")) + else if (!git__prefixncmp(line, len, "ready")) pkt->status = GIT_ACK_READY; + else + goto out_err; } *out = (git_pkt *) pkt; return 0; + +out_err: + giterr_set(GITERR_NET, "error parsing ACK pkt-line"); + git__free(pkt); + return -1; } static int nak_pkt(git_pkt **out) @@ -107,10 +116,12 @@ static int comment_pkt(git_pkt **out, const char *line, size_t len) static int err_pkt(git_pkt **out, const char *line, size_t len) { - git_pkt_err *pkt; + git_pkt_err *pkt = NULL; size_t alloclen; /* Remove "ERR " from the line */ + if (git__prefixncmp(line, len, "ERR ")) + goto out_err; line += 4; len -= 4; @@ -118,15 +129,20 @@ static int err_pkt(git_pkt **out, const char *line, size_t len) GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); pkt = git__malloc(alloclen); GITERR_CHECK_ALLOC(pkt); - pkt->type = GIT_PKT_ERR; - pkt->len = (int)len; + pkt->len = len; + memcpy(pkt->error, line, len); pkt->error[len] = '\0'; *out = (git_pkt *) pkt; return 0; + +out_err: + giterr_set(GITERR_NET, "error parsing ERR pkt-line"); + git__free(pkt); + return -1; } static int data_pkt(git_pkt **out, const char *line, size_t len) @@ -142,7 +158,7 @@ static int data_pkt(git_pkt **out, const char *line, size_t len) GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_DATA; - pkt->len = (int) len; + pkt->len = len; memcpy(pkt->data, line, len); *out = (git_pkt *) pkt; @@ -163,7 +179,7 @@ static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len) GITERR_CHECK_ALLOC(pkt); pkt->type = GIT_PKT_PROGRESS; - pkt->len = (int) len; + pkt->len = len; memcpy(pkt->data, line, len); *out = (git_pkt *) pkt; @@ -199,33 +215,25 @@ static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) */ static int ref_pkt(git_pkt **out, const char *line, size_t len) { - int error; git_pkt_ref *pkt; size_t alloclen; - if (len < GIT_OID_HEXSZ + 1) { - giterr_set(GITERR_NET, "error parsing pkt-line"); - return -1; - } - - pkt = git__malloc(sizeof(git_pkt_ref)); + pkt = git__calloc(1, sizeof(git_pkt_ref)); GITERR_CHECK_ALLOC(pkt); - - memset(pkt, 0x0, sizeof(git_pkt_ref)); pkt->type = GIT_PKT_REF; - if ((error = git_oid_fromstr(&pkt->head.oid, line)) < 0) - goto error_out; - - /* Check for a bit of consistency */ - if (line[GIT_OID_HEXSZ] != ' ') { - giterr_set(GITERR_NET, "error parsing pkt-line"); - error = -1; - goto error_out; - } - /* Jump from the name */ - line += GIT_OID_HEXSZ + 1; - len -= (GIT_OID_HEXSZ + 1); + if (len < GIT_OID_HEXSZ || git_oid_fromstr(&pkt->head.oid, line) < 0) + goto out_err; + line += GIT_OID_HEXSZ; + len -= GIT_OID_HEXSZ; + + if (git__prefixncmp(line, len, " ")) + goto out_err; + line++; + len--; + + if (!len) + goto out_err; if (line[len - 1] == '\n') --len; @@ -237,36 +245,36 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len) memcpy(pkt->head.name, line, len); pkt->head.name[len] = '\0'; - if (strlen(pkt->head.name) < len) { + if (strlen(pkt->head.name) < len) pkt->capabilities = strchr(pkt->head.name, '\0') + 1; - } *out = (git_pkt *)pkt; return 0; -error_out: +out_err: + giterr_set(GITERR_NET, "error parsing REF pkt-line"); + if (pkt) + git__free(pkt->head.name); git__free(pkt); - return error; + return -1; } static int ok_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_ok *pkt; - const char *ptr; size_t alloc_len; pkt = git__malloc(sizeof(*pkt)); GITERR_CHECK_ALLOC(pkt); - pkt->type = GIT_PKT_OK; - line += 3; /* skip "ok " */ - if (!(ptr = strchr(line, '\n'))) { - giterr_set(GITERR_NET, "invalid packet line"); - git__free(pkt); - return -1; - } - len = ptr - line; + if (git__prefixncmp(line, len, "ok ")) + goto out_err; + line += 3; + len -= 3; + + if (line[len - 1] == '\n') + --len; GITERR_CHECK_ALLOC_ADD(&alloc_len, len, 1); pkt->ref = git__malloc(alloc_len); @@ -277,6 +285,11 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len) *out = (git_pkt *)pkt; return 0; + +out_err: + giterr_set(GITERR_NET, "error parsing OK pkt-line"); + git__free(pkt); + return -1; } static int ng_pkt(git_pkt **out, const char *line, size_t len) @@ -293,9 +306,9 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len) eol = line + len; - if (len < 3) + if (git__prefixncmp(line, len, "ng ")) goto out_err; - line += 3; /* skip "ng " */ + line += 3; if (!(ptr = memchr(line, ' ', eol - line))) goto out_err; @@ -337,13 +350,11 @@ static int unpack_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_unpack *pkt; - GIT_UNUSED(len); - pkt = git__malloc(sizeof(*pkt)); GITERR_CHECK_ALLOC(pkt); - pkt->type = GIT_PKT_UNPACK; - if (!git__prefixcmp(line, "unpack ok")) + + if (!git__prefixncmp(line, len, "unpack ok")) pkt->unpack_ok = 1; else pkt->unpack_ok = 0; @@ -352,13 +363,17 @@ static int unpack_pkt(git_pkt **out, const char *line, size_t len) return 0; } -static int32_t parse_len(const char *line) +static int parse_len(size_t *out, const char *line, size_t linelen) { char num[PKT_LEN_SIZE + 1]; int i, k, error; int32_t len; const char *num_end; + /* Not even enough for the length */ + if (linelen < PKT_LEN_SIZE) + return GIT_EBUFS; + memcpy(num, line, PKT_LEN_SIZE); num[PKT_LEN_SIZE] = '\0'; @@ -379,7 +394,11 @@ static int32_t parse_len(const char *line) if ((error = git__strtol32(&len, num, &num_end, 16)) < 0) return error; - return len; + if (len < 0) + return -1; + + *out = (size_t) len; + return 0; } /* @@ -396,35 +415,32 @@ static int32_t parse_len(const char *line) */ int git_pkt_parse_line( - git_pkt **head, const char *line, const char **out, size_t bufflen) + git_pkt **pkt, const char **endptr, const char *line, size_t linelen) { - int ret; - int32_t len; - - /* Not even enough for the length */ - if (bufflen > 0 && bufflen < PKT_LEN_SIZE) - return GIT_EBUFS; + int error; + size_t len; - len = parse_len(line); - if (len < 0) { + if ((error = parse_len(&len, line, linelen)) < 0) { /* - * If we fail to parse the length, it might be because the - * server is trying to send us the packfile already. + * If we fail to parse the length, it might be + * because the server is trying to send us the + * packfile already or because we do not yet have + * enough data. */ - if (bufflen >= 4 && !git__prefixcmp(line, "PACK")) { + if (error == GIT_EBUFS) + ; + else if (!git__prefixncmp(line, linelen, "PACK")) giterr_set(GITERR_NET, "unexpected pack file"); - } else { + else giterr_set(GITERR_NET, "bad packet length"); - } - - return -1; + return error; } /* - * If we were given a buffer length, then make sure there is - * enough in the buffer to satisfy this line + * Make sure there is enough in the buffer to satisfy + * this line. */ - if (bufflen > 0 && bufflen < (size_t)len) + if (linelen < len) return GIT_EBUFS; /* @@ -447,38 +463,38 @@ int git_pkt_parse_line( } if (len == 0) { /* Flush pkt */ - *out = line; - return flush_pkt(head); + *endptr = line; + return flush_pkt(pkt); } len -= PKT_LEN_SIZE; /* the encoded length includes its own size */ if (*line == GIT_SIDE_BAND_DATA) - ret = data_pkt(head, line, len); + error = data_pkt(pkt, line, len); else if (*line == GIT_SIDE_BAND_PROGRESS) - ret = sideband_progress_pkt(head, line, len); + error = sideband_progress_pkt(pkt, line, len); else if (*line == GIT_SIDE_BAND_ERROR) - ret = sideband_error_pkt(head, line, len); - else if (!git__prefixcmp(line, "ACK")) - ret = ack_pkt(head, line, len); - else if (!git__prefixcmp(line, "NAK")) - ret = nak_pkt(head); - else if (!git__prefixcmp(line, "ERR ")) - ret = err_pkt(head, line, len); + error = sideband_error_pkt(pkt, line, len); + else if (!git__prefixncmp(line, len, "ACK")) + error = ack_pkt(pkt, line, len); + else if (!git__prefixncmp(line, len, "NAK")) + error = nak_pkt(pkt); + else if (!git__prefixncmp(line, len, "ERR")) + error = err_pkt(pkt, line, len); else if (*line == '#') - ret = comment_pkt(head, line, len); - else if (!git__prefixcmp(line, "ok")) - ret = ok_pkt(head, line, len); - else if (!git__prefixcmp(line, "ng")) - ret = ng_pkt(head, line, len); - else if (!git__prefixcmp(line, "unpack")) - ret = unpack_pkt(head, line, len); + error = comment_pkt(pkt, line, len); + else if (!git__prefixncmp(line, len, "ok")) + error = ok_pkt(pkt, line, len); + else if (!git__prefixncmp(line, len, "ng")) + error = ng_pkt(pkt, line, len); + else if (!git__prefixncmp(line, len, "unpack")) + error = unpack_pkt(pkt, line, len); else - ret = ref_pkt(head, line, len); + error = ref_pkt(pkt, line, len); - *out = line + len; + *endptr = line + len; - return ret; + return error; } void git_pkt_free(git_pkt *pkt) diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index ce63cb195..10a5b4e2e 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -44,7 +44,7 @@ int git_smart__store_refs(transport_smart *t, int flushes) do { 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 error = GIT_EBUFS; @@ -217,7 +217,7 @@ static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf do { 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 error = GIT_EBUFS; @@ -755,7 +755,7 @@ static int add_push_report_sideband_pkt(git_push *push, git_pkt_data *data_pkt, } 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) { /* Buffer the data when the inner packet is split @@ -798,8 +798,8 @@ static int parse_report(transport_smart *transport, git_push *push) for (;;) { 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 error = GIT_EBUFS; diff --git a/tests/config/include.c b/tests/config/include.c index d2ea2c2fd..bab59bcbe 100644 --- a/tests/config/include.c +++ b/tests/config/include.c @@ -35,6 +35,8 @@ void test_config_include__absolute(void) cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz")); cl_assert_equal_s("huzzah", git_buf_cstr(&buf)); + + cl_git_pass(p_unlink("config-include-absolute")); } void test_config_include__homedir(void) @@ -48,6 +50,8 @@ void test_config_include__homedir(void) cl_assert_equal_s("huzzah", git_buf_cstr(&buf)); 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 */ @@ -66,6 +70,9 @@ void test_config_include__ordering(void) git_buf_clear(&buf); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz")); cl_assert_equal_s("huzzah", git_buf_cstr(&buf)); + + 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 */ @@ -76,8 +83,18 @@ void test_config_include__depth(void) cl_git_fail(git_config_open_ondisk(&cfg, "a")); - p_unlink("a"); - p_unlink("b"); + cl_git_pass(p_unlink("a")); + cl_git_pass(p_unlink("b")); +} + +void test_config_include__empty_path_sanely_handled(void) +{ + 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)); + + cl_git_pass(p_unlink("a")); } void test_config_include__missing(void) @@ -89,6 +106,8 @@ void test_config_include__missing(void) cl_assert(giterr_last() == NULL); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar")); cl_assert_equal_s("baz", git_buf_cstr(&buf)); + + cl_git_pass(p_unlink("including")); } void test_config_include__missing_homedir(void) @@ -103,6 +122,7 @@ void test_config_include__missing_homedir(void) cl_assert_equal_s("baz", git_buf_cstr(&buf)); 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 @@ -122,6 +142,10 @@ void test_config_include__depth2(void) git_buf_clear(&buf); cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar2")); cl_assert_equal_s("baz2", git_buf_cstr(&buf)); + + cl_git_pass(p_unlink("top-level")); + cl_git_pass(p_unlink("middle")); + cl_git_pass(p_unlink("bottom")); } void test_config_include__removing_include_removes_values(void) @@ -132,6 +156,9 @@ void test_config_include__removing_include_removes_values(void) cl_git_pass(git_config_open_ondisk(&cfg, "top-level")); cl_git_mkfile("top-level", ""); cl_git_fail(git_config_get_string_buf(&buf, cfg, "foo.bar")); + + cl_git_pass(p_unlink("top-level")); + cl_git_pass(p_unlink("included")); } void test_config_include__rewriting_include_refreshes_values(void) @@ -145,6 +172,10 @@ void test_config_include__rewriting_include_refreshes_values(void) cl_git_fail(git_config_get_string_buf(&buf, cfg, "foo.bar")); cl_git_pass(git_config_get_string_buf(&buf, cfg, "first.other")); cl_assert_equal_s(buf.ptr, "value"); + + cl_git_pass(p_unlink("top-level")); + cl_git_pass(p_unlink("first")); + cl_git_pass(p_unlink("second")); } void test_config_include__included_variables_cannot_be_deleted(void) @@ -154,13 +185,20 @@ void test_config_include__included_variables_cannot_be_deleted(void) cl_git_pass(git_config_open_ondisk(&cfg, "top-level")); cl_git_fail(git_config_delete_entry(cfg, "foo.bar")); + + cl_git_pass(p_unlink("top-level")); + cl_git_pass(p_unlink("included")); } void test_config_include__included_variables_cannot_be_modified(void) { cl_git_mkfile("top-level", "[include]\npath = included\n"); + cl_git_mkfile("included", "[foo]\nbar = value"); cl_git_pass(git_config_open_ondisk(&cfg, "top-level")); cl_git_fail(git_config_set_string(cfg, "foo.bar", "other-value")); + + cl_git_pass(p_unlink("top-level")); + cl_git_pass(p_unlink("included")); } diff --git a/tests/core/vector.c b/tests/core/vector.c index 6b8ea574d..2be7e86bd 100644 --- a/tests/core/vector.c +++ b/tests/core/vector.c @@ -412,7 +412,7 @@ void test_core_vector__dup_empty_vector(void) { git_vector v = GIT_VECTOR_INIT; git_vector dup = GIT_VECTOR_INIT; - void *dummy = 0xDEAFBEEB; + int dummy; cl_assert_equal_i(0, v.length); @@ -420,7 +420,7 @@ void test_core_vector__dup_empty_vector(void) cl_assert_equal_i(0, dup._alloc_size); cl_assert_equal_i(0, dup.length); - cl_git_pass(git_vector_insert(&dup, dummy)); + cl_git_pass(git_vector_insert(&dup, &dummy)); cl_assert_equal_i(8, dup._alloc_size); cl_assert_equal_i(1, dup.length); diff --git a/tests/submodule/inject_option.c b/tests/submodule/inject_option.c new file mode 100644 index 000000000..182f088be --- /dev/null +++ b/tests/submodule/inject_option.c @@ -0,0 +1,80 @@ +#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_dispose(&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_dispose(&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); +} diff --git a/tests/transports/smart/packet.c b/tests/transports/smart/packet.c new file mode 100644 index 000000000..5b623a378 --- /dev/null +++ b/tests/transports/smart/packet.c @@ -0,0 +1,340 @@ +#include "clar_libgit2.h" +#include "transports/smart.h" + +enum expected_status { + PARSE_SUCCESS, + PARSE_FAILURE +}; + +static void assert_flush_parses(const char *line) +{ + size_t linelen = strlen(line) + 1; + const char *endptr; + git_pkt *pkt; + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_FLUSH); + cl_assert_equal_strn(endptr, line + 4, linelen - 4); + + git_pkt_free((git_pkt *) pkt); +} + +static void assert_data_pkt_parses(const char *line, const char *expected_data, size_t expected_len) +{ + size_t linelen = strlen(line) + 1; + const char *endptr; + git_pkt_data *pkt; + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_DATA); + cl_assert_equal_i(pkt->len, expected_len); + cl_assert_equal_strn(pkt->data, expected_data, expected_len); + + git_pkt_free((git_pkt *) pkt); +} + +static void assert_sideband_progress_parses(const char *line, const char *expected_data, size_t expected_len) +{ + size_t linelen = strlen(line) + 1; + const char *endptr; + git_pkt_progress *pkt; + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_PROGRESS); + cl_assert_equal_i(pkt->len, expected_len); + cl_assert_equal_strn(pkt->data, expected_data, expected_len); + + git_pkt_free((git_pkt *) pkt); +} + +static void assert_error_parses(const char *line, const char *expected_error, size_t expected_len) +{ + size_t linelen = strlen(line) + 1; + const char *endptr; + git_pkt_err *pkt; + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_ERR); + cl_assert_equal_i(pkt->len, expected_len); + cl_assert_equal_strn(pkt->error, expected_error, expected_len); + + git_pkt_free((git_pkt *) pkt); +} + +static void assert_ack_parses(const char *line, const char *expected_oid, enum git_ack_status expected_status) +{ + size_t linelen = strlen(line) + 1; + const char *endptr; + git_pkt_ack *pkt; + git_oid oid; + + cl_git_pass(git_oid_fromstr(&oid, expected_oid)); + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_ACK); + cl_assert_equal_oid(&pkt->oid, &oid); + cl_assert_equal_i(pkt->status, expected_status); + + git_pkt_free((git_pkt *) pkt); +} + +static void assert_nak_parses(const char *line) +{ + size_t linelen = strlen(line) + 1; + const char *endptr; + git_pkt *pkt; + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_NAK); + cl_assert_equal_strn(endptr, line + 7, linelen - 7); + + git_pkt_free((git_pkt *) pkt); +} + +static void assert_comment_parses(const char *line, const char *expected_comment) +{ + size_t linelen = strlen(line) + 1; + const char *endptr; + git_pkt_comment *pkt; + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_COMMENT); + cl_assert_equal_strn(pkt->comment, expected_comment, strlen(expected_comment)); + + git_pkt_free((git_pkt *) pkt); +} + +static void assert_ok_parses(const char *line, const char *expected_ref) +{ + size_t linelen = strlen(line) + 1; + const char *endptr; + git_pkt_ok *pkt; + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_OK); + cl_assert_equal_strn(pkt->ref, expected_ref, strlen(expected_ref)); + + git_pkt_free((git_pkt *) pkt); +} + +static void assert_unpack_parses(const char *line, bool ok) +{ + size_t linelen = strlen(line) + 1; + const char *endptr; + git_pkt_unpack *pkt; + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_UNPACK); + cl_assert_equal_i(pkt->unpack_ok, ok); + + git_pkt_free((git_pkt *) pkt); +} + +static void assert_ng_parses(const char *line, const char *expected_ref, const char *expected_msg) +{ + size_t linelen = strlen(line) + 1; + const char *endptr; + git_pkt_ng *pkt; + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_NG); + cl_assert_equal_strn(pkt->ref, expected_ref, strlen(expected_ref)); + cl_assert_equal_strn(pkt->msg, expected_msg, strlen(expected_msg)); + + git_pkt_free((git_pkt *) pkt); +} + +#define assert_ref_parses(line, expected_oid, expected_ref, expected_capabilities) \ + assert_ref_parses_(line, sizeof(line), expected_oid, expected_ref, expected_capabilities) + +static void assert_ref_parses_(const char *line, size_t linelen, const char *expected_oid, + const char *expected_ref, const char *expected_capabilities) +{ + const char *endptr; + git_pkt_ref *pkt; + git_oid oid; + + cl_git_pass(git_oid_fromstr(&oid, expected_oid)); + + cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen)); + cl_assert_equal_i(pkt->type, GIT_PKT_REF); + cl_assert_equal_oid(&pkt->head.oid, &oid); + cl_assert_equal_strn(pkt->head.name, expected_ref, strlen(expected_ref)); + if (expected_capabilities) + cl_assert_equal_strn(pkt->capabilities, expected_capabilities, strlen(expected_capabilities)); + else + cl_assert_equal_p(NULL, pkt->capabilities); + + git_pkt_free((git_pkt *) pkt); +} + +static void assert_pkt_fails(const char *line) +{ + const char *endptr; + git_pkt *pkt; + cl_git_fail(git_pkt_parse_line(&pkt, &endptr, line, strlen(line) + 1)); +} + +void test_transports_smart_packet__parsing_garbage_fails(void) +{ + assert_pkt_fails("0foobar"); + assert_pkt_fails("00foobar"); + assert_pkt_fails("000foobar"); + assert_pkt_fails("0001"); + assert_pkt_fails(""); + assert_pkt_fails("0"); + assert_pkt_fails("0i00"); + assert_pkt_fails("f"); +} + +void test_transports_smart_packet__flush_parses(void) +{ + assert_flush_parses("0000"); + assert_flush_parses("0000foobar"); +} + +void test_transports_smart_packet__data_pkt(void) +{ + assert_pkt_fails("000foobar"); + assert_pkt_fails("0001o"); + assert_pkt_fails("0001\1"); + assert_data_pkt_parses("0005\1", "", 0); + assert_pkt_fails("0009\1o"); + assert_data_pkt_parses("0009\1data", "data", 4); + assert_data_pkt_parses("000a\1data", "data", 5); +} + +void test_transports_smart_packet__sideband_progress_pkt(void) +{ + assert_pkt_fails("0001\2"); + assert_sideband_progress_parses("0005\2", "", 0); + assert_pkt_fails("0009\2o"); + assert_sideband_progress_parses("0009\2data", "data", 4); + assert_sideband_progress_parses("000a\2data", "data", 5); +} + +void test_transports_smart_packet__sideband_err_pkt(void) +{ + assert_pkt_fails("0001\3"); + assert_error_parses("0005\3", "", 0); + assert_pkt_fails("0009\3o"); + assert_error_parses("0009\3data", "data", 4); + assert_error_parses("000a\3data", "data", 5); +} + +void test_transports_smart_packet__ack_pkt(void) +{ + assert_ack_parses("0030ACK 0000000000000000000000000000000000000000", + "0000000000000000000000000000000000000000", 0); + assert_ack_parses("0039ACK 0000000000000000000000000000000000000000 continue", + "0000000000000000000000000000000000000000", + GIT_ACK_CONTINUE); + assert_ack_parses("0037ACK 0000000000000000000000000000000000000000 common", + "0000000000000000000000000000000000000000", + GIT_ACK_COMMON); + assert_ack_parses("0037ACK 0000000000000000000000000000000000000000 ready", + "0000000000000000000000000000000000000000", + GIT_ACK_READY); + + /* these should fail as they don't have OIDs */ + assert_pkt_fails("0007ACK"); + assert_pkt_fails("0008ACK "); + + /* this one is missing a space and should thus fail */ + assert_pkt_fails("0036ACK00000000000000000x0000000000000000000000 ready"); + + /* the following ones have invalid OIDs and should thus fail */ + assert_pkt_fails("0037ACK 00000000000000000x0000000000000000000000 ready"); + assert_pkt_fails("0036ACK 000000000000000000000000000000000000000 ready"); + assert_pkt_fails("0036ACK 00000000000000000x0000000000000000000000ready"); + + /* this one has an invalid status and should thus fail */ + assert_pkt_fails("0036ACK 0000000000000000000000000000000000000000 read"); +} + +void test_transports_smart_packet__nak_pkt(void) +{ + assert_nak_parses("0007NAK"); + assert_pkt_fails("0007NaK"); + assert_pkt_fails("0007nak"); + assert_nak_parses("0007NAKfoobar"); + assert_pkt_fails("0007nakfoobar"); + assert_pkt_fails("0007 NAK"); +} + +void test_transports_smart_packet__error_pkt(void) +{ + assert_pkt_fails("0007ERR"); + assert_pkt_fails("0008ERRx"); + assert_error_parses("0008ERR ", "", 0); + assert_error_parses("000EERR ERRMSG", "ERRMSG", 6); +} + +void test_transports_smart_packet__comment_pkt(void) +{ + assert_comment_parses("0005#", ""); + assert_comment_parses("000B#foobar", "#fooba"); + assert_comment_parses("000C#foobar", "#foobar"); + assert_comment_parses("001A#this is a comment\nfoo", "#this is a comment\nfoo"); +} + +void test_transports_smart_packet__ok_pkt(void) +{ + assert_pkt_fails("0007ok\n"); + assert_ok_parses("0007ok ", ""); + assert_ok_parses("0008ok \n", ""); + assert_ok_parses("0008ok x", "x"); + assert_ok_parses("0009ok x\n", "x"); + assert_pkt_fails("001OK ref/foo/bar"); + assert_ok_parses("0012ok ref/foo/bar", "ref/foo/bar"); + assert_pkt_fails("0013OK ref/foo/bar\n"); + assert_ok_parses("0013ok ref/foo/bar\n", "ref/foo/bar"); +} + +void test_transports_smart_packet__ng_pkt(void) +{ + /* TODO: same as for ok pkt */ + assert_pkt_fails("0007ng\n"); + assert_pkt_fails("0008ng \n"); + assert_pkt_fails("000Bng ref\n"); + assert_pkt_fails("000Bng ref\n"); + /* TODO: is this a valid packet line? Probably not. */ + assert_ng_parses("000Ang x\n", "", "x"); + assert_ng_parses("000Fng ref msg\n", "ref", "msg"); + assert_ng_parses("000Fng ref msg\n", "ref", "msg"); +} + +void test_transports_smart_packet__unpack_pkt(void) +{ + assert_unpack_parses("000Dunpack ok", 1); + assert_unpack_parses("000Dunpack ng error-msg", 0); + /* TODO: the following tests should fail */ + assert_unpack_parses("000Aunpack", 0); + assert_unpack_parses("0011unpack foobar", 0); + assert_unpack_parses("0010unpack ng ok", 0); + assert_unpack_parses("0010unpack okfoo", 1); +} + +void test_transports_smart_packet__ref_pkt(void) +{ + assert_pkt_fails("002C0000000000000000000000000000000000000000"); + assert_pkt_fails("002D0000000000000000000000000000000000000000\n"); + assert_pkt_fails("00300000000000000000000000000000000000000000HEAD"); + assert_pkt_fails("004800000000x0000000000000000000000000000000 refs/heads/master\0multi_ack"); + assert_ref_parses( + "003F0000000000000000000000000000000000000000 refs/heads/master\0", + "0000000000000000000000000000000000000000", "refs/heads/master", ""); + assert_ref_parses( + "00480000000000000000000000000000000000000000 refs/heads/master\0multi_ack", + "0000000000000000000000000000000000000000", "refs/heads/master", "multi_ack"); + assert_ref_parses( + "00460000000000000000000000000000000000000000 refs/heads/master\0one two", + "0000000000000000000000000000000000000000", "refs/heads/master", "one two"); + assert_ref_parses( + "00310000000000000000000000000000000000000000 HEAD", + "0000000000000000000000000000000000000000", "HEAD", NULL); + assert_pkt_fails("0031000000000000000000000000000000000000000 HEAD"); + assert_ref_parses( + "00360000000000000000000000000000000000000000 HEAD HEAD", + "0000000000000000000000000000000000000000", "HEAD HEAD", NULL); +} |