]>
Commit | Line | Data |
---|---|---|
def88e9a | 1 | #include "cache.h" |
fb9040cc | 2 | #include "refs.h" |
def88e9a | 3 | #include "pkt-line.h" |
75bfc6c2 | 4 | #include <sys/wait.h> |
def88e9a LT |
5 | |
6 | static const char fetch_pack_usage[] = "git-fetch-pack [host:]directory [heads]* < mycommitlist"; | |
7 | static const char *exec = "git-upload-pack"; | |
8 | ||
9 | static int get_ack(int fd, unsigned char *result_sha1) | |
10 | { | |
11 | static char line[1000]; | |
12 | int len = packet_read_line(fd, line, sizeof(line)); | |
13 | ||
14 | if (!len) | |
15 | die("git-fetch-pack: expected ACK/NAK, got EOF"); | |
16 | if (line[len-1] == '\n') | |
17 | line[--len] = 0; | |
18 | if (!strcmp(line, "NAK")) | |
19 | return 0; | |
20 | if (!strncmp(line, "ACK ", 3)) { | |
21 | if (!get_sha1_hex(line+4, result_sha1)) | |
22 | return 1; | |
23 | } | |
24 | die("git-fetch_pack: expected ACK/NAK, got '%s'", line); | |
25 | } | |
26 | ||
fb9040cc | 27 | static int find_common(int fd[2], unsigned char *result_sha1, unsigned char *remote) |
def88e9a LT |
28 | { |
29 | static char line[1000]; | |
75bfc6c2 LT |
30 | int count = 0, flushes = 0, retval; |
31 | FILE *revs; | |
def88e9a | 32 | |
75bfc6c2 LT |
33 | revs = popen("git-rev-list $(git-rev-parse --all)", "r"); |
34 | if (!revs) | |
35 | die("unable to run 'git-rev-list'"); | |
fb9040cc LT |
36 | packet_write(fd[1], "want %s\n", sha1_to_hex(remote)); |
37 | packet_flush(fd[1]); | |
75bfc6c2 LT |
38 | flushes = 1; |
39 | retval = -1; | |
40 | while (fgets(line, sizeof(line), revs) != NULL) { | |
def88e9a LT |
41 | unsigned char sha1[20]; |
42 | if (get_sha1_hex(line, sha1)) | |
43 | die("git-fetch-pack: expected object name, got crud"); | |
44 | packet_write(fd[1], "have %s\n", sha1_to_hex(sha1)); | |
45 | if (!(31 & ++count)) { | |
46 | packet_flush(fd[1]); | |
47 | flushes++; | |
48 | ||
49 | /* | |
50 | * We keep one window "ahead" of the other side, and | |
51 | * will wait for an ACK only on the next one | |
52 | */ | |
53 | if (count == 32) | |
54 | continue; | |
75bfc6c2 LT |
55 | if (get_ack(fd[0], result_sha1)) { |
56 | flushes = 0; | |
57 | retval = 0; | |
58 | break; | |
59 | } | |
def88e9a LT |
60 | flushes--; |
61 | } | |
62 | } | |
75bfc6c2 LT |
63 | pclose(revs); |
64 | packet_write(fd[1], "done\n"); | |
def88e9a LT |
65 | while (flushes) { |
66 | flushes--; | |
67 | if (get_ack(fd[0], result_sha1)) | |
68 | return 0; | |
69 | } | |
75bfc6c2 | 70 | return retval; |
def88e9a LT |
71 | } |
72 | ||
fb9040cc LT |
73 | static int get_old_sha1(const char *refname, unsigned char *sha1) |
74 | { | |
75 | static char pathname[PATH_MAX]; | |
76 | const char *git_dir; | |
77 | int fd, ret; | |
78 | ||
79 | git_dir = gitenv(GIT_DIR_ENVIRONMENT) ? : DEFAULT_GIT_DIR_ENVIRONMENT; | |
80 | snprintf(pathname, sizeof(pathname), "%s/%s", git_dir, refname); | |
81 | fd = open(pathname, O_RDONLY); | |
82 | ret = -1; | |
83 | if (fd >= 0) { | |
84 | char buffer[60]; | |
85 | if (read(fd, buffer, sizeof(buffer)) >= 40) | |
86 | ret = get_sha1_hex(buffer, sha1); | |
87 | close(fd); | |
88 | } | |
89 | return ret; | |
90 | } | |
91 | ||
92 | static int check_ref(const char *refname, const unsigned char *sha1) | |
def88e9a | 93 | { |
fb9040cc LT |
94 | unsigned char mysha1[20]; |
95 | char oldhex[41]; | |
96 | ||
97 | if (get_old_sha1(refname, mysha1) < 0) | |
98 | memset(mysha1, 0, 20); | |
99 | ||
100 | if (!memcmp(sha1, mysha1, 20)) { | |
75bfc6c2 | 101 | fprintf(stderr, "%s: unchanged\n", refname); |
fb9040cc LT |
102 | return 0; |
103 | } | |
104 | ||
105 | memcpy(oldhex, sha1_to_hex(mysha1), 41); | |
75bfc6c2 | 106 | fprintf(stderr, "%s: %s (%s)\n", refname, sha1_to_hex(sha1), oldhex); |
fb9040cc LT |
107 | return 1; |
108 | } | |
109 | ||
110 | static int get_remote_heads(int fd, int nr_match, char **match, unsigned char *result) | |
111 | { | |
112 | int count = 0; | |
113 | ||
def88e9a LT |
114 | for (;;) { |
115 | static char line[1000]; | |
116 | unsigned char sha1[20]; | |
117 | char *refname; | |
118 | int len; | |
119 | ||
120 | len = packet_read_line(fd, line, sizeof(line)); | |
121 | if (!len) | |
122 | break; | |
123 | if (line[len-1] == '\n') | |
124 | line[--len] = 0; | |
125 | if (len < 42 || get_sha1_hex(line, sha1)) | |
126 | die("git-fetch-pack: protocol error - expected ref descriptor, got '%sä'", line); | |
127 | refname = line+41; | |
128 | if (nr_match && !path_match(refname, nr_match, match)) | |
129 | continue; | |
fb9040cc LT |
130 | if (check_ref(refname, sha1)) { |
131 | count++; | |
132 | memcpy(result, sha1, 20); | |
133 | } | |
def88e9a | 134 | } |
fb9040cc | 135 | return count; |
def88e9a LT |
136 | } |
137 | ||
138 | static int fetch_pack(int fd[2], int nr_match, char **match) | |
139 | { | |
fb9040cc | 140 | unsigned char sha1[20], remote[20]; |
75bfc6c2 LT |
141 | int heads, status; |
142 | pid_t pid; | |
def88e9a | 143 | |
fb9040cc LT |
144 | heads = get_remote_heads(fd[0], nr_match, match, remote); |
145 | if (heads != 1) { | |
146 | packet_flush(fd[1]); | |
147 | die(heads ? "multiple remote heads" : "no matching remote head"); | |
148 | } | |
149 | if (find_common(fd, sha1, remote) < 0) | |
def88e9a | 150 | die("git-fetch-pack: no common commits"); |
75bfc6c2 LT |
151 | pid = fork(); |
152 | if (pid < 0) | |
153 | die("git-fetch-pack: unable to fork off git-unpack-objects"); | |
154 | if (!pid) { | |
155 | close(fd[1]); | |
156 | dup2(fd[0], 0); | |
157 | close(fd[0]); | |
158 | execlp("git-unpack-objects", "git-unpack-objects", NULL); | |
159 | die("git-unpack-objects exec failed"); | |
160 | } | |
fb9040cc | 161 | close(fd[0]); |
75bfc6c2 LT |
162 | close(fd[1]); |
163 | while (waitpid(pid, &status, 0) < 0) { | |
164 | if (errno != EINTR) | |
165 | die("waiting for git-unpack-objects: %s", strerror(errno)); | |
166 | } | |
167 | if (WIFEXITED(status)) { | |
168 | int code = WEXITSTATUS(status); | |
169 | if (code) | |
170 | die("git-unpack-objects died with error code %d", code); | |
171 | puts(sha1_to_hex(remote)); | |
172 | return 0; | |
173 | } | |
174 | if (WIFSIGNALED(status)) { | |
175 | int sig = WTERMSIG(status); | |
176 | die("git-unpack-objects died of signal %d", sig); | |
177 | } | |
178 | die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status); | |
def88e9a LT |
179 | } |
180 | ||
181 | int main(int argc, char **argv) | |
182 | { | |
183 | int i, ret, nr_heads; | |
184 | char *dest = NULL, **heads; | |
185 | int fd[2]; | |
186 | pid_t pid; | |
187 | ||
188 | nr_heads = 0; | |
189 | heads = NULL; | |
190 | for (i = 1; i < argc; i++) { | |
191 | char *arg = argv[i]; | |
192 | ||
193 | if (*arg == '-') { | |
194 | /* Arguments go here */ | |
195 | usage(fetch_pack_usage); | |
196 | } | |
197 | dest = arg; | |
198 | heads = argv + i + 1; | |
199 | nr_heads = argc - i - 1; | |
200 | break; | |
201 | } | |
202 | if (!dest) | |
203 | usage(fetch_pack_usage); | |
204 | pid = git_connect(fd, dest, exec); | |
205 | if (pid < 0) | |
206 | return 1; | |
207 | ret = fetch_pack(fd, nr_heads, heads); | |
208 | close(fd[0]); | |
209 | close(fd[1]); | |
210 | finish_connect(pid); | |
211 | return ret; | |
212 | } |