]> git.ipfire.org Git - thirdparty/git.git/blame - transport.c
fetch/push: readd rsync support
[thirdparty/git.git] / transport.c
CommitLineData
9b288516
DB
1#include "cache.h"
2#include "transport.h"
3#include "run-command.h"
c29727d5
DB
4#include "http.h"
5#include "pkt-line.h"
6#include "fetch-pack.h"
7#include "walker.h"
c7a8a162 8#include "bundle.h"
cd547b48
JS
9#include "dir.h"
10#include "refs.h"
11
12/* rsync support */
13
14/*
15 * We copy packed-refs and refs/ into a temporary file, then read the
16 * loose refs recursively (sorting whenever possible), and then inserting
17 * those packed refs that are not yet in the list (not validating, but
18 * assuming that the file is sorted).
19 *
20 * Appears refactoring this from refs.c is too cumbersome.
21 */
22
23static int str_cmp(const void *a, const void *b)
24{
25 const char *s1 = a;
26 const char *s2 = b;
27
28 return strcmp(s1, s2);
29}
30
31/* path->buf + name_offset is expected to point to "refs/" */
32
33static int read_loose_refs(struct strbuf *path, int name_offset,
34 struct ref **tail)
35{
36 DIR *dir = opendir(path->buf);
37 struct dirent *de;
38 struct {
39 char **entries;
40 int nr, alloc;
41 } list;
42 int i, pathlen;
43
44 if (!dir)
45 return -1;
46
47 memset (&list, 0, sizeof(list));
48
49 while ((de = readdir(dir))) {
50 if (de->d_name[0] == '.' && (de->d_name[1] == '\0' ||
51 (de->d_name[1] == '.' &&
52 de->d_name[2] == '\0')))
53 continue;
54 ALLOC_GROW(list.entries, list.nr + 1, list.alloc);
55 list.entries[list.nr++] = xstrdup(de->d_name);
56 }
57 closedir(dir);
58
59 /* sort the list */
60
61 qsort(list.entries, list.nr, sizeof(char *), str_cmp);
62
63 pathlen = path->len;
64 strbuf_addch(path, '/');
65
66 for (i = 0; i < list.nr; i++, strbuf_setlen(path, pathlen + 1)) {
67 strbuf_addstr(path, list.entries[i]);
68 if (read_loose_refs(path, name_offset, tail)) {
69 int fd = open(path->buf, O_RDONLY);
70 char buffer[40];
71 struct ref *next;
72
73 if (fd < 0)
74 continue;
75 next = alloc_ref(path->len - name_offset + 1);
76 if (read_in_full(fd, buffer, 40) != 40 ||
77 get_sha1_hex(buffer, next->old_sha1)) {
78 close(fd);
79 free(next);
80 continue;
81 }
82 close(fd);
83 strcpy(next->name, path->buf + name_offset);
84 (*tail)->next = next;
85 *tail = next;
86 }
87 }
88 strbuf_setlen(path, pathlen);
89
90 for (i = 0; i < list.nr; i++)
91 free(list.entries[i]);
92 free(list.entries);
93
94 return 0;
95}
96
97/* insert the packed refs for which no loose refs were found */
98
99static void insert_packed_refs(const char *packed_refs, struct ref **list)
100{
101 FILE *f = fopen(packed_refs, "r");
102 static char buffer[PATH_MAX];
103
104 if (!f)
105 return;
106
107 for (;;) {
108 int cmp, len;
109
110 if (!fgets(buffer, sizeof(buffer), f)) {
111 fclose(f);
112 return;
113 }
114
115 if (hexval(buffer[0]) > 0xf)
116 continue;
117 len = strlen(buffer);
118 if (buffer[len - 1] == '\n')
119 buffer[--len] = '\0';
120 if (len < 41)
121 continue;
122 while ((*list)->next &&
123 (cmp = strcmp(buffer + 41,
124 (*list)->next->name)) > 0)
125 list = &(*list)->next;
126 if (!(*list)->next || cmp < 0) {
127 struct ref *next = alloc_ref(len - 40);
128 buffer[40] = '\0';
129 if (get_sha1_hex(buffer, next->old_sha1)) {
130 warning ("invalid SHA-1: %s", buffer);
131 free(next);
132 continue;
133 }
134 strcpy(next->name, buffer + 41);
135 next->next = (*list)->next;
136 (*list)->next = next;
137 list = &(*list)->next;
138 }
139 }
140}
141
142static struct ref *get_refs_via_rsync(const struct transport *transport)
143{
144 struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
145 struct ref dummy, *tail = &dummy;
146 struct child_process rsync;
147 const char *args[5];
148 int temp_dir_len;
149
150 /* copy the refs to the temporary directory */
151
152 strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
153 if (!mkdtemp(temp_dir.buf))
154 die ("Could not make temporary directory");
155 temp_dir_len = temp_dir.len;
156
157 strbuf_addstr(&buf, transport->url);
158 strbuf_addstr(&buf, "/refs");
159
160 memset(&rsync, 0, sizeof(rsync));
161 rsync.argv = args;
162 rsync.stdout_to_stderr = 1;
163 args[0] = "rsync";
164 args[1] = transport->verbose ? "-rv" : "-r";
165 args[2] = buf.buf;
166 args[3] = temp_dir.buf;
167 args[4] = NULL;
168
169 if (run_command(&rsync))
170 die ("Could not run rsync to get refs");
171
172 strbuf_reset(&buf);
173 strbuf_addstr(&buf, transport->url);
174 strbuf_addstr(&buf, "/packed-refs");
175
176 args[2] = buf.buf;
177
178 if (run_command(&rsync))
179 die ("Could not run rsync to get refs");
180
181 /* read the copied refs */
182
183 strbuf_addstr(&temp_dir, "/refs");
184 read_loose_refs(&temp_dir, temp_dir_len + 1, &tail);
185 strbuf_setlen(&temp_dir, temp_dir_len);
186
187 tail = &dummy;
188 strbuf_addstr(&temp_dir, "/packed-refs");
189 insert_packed_refs(temp_dir.buf, &tail);
190 strbuf_setlen(&temp_dir, temp_dir_len);
191
192 if (remove_dir_recursively(&temp_dir, 0))
193 warning ("Error removing temporary directory %s.",
194 temp_dir.buf);
195
196 strbuf_release(&buf);
197 strbuf_release(&temp_dir);
198
199 return dummy.next;
200}
201
202static int fetch_objs_via_rsync(struct transport *transport,
203 int nr_objs, struct ref **to_fetch)
204{
205 struct strbuf buf = STRBUF_INIT;
206 struct child_process rsync;
207 const char *args[8];
208 int result;
209
210 strbuf_addstr(&buf, transport->url);
211 strbuf_addstr(&buf, "/objects/");
212
213 memset(&rsync, 0, sizeof(rsync));
214 rsync.argv = args;
215 rsync.stdout_to_stderr = 1;
216 args[0] = "rsync";
217 args[1] = transport->verbose ? "-rv" : "-r";
218 args[2] = "--ignore-existing";
219 args[3] = "--exclude";
220 args[4] = "info";
221 args[5] = buf.buf;
222 args[6] = get_object_directory();
223 args[7] = NULL;
224
225 /* NEEDSWORK: handle one level of alternates */
226 result = run_command(&rsync);
227
228 strbuf_release(&buf);
229
230 return result;
231}
232
233static int write_one_ref(const char *name, const unsigned char *sha1,
234 int flags, void *data)
235{
236 struct strbuf *buf = data;
237 int len = buf->len;
238 FILE *f;
239
240 /* when called via for_each_ref(), flags is non-zero */
241 if (flags && prefixcmp(name, "refs/heads/") &&
242 prefixcmp(name, "refs/tags/"))
243 return 0;
244
245 strbuf_addstr(buf, name);
246 if (safe_create_leading_directories(buf->buf) ||
247 !(f = fopen(buf->buf, "w")) ||
248 fprintf(f, "%s\n", sha1_to_hex(sha1)) < 0 ||
249 fclose(f))
250 return error("problems writing temporary file %s", buf->buf);
251 strbuf_setlen(buf, len);
252 return 0;
253}
254
255static int write_refs_to_temp_dir(struct strbuf *temp_dir,
256 int refspec_nr, const char **refspec)
257{
258 int i;
259
260 for (i = 0; i < refspec_nr; i++) {
261 unsigned char sha1[20];
262 char *ref;
263
264 if (dwim_ref(refspec[i], strlen(refspec[i]), sha1, &ref) != 1)
265 return error("Could not get ref %s", refspec[i]);
266
267 if (write_one_ref(ref, sha1, 0, temp_dir)) {
268 free(ref);
269 return -1;
270 }
271 free(ref);
272 }
273 return 0;
274}
275
276static int rsync_transport_push(struct transport *transport,
277 int refspec_nr, const char **refspec, int flags)
278{
279 struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
280 int result = 0, i;
281 struct child_process rsync;
282 const char *args[8];
283
284 /* first push the objects */
285
286 strbuf_addstr(&buf, transport->url);
287 strbuf_addch(&buf, '/');
288
289 memset(&rsync, 0, sizeof(rsync));
290 rsync.argv = args;
291 rsync.stdout_to_stderr = 1;
292 args[0] = "rsync";
293 args[1] = transport->verbose ? "-av" : "-a";
294 args[2] = "--ignore-existing";
295 args[3] = "--exclude";
296 args[4] = "info";
297 args[5] = get_object_directory();;
298 args[6] = buf.buf;
299 args[7] = NULL;
300
301 if (run_command(&rsync))
302 return error("Could not push objects to %s", transport->url);
303
304 /* copy the refs to the temporary directory; they could be packed. */
305
306 strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
307 if (!mkdtemp(temp_dir.buf))
308 die ("Could not make temporary directory");
309 strbuf_addch(&temp_dir, '/');
310
311 if (flags & TRANSPORT_PUSH_ALL) {
312 if (for_each_ref(write_one_ref, &temp_dir))
313 return -1;
314 } else if (write_refs_to_temp_dir(&temp_dir, refspec_nr, refspec))
315 return -1;
316
317 i = (flags & TRANSPORT_PUSH_FORCE) ? 2 : 3;
318 args[i++] = temp_dir.buf;
319 args[i++] = transport->url;
320 args[i++] = NULL;
321 if (run_command(&rsync))
322 result = error("Could not push to %s", transport->url);
323
324 if (remove_dir_recursively(&temp_dir, 0))
325 warning ("Could not remove temporary directory %s.",
326 temp_dir.buf);
327
328 strbuf_release(&buf);
329 strbuf_release(&temp_dir);
330
331 return result;
332}
c29727d5
DB
333
334/* Generic functions for using commit walkers */
335
1788c39c 336static int fetch_objs_via_walker(struct transport *transport,
425b1393 337 int nr_objs, struct ref **to_fetch)
c29727d5
DB
338{
339 char *dest = xstrdup(transport->url);
340 struct walker *walker = transport->data;
425b1393
SP
341 char **objs = xmalloc(nr_objs * sizeof(*objs));
342 int i;
c29727d5
DB
343
344 walker->get_all = 1;
345 walker->get_tree = 1;
346 walker->get_history = 1;
347 walker->get_verbosely = transport->verbose;
348 walker->get_recover = 0;
349
425b1393
SP
350 for (i = 0; i < nr_objs; i++)
351 objs[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
352
b6abb48a 353 if (walker_fetch(walker, nr_objs, objs, NULL, NULL))
c29727d5
DB
354 die("Fetch failed.");
355
425b1393
SP
356 for (i = 0; i < nr_objs; i++)
357 free(objs[i]);
358 free(objs);
c29727d5
DB
359 free(dest);
360 return 0;
361}
362
363static int disconnect_walker(struct transport *transport)
364{
365 struct walker *walker = transport->data;
366 if (walker)
367 walker_free(walker);
368 return 0;
369}
9b288516 370
9b288516
DB
371static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
372 const char **argv;
373 int argc;
374 int err;
375
376 argv = xmalloc((refspec_nr + 11) * sizeof(char *));
377 argv[0] = "http-push";
378 argc = 1;
379 if (flags & TRANSPORT_PUSH_ALL)
380 argv[argc++] = "--all";
381 if (flags & TRANSPORT_PUSH_FORCE)
382 argv[argc++] = "--force";
383 argv[argc++] = transport->url;
384 while (refspec_nr--)
385 argv[argc++] = *refspec++;
386 argv[argc] = NULL;
387 err = run_command_v_opt(argv, RUN_GIT_CMD);
388 switch (err) {
389 case -ERR_RUN_COMMAND_FORK:
390 error("unable to fork for %s", argv[0]);
391 case -ERR_RUN_COMMAND_EXEC:
392 error("unable to exec %s", argv[0]);
393 break;
394 case -ERR_RUN_COMMAND_WAITPID:
395 case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
396 case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
397 case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
398 error("%s died with strange error", argv[0]);
399 }
400 return !!err;
401}
402
c29727d5
DB
403#ifndef NO_CURL
404static int missing__target(int code, int result)
405{
406 return /* file:// URL -- do we ever use one??? */
407 (result == CURLE_FILE_COULDNT_READ_FILE) ||
408 /* http:// and https:// URL */
409 (code == 404 && result == CURLE_HTTP_RETURNED_ERROR) ||
410 /* ftp:// URL */
411 (code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE)
412 ;
413}
414
415#define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
416
417static struct ref *get_refs_via_curl(const struct transport *transport)
418{
419 struct buffer buffer;
420 char *data, *start, *mid;
421 char *ref_name;
422 char *refs_url;
423 int i = 0;
424
425 struct active_request_slot *slot;
426 struct slot_results results;
427
428 struct ref *refs = NULL;
429 struct ref *ref = NULL;
430 struct ref *last_ref = NULL;
431
432 data = xmalloc(4096);
433 buffer.size = 4096;
434 buffer.posn = 0;
435 buffer.buffer = data;
436
437 refs_url = xmalloc(strlen(transport->url) + 11);
438 sprintf(refs_url, "%s/info/refs", transport->url);
439
440 http_init();
441
442 slot = get_active_slot();
443 slot->results = &results;
444 curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
445 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
446 curl_easy_setopt(slot->curl, CURLOPT_URL, refs_url);
447 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
448 if (start_active_slot(slot)) {
449 run_active_slot(slot);
450 if (results.curl_result != CURLE_OK) {
451 if (missing_target(&results)) {
452 free(buffer.buffer);
453 return NULL;
454 } else {
455 free(buffer.buffer);
456 error("%s", curl_errorstr);
457 return NULL;
458 }
459 }
460 } else {
461 free(buffer.buffer);
462 error("Unable to start request");
463 return NULL;
464 }
465
466 http_cleanup();
467
468 data = buffer.buffer;
469 start = NULL;
470 mid = data;
471 while (i < buffer.posn) {
472 if (!start)
473 start = &data[i];
474 if (data[i] == '\t')
475 mid = &data[i];
476 if (data[i] == '\n') {
477 data[i] = 0;
478 ref_name = mid + 1;
479 ref = xmalloc(sizeof(struct ref) +
480 strlen(ref_name) + 1);
481 memset(ref, 0, sizeof(struct ref));
482 strcpy(ref->name, ref_name);
483 get_sha1_hex(start, ref->old_sha1);
484 if (!refs)
485 refs = ref;
486 if (last_ref)
487 last_ref->next = ref;
488 last_ref = ref;
489 start = NULL;
490 }
491 i++;
492 }
493
494 free(buffer.buffer);
495
496 return refs;
497}
498
e5f4e214
SP
499static int fetch_objs_via_curl(struct transport *transport,
500 int nr_objs, struct ref **to_fetch)
501{
502 if (!transport->data)
503 transport->data = get_http_walker(transport->url);
504 return fetch_objs_via_walker(transport, nr_objs, to_fetch);
505}
506
c29727d5
DB
507#else
508
509static struct ref *get_refs_via_curl(const struct transport *transport)
510{
511 die("Cannot fetch from '%s' without curl ...", transport->url);
512 return NULL;
513}
514
e5f4e214
SP
515static int fetch_objs_via_curl(struct transport *transport,
516 int nr_objs, struct ref **to_fetch)
517{
518 die("Cannot fetch from '%s' without curl ...", transport->url);
519 return -1;
520}
521
c29727d5
DB
522#endif
523
c7a8a162
JS
524struct bundle_transport_data {
525 int fd;
526 struct bundle_header header;
527};
528
529static struct ref *get_refs_from_bundle(const struct transport *transport)
530{
531 struct bundle_transport_data *data = transport->data;
532 struct ref *result = NULL;
533 int i;
534
535 if (data->fd > 0)
536 close(data->fd);
537 data->fd = read_bundle_header(transport->url, &data->header);
538 if (data->fd < 0)
539 die ("Could not read bundle '%s'.", transport->url);
540 for (i = 0; i < data->header.references.nr; i++) {
541 struct ref_list_entry *e = data->header.references.list + i;
90446a00 542 struct ref *ref = alloc_ref(strlen(e->name) + 1);
c7a8a162
JS
543 hashcpy(ref->old_sha1, e->sha1);
544 strcpy(ref->name, e->name);
545 ref->next = result;
546 result = ref;
547 }
548 return result;
549}
550
1788c39c 551static int fetch_refs_from_bundle(struct transport *transport,
425b1393 552 int nr_heads, struct ref **to_fetch)
c7a8a162
JS
553{
554 struct bundle_transport_data *data = transport->data;
555 return unbundle(&data->header, data->fd);
556}
557
558static int close_bundle(struct transport *transport)
559{
560 struct bundle_transport_data *data = transport->data;
561 if (data->fd > 0)
562 close(data->fd);
f4e95765 563 free(data);
c7a8a162
JS
564 return 0;
565}
566
9b288516
DB
567struct git_transport_data {
568 unsigned thin : 1;
c29727d5 569 unsigned keep : 1;
c29727d5 570 int depth;
c29727d5 571 const char *uploadpack;
9b288516
DB
572 const char *receivepack;
573};
574
575static int set_git_option(struct transport *connection,
576 const char *name, const char *value)
577{
578 struct git_transport_data *data = connection->data;
c29727d5
DB
579 if (!strcmp(name, TRANS_OPT_UPLOADPACK)) {
580 data->uploadpack = value;
581 return 0;
582 } else if (!strcmp(name, TRANS_OPT_RECEIVEPACK)) {
9b288516
DB
583 data->receivepack = value;
584 return 0;
585 } else if (!strcmp(name, TRANS_OPT_THIN)) {
586 data->thin = !!value;
587 return 0;
c29727d5
DB
588 } else if (!strcmp(name, TRANS_OPT_KEEP)) {
589 data->keep = !!value;
590 return 0;
c29727d5
DB
591 } else if (!strcmp(name, TRANS_OPT_DEPTH)) {
592 if (!value)
593 data->depth = 0;
594 else
595 data->depth = atoi(value);
596 return 0;
9b288516
DB
597 }
598 return 1;
599}
600
c29727d5
DB
601static struct ref *get_refs_via_connect(const struct transport *transport)
602{
603 struct git_transport_data *data = transport->data;
604 struct ref *refs;
605 int fd[2];
606 pid_t pid;
607 char *dest = xstrdup(transport->url);
608
609 pid = git_connect(fd, dest, data->uploadpack, 0);
610
611 if (pid < 0)
612 die("Failed to connect to \"%s\"", transport->url);
613
614 get_remote_heads(fd[0], &refs, 0, NULL, 0);
615 packet_flush(fd[1]);
616
617 finish_connect(pid);
618
619 free(dest);
620
621 return refs;
622}
623
1788c39c 624static int fetch_refs_via_pack(struct transport *transport,
425b1393 625 int nr_heads, struct ref **to_fetch)
c29727d5
DB
626{
627 struct git_transport_data *data = transport->data;
425b1393 628 char **heads = xmalloc(nr_heads * sizeof(*heads));
e4cd6c7a 629 char **origh = xmalloc(nr_heads * sizeof(*origh));
c29727d5
DB
630 struct ref *refs;
631 char *dest = xstrdup(transport->url);
632 struct fetch_pack_args args;
425b1393 633 int i;
c29727d5 634
fa740529 635 memset(&args, 0, sizeof(args));
c29727d5 636 args.uploadpack = data->uploadpack;
c29727d5 637 args.keep_pack = data->keep;
fa740529 638 args.lock_pack = 1;
c29727d5 639 args.use_thin_pack = data->thin;
c29727d5
DB
640 args.verbose = transport->verbose;
641 args.depth = data->depth;
c29727d5 642
425b1393 643 for (i = 0; i < nr_heads; i++)
e4cd6c7a 644 origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
fa740529 645 refs = fetch_pack(&args, dest, nr_heads, heads, &transport->pack_lockfile);
c29727d5 646
425b1393 647 for (i = 0; i < nr_heads; i++)
e4cd6c7a
SP
648 free(origh[i]);
649 free(origh);
650 free(heads);
c29727d5 651 free_refs(refs);
c29727d5
DB
652 free(dest);
653 return 0;
654}
655
9b288516
DB
656static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
657 struct git_transport_data *data = transport->data;
658 const char **argv;
659 char *rem;
660 int argc;
661 int err;
662
663 argv = xmalloc((refspec_nr + 11) * sizeof(char *));
664 argv[0] = "send-pack";
665 argc = 1;
666 if (flags & TRANSPORT_PUSH_ALL)
667 argv[argc++] = "--all";
668 if (flags & TRANSPORT_PUSH_FORCE)
669 argv[argc++] = "--force";
670 if (data->receivepack) {
671 char *rp = xmalloc(strlen(data->receivepack) + 16);
672 sprintf(rp, "--receive-pack=%s", data->receivepack);
673 argv[argc++] = rp;
674 }
675 if (data->thin)
676 argv[argc++] = "--thin";
677 rem = xmalloc(strlen(transport->remote->name) + 10);
678 sprintf(rem, "--remote=%s", transport->remote->name);
679 argv[argc++] = rem;
680 argv[argc++] = transport->url;
681 while (refspec_nr--)
682 argv[argc++] = *refspec++;
683 argv[argc] = NULL;
684 err = run_command_v_opt(argv, RUN_GIT_CMD);
685 switch (err) {
686 case -ERR_RUN_COMMAND_FORK:
687 error("unable to fork for %s", argv[0]);
688 case -ERR_RUN_COMMAND_EXEC:
689 error("unable to exec %s", argv[0]);
690 break;
691 case -ERR_RUN_COMMAND_WAITPID:
692 case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
693 case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
694 case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
695 error("%s died with strange error", argv[0]);
696 }
697 return !!err;
698}
699
f4e95765
SP
700static int disconnect_git(struct transport *transport)
701{
702 free(transport->data);
703 return 0;
704}
705
9b288516
DB
706static int is_local(const char *url)
707{
708 const char *colon = strchr(url, ':');
709 const char *slash = strchr(url, '/');
710 return !colon || (slash && slash < colon);
711}
712
713static int is_file(const char *url)
714{
715 struct stat buf;
716 if (stat(url, &buf))
717 return 0;
718 return S_ISREG(buf.st_mode);
719}
720
e5f4e214 721struct transport *transport_get(struct remote *remote, const char *url)
9b288516 722{
8eb554ae
SP
723 struct transport *ret = xcalloc(1, sizeof(*ret));
724
725 ret->remote = remote;
726 ret->url = url;
8eb554ae 727
9b288516 728 if (!prefixcmp(url, "rsync://")) {
cd547b48
JS
729 ret->get_refs_list = get_refs_via_rsync;
730 ret->fetch = fetch_objs_via_rsync;
731 ret->push = rsync_transport_push;
824d5776 732
8eb554ae
SP
733 } else if (!prefixcmp(url, "http://")
734 || !prefixcmp(url, "https://")
735 || !prefixcmp(url, "ftp://")) {
824d5776
SP
736 ret->get_refs_list = get_refs_via_curl;
737 ret->fetch = fetch_objs_via_curl;
738 ret->push = curl_transport_push;
739 ret->disconnect = disconnect_walker;
740
9b288516 741 } else if (is_local(url) && is_file(url)) {
c7a8a162 742 struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
c7a8a162 743 ret->data = data;
824d5776
SP
744 ret->get_refs_list = get_refs_from_bundle;
745 ret->fetch = fetch_refs_from_bundle;
746 ret->disconnect = close_bundle;
747
9b288516
DB
748 } else {
749 struct git_transport_data *data = xcalloc(1, sizeof(*data));
9b288516 750 ret->data = data;
824d5776
SP
751 ret->set_option = set_git_option;
752 ret->get_refs_list = get_refs_via_connect;
753 ret->fetch = fetch_refs_via_pack;
754 ret->push = git_transport_push;
f4e95765 755 ret->disconnect = disconnect_git;
824d5776 756
9b288516 757 data->thin = 1;
c29727d5
DB
758 data->uploadpack = "git-upload-pack";
759 if (remote && remote->uploadpack)
760 data->uploadpack = remote->uploadpack;
9b288516
DB
761 data->receivepack = "git-receive-pack";
762 if (remote && remote->receivepack)
763 data->receivepack = remote->receivepack;
9b288516 764 }
8eb554ae 765
9b288516
DB
766 return ret;
767}
768
769int transport_set_option(struct transport *transport,
770 const char *name, const char *value)
771{
824d5776
SP
772 if (transport->set_option)
773 return transport->set_option(transport, name, value);
ab865e6e 774 return 1;
9b288516
DB
775}
776
777int transport_push(struct transport *transport,
778 int refspec_nr, const char **refspec, int flags)
779{
824d5776 780 if (!transport->push)
9b288516 781 return 1;
824d5776 782 return transport->push(transport, refspec_nr, refspec, flags);
9b288516
DB
783}
784
c29727d5
DB
785struct ref *transport_get_remote_refs(struct transport *transport)
786{
787 if (!transport->remote_refs)
824d5776 788 transport->remote_refs = transport->get_refs_list(transport);
c29727d5
DB
789 return transport->remote_refs;
790}
791
c29727d5
DB
792int transport_fetch_refs(struct transport *transport, struct ref *refs)
793{
425b1393 794 int rc;
7a2bff45 795 int nr_heads = 0, nr_alloc = 0;
425b1393 796 struct ref **heads = NULL;
c29727d5 797 struct ref *rm;
c29727d5
DB
798
799 for (rm = refs; rm; rm = rm->next) {
800 if (rm->peer_ref &&
801 !hashcmp(rm->peer_ref->old_sha1, rm->old_sha1))
802 continue;
7a2bff45 803 ALLOC_GROW(heads, nr_heads + 1, nr_alloc);
425b1393 804 heads[nr_heads++] = rm;
c29727d5
DB
805 }
806
824d5776 807 rc = transport->fetch(transport, nr_heads, heads);
c29727d5 808 free(heads);
425b1393 809 return rc;
c29727d5
DB
810}
811
1788c39c
SP
812void transport_unlock_pack(struct transport *transport)
813{
814 if (transport->pack_lockfile) {
815 unlink(transport->pack_lockfile);
816 free(transport->pack_lockfile);
817 transport->pack_lockfile = NULL;
818 }
819}
820
9b288516
DB
821int transport_disconnect(struct transport *transport)
822{
823 int ret = 0;
824d5776
SP
824 if (transport->disconnect)
825 ret = transport->disconnect(transport);
9b288516
DB
826 free(transport);
827 return ret;
828}