Hello community,

here is the log from the commit of package libgit2 for openSUSE:Factory checked 
in at 2018-10-11 11:47:15
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libgit2 (Old)
 and      /work/SRC/openSUSE:Factory/.libgit2.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libgit2"

Thu Oct 11 11:47:15 2018 rev:34 rq:640549 version:0.27.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/libgit2/libgit2.changes  2018-09-11 
17:08:43.684206327 +0200
+++ /work/SRC/openSUSE:Factory/.libgit2.new/libgit2.changes     2018-10-11 
11:47:20.882642028 +0200
@@ -1,0 +2,16 @@
+Sun Oct  7 12:32:42 UTC 2018 - [email protected]
+
+- libgit2 0.27.5:
+  * CVE-2018-17456: Submodule URLs and paths with a leading "-"
+    are now ignored to avoid injecting options into library
+    consumers that perform recursive clones (bsc#1110949)
+  * Avoid a buffer overflow when running repack
+  * Avoid stack overflow from unbounded recursion in configuration
+    file parser
+  * Avoid heap-buffer overflow when parsing "ok" packets
+  * Fix heap-buffer overflows in smart protocol parsing code
+  * Fix potential integer overflows on platforms with 16 bit ints
+  * Fix potential NULL pointer dereference when parsing
+    configuration files
+
+-------------------------------------------------------------------

Old:
----
  libgit2-0.27.4.tar.gz

New:
----
  libgit2-0.27.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libgit2.spec ++++++
--- /var/tmp/diff_new_pack.WQ2U9U/_old  2018-10-11 11:47:22.606639834 +0200
+++ /var/tmp/diff_new_pack.WQ2U9U/_new  2018-10-11 11:47:22.606639834 +0200
@@ -19,7 +19,7 @@
 
 %define sover 27
 Name:           libgit2
-Version:        0.27.4
+Version:        0.27.5
 Release:        0
 Summary:        C git library
 License:        GPL-2.0 WITH GCC-exception-2.0

++++++ libgit2-0.27.4.tar.gz -> libgit2-0.27.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/CHANGELOG.md 
new/libgit2-0.27.5/CHANGELOG.md
--- old/libgit2-0.27.4/CHANGELOG.md     2018-08-06 10:49:49.000000000 +0200
+++ new/libgit2-0.27.5/CHANGELOG.md     2018-10-05 19:32:10.000000000 +0200
@@ -1,3 +1,50 @@
+v0.27.5
+-------
+
+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" or
+  "includeIf..path" statements without a value.
+
 v0.27.4
 -------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/include/git2/version.h 
new/libgit2-0.27.5/include/git2/version.h
--- old/libgit2-0.27.4/include/git2/version.h   2018-08-06 10:49:49.000000000 
+0200
+++ new/libgit2-0.27.5/include/git2/version.h   2018-10-05 19:32:10.000000000 
+0200
@@ -7,10 +7,10 @@
 #ifndef INCLUDE_git_version_h__
 #define INCLUDE_git_version_h__
 
-#define LIBGIT2_VERSION "0.27.4"
+#define LIBGIT2_VERSION "0.27.5"
 #define LIBGIT2_VER_MAJOR 0
 #define LIBGIT2_VER_MINOR 27
-#define LIBGIT2_VER_REVISION 4
+#define LIBGIT2_VER_REVISION 5
 #define LIBGIT2_VER_PATCH 0
 
 #define LIBGIT2_SOVERSION 27
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/src/config_file.c 
new/libgit2-0.27.5/src/config_file.c
--- old/libgit2-0.27.4/src/config_file.c        2018-08-06 10:49:49.000000000 
+0200
+++ new/libgit2-0.27.5/src/config_file.c        2018-10-05 19:32:10.000000000 
+0200
@@ -928,6 +928,9 @@
        char *dir;
        int result;
 
+       if (!file)
+               return 0;
+
        if ((result = git_path_dirname_r(&path, reader->file->path)) < 0)
                return result;
 
@@ -1029,7 +1032,7 @@
        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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/src/config_parse.c 
new/libgit2-0.27.5/src/config_parse.c
--- old/libgit2-0.27.4/src/config_parse.c       2018-08-06 10:49:49.000000000 
+0200
+++ new/libgit2-0.27.5/src/config_parse.c       2018-10-05 19:32:10.000000000 
+0200
@@ -315,49 +315,51 @@
 
 static int parse_multiline_variable(git_config_parser *reader, git_buf *value, 
int in_quotes)
 {
-       char *line = NULL, *proc_line = NULL;
        int quote_count;
-       bool multiline;
+       bool multiline = true;
 
-       /* Check that the next line exists */
-       git_parse_advance_line(&reader->ctx);
-       line = git__strndup(reader->ctx.line, reader->ctx.line_len);
-       if (line == NULL)
-               return -1;
-
-       /* We've reached the end of the file, there is no continuation.
-        * (this is not an error).
-        */
-       if (line[0] == '\0') {
-               git__free(line);
-               return 0;
-       }
-
-       quote_count = strip_comments(line, !!in_quotes);
+       while (multiline) {
+               char *line = NULL, *proc_line = NULL;
+               int error;
+
+               /* Check that the next line exists */
+               git_parse_advance_line(&reader->ctx);
+               line = git__strndup(reader->ctx.line, reader->ctx.line_len);
+               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;
+               }
+
+               /* If it was just a comment, pretend it didn't exist */
+               quote_count = strip_comments(line, !!in_quotes);
+               if (line[0] == '\0')
+                       goto next;
+
+               if ((error = unescape_line(&proc_line, &multiline,
+                                          line, in_quotes)) < 0)
+                       goto out;
+
+               /* 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 */
-       if (line[0] == '\0') {
+next:
                git__free(line);
-               return parse_multiline_variable(reader, value, quote_count);
-               /* TODO: unbounded recursion. This **could** be exploitable */
-       }
+               git__free(proc_line);
+               in_quotes = quote_count;
+               continue;
 
-       if (unescape_line(&proc_line, &multiline, line, in_quotes) < 0) {
+out:
                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;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/src/odb_pack.c 
new/libgit2-0.27.5/src/odb_pack.c
--- old/libgit2-0.27.4/src/odb_pack.c   2018-08-06 10:49:49.000000000 +0200
+++ new/libgit2-0.27.5/src/odb_pack.c   2018-10-05 19:32:10.000000000 +0200
@@ -210,7 +210,7 @@
        for (i = 0; i < backend->packs.length; ++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;
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/src/submodule.c 
new/libgit2-0.27.5/src/submodule.c
--- old/libgit2-0.27.4/src/submodule.c  2018-08-06 10:49:49.000000000 +0200
+++ new/libgit2-0.27.5/src/submodule.c  2018-10-05 19:32:10.000000000 +0200
@@ -1813,6 +1813,14 @@
        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;
@@ -1826,24 +1834,31 @@
 
        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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/src/transports/smart.h 
new/libgit2-0.27.5/src/transports/smart.h
--- old/libgit2-0.27.4/src/transports/smart.h   2018-08-06 10:49:49.000000000 
+0200
+++ new/libgit2-0.27.5/src/transports/smart.h   2018-10-05 19:32:10.000000000 
+0200
@@ -33,14 +33,14 @@
 
 extern bool git_smart__ofs_delta_enabled;
 
-enum git_pkt_type {
+typedef enum {
        GIT_PKT_CMD,
        GIT_PKT_FLUSH,
        GIT_PKT_REF,
        GIT_PKT_HAVE,
        GIT_PKT_ACK,
        GIT_PKT_NAK,
-       GIT_PKT_PACK,
+       GIT_PKT_PACK__UNUSED,
        GIT_PKT_COMMENT,
        GIT_PKT_ERR,
        GIT_PKT_DATA,
@@ -48,7 +48,7 @@
        GIT_PKT_OK,
        GIT_PKT_NG,
        GIT_PKT_UNPACK,
-};
+} git_pkt_type;
 
 /* Used for multi_ack and mutli_ack_detailed */
 enum git_ack_status {
@@ -60,11 +60,11 @@
 
 /* This would be a flush pkt */
 typedef struct {
-       enum git_pkt_type type;
+       git_pkt_type type;
 } git_pkt;
 
 struct git_pkt_cmd {
-       enum git_pkt_type type;
+       git_pkt_type type;
        char *cmd;
        char *path;
        char *host;
@@ -72,50 +72,50 @@
 
 /* This is a pkt-line with some info in it */
 typedef struct {
-       enum git_pkt_type type;
+       git_pkt_type type;
        git_remote_head head;
        char *capabilities;
 } git_pkt_ref;
 
 /* Useful later */
 typedef struct {
-       enum git_pkt_type type;
+       git_pkt_type type;
        git_oid oid;
        enum git_ack_status status;
 } git_pkt_ack;
 
 typedef struct {
-       enum git_pkt_type type;
+       git_pkt_type type;
        char comment[GIT_FLEX_ARRAY];
 } git_pkt_comment;
 
 typedef struct {
-       enum git_pkt_type type;
-       int len;
+       git_pkt_type type;
+       size_t len;
        char data[GIT_FLEX_ARRAY];
 } git_pkt_data;
 
 typedef git_pkt_data git_pkt_progress;
 
 typedef struct {
-       enum git_pkt_type type;
-       int len;
+       git_pkt_type type;
+       size_t len;
        char error[GIT_FLEX_ARRAY];
 } git_pkt_err;
 
 typedef struct {
-       enum git_pkt_type type;
+       git_pkt_type type;
        char *ref;
 } git_pkt_ok;
 
 typedef struct {
-       enum git_pkt_type type;
+       git_pkt_type type;
        char *ref;
        char *msg;
 } git_pkt_ng;
 
 typedef struct {
-       enum git_pkt_type type;
+       git_pkt_type type;
        int unpack_ok;
 } git_pkt_unpack;
 
@@ -189,7 +189,7 @@
 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/src/transports/smart_pkt.c 
new/libgit2-0.27.5/src/transports/smart_pkt.c
--- old/libgit2-0.27.4/src/transports/smart_pkt.c       2018-08-06 
10:49:49.000000000 +0200
+++ new/libgit2-0.27.5/src/transports/smart_pkt.c       2018-10-05 
19:32:10.000000000 +0200
@@ -43,34 +43,43 @@
 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 >= 7) {
-               if (!git__prefixcmp(line + 1, "continue"))
+       if (len && line[0] == ' ') {
+               line++;
+               len--;
+
+               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)
@@ -86,19 +95,6 @@
        return 0;
 }
 
-static int pack_pkt(git_pkt **out)
-{
-       git_pkt *pkt;
-
-       pkt = git__malloc(sizeof(git_pkt));
-       GITERR_CHECK_ALLOC(pkt);
-
-       pkt->type = GIT_PKT_PACK;
-       *out = pkt;
-
-       return 0;
-}
-
 static int comment_pkt(git_pkt **out, const char *line, size_t len)
 {
        git_pkt_comment *pkt;
@@ -120,10 +116,12 @@
 
 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;
 
@@ -131,15 +129,20 @@
        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)
@@ -155,7 +158,7 @@
        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;
@@ -176,7 +179,7 @@
        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;
@@ -212,28 +215,25 @@
  */
 static int ref_pkt(git_pkt **out, const char *line, size_t len)
 {
-       int error;
        git_pkt_ref *pkt;
        size_t alloclen;
 
-       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;
-       }
+       if (len < GIT_OID_HEXSZ || git_oid_fromstr(&pkt->head.oid, line) < 0)
+               goto out_err;
+       line += GIT_OID_HEXSZ;
+       len -= GIT_OID_HEXSZ;
 
-       /* Jump from the name */
-       line += GIT_OID_HEXSZ + 1;
-       len -= (GIT_OID_HEXSZ + 1);
+       if (git__prefixncmp(line, len, " "))
+               goto out_err;
+       line++;
+       len--;
+
+       if (!len)
+               goto out_err;
 
        if (line[len - 1] == '\n')
                --len;
@@ -245,36 +245,36 @@
        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);
@@ -285,12 +285,17 @@
 
        *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)
 {
        git_pkt_ng *pkt;
-       const char *ptr;
+       const char *ptr, *eol;
        size_t alloclen;
 
        pkt = git__malloc(sizeof(*pkt));
@@ -299,11 +304,13 @@
        pkt->ref = NULL;
        pkt->type = GIT_PKT_NG;
 
-       if (len < 3)
+       eol = line + len;
+
+       if (git__prefixncmp(line, len, "ng "))
                goto out_err;
-       line += 3; /* skip "ng " */
-       len -= 3;
-       if (!(ptr = memchr(line, ' ', len)))
+       line += 3;
+
+       if (!(ptr = memchr(line, ' ', eol - line)))
                goto out_err;
        len = ptr - line;
 
@@ -314,11 +321,11 @@
        memcpy(pkt->ref, line, len);
        pkt->ref[len] = '\0';
 
-       if (len < 1)
-               goto out_err;
        line = ptr + 1;
-       len -= 1;
-       if (!(ptr = memchr(line, '\n', len)))
+       if (line >= eol)
+               goto out_err;
+
+       if (!(ptr = memchr(line, '\n', eol - line)))
                goto out_err;
        len = ptr - line;
 
@@ -343,13 +350,11 @@
 {
        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;
@@ -358,13 +363,17 @@
        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';
 
@@ -376,7 +385,7 @@
                                        num[k] = '.';
                                }
                        }
-                       
+
                        giterr_set(GITERR_NET, "invalid hex digit in length: 
'%s'", num);
                        return -1;
                }
@@ -385,7 +394,11 @@
        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;
 }
 
 /*
@@ -402,35 +415,32 @@
  */
 
 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")) {
-                       giterr_clear();
-                       *out = line;
-                       return pack_pkt(head);
-               }
-
-               return (int)len;
+               if (error == GIT_EBUFS)
+                       ;
+               else if (!git__prefixncmp(line, linelen, "PACK"))
+                       giterr_set(GITERR_NET, "unexpected pack file");
+               else
+                       giterr_set(GITERR_NET, "bad packet length");
+               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;
 
        /*
@@ -453,38 +463,38 @@
        }
 
        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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/src/transports/smart_protocol.c 
new/libgit2-0.27.5/src/transports/smart_protocol.c
--- old/libgit2-0.27.4/src/transports/smart_protocol.c  2018-08-06 
10:49:49.000000000 +0200
+++ new/libgit2-0.27.5/src/transports/smart_protocol.c  2018-10-05 
19:32:10.000000000 +0200
@@ -44,7 +44,7 @@
 
        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;
 
@@ -209,15 +209,15 @@
        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;
        git_pkt *pkt = NULL;
-       int pkt_type, error = 0, ret;
+       int error = 0, ret;
 
        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;
 
@@ -236,13 +236,14 @@
        } while (error);
 
        gitno_consume(buf, line_end);
-       pkt_type = pkt->type;
+       if (pkt_type)
+               *pkt_type = pkt->type;
        if (out != NULL)
                *out = pkt;
        else
                git__free(pkt);
 
-       return pkt_type;
+       return error;
 }
 
 static int store_common(transport_smart *t)
@@ -252,7 +253,7 @@
        int error;
 
        do {
-               if ((error = recv_pkt(&pkt, buf)) < 0)
+               if ((error = recv_pkt(&pkt, NULL, buf)) < 0)
                        return error;
 
                if (pkt->type == GIT_PKT_ACK) {
@@ -320,7 +321,7 @@
        while (1) {
                git__free(pkt);
 
-               if ((error = recv_pkt((git_pkt **)&pkt, buf)) < 0)
+               if ((error = recv_pkt((git_pkt **)&pkt, NULL, buf)) < 0)
                        return error;
 
                if (pkt->type == GIT_PKT_NAK)
@@ -345,7 +346,8 @@
        gitno_buffer *buf = &t->buffer;
        git_buf data = GIT_BUF_INIT;
        git_revwalk *walk = NULL;
-       int error = -1, pkt_type;
+       int error = -1;
+       git_pkt_type pkt_type;
        unsigned int i;
        git_oid oid;
 
@@ -395,16 +397,13 @@
                                if ((error = store_common(t)) < 0)
                                        goto on_error;
                        } else {
-                               pkt_type = recv_pkt(NULL, buf);
-
-                               if (pkt_type == GIT_PKT_ACK) {
+                               error = recv_pkt(NULL, &pkt_type, buf);
+                               if (error < 0) {
+                                       goto on_error;
+                               } else if (pkt_type == GIT_PKT_ACK) {
                                        break;
                                } else if (pkt_type == GIT_PKT_NAK) {
                                        continue;
-                               } else if (pkt_type < 0) {
-                                       /* recv_pkt returned an error */
-                                       error = pkt_type;
-                                       goto on_error;
                                } else {
                                        giterr_set(GITERR_NET, "Unexpected pkt 
type");
                                        error = -1;
@@ -470,10 +469,10 @@
 
        /* Now let's eat up whatever the server gives us */
        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) {
-                       return pkt_type;
+               if (error < 0) {
+                       return error;
                } else if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) {
                        giterr_set(GITERR_NET, "Unexpected pkt type");
                        return -1;
@@ -594,7 +593,7 @@
                        goto done;
                }
 
-               if ((error = recv_pkt(&pkt, buf)) >= 0) {
+               if ((error = recv_pkt(&pkt, NULL, buf)) >= 0) {
                        /* Check cancellation after network call */
                        if (t->cancelled.val) {
                                giterr_clear();
@@ -752,7 +751,7 @@
        }
 
        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
@@ -795,8 +794,8 @@
 
        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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/tests/config/include.c 
new/libgit2-0.27.5/tests/config/include.c
--- old/libgit2-0.27.4/tests/config/include.c   2018-08-06 10:49:49.000000000 
+0200
+++ new/libgit2-0.27.5/tests/config/include.c   2018-10-05 19:32:10.000000000 
+0200
@@ -35,6 +35,8 @@
 
        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 @@
        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 @@
        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 @@
 
        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 @@
        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 @@
        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 @@
        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 @@
        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 @@
        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 @@
 
        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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/tests/submodule/inject_option.c 
new/libgit2-0.27.5/tests/submodule/inject_option.c
--- old/libgit2-0.27.4/tests/submodule/inject_option.c  1970-01-01 
01:00:00.000000000 +0100
+++ new/libgit2-0.27.5/tests/submodule/inject_option.c  2018-10-05 
19:32:10.000000000 +0200
@@ -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_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);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libgit2-0.27.4/tests/transports/smart/packet.c 
new/libgit2-0.27.5/tests/transports/smart/packet.c
--- old/libgit2-0.27.4/tests/transports/smart/packet.c  1970-01-01 
01:00:00.000000000 +0100
+++ new/libgit2-0.27.5/tests/transports/smart/packet.c  2018-10-05 
19:32:10.000000000 +0200
@@ -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);
+}


Reply via email to