Merge branch 'lt/gitweb'
[gitweb.git] / connect.c
index 52d709e58d53f053ec00bfb9f31501684cbaf0e5..4422a0d8d38c225c6c4716ce8ff826bc1acbd981 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -8,14 +8,44 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <signal.h>
 
 static char *server_capabilities = NULL;
 
+static int check_ref(const char *name, int len, unsigned int flags)
+{
+       if (!flags)
+               return 1;
+
+       if (len > 45 || memcmp(name, "refs/", 5))
+               return 0;
+
+       /* Skip the "refs/" part */
+       name += 5;
+       len -= 5;
+
+       /* REF_NORMAL means that we don't want the magic fake tag refs */
+       if ((flags & REF_NORMAL) && check_ref_format(name) < 0)
+               return 0;
+
+       /* REF_HEADS means that we want regular branch heads */
+       if ((flags & REF_HEADS) && !memcmp(name, "heads/", 6))
+               return 1;
+
+       /* REF_TAGS means that we want tags */
+       if ((flags & REF_TAGS) && !memcmp(name, "tags/", 5))
+               return 1;
+
+       /* All type bits clear means that we are ok with anything */
+       return !(flags & ~REF_NORMAL);
+}
+
 /*
  * Read all the refs from the other end
  */
 struct ref **get_remote_heads(int in, struct ref **list,
-                             int nr_match, char **match, int ignore_funny)
+                             int nr_match, char **match,
+                             unsigned int flags)
 {
        *list = NULL;
        for (;;) {
@@ -42,10 +72,8 @@ struct ref **get_remote_heads(int in, struct ref **list,
                        server_capabilities = strdup(name + name_len + 1);
                }
 
-               if (ignore_funny && 45 < len && !memcmp(name, "refs/", 5) &&
-                   check_ref_format(name + 5))
+               if (!check_ref(name, name_len, flags))
                        continue;
-
                if (nr_match && !path_match(name, nr_match, match))
                        continue;
                ref = xcalloc(1, sizeof(*ref) + len - 40);
@@ -327,9 +355,9 @@ static enum protocol get_protocol(const char *name)
  */
 static int git_tcp_connect_sock(char *host)
 {
-       int sockfd = -1;
+       int sockfd = -1, saved_errno = 0;
        char *colon, *end;
-       char *port = STR(DEFAULT_GIT_PORT);
+       const char *port = STR(DEFAULT_GIT_PORT);
        struct addrinfo hints, *ai0, *ai;
        int gai;
 
@@ -361,9 +389,12 @@ static int git_tcp_connect_sock(char *host)
        for (ai0 = ai; ai; ai = ai->ai_next) {
                sockfd = socket(ai->ai_family,
                                ai->ai_socktype, ai->ai_protocol);
-               if (sockfd < 0)
+               if (sockfd < 0) {
+                       saved_errno = errno;
                        continue;
+               }
                if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
+                       saved_errno = errno;
                        close(sockfd);
                        sockfd = -1;
                        continue;
@@ -374,7 +405,7 @@ static int git_tcp_connect_sock(char *host)
        freeaddrinfo(ai0);
 
        if (sockfd < 0)
-               die("unable to connect a socket (%s)", strerror(errno));
+               die("unable to connect a socket (%s)", strerror(saved_errno));
 
        return sockfd;
 }
@@ -386,7 +417,7 @@ static int git_tcp_connect_sock(char *host)
  */
 static int git_tcp_connect_sock(char *host)
 {
-       int sockfd = -1;
+       int sockfd = -1, saved_errno = 0;
        char *colon, *end;
        char *port = STR(DEFAULT_GIT_PORT), *ep;
        struct hostent *he;
@@ -425,8 +456,10 @@ static int git_tcp_connect_sock(char *host)
 
        for (ap = he->h_addr_list; *ap; ap++) {
                sockfd = socket(he->h_addrtype, SOCK_STREAM, 0);
-               if (sockfd < 0)
+               if (sockfd < 0) {
+                       saved_errno = errno;
                        continue;
+               }
 
                memset(&sa, 0, sizeof sa);
                sa.sin_family = he->h_addrtype;
@@ -434,6 +467,7 @@ static int git_tcp_connect_sock(char *host)
                memcpy(&sa.sin_addr, *ap, he->h_length);
 
                if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
+                       saved_errno = errno;
                        close(sockfd);
                        sockfd = -1;
                        continue;
@@ -442,7 +476,7 @@ static int git_tcp_connect_sock(char *host)
        }
 
        if (sockfd < 0)
-               die("unable to connect a socket (%s)", strerror(errno));
+               die("unable to connect a socket (%s)", strerror(saved_errno));
 
        return sockfd;
 }
@@ -450,8 +484,7 @@ static int git_tcp_connect_sock(char *host)
 #endif /* NO_IPV6 */
 
 
-static void git_tcp_connect(int fd[2],
-                           const char *prog, char *host, char *path)
+static void git_tcp_connect(int fd[2], char *host)
 {
        int sockfd = git_tcp_connect_sock(host);
 
@@ -521,10 +554,9 @@ static int git_use_proxy(const char *host)
        return (git_proxy_command && *git_proxy_command);
 }
 
-static void git_proxy_connect(int fd[2],
-                             const char *prog, char *host, char *path)
+static void git_proxy_connect(int fd[2], char *host)
 {
-       char *port = STR(DEFAULT_GIT_PORT);
+       const char *port = STR(DEFAULT_GIT_PORT);
        char *colon, *end;
        int pipefd[2][2];
        pid_t pid;
@@ -581,6 +613,11 @@ int git_connect(int fd[2], char *url, const char *prog)
        enum protocol protocol = PROTO_LOCAL;
        int free_path = 0;
 
+       /* Without this we cannot rely on waitpid() to tell
+        * what happened to our children.
+        */
+       signal(SIGCHLD, SIG_DFL);
+
        host = strstr(url, "://");
        if(host) {
                *host = '\0';
@@ -637,9 +674,9 @@ int git_connect(int fd[2], char *url, const char *prog)
                 */
                char *target_host = strdup(host);
                if (git_use_proxy(host))
-                       git_proxy_connect(fd, prog, host, path);
+                       git_proxy_connect(fd, host);
                else
-                       git_tcp_connect(fd, prog, host, path);
+                       git_tcp_connect(fd, host);
                /*
                 * Separate original protocol components prog and path
                 * from extended components with a NUL byte.