1#include "cache.h"
2#include "refs.h"
3#include "pkt-line.h"
4#include <sys/wait.h>
56
static const char fetch_pack_usage[] = "git-fetch-pack [host:]directory [heads]* < mycommitlist";
7static const char *exec = "git-upload-pack";
89
static int get_ack(int fd, unsigned char *result_sha1)
10{
11static char line[1000];
12int len = packet_read_line(fd, line, sizeof(line));
1314
if (!len)
15die("git-fetch-pack: expected ACK/NAK, got EOF");
16if (line[len-1] == '\n')
17line[--len] = 0;
18if (!strcmp(line, "NAK"))
19return 0;
20if (!strncmp(line, "ACK ", 3)) {
21if (!get_sha1_hex(line+4, result_sha1))
22return 1;
23}
24die("git-fetch_pack: expected ACK/NAK, got '%s'", line);
25}
2627
static int find_common(int fd[2], unsigned char *result_sha1, unsigned char *remote)
28{
29static char line[1000];
30int count = 0, flushes = 0, retval;
31FILE *revs;
3233
revs = popen("git-rev-list $(git-rev-parse --all)", "r");
34if (!revs)
35die("unable to run 'git-rev-list'");
36packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
37packet_flush(fd[1]);
38flushes = 1;
39retval = -1;
40while (fgets(line, sizeof(line), revs) != NULL) {
41unsigned char sha1[20];
42if (get_sha1_hex(line, sha1))
43die("git-fetch-pack: expected object name, got crud");
44packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
45if (!(31 & ++count)) {
46packet_flush(fd[1]);
47flushes++;
4849
/*
50* We keep one window "ahead" of the other side, and
51* will wait for an ACK only on the next one
52*/
53if (count == 32)
54continue;
55if (get_ack(fd[0], result_sha1)) {
56flushes = 0;
57retval = 0;
58break;
59}
60flushes--;
61}
62}
63pclose(revs);
64packet_write(fd[1], "done\n");
65while (flushes) {
66flushes--;
67if (get_ack(fd[0], result_sha1))
68return 0;
69}
70return retval;
71}
7273
static int get_remote_heads(int fd, int nr_match, char **match, unsigned char *result)
74{
75int count = 0;
7677
for (;;) {
78static char line[1000];
79unsigned char sha1[20];
80char *refname;
81int len;
8283
len = packet_read_line(fd, line, sizeof(line));
84if (!len)
85break;
86if (line[len-1] == '\n')
87line[--len] = 0;
88if (len < 42 || get_sha1_hex(line, sha1))
89die("git-fetch-pack: protocol error - expected ref descriptor, got '%sยค'", line);
90refname = line+41;
91if (nr_match && !path_match(refname, nr_match, match))
92continue;
93count++;
94memcpy(result, sha1, 20);
95}
96return count;
97}
9899
static int fetch_pack(int fd[2], int nr_match, char **match)
100{
101unsigned char sha1[20], remote[20];
102int heads, status;
103pid_t pid;
104105
heads = get_remote_heads(fd[0], nr_match, match, remote);
106if (heads != 1) {
107packet_flush(fd[1]);
108die(heads ? "multiple remote heads" : "no matching remote head");
109}
110if (find_common(fd, sha1, remote) < 0)
111die("git-fetch-pack: no common commits");
112pid = fork();
113if (pid < 0)
114die("git-fetch-pack: unable to fork off git-unpack-objects");
115if (!pid) {
116close(fd[1]);
117dup2(fd[0], 0);
118close(fd[0]);
119execlp("git-unpack-objects", "git-unpack-objects", NULL);
120die("git-unpack-objects exec failed");
121}
122close(fd[0]);
123close(fd[1]);
124while (waitpid(pid, &status, 0) < 0) {
125if (errno != EINTR)
126die("waiting for git-unpack-objects: %s", strerror(errno));
127}
128if (WIFEXITED(status)) {
129int code = WEXITSTATUS(status);
130if (code)
131die("git-unpack-objects died with error code %d", code);
132puts(sha1_to_hex(remote));
133return 0;
134}
135if (WIFSIGNALED(status)) {
136int sig = WTERMSIG(status);
137die("git-unpack-objects died of signal %d", sig);
138}
139die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
140}
141142
int main(int argc, char **argv)
143{
144int i, ret, nr_heads;
145char *dest = NULL, **heads;
146int fd[2];
147pid_t pid;
148149
nr_heads = 0;
150heads = NULL;
151for (i = 1; i < argc; i++) {
152char *arg = argv[i];
153154
if (*arg == '-') {
155/* Arguments go here */
156usage(fetch_pack_usage);
157}
158dest = arg;
159heads = argv + i + 1;
160nr_heads = argc - i - 1;
161break;
162}
163if (!dest)
164usage(fetch_pack_usage);
165pid = git_connect(fd, dest, exec);
166if (pid < 0)
167return 1;
168ret = fetch_pack(fd, nr_heads, heads);
169close(fd[0]);
170close(fd[1]);
171finish_connect(pid);
172return ret;
173}