+ die("git-fetch_pack: expected ACK/NAK, got '%s'", line);
+}
+
+int path_match(const char *path, int nr, char **match)
+{
+ int i;
+ int pathlen = strlen(path);
+
+ for (i = 0; i < nr; i++) {
+ char *s = match[i];
+ int len = strlen(s);
+
+ if (!len || len > pathlen)
+ continue;
+ if (memcmp(path + pathlen - len, s, len))
+ continue;
+ if (pathlen > len && path[pathlen - len - 1] != '/')
+ continue;
+ *s = 0;
+ return 1;
+ }
+ return 0;
+}
+
+enum protocol {
+ PROTO_LOCAL = 1,
+ PROTO_SSH,
+ PROTO_GIT,
+};
+
+static enum protocol get_protocol(const char *name)
+{
+ if (!strcmp(name, "ssh"))
+ return PROTO_SSH;
+ if (!strcmp(name, "git"))
+ return PROTO_GIT;
+ die("I don't handle protocol '%s'", name);
+}
+
+#define STR_(s) # s
+#define STR(s) STR_(s)
+
+static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path)
+{
+ int sockfd = -1;
+ char *colon, *end;
+ char *port = STR(DEFAULT_GIT_PORT);
+ struct addrinfo hints, *ai0, *ai;
+ int gai;
+
+ if (host[0] == '[') {
+ end = strchr(host + 1, ']');
+ if (end) {
+ *end = 0;
+ end++;
+ host++;
+ } else
+ end = host;
+ } else
+ end = host;
+ colon = strchr(end, ':');
+
+ if (colon) {
+ *colon = 0;
+ port = colon + 1;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ gai = getaddrinfo(host, port, &hints, &ai);
+ if (gai)
+ die("Unable to look up %s (%s)", host, gai_strerror(gai));
+
+ for (ai0 = ai; ai; ai = ai->ai_next) {
+ sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (sockfd < 0)
+ continue;
+ if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
+ close(sockfd);
+ sockfd = -1;
+ continue;
+ }
+ break;
+ }
+
+ freeaddrinfo(ai0);
+
+ if (sockfd < 0)
+ die("unable to connect a socket (%s)", strerror(errno));
+
+ fd[0] = sockfd;
+ fd[1] = sockfd;
+ packet_write(sockfd, "%s %s\n", prog, path);
+ return 0;