]> git.ipfire.org Git - thirdparty/git.git/blame - clone-pack.c
Ignore funny refname sent from remote
[thirdparty/git.git] / clone-pack.c
CommitLineData
1fcc8ea5
LT
1#include "cache.h"
2#include "refs.h"
3#include "pkt-line.h"
4#include <sys/wait.h>
5
167a4a33 6static int quiet;
11dcec07 7static int keep_pack;
64c381bf
JH
8static const char clone_pack_usage[] =
9"git-clone-pack [-q] [--keep] [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
1fcc8ea5
LT
10static const char *exec = "git-upload-pack";
11
1fcc8ea5
LT
12static void clone_handshake(int fd[2], struct ref *ref)
13{
14 unsigned char sha1[20];
15
16 while (ref) {
d1c133f5 17 packet_write(fd[1], "want %s\n", sha1_to_hex(ref->old_sha1));
1fcc8ea5
LT
18 ref = ref->next;
19 }
20 packet_flush(fd[1]);
21
22 /* We don't have nuttin' */
23 packet_write(fd[1], "done\n");
24 if (get_ack(fd[0], sha1))
25 error("Huh! git-clone-pack got positive ack for %s", sha1_to_hex(sha1));
26}
27
28static int is_master(struct ref *ref)
29{
30 return !strcmp(ref->name, "refs/heads/master");
31}
32
33static void write_one_ref(struct ref *ref)
34{
4ec99bf0 35 char *path = git_path("%s", ref->name);
b2cb9425 36 int fd;
1fcc8ea5
LT
37 char *hex;
38
d8a1deec
JH
39 if (!strncmp(ref->name, "refs/", 5) &&
40 check_ref_format(ref->name + 5)) {
41 error("refusing to create funny ref '%s' locally", ref->name);
42 return;
43 }
44
b2cb9425
JH
45 if (safe_create_leading_directories(path))
46 die("unable to create leading directory for %s", ref->name);
47 fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0666);
1fcc8ea5
LT
48 if (fd < 0)
49 die("unable to create ref %s", ref->name);
d1c133f5 50 hex = sha1_to_hex(ref->old_sha1);
1fcc8ea5
LT
51 hex[40] = '\n';
52 if (write(fd, hex, 41) != 41)
53 die("unable to write ref %s", ref->name);
54 close(fd);
55}
56
57static void write_refs(struct ref *ref)
58{
59 struct ref *head = NULL, *head_ptr, *master_ref;
60 char *head_path;
61
4cfc63db 62 /* Upload-pack must report HEAD first */
1fcc8ea5
LT
63 if (!strcmp(ref->name, "HEAD")) {
64 head = ref;
65 ref = ref->next;
66 }
67 head_ptr = NULL;
68 master_ref = NULL;
69 while (ref) {
70 if (is_master(ref))
71 master_ref = ref;
4cfc63db
JH
72 if (head &&
73 !memcmp(ref->old_sha1, head->old_sha1, 20) &&
74 !strncmp(ref->name, "refs/heads/",11) &&
75 (!head_ptr || ref == master_ref))
76 head_ptr = ref;
77
1fcc8ea5
LT
78 write_one_ref(ref);
79 ref = ref->next;
80 }
4cfc63db
JH
81 if (!head) {
82 fprintf(stderr, "No HEAD in remote.\n");
1fcc8ea5 83 return;
4cfc63db 84 }
1fcc8ea5 85
4cfc63db 86 head_path = strdup(git_path("HEAD"));
1fcc8ea5
LT
87 if (!head_ptr) {
88 /*
89 * If we had a master ref, and it wasn't HEAD, we need to undo the
90 * symlink, and write a standalone HEAD. Give a warning, because that's
91 * really really wrong.
92 */
93 if (master_ref) {
94 error("HEAD doesn't point to any refs! Making standalone HEAD");
95 unlink(head_path);
96 }
97 write_one_ref(head);
4cfc63db 98 free(head_path);
1fcc8ea5
LT
99 return;
100 }
101
102 /* We reset to the master branch if it's available */
103 if (master_ref)
104 return;
105
4cfc63db
JH
106 fprintf(stderr, "Setting HEAD to %s\n", head_ptr->name);
107
1fcc8ea5
LT
108 /*
109 * Uhhuh. Other end didn't have master. We start HEAD off with
110 * the first branch with the same value.
111 */
4cfc63db 112 if (create_symref(head_path, head_ptr->name) < 0)
1fcc8ea5 113 die("unable to link HEAD to %s", head_ptr->name);
4cfc63db 114 free(head_path);
1fcc8ea5
LT
115}
116
11dcec07 117static int clone_by_unpack(int fd[2])
1fcc8ea5 118{
1fcc8ea5
LT
119 int status;
120 pid_t pid;
121
1fcc8ea5
LT
122 pid = fork();
123 if (pid < 0)
124 die("git-clone-pack: unable to fork off git-unpack-objects");
125 if (!pid) {
1fcc8ea5
LT
126 dup2(fd[0], 0);
127 close(fd[0]);
5ccdf4ce 128 close(fd[1]);
167a4a33
LT
129 execlp("git-unpack-objects", "git-unpack-objects",
130 quiet ? "-q" : NULL, NULL);
1fcc8ea5
LT
131 die("git-unpack-objects exec failed");
132 }
133 close(fd[0]);
134 close(fd[1]);
135 while (waitpid(pid, &status, 0) < 0) {
136 if (errno != EINTR)
137 die("waiting for git-unpack-objects: %s", strerror(errno));
138 }
139 if (WIFEXITED(status)) {
140 int code = WEXITSTATUS(status);
141 if (code)
142 die("git-unpack-objects died with error code %d", code);
1fcc8ea5
LT
143 return 0;
144 }
145 if (WIFSIGNALED(status)) {
146 int sig = WTERMSIG(status);
147 die("git-unpack-objects died of signal %d", sig);
148 }
149 die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
150}
151
11dcec07
JH
152static int finish_pack(const char *pack_tmp_name)
153{
154 int pipe_fd[2];
155 pid_t pid;
156 char idx[PATH_MAX];
157 char final[PATH_MAX];
158 char hash[41];
159 unsigned char sha1[20];
160 char *cp;
161 int err = 0;
162
163 if (pipe(pipe_fd) < 0)
164 die("git-clone-pack: unable to set up pipe");
165
166 strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
167 cp = strrchr(idx, '/');
168 memcpy(cp, "/pidx", 5);
169
170 pid = fork();
171 if (pid < 0)
172 die("git-clone-pack: unable to fork off git-index-pack");
173 if (!pid) {
174 close(0);
175 dup2(pipe_fd[1], 1);
176 close(pipe_fd[0]);
177 close(pipe_fd[1]);
178 execlp("git-index-pack","git-index-pack",
179 "-o", idx, pack_tmp_name, NULL);
180 error("cannot exec git-index-pack <%s> <%s>",
181 idx, pack_tmp_name);
182 exit(1);
183 }
184 close(pipe_fd[1]);
185 if (read(pipe_fd[0], hash, 40) != 40) {
186 error("git-clone-pack: unable to read from git-index-pack");
187 err = 1;
188 }
189 close(pipe_fd[0]);
190
191 for (;;) {
192 int status, code;
193 int retval = waitpid(pid, &status, 0);
194
195 if (retval < 0) {
196 if (errno == EINTR)
197 continue;
198 error("waitpid failed (%s)", strerror(retval));
199 goto error_die;
200 }
201 if (WIFSIGNALED(status)) {
202 int sig = WTERMSIG(status);
203 error("git-index-pack died of signal %d", sig);
204 goto error_die;
205 }
206 if (!WIFEXITED(status)) {
207 error("git-index-pack died of unnatural causes %d",
208 status);
209 goto error_die;
210 }
211 code = WEXITSTATUS(status);
212 if (code) {
213 error("git-index-pack died with error code %d", code);
214 goto error_die;
215 }
216 if (err)
217 goto error_die;
218 break;
219 }
220 hash[40] = 0;
221 if (get_sha1_hex(hash, sha1)) {
222 error("git-index-pack reported nonsense '%s'", hash);
223 goto error_die;
224 }
225 /* Now we have pack in pack_tmp_name[], and
226 * idx in idx[]; rename them to their final names.
227 */
228 snprintf(final, sizeof(final),
229 "%s/pack/pack-%s.pack", get_object_directory(), hash);
230 move_temp_to_file(pack_tmp_name, final);
64c381bf 231 chmod(final, 0444);
11dcec07
JH
232 snprintf(final, sizeof(final),
233 "%s/pack/pack-%s.idx", get_object_directory(), hash);
234 move_temp_to_file(idx, final);
64c381bf 235 chmod(final, 0444);
11dcec07
JH
236 return 0;
237
238 error_die:
239 unlink(idx);
240 unlink(pack_tmp_name);
241 exit(1);
242}
243
244static int clone_without_unpack(int fd[2])
245{
246 char tmpfile[PATH_MAX];
247 int ofd, ifd;
248
249 ifd = fd[0];
250 snprintf(tmpfile, sizeof(tmpfile),
251 "%s/pack-XXXXXX", get_object_directory());
252 ofd = mkstemp(tmpfile);
253 if (ofd < 0)
254 return error("unable to create temporary file %s", tmpfile);
255
256 while (1) {
257 char buf[8192];
258 ssize_t sz, wsz, pos;
259 sz = read(ifd, buf, sizeof(buf));
260 if (sz == 0)
261 break;
262 if (sz < 0) {
263 error("error reading pack (%s)", strerror(errno));
264 close(ofd);
265 unlink(tmpfile);
266 return -1;
267 }
268 pos = 0;
269 while (pos < sz) {
270 wsz = write(ofd, buf + pos, sz - pos);
271 if (wsz < 0) {
272 error("error writing pack (%s)",
273 strerror(errno));
274 close(ofd);
275 unlink(tmpfile);
276 return -1;
277 }
278 pos += wsz;
279 }
280 }
281 close(ofd);
282 return finish_pack(tmpfile);
283}
284
285static int clone_pack(int fd[2], int nr_match, char **match)
286{
287 struct ref *refs;
288 int status;
289
1a7141ff 290 get_remote_heads(fd[0], &refs, nr_match, match, 1);
11dcec07
JH
291 if (!refs) {
292 packet_flush(fd[1]);
293 die("no matching remote head");
294 }
295 clone_handshake(fd, refs);
296
297 if (keep_pack)
298 status = clone_without_unpack(fd);
299 else
300 status = clone_by_unpack(fd);
301
302 if (!status)
303 write_refs(refs);
304 return status;
305}
306
307static int clone_options(const char *var, const char *value)
308{
309 if (!strcmp("clone.keeppack", var)) {
310 keep_pack = git_config_bool(var, value);
311 return 0;
312 }
313 if (!strcmp("clone.quiet", var)) {
314 quiet = git_config_bool(var, value);
315 return 0;
316 }
317 /*
318 * Put other local option parsing for this program
319 * here ...
320 */
321
322 /* Fall back on the default ones */
323 return git_default_config(var, value);
324}
325
1fcc8ea5
LT
326int main(int argc, char **argv)
327{
328 int i, ret, nr_heads;
329 char *dest = NULL, **heads;
330 int fd[2];
331 pid_t pid;
332
11dcec07 333 git_config(clone_options);
1fcc8ea5
LT
334 nr_heads = 0;
335 heads = NULL;
336 for (i = 1; i < argc; i++) {
337 char *arg = argv[i];
338
339 if (*arg == '-') {
167a4a33
LT
340 if (!strcmp("-q", arg)) {
341 quiet = 1;
342 continue;
343 }
6ec311da
JH
344 if (!strncmp("--exec=", arg, 7)) {
345 exec = arg + 7;
346 continue;
347 }
11dcec07
JH
348 if (!strcmp("--keep", arg)) {
349 keep_pack = 1;
350 continue;
351 }
1fcc8ea5
LT
352 usage(clone_pack_usage);
353 }
354 dest = arg;
355 heads = argv + i + 1;
356 nr_heads = argc - i - 1;
357 break;
358 }
359 if (!dest)
360 usage(clone_pack_usage);
361 pid = git_connect(fd, dest, exec);
362 if (pid < 0)
363 return 1;
364 ret = clone_pack(fd, nr_heads, heads);
365 close(fd[0]);
366 close(fd[1]);
367 finish_connect(pid);
368 return ret;
369}