[PATCH] Fix local pull that uses packs.
[git] / fetch-pack.c
1 #include "cache.h"
2 #include "refs.h"
3 #include "pkt-line.h"
4 #include <sys/wait.h>
5
6 static int quiet;
7 static int verbose;
8 static const char fetch_pack_usage[] =
9 "git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...";
10 static const char *exec = "git-upload-pack";
11
12 static int find_common(int fd[2], unsigned char *result_sha1,
13                        struct ref *refs)
14 {
15         static char line[1000];
16         int count = 0, flushes = 0, retval;
17         FILE *revs;
18
19         revs = popen("git-rev-list $(git-rev-parse --all)", "r");
20         if (!revs)
21                 die("unable to run 'git-rev-list'");
22
23         while (refs) {
24                 unsigned char *remote = refs->old_sha1;
25                 if (verbose)
26                         fprintf(stderr,
27                                 "want %s (%s)\n", sha1_to_hex(remote),
28                                 refs->name);
29                 packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
30                 refs = refs->next;
31         }
32         packet_flush(fd[1]);
33         flushes = 1;
34         retval = -1;
35         while (fgets(line, sizeof(line), revs) != NULL) {
36                 unsigned char sha1[20];
37                 if (get_sha1_hex(line, sha1))
38                         die("git-fetch-pack: expected object name, got crud");
39                 packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
40                 if (verbose)
41                         fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
42                 if (!(31 & ++count)) {
43                         packet_flush(fd[1]);
44                         flushes++;
45
46                         /*
47                          * We keep one window "ahead" of the other side, and
48                          * will wait for an ACK only on the next one
49                          */
50                         if (count == 32)
51                                 continue;
52                         if (get_ack(fd[0], result_sha1)) {
53                                 flushes = 0;
54                                 retval = 0;
55                                 if (verbose)
56                                         fprintf(stderr, "got ack\n");
57                                 break;
58                         }
59                         flushes--;
60                 }
61         }
62         pclose(revs);
63         packet_write(fd[1], "done\n");
64         if (verbose)
65                 fprintf(stderr, "done\n");
66         while (flushes) {
67                 flushes--;
68                 if (get_ack(fd[0], result_sha1)) {
69                         if (verbose)
70                                 fprintf(stderr, "got ack\n");
71                         return 0;
72                 }
73         }
74         return retval;
75 }
76
77 static int fetch_pack(int fd[2], int nr_match, char **match)
78 {
79         struct ref *ref;
80         unsigned char sha1[20];
81         int status;
82         pid_t pid;
83
84         get_remote_heads(fd[0], &ref, nr_match, match);
85         if (!ref) {
86                 packet_flush(fd[1]);
87                 die("no matching remote head");
88         }
89         if (find_common(fd, sha1, ref) < 0)
90                 fprintf(stderr, "warning: no common commits\n");
91         pid = fork();
92         if (pid < 0)
93                 die("git-fetch-pack: unable to fork off git-unpack-objects");
94         if (!pid) {
95                 dup2(fd[0], 0);
96                 close(fd[0]);
97                 close(fd[1]);
98                 execlp("git-unpack-objects", "git-unpack-objects",
99                        quiet ? "-q" : NULL, NULL);
100                 die("git-unpack-objects exec failed");
101         }
102         close(fd[0]);
103         close(fd[1]);
104         while (waitpid(pid, &status, 0) < 0) {
105                 if (errno != EINTR)
106                         die("waiting for git-unpack-objects: %s", strerror(errno));
107         }
108         if (WIFEXITED(status)) {
109                 int code = WEXITSTATUS(status);
110                 if (code)
111                         die("git-unpack-objects died with error code %d", code);
112                 while (ref) {
113                         printf("%s %s\n",
114                                sha1_to_hex(ref->old_sha1), ref->name);
115                         ref = ref->next;
116                 }
117                 return 0;
118         }
119         if (WIFSIGNALED(status)) {
120                 int sig = WTERMSIG(status);
121                 die("git-unpack-objects died of signal %d", sig);
122         }
123         die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
124 }
125
126 int main(int argc, char **argv)
127 {
128         int i, ret, nr_heads;
129         char *dest = NULL, **heads;
130         int fd[2];
131         pid_t pid;
132
133         nr_heads = 0;
134         heads = NULL;
135         for (i = 1; i < argc; i++) {
136                 char *arg = argv[i];
137
138                 if (*arg == '-') {
139                         if (!strncmp("--exec=", arg, 7)) {
140                                 exec = arg + 7;
141                                 continue;
142                         }
143                         if (!strcmp("-q", arg)) {
144                                 quiet = 1;
145                                 continue;
146                         }
147                         if (!strcmp("-v", arg)) {
148                                 verbose = 1;
149                                 continue;
150                         }
151                         usage(fetch_pack_usage);
152                 }
153                 dest = arg;
154                 heads = argv + i + 1;
155                 nr_heads = argc - i - 1;
156                 break;
157         }
158         if (!dest)
159                 usage(fetch_pack_usage);
160         pid = git_connect(fd, dest, exec);
161         if (pid < 0)
162                 return 1;
163         ret = fetch_pack(fd, nr_heads, heads);
164         close(fd[0]);
165         close(fd[1]);
166         finish_connect(pid);
167         return ret;
168 }