docs/diff-options: clarify scope of diff-filter types
[gitweb.git] / connect.c
index d3283b8a4f3e8ed8451e723ce8b39d468aaa3dd3..ea316c485ab3d0329caf6711b1f422ee298fb0b0 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -43,14 +43,14 @@ int check_ref_type(const struct ref *ref, int flags)
        return check_ref(ref->name, flags);
 }
 
-static void die_initial_contact(int got_at_least_one_head)
+static void die_initial_contact(int unexpected)
 {
-       if (got_at_least_one_head)
-               die("The remote end hung up upon initial contact");
+       if (unexpected)
+               die(_("The remote end hung up upon initial contact"));
        else
-               die("Could not read from remote repository.\n\n"
-                   "Please make sure you have the correct access rights\n"
-                   "and the repository exists.");
+               die(_("Could not read from remote repository.\n\n"
+                     "Please make sure you have the correct access rights\n"
+                     "and the repository exists."));
 }
 
 static void parse_one_symref_info(struct string_list *symref, const char *val, int len)
@@ -115,12 +115,20 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                              struct sha1_array *shallow_points)
 {
        struct ref **orig_list = list;
-       int got_at_least_one_head = 0;
+
+       /*
+        * A hang-up after seeing some response from the other end
+        * means that it is unexpected, as we know the other end is
+        * willing to talk to us.  A hang-up before seeing any
+        * response does not necessarily mean an ACL problem, though.
+        */
+       int saw_response;
+       int got_dummy_ref_with_capabilities_declaration = 0;
 
        *list = NULL;
-       for (;;) {
+       for (saw_response = 0; ; saw_response = 1) {
                struct ref *ref;
-               unsigned char old_sha1[20];
+               struct object_id old_oid;
                char *name;
                int len, name_len;
                char *buffer = packet_buffer;
@@ -131,7 +139,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                                  PACKET_READ_GENTLE_ON_EOF |
                                  PACKET_READ_CHOMP_NEWLINE);
                if (len < 0)
-                       die_initial_contact(got_at_least_one_head);
+                       die_initial_contact(saw_response);
 
                if (!len)
                        break;
@@ -139,37 +147,51 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                if (len > 4 && skip_prefix(buffer, "ERR ", &arg))
                        die("remote error: %s", arg);
 
-               if (len == 48 && skip_prefix(buffer, "shallow ", &arg)) {
-                       if (get_sha1_hex(arg, old_sha1))
+               if (len == GIT_SHA1_HEXSZ + strlen("shallow ") &&
+                       skip_prefix(buffer, "shallow ", &arg)) {
+                       if (get_oid_hex(arg, &old_oid))
                                die("protocol error: expected shallow sha-1, got '%s'", arg);
                        if (!shallow_points)
                                die("repository on the other end cannot be shallow");
-                       sha1_array_append(shallow_points, old_sha1);
+                       sha1_array_append(shallow_points, old_oid.hash);
                        continue;
                }
 
-               if (len < 42 || get_sha1_hex(buffer, old_sha1) || buffer[40] != ' ')
+               if (len < GIT_SHA1_HEXSZ + 2 || get_oid_hex(buffer, &old_oid) ||
+                       buffer[GIT_SHA1_HEXSZ] != ' ')
                        die("protocol error: expected sha/ref, got '%s'", buffer);
-               name = buffer + 41;
+               name = buffer + GIT_SHA1_HEXSZ + 1;
 
                name_len = strlen(name);
-               if (len != name_len + 41) {
+               if (len != name_len + GIT_SHA1_HEXSZ + 1) {
                        free(server_capabilities);
                        server_capabilities = xstrdup(name + name_len + 1);
                }
 
                if (extra_have && !strcmp(name, ".have")) {
-                       sha1_array_append(extra_have, old_sha1);
+                       sha1_array_append(extra_have, old_oid.hash);
+                       continue;
+               }
+
+               if (!strcmp(name, "capabilities^{}")) {
+                       if (saw_response)
+                               die("protocol error: unexpected capabilities^{}");
+                       if (got_dummy_ref_with_capabilities_declaration)
+                               die("protocol error: multiple capabilities^{}");
+                       got_dummy_ref_with_capabilities_declaration = 1;
                        continue;
                }
 
                if (!check_ref(name, flags))
                        continue;
-               ref = alloc_ref(buffer + 41);
-               hashcpy(ref->old_sha1, old_sha1);
+
+               if (got_dummy_ref_with_capabilities_declaration)
+                       die("protocol error: unexpected ref after capabilities^{}");
+
+               ref = alloc_ref(buffer + GIT_SHA1_HEXSZ + 1);
+               oidcpy(&ref->old_oid, &old_oid);
                *list = ref;
                list = &ref->next;
-               got_at_least_one_head = 1;
        }
 
        annotate_refs_with_symref_info(*orig_list);
@@ -265,9 +287,9 @@ static enum protocol get_protocol(const char *name)
                return PROTO_SSH;
        if (!strcmp(name, "git"))
                return PROTO_GIT;
-       if (!strcmp(name, "git+ssh"))
+       if (!strcmp(name, "git+ssh")) /* deprecated - do not use */
                return PROTO_SSH;
-       if (!strcmp(name, "ssh+git"))
+       if (!strcmp(name, "ssh+git")) /* deprecated - do not use */
                return PROTO_SSH;
        if (!strcmp(name, "file"))
                return PROTO_FILE;
@@ -333,7 +355,7 @@ static const char *ai_name(const struct addrinfo *ai)
        static char addr[NI_MAXHOST];
        if (getnameinfo(ai->ai_addr, ai->ai_addrlen, addr, sizeof(addr), NULL, 0,
                        NI_NUMERICHOST) != 0)
-               strcpy(addr, "(unknown)");
+               xsnprintf(addr, sizeof(addr), "(unknown)");
 
        return addr;
 }
@@ -355,6 +377,10 @@ static int git_tcp_connect_sock(char *host, int flags)
                port = "<none>";
 
        memset(&hints, 0, sizeof(hints));
+       if (flags & CONNECT_IPV4)
+               hints.ai_family = AF_INET;
+       else if (flags & CONNECT_IPV6)
+               hints.ai_family = AF_INET6;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
 
@@ -551,6 +577,11 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
 
        get_host_and_port(&host, &port);
 
+       if (looks_like_command_line_option(host))
+               die("strange hostname '%s' blocked", host);
+       if (looks_like_command_line_option(port))
+               die("strange port '%s' blocked", port);
+
        proxy = xmalloc(sizeof(*proxy));
        child_process_init(proxy);
        argv_array_push(&proxy->args, git_proxy_command);
@@ -652,6 +683,19 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
 
 static struct child_process no_fork = CHILD_PROCESS_INIT;
 
+static const char *get_ssh_command(void)
+{
+       const char *ssh;
+
+       if ((ssh = getenv("GIT_SSH_COMMAND")))
+               return ssh;
+
+       if (!git_config_get_string_const("core.sshcommand", &ssh))
+               return ssh;
+
+       return NULL;
+}
+
 /*
  * This returns a dummy child_process if the transport protocol does not
  * need fork(2), or a struct child_process object if it does.  Once done,
@@ -711,7 +755,7 @@ struct child_process *git_connect(int fd[2], const char *url,
                 * Note: Do not add any other headers here!  Doing so
                 * will cause older git-daemon servers to crash.
                 */
-               packet_write(fd[1],
+               packet_write_fmt(fd[1],
                             "%s %s%chost=%s%c",
                             prog, path, 0,
                             target_host, 0);
@@ -720,6 +764,9 @@ struct child_process *git_connect(int fd[2], const char *url,
                conn = xmalloc(sizeof(*conn));
                child_process_init(conn);
 
+               if (looks_like_command_line_option(path))
+                       die("strange pathname '%s' blocked", path);
+
                strbuf_addstr(&cmd, prog);
                strbuf_addch(&cmd, ' ');
                sq_quote_buf(&cmd, path);
@@ -752,7 +799,10 @@ struct child_process *git_connect(int fd[2], const char *url,
                                return NULL;
                        }
 
-                       ssh = getenv("GIT_SSH_COMMAND");
+                       if (looks_like_command_line_option(ssh_host))
+                               die("strange hostname '%s' blocked", ssh_host);
+
+                       ssh = get_ssh_command();
                        if (!ssh) {
                                const char *base;
                                char *ssh_dup;
@@ -781,6 +831,10 @@ struct child_process *git_connect(int fd[2], const char *url,
                        }
 
                        argv_array_push(&conn->args, ssh);
+                       if (flags & CONNECT_IPV4)
+                               argv_array_push(&conn->args, "-4");
+                       else if (flags & CONNECT_IPV6)
+                               argv_array_push(&conn->args, "-6");
                        if (tortoiseplink)
                                argv_array_push(&conn->args, "-batch");
                        if (port) {