tree-diff: allow diff_tree_sha1 to accept NULL sha1
[gitweb.git] / connect.c
index 04093c41809c3f1a6cd1c9488cfdb672c31665b8..4150412e2c0ebf6129137baf41c9d268d50c60bd 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -8,6 +8,7 @@
 #include "connect.h"
 #include "url.h"
 #include "string-list.h"
+#include "sha1-array.h"
 
 static char *server_capabilities;
 static const char *parse_feature_value(const char *, const char *, int *);
@@ -45,13 +46,6 @@ int check_ref_type(const struct ref *ref, int flags)
        return check_ref(ref->name, strlen(ref->name), flags);
 }
 
-static void add_extra_have(struct extra_have_objects *extra, unsigned char *sha1)
-{
-       ALLOC_GROW(extra->array, extra->nr + 1, extra->alloc);
-       hashcpy(&(extra->array[extra->nr][0]), sha1);
-       extra->nr++;
-}
-
 static void die_initial_contact(int got_at_least_one_head)
 {
        if (got_at_least_one_head)
@@ -122,7 +116,8 @@ static void annotate_refs_with_symref_info(struct ref *ref)
  */
 struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                              struct ref **list, unsigned int flags,
-                             struct extra_have_objects *extra_have)
+                             struct sha1_array *extra_have,
+                             struct sha1_array *shallow_points)
 {
        struct ref **orig_list = list;
        int got_at_least_one_head = 0;
@@ -145,9 +140,18 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                if (!len)
                        break;
 
-               if (len > 4 && !prefixcmp(buffer, "ERR "))
+               if (len > 4 && starts_with(buffer, "ERR "))
                        die("remote error: %s", buffer + 4);
 
+               if (len == 48 && starts_with(buffer, "shallow ")) {
+                       if (get_sha1_hex(buffer + 8, old_sha1))
+                               die("protocol error: expected shallow sha-1, got '%s'", buffer + 8);
+                       if (!shallow_points)
+                               die("repository on the other end cannot be shallow");
+                       sha1_array_append(shallow_points, old_sha1);
+                       continue;
+               }
+
                if (len < 42 || get_sha1_hex(buffer, old_sha1) || buffer[40] != ' ')
                        die("protocol error: expected sha/ref, got '%s'", buffer);
                name = buffer + 41;
@@ -160,7 +164,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
 
                if (extra_have &&
                    name_len == 5 && !memcmp(".have", name, 5)) {
-                       add_extra_have(extra_have, old_sha1);
+                       sha1_array_append(extra_have, old_sha1);
                        continue;
                }
 
@@ -656,7 +660,7 @@ static struct child_process no_fork;
 struct child_process *git_connect(int fd[2], const char *url,
                                  const char *prog, int flags)
 {
-       char *host, *path;
+       char *hostandport, *path;
        struct child_process *conn = &no_fork;
        enum protocol protocol;
        const char **arg;
@@ -667,26 +671,22 @@ struct child_process *git_connect(int fd[2], const char *url,
         */
        signal(SIGCHLD, SIG_DFL);
 
-       protocol = parse_connect_url(url, &host, &path);
+       protocol = parse_connect_url(url, &hostandport, &path);
        if (flags & CONNECT_DIAG_URL) {
                printf("Diag: url=%s\n", url ? url : "NULL");
                printf("Diag: protocol=%s\n", prot_name(protocol));
-               printf("Diag: hostandport=%s\n", host ? host : "NULL");
+               printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL");
                printf("Diag: path=%s\n", path ? path : "NULL");
-               free(host);
-               free(path);
-               return NULL;
-       }
-
-       if (protocol == PROTO_GIT) {
+               conn = NULL;
+       } else if (protocol == PROTO_GIT) {
                /* These underlying connection commands die() if they
                 * cannot connect.
                 */
-               char *target_host = xstrdup(host);
-               if (git_use_proxy(host))
-                       conn = git_proxy_connect(fd, host);
+               char *target_host = xstrdup(hostandport);
+               if (git_use_proxy(hostandport))
+                       conn = git_proxy_connect(fd, hostandport);
                else
-                       git_tcp_connect(fd, host, flags);
+                       git_tcp_connect(fd, hostandport, flags);
                /*
                 * Separate original protocol components prog and path
                 * from extended host header with a NUL byte.
@@ -699,54 +699,50 @@ struct child_process *git_connect(int fd[2], const char *url,
                             prog, path, 0,
                             target_host, 0);
                free(target_host);
-               free(host);
-               free(path);
-               return conn;
-       }
-
-       conn = xcalloc(1, sizeof(*conn));
-
-       strbuf_addstr(&cmd, prog);
-       strbuf_addch(&cmd, ' ');
-       sq_quote_buf(&cmd, path);
-
-       conn->in = conn->out = -1;
-       conn->argv = arg = xcalloc(7, sizeof(*arg));
-       if (protocol == PROTO_SSH) {
-               const char *ssh = getenv("GIT_SSH");
-               int putty = ssh && strcasestr(ssh, "plink");
-               char *ssh_host = host; /* keep host for the free() below */
-               const char *port = NULL;
-               get_host_and_port(&ssh_host, &port);
-               port = get_port_numeric(port);
-
-               if (!ssh) ssh = "ssh";
-
-               *arg++ = ssh;
-               if (putty && !strcasestr(ssh, "tortoiseplink"))
-                       *arg++ = "-batch";
-               if (port) {
-                       /* P is for PuTTY, p is for OpenSSH */
-                       *arg++ = putty ? "-P" : "-p";
-                       *arg++ = port;
+       } else {
+               conn = xcalloc(1, sizeof(*conn));
+
+               strbuf_addstr(&cmd, prog);
+               strbuf_addch(&cmd, ' ');
+               sq_quote_buf(&cmd, path);
+
+               conn->in = conn->out = -1;
+               conn->argv = arg = xcalloc(7, sizeof(*arg));
+               if (protocol == PROTO_SSH) {
+                       const char *ssh = getenv("GIT_SSH");
+                       int putty = ssh && strcasestr(ssh, "plink");
+                       char *ssh_host = hostandport;
+                       const char *port = NULL;
+                       get_host_and_port(&ssh_host, &port);
+                       port = get_port_numeric(port);
+
+                       if (!ssh) ssh = "ssh";
+
+                       *arg++ = ssh;
+                       if (putty && !strcasestr(ssh, "tortoiseplink"))
+                               *arg++ = "-batch";
+                       if (port) {
+                               /* P is for PuTTY, p is for OpenSSH */
+                               *arg++ = putty ? "-P" : "-p";
+                               *arg++ = port;
+                       }
+                       *arg++ = ssh_host;
+               }       else {
+                       /* remove repo-local variables from the environment */
+                       conn->env = local_repo_env;
+                       conn->use_shell = 1;
                }
-               *arg++ = ssh_host;
-       }
-       else {
-               /* remove repo-local variables from the environment */
-               conn->env = local_repo_env;
-               conn->use_shell = 1;
-       }
-       *arg++ = cmd.buf;
-       *arg = NULL;
+               *arg++ = cmd.buf;
+               *arg = NULL;
 
-       if (start_command(conn))
-               die("unable to fork");
+               if (start_command(conn))
+                       die("unable to fork");
 
-       fd[0] = conn->out; /* read from child's stdout */
-       fd[1] = conn->in;  /* write to child's stdin */
-       strbuf_release(&cmd);
-       free(host);
+               fd[0] = conn->out; /* read from child's stdout */
+               fd[1] = conn->in;  /* write to child's stdin */
+               strbuf_release(&cmd);
+       }
+       free(hostandport);
        free(path);
        return conn;
 }