Code

Merge branch 'js/rebase' into HEAD
[git.git] / connect.c
index 8cbda88dda02e7de74149af1b387e537f77bc497..3d5c4ab7550d3665a4b24265c0c052e3c7e00231 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -72,9 +72,9 @@ struct ref **get_remote_heads(int in, struct ref **list,
                        continue;
                if (nr_match && !path_match(name, nr_match, match))
                        continue;
-               ref = xcalloc(1, sizeof(*ref) + len - 40);
+               ref = alloc_ref(name_len + 1);
                hashcpy(ref->old_sha1, old_sha1);
-               memcpy(ref->name, buffer + 41, len - 40);
+               memcpy(ref->name, buffer + 41, name_len + 1);
                *list = ref;
                list = &ref->next;
        }
@@ -145,6 +145,8 @@ static enum protocol get_protocol(const char *name)
                return PROTO_SSH;
        if (!strcmp(name, "ssh+git"))
                return PROTO_SSH;
+       if (!strcmp(name, "file"))
+               return PROTO_LOCAL;
        die("I don't handle protocol '%s'", name);
 }
 
@@ -224,11 +226,10 @@ static int git_tcp_connect_sock(char *host, int flags)
                }
                if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
                        saved_errno = errno;
-                       fprintf(stderr, "%s[%d: %s]: net=%s, errno=%s\n",
+                       fprintf(stderr, "%s[%d: %s]: errno=%s\n",
                                host,
                                cnt,
                                ai_name(ai),
-                               hstrerror(h_errno),
                                strerror(saved_errno));
                        close(sockfd);
                        sockfd = -1;
@@ -315,11 +316,10 @@ static int git_tcp_connect_sock(char *host, int flags)
 
                if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
                        saved_errno = errno;
-                       fprintf(stderr, "%s[%d: %s]: net=%s, errno=%s\n",
+                       fprintf(stderr, "%s[%d: %s]: errno=%s\n",
                                host,
                                cnt,
                                inet_ntoa(*(struct in_addr *)&sa.sin_addr),
-                               hstrerror(h_errno),
                                strerror(saved_errno));
                        close(sockfd);
                        sockfd = -1;
@@ -390,12 +390,10 @@ static int git_proxy_command_options(const char *var, const char *value)
                }
                if (0 <= matchlen) {
                        /* core.gitproxy = none for kernel.org */
-                       if (matchlen == 4 && 
+                       if (matchlen == 4 &&
                            !memcmp(value, "none", 4))
                                matchlen = 0;
-                       git_proxy_command = xmalloc(matchlen + 1);
-                       memcpy(git_proxy_command, value, matchlen);
-                       git_proxy_command[matchlen] = 0;
+                       git_proxy_command = xmemdupz(value, matchlen);
                }
                return 0;
        }
@@ -453,6 +451,22 @@ static void git_proxy_connect(int fd[2], char *host)
 
 #define MAX_CMD_LEN 1024
 
+char *get_port(char *host)
+{
+       char *end;
+       char *p = strchr(host, ':');
+
+       if (p) {
+               strtol(p+1, &end, 10);
+               if (*end == '\0') {
+                       *p = '\0';
+                       return p+1;
+               }
+       }
+
+       return NULL;
+}
+
 /*
  * This returns 0 if the transport protocol does not need fork(2),
  * or a process id if it does.  Once done, finish the connection
@@ -471,6 +485,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
        pid_t pid;
        enum protocol protocol = PROTO_LOCAL;
        int free_path = 0;
+       char *port = NULL;
 
        /* Without this we cannot rely on waitpid() to tell
         * what happened to our children.
@@ -500,13 +515,13 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
                end = host;
 
        path = strchr(end, c);
-       if (c == ':') {
-               if (path) {
+       if (path) {
+               if (c == ':') {
                        protocol = PROTO_SSH;
                        *path++ = '\0';
-               } else
-                       path = host;
-       }
+               }
+       } else
+               path = end;
 
        if (!path || !*path)
                die("No path specified. See 'man git-pull' for valid url syntax");
@@ -527,6 +542,12 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
                *ptr = '\0';
        }
 
+       /*
+        * Add support for ssh port: ssh://host.xy:<port>/...
+        */
+       if (protocol == PROTO_SSH && host != url)
+               port = get_port(host);
+
        if (protocol == PROTO_GIT) {
                /* These underlying connection commands die() if they
                 * cannot connect.
@@ -556,16 +577,13 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
        if (pid < 0)
                die("unable to fork");
        if (!pid) {
-               char command[MAX_CMD_LEN];
-               char *posn = command;
-               int size = MAX_CMD_LEN;
-               int of = 0;
-
-               of |= add_to_string(&posn, &size, prog, 0);
-               of |= add_to_string(&posn, &size, " ", 0);
-               of |= add_to_string(&posn, &size, path, 1);
+               struct strbuf cmd;
 
-               if (of)
+               strbuf_init(&cmd, MAX_CMD_LEN);
+               strbuf_addstr(&cmd, prog);
+               strbuf_addch(&cmd, ' ');
+               sq_quote_buf(&cmd, path);
+               if (cmd.len >= MAX_CMD_LEN)
                        die("command line too long");
 
                dup2(pipefd[1][0], 0);
@@ -583,15 +601,21 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
                                ssh_basename = ssh;
                        else
                                ssh_basename++;
-                       execlp(ssh, ssh_basename, host, command, NULL);
+
+                       if (!port)
+                               execlp(ssh, ssh_basename, host, cmd.buf, NULL);
+                       else
+                               execlp(ssh, ssh_basename, "-p", port, host,
+                                      cmd.buf, NULL);
                }
                else {
                        unsetenv(ALTERNATE_DB_ENVIRONMENT);
                        unsetenv(DB_ENVIRONMENT);
                        unsetenv(GIT_DIR_ENVIRONMENT);
+                       unsetenv(GIT_WORK_TREE_ENVIRONMENT);
                        unsetenv(GRAFT_ENVIRONMENT);
                        unsetenv(INDEX_ENVIRONMENT);
-                       execlp("sh", "sh", "-c", command, NULL);
+                       execlp("sh", "sh", "-c", cmd.buf, NULL);
                }
                die("exec failed");
        }