transport.con commit Restore default verbosity for http fetches. (2b5a06e)
   1#include "cache.h"
   2#include "transport.h"
   3#include "run-command.h"
   4#include "http.h"
   5#include "pkt-line.h"
   6#include "fetch-pack.h"
   7#include "walker.h"
   8#include "bundle.h"
   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 > 0) ? "-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 > 0) ? "-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 > 0) ? "-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}
 333
 334/* Generic functions for using commit walkers */
 335
 336static int fetch_objs_via_walker(struct transport *transport,
 337                                 int nr_objs, struct ref **to_fetch)
 338{
 339        char *dest = xstrdup(transport->url);
 340        struct walker *walker = transport->data;
 341        char **objs = xmalloc(nr_objs * sizeof(*objs));
 342        int i;
 343
 344        walker->get_all = 1;
 345        walker->get_tree = 1;
 346        walker->get_history = 1;
 347        walker->get_verbosely = transport->verbose >= 0;
 348        walker->get_recover = 0;
 349
 350        for (i = 0; i < nr_objs; i++)
 351                objs[i] = xstrdup(sha1_to_hex(to_fetch[i]->old_sha1));
 352
 353        if (walker_fetch(walker, nr_objs, objs, NULL, NULL))
 354                die("Fetch failed.");
 355
 356        for (i = 0; i < nr_objs; i++)
 357                free(objs[i]);
 358        free(objs);
 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}
 370
 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
 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
 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
 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
 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
 522#endif
 523
 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;
 542                struct ref *ref = alloc_ref(strlen(e->name) + 1);
 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
 551static int fetch_refs_from_bundle(struct transport *transport,
 552                               int nr_heads, struct ref **to_fetch)
 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);
 563        free(data);
 564        return 0;
 565}
 566
 567struct git_transport_data {
 568        unsigned thin : 1;
 569        unsigned keep : 1;
 570        int depth;
 571        const char *uploadpack;
 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;
 579        if (!strcmp(name, TRANS_OPT_UPLOADPACK)) {
 580                data->uploadpack = value;
 581                return 0;
 582        } else if (!strcmp(name, TRANS_OPT_RECEIVEPACK)) {
 583                data->receivepack = value;
 584                return 0;
 585        } else if (!strcmp(name, TRANS_OPT_THIN)) {
 586                data->thin = !!value;
 587                return 0;
 588        } else if (!strcmp(name, TRANS_OPT_KEEP)) {
 589                data->keep = !!value;
 590                return 0;
 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;
 597        }
 598        return 1;
 599}
 600
 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
 624static int fetch_refs_via_pack(struct transport *transport,
 625                               int nr_heads, struct ref **to_fetch)
 626{
 627        struct git_transport_data *data = transport->data;
 628        char **heads = xmalloc(nr_heads * sizeof(*heads));
 629        char **origh = xmalloc(nr_heads * sizeof(*origh));
 630        struct ref *refs;
 631        char *dest = xstrdup(transport->url);
 632        struct fetch_pack_args args;
 633        int i;
 634
 635        memset(&args, 0, sizeof(args));
 636        args.uploadpack = data->uploadpack;
 637        args.keep_pack = data->keep;
 638        args.lock_pack = 1;
 639        args.use_thin_pack = data->thin;
 640        args.verbose = transport->verbose > 0;
 641        args.depth = data->depth;
 642
 643        for (i = 0; i < nr_heads; i++)
 644                origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
 645        refs = fetch_pack(&args, dest, nr_heads, heads, &transport->pack_lockfile);
 646
 647        for (i = 0; i < nr_heads; i++)
 648                free(origh[i]);
 649        free(origh);
 650        free(heads);
 651        free_refs(refs);
 652        free(dest);
 653        return 0;
 654}
 655
 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
 700static int disconnect_git(struct transport *transport)
 701{
 702        free(transport->data);
 703        return 0;
 704}
 705
 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
 721struct transport *transport_get(struct remote *remote, const char *url)
 722{
 723        struct transport *ret = xcalloc(1, sizeof(*ret));
 724
 725        ret->remote = remote;
 726        ret->url = url;
 727
 728        if (!prefixcmp(url, "rsync://")) {
 729                ret->get_refs_list = get_refs_via_rsync;
 730                ret->fetch = fetch_objs_via_rsync;
 731                ret->push = rsync_transport_push;
 732
 733        } else if (!prefixcmp(url, "http://")
 734                || !prefixcmp(url, "https://")
 735                || !prefixcmp(url, "ftp://")) {
 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
 741        } else if (is_local(url) && is_file(url)) {
 742                struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
 743                ret->data = data;
 744                ret->get_refs_list = get_refs_from_bundle;
 745                ret->fetch = fetch_refs_from_bundle;
 746                ret->disconnect = close_bundle;
 747
 748        } else {
 749                struct git_transport_data *data = xcalloc(1, sizeof(*data));
 750                ret->data = data;
 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;
 755                ret->disconnect = disconnect_git;
 756
 757                data->thin = 1;
 758                data->uploadpack = "git-upload-pack";
 759                if (remote && remote->uploadpack)
 760                        data->uploadpack = remote->uploadpack;
 761                data->receivepack = "git-receive-pack";
 762                if (remote && remote->receivepack)
 763                        data->receivepack = remote->receivepack;
 764        }
 765
 766        return ret;
 767}
 768
 769int transport_set_option(struct transport *transport,
 770                         const char *name, const char *value)
 771{
 772        if (transport->set_option)
 773                return transport->set_option(transport, name, value);
 774        return 1;
 775}
 776
 777int transport_push(struct transport *transport,
 778                   int refspec_nr, const char **refspec, int flags)
 779{
 780        if (!transport->push)
 781                return 1;
 782        return transport->push(transport, refspec_nr, refspec, flags);
 783}
 784
 785struct ref *transport_get_remote_refs(struct transport *transport)
 786{
 787        if (!transport->remote_refs)
 788                transport->remote_refs = transport->get_refs_list(transport);
 789        return transport->remote_refs;
 790}
 791
 792int transport_fetch_refs(struct transport *transport, struct ref *refs)
 793{
 794        int rc;
 795        int nr_heads = 0, nr_alloc = 0;
 796        struct ref **heads = NULL;
 797        struct ref *rm;
 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;
 803                ALLOC_GROW(heads, nr_heads + 1, nr_alloc);
 804                heads[nr_heads++] = rm;
 805        }
 806
 807        rc = transport->fetch(transport, nr_heads, heads);
 808        free(heads);
 809        return rc;
 810}
 811
 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
 821int transport_disconnect(struct transport *transport)
 822{
 823        int ret = 0;
 824        if (transport->disconnect)
 825                ret = transport->disconnect(transport);
 826        free(transport);
 827        return ret;
 828}