ba5cc32584d9e2f9f372cd2e8ecabcf7049ec2b3
   1#include "cache.h"
   2#include "commit.h"
   3#include "pack.h"
   4#include "tag.h"
   5#include "blob.h"
   6#include "http.h"
   7#include "refs.h"
   8#include "diff.h"
   9#include "revision.h"
  10#include "exec_cmd.h"
  11#include "remote.h"
  12#include "list-objects.h"
  13
  14#include <expat.h>
  15
  16static const char http_push_usage[] =
  17"git http-push [--all] [--dry-run] [--force] [--verbose] <remote> [<head>...]\n";
  18
  19#ifndef XML_STATUS_OK
  20enum XML_Status {
  21  XML_STATUS_OK = 1,
  22  XML_STATUS_ERROR = 0
  23};
  24#define XML_STATUS_OK    1
  25#define XML_STATUS_ERROR 0
  26#endif
  27
  28#define PREV_BUF_SIZE 4096
  29#define RANGE_HEADER_SIZE 30
  30
  31/* DAV methods */
  32#define DAV_LOCK "LOCK"
  33#define DAV_MKCOL "MKCOL"
  34#define DAV_MOVE "MOVE"
  35#define DAV_PROPFIND "PROPFIND"
  36#define DAV_PUT "PUT"
  37#define DAV_UNLOCK "UNLOCK"
  38#define DAV_DELETE "DELETE"
  39
  40/* DAV lock flags */
  41#define DAV_PROP_LOCKWR (1u << 0)
  42#define DAV_PROP_LOCKEX (1u << 1)
  43#define DAV_LOCK_OK (1u << 2)
  44
  45/* DAV XML properties */
  46#define DAV_CTX_LOCKENTRY ".multistatus.response.propstat.prop.supportedlock.lockentry"
  47#define DAV_CTX_LOCKTYPE_WRITE ".multistatus.response.propstat.prop.supportedlock.lockentry.locktype.write"
  48#define DAV_CTX_LOCKTYPE_EXCLUSIVE ".multistatus.response.propstat.prop.supportedlock.lockentry.lockscope.exclusive"
  49#define DAV_ACTIVELOCK_OWNER ".prop.lockdiscovery.activelock.owner.href"
  50#define DAV_ACTIVELOCK_TIMEOUT ".prop.lockdiscovery.activelock.timeout"
  51#define DAV_ACTIVELOCK_TOKEN ".prop.lockdiscovery.activelock.locktoken.href"
  52#define DAV_PROPFIND_RESP ".multistatus.response"
  53#define DAV_PROPFIND_NAME ".multistatus.response.href"
  54#define DAV_PROPFIND_COLLECTION ".multistatus.response.propstat.prop.resourcetype.collection"
  55
  56/* DAV request body templates */
  57#define PROPFIND_SUPPORTEDLOCK_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:propfind xmlns:D=\"DAV:\">\n<D:prop xmlns:R=\"%s\">\n<D:supportedlock/>\n</D:prop>\n</D:propfind>"
  58#define PROPFIND_ALL_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:propfind xmlns:D=\"DAV:\">\n<D:allprop/>\n</D:propfind>"
  59#define LOCK_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:lockinfo xmlns:D=\"DAV:\">\n<D:lockscope><D:exclusive/></D:lockscope>\n<D:locktype><D:write/></D:locktype>\n<D:owner>\n<D:href>mailto:%s</D:href>\n</D:owner>\n</D:lockinfo>"
  60
  61#define LOCK_TIME 600
  62#define LOCK_REFRESH 30
  63
  64/* bits #0-15 in revision.h */
  65
  66#define LOCAL    (1u<<16)
  67#define REMOTE   (1u<<17)
  68#define FETCHING (1u<<18)
  69#define PUSHING  (1u<<19)
  70
  71/* We allow "recursive" symbolic refs. Only within reason, though */
  72#define MAXDEPTH 5
  73
  74static int pushing;
  75static int aborted;
  76static signed char remote_dir_exists[256];
  77
  78static struct curl_slist *no_pragma_header;
  79
  80static int push_verbosely;
  81static int push_all = MATCH_REFS_NONE;
  82static int force_all;
  83static int dry_run;
  84
  85static struct object_list *objects;
  86
  87struct repo
  88{
  89        char *url;
  90        char *path;
  91        int path_len;
  92        int has_info_refs;
  93        int can_update_info_refs;
  94        int has_info_packs;
  95        struct packed_git *packs;
  96        struct remote_lock *locks;
  97};
  98
  99static struct repo *remote;
 100
 101enum transfer_state {
 102        NEED_FETCH,
 103        RUN_FETCH_LOOSE,
 104        RUN_FETCH_PACKED,
 105        NEED_PUSH,
 106        RUN_MKCOL,
 107        RUN_PUT,
 108        RUN_MOVE,
 109        ABORTED,
 110        COMPLETE,
 111};
 112
 113struct transfer_request
 114{
 115        struct object *obj;
 116        char *url;
 117        char *dest;
 118        struct remote_lock *lock;
 119        struct curl_slist *headers;
 120        struct buffer buffer;
 121        char filename[PATH_MAX];
 122        char tmpfile[PATH_MAX];
 123        int local_fileno;
 124        FILE *local_stream;
 125        enum transfer_state state;
 126        CURLcode curl_result;
 127        char errorstr[CURL_ERROR_SIZE];
 128        long http_code;
 129        unsigned char real_sha1[20];
 130        git_SHA_CTX c;
 131        z_stream stream;
 132        int zret;
 133        int rename;
 134        void *userData;
 135        struct active_request_slot *slot;
 136        struct transfer_request *next;
 137};
 138
 139static struct transfer_request *request_queue_head;
 140
 141struct xml_ctx
 142{
 143        char *name;
 144        int len;
 145        char *cdata;
 146        void (*userFunc)(struct xml_ctx *ctx, int tag_closed);
 147        void *userData;
 148};
 149
 150struct remote_lock
 151{
 152        char *url;
 153        char *owner;
 154        char *token;
 155        time_t start_time;
 156        long timeout;
 157        int refreshing;
 158        struct remote_lock *next;
 159};
 160
 161/* Flags that control remote_ls processing */
 162#define PROCESS_FILES (1u << 0)
 163#define PROCESS_DIRS  (1u << 1)
 164#define RECURSIVE     (1u << 2)
 165
 166/* Flags that remote_ls passes to callback functions */
 167#define IS_DIR (1u << 0)
 168
 169struct remote_ls_ctx
 170{
 171        char *path;
 172        void (*userFunc)(struct remote_ls_ctx *ls);
 173        void *userData;
 174        int flags;
 175        char *dentry_name;
 176        int dentry_flags;
 177        struct remote_ls_ctx *parent;
 178};
 179
 180/* get_dav_token_headers options */
 181enum dav_header_flag {
 182        DAV_HEADER_IF = (1u << 0),
 183        DAV_HEADER_LOCK = (1u << 1),
 184        DAV_HEADER_TIMEOUT = (1u << 2)
 185};
 186
 187static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum dav_header_flag options)
 188{
 189        struct strbuf buf = STRBUF_INIT;
 190        struct curl_slist *dav_headers = NULL;
 191
 192        if (options & DAV_HEADER_IF) {
 193                strbuf_addf(&buf, "If: (<%s>)", lock->token);
 194                dav_headers = curl_slist_append(dav_headers, buf.buf);
 195                strbuf_reset(&buf);
 196        }
 197        if (options & DAV_HEADER_LOCK) {
 198                strbuf_addf(&buf, "Lock-Token: <%s>", lock->token);
 199                dav_headers = curl_slist_append(dav_headers, buf.buf);
 200                strbuf_reset(&buf);
 201        }
 202        if (options & DAV_HEADER_TIMEOUT) {
 203                strbuf_addf(&buf, "Timeout: Second-%ld", lock->timeout);
 204                dav_headers = curl_slist_append(dav_headers, buf.buf);
 205                strbuf_reset(&buf);
 206        }
 207        strbuf_release(&buf);
 208
 209        return dav_headers;
 210}
 211
 212static void append_remote_object_url(struct strbuf *buf, const char *url,
 213                                     const char *hex,
 214                                     int only_two_digit_prefix)
 215{
 216        strbuf_addf(buf, "%sobjects/%.*s/", url, 2, hex);
 217        if (!only_two_digit_prefix)
 218                strbuf_addf(buf, "%s", hex+2);
 219}
 220
 221static char *get_remote_object_url(const char *url, const char *hex, int only_two_digit_prefix)
 222{
 223        struct strbuf buf = STRBUF_INIT;
 224        append_remote_object_url(&buf, url, hex, only_two_digit_prefix);
 225        return strbuf_detach(&buf, NULL);
 226}
 227
 228static void finish_request(struct transfer_request *request);
 229static void release_request(struct transfer_request *request);
 230
 231static void process_response(void *callback_data)
 232{
 233        struct transfer_request *request =
 234                (struct transfer_request *)callback_data;
 235
 236        finish_request(request);
 237}
 238
 239#ifdef USE_CURL_MULTI
 240static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
 241                               void *data)
 242{
 243        unsigned char expn[4096];
 244        size_t size = eltsize * nmemb;
 245        int posn = 0;
 246        struct transfer_request *request = (struct transfer_request *)data;
 247        do {
 248                ssize_t retval = xwrite(request->local_fileno,
 249                                       (char *) ptr + posn, size - posn);
 250                if (retval < 0)
 251                        return posn;
 252                posn += retval;
 253        } while (posn < size);
 254
 255        request->stream.avail_in = size;
 256        request->stream.next_in = ptr;
 257        do {
 258                request->stream.next_out = expn;
 259                request->stream.avail_out = sizeof(expn);
 260                request->zret = git_inflate(&request->stream, Z_SYNC_FLUSH);
 261                git_SHA1_Update(&request->c, expn,
 262                            sizeof(expn) - request->stream.avail_out);
 263        } while (request->stream.avail_in && request->zret == Z_OK);
 264        data_received++;
 265        return size;
 266}
 267
 268static void start_fetch_loose(struct transfer_request *request)
 269{
 270        char *hex = sha1_to_hex(request->obj->sha1);
 271        char *filename;
 272        char prevfile[PATH_MAX];
 273        char *url;
 274        int prevlocal;
 275        unsigned char prev_buf[PREV_BUF_SIZE];
 276        ssize_t prev_read = 0;
 277        long prev_posn = 0;
 278        char range[RANGE_HEADER_SIZE];
 279        struct curl_slist *range_header = NULL;
 280        struct active_request_slot *slot;
 281
 282        filename = sha1_file_name(request->obj->sha1);
 283        snprintf(request->filename, sizeof(request->filename), "%s", filename);
 284        snprintf(request->tmpfile, sizeof(request->tmpfile),
 285                 "%s.temp", filename);
 286
 287        snprintf(prevfile, sizeof(prevfile), "%s.prev", request->filename);
 288        unlink(prevfile);
 289        rename(request->tmpfile, prevfile);
 290        unlink(request->tmpfile);
 291
 292        if (request->local_fileno != -1)
 293                error("fd leakage in start: %d", request->local_fileno);
 294        request->local_fileno = open(request->tmpfile,
 295                                     O_WRONLY | O_CREAT | O_EXCL, 0666);
 296        /* This could have failed due to the "lazy directory creation";
 297         * try to mkdir the last path component.
 298         */
 299        if (request->local_fileno < 0 && errno == ENOENT) {
 300                char *dir = strrchr(request->tmpfile, '/');
 301                if (dir) {
 302                        *dir = 0;
 303                        mkdir(request->tmpfile, 0777);
 304                        *dir = '/';
 305                }
 306                request->local_fileno = open(request->tmpfile,
 307                                             O_WRONLY | O_CREAT | O_EXCL, 0666);
 308        }
 309
 310        if (request->local_fileno < 0) {
 311                request->state = ABORTED;
 312                error("Couldn't create temporary file %s for %s: %s",
 313                      request->tmpfile, request->filename, strerror(errno));
 314                return;
 315        }
 316
 317        memset(&request->stream, 0, sizeof(request->stream));
 318
 319        git_inflate_init(&request->stream);
 320
 321        git_SHA1_Init(&request->c);
 322
 323        url = get_remote_object_url(remote->url, hex, 0);
 324        request->url = xstrdup(url);
 325
 326        /* If a previous temp file is present, process what was already
 327           fetched. */
 328        prevlocal = open(prevfile, O_RDONLY);
 329        if (prevlocal != -1) {
 330                do {
 331                        prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
 332                        if (prev_read>0) {
 333                                if (fwrite_sha1_file(prev_buf,
 334                                                     1,
 335                                                     prev_read,
 336                                                     request) == prev_read) {
 337                                        prev_posn += prev_read;
 338                                } else {
 339                                        prev_read = -1;
 340                                }
 341                        }
 342                } while (prev_read > 0);
 343                close(prevlocal);
 344        }
 345        unlink(prevfile);
 346
 347        /* Reset inflate/SHA1 if there was an error reading the previous temp
 348           file; also rewind to the beginning of the local file. */
 349        if (prev_read == -1) {
 350                memset(&request->stream, 0, sizeof(request->stream));
 351                git_inflate_init(&request->stream);
 352                git_SHA1_Init(&request->c);
 353                if (prev_posn>0) {
 354                        prev_posn = 0;
 355                        lseek(request->local_fileno, 0, SEEK_SET);
 356                        ftruncate(request->local_fileno, 0);
 357                }
 358        }
 359
 360        slot = get_active_slot();
 361        slot->callback_func = process_response;
 362        slot->callback_data = request;
 363        request->slot = slot;
 364
 365        curl_easy_setopt(slot->curl, CURLOPT_FILE, request);
 366        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
 367        curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
 368        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
 369        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
 370
 371        /* If we have successfully processed data from a previous fetch
 372           attempt, only fetch the data we don't already have. */
 373        if (prev_posn>0) {
 374                if (push_verbosely)
 375                        fprintf(stderr,
 376                                "Resuming fetch of object %s at byte %ld\n",
 377                                hex, prev_posn);
 378                sprintf(range, "Range: bytes=%ld-", prev_posn);
 379                range_header = curl_slist_append(range_header, range);
 380                curl_easy_setopt(slot->curl,
 381                                 CURLOPT_HTTPHEADER, range_header);
 382        }
 383
 384        /* Try to get the request started, abort the request on error */
 385        request->state = RUN_FETCH_LOOSE;
 386        if (!start_active_slot(slot)) {
 387                fprintf(stderr, "Unable to start GET request\n");
 388                remote->can_update_info_refs = 0;
 389                release_request(request);
 390        }
 391}
 392
 393static void start_mkcol(struct transfer_request *request)
 394{
 395        char *hex = sha1_to_hex(request->obj->sha1);
 396        struct active_request_slot *slot;
 397
 398        request->url = get_remote_object_url(remote->url, hex, 1);
 399
 400        slot = get_active_slot();
 401        slot->callback_func = process_response;
 402        slot->callback_data = request;
 403        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); /* undo PUT setup */
 404        curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
 405        curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
 406        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MKCOL);
 407        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
 408
 409        if (start_active_slot(slot)) {
 410                request->slot = slot;
 411                request->state = RUN_MKCOL;
 412        } else {
 413                request->state = ABORTED;
 414                free(request->url);
 415                request->url = NULL;
 416        }
 417}
 418#endif
 419
 420static void start_fetch_packed(struct transfer_request *request)
 421{
 422        char *url;
 423        struct packed_git *target;
 424        FILE *packfile;
 425        char *filename;
 426        long prev_posn = 0;
 427        char range[RANGE_HEADER_SIZE];
 428        struct curl_slist *range_header = NULL;
 429
 430        struct transfer_request *check_request = request_queue_head;
 431        struct active_request_slot *slot;
 432
 433        target = find_sha1_pack(request->obj->sha1, remote->packs);
 434        if (!target) {
 435                fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", sha1_to_hex(request->obj->sha1));
 436                remote->can_update_info_refs = 0;
 437                release_request(request);
 438                return;
 439        }
 440
 441        fprintf(stderr, "Fetching pack %s\n", sha1_to_hex(target->sha1));
 442        fprintf(stderr, " which contains %s\n", sha1_to_hex(request->obj->sha1));
 443
 444        filename = sha1_pack_name(target->sha1);
 445        snprintf(request->filename, sizeof(request->filename), "%s", filename);
 446        snprintf(request->tmpfile, sizeof(request->tmpfile),
 447                 "%s.temp", filename);
 448
 449        url = xmalloc(strlen(remote->url) + 64);
 450        sprintf(url, "%sobjects/pack/pack-%s.pack",
 451                remote->url, sha1_to_hex(target->sha1));
 452
 453        /* Make sure there isn't another open request for this pack */
 454        while (check_request) {
 455                if (check_request->state == RUN_FETCH_PACKED &&
 456                    !strcmp(check_request->url, url)) {
 457                        free(url);
 458                        release_request(request);
 459                        return;
 460                }
 461                check_request = check_request->next;
 462        }
 463
 464        packfile = fopen(request->tmpfile, "a");
 465        if (!packfile) {
 466                fprintf(stderr, "Unable to open local file %s for pack",
 467                        request->tmpfile);
 468                remote->can_update_info_refs = 0;
 469                free(url);
 470                return;
 471        }
 472
 473        slot = get_active_slot();
 474        slot->callback_func = process_response;
 475        slot->callback_data = request;
 476        request->slot = slot;
 477        request->local_stream = packfile;
 478        request->userData = target;
 479
 480        request->url = url;
 481        curl_easy_setopt(slot->curl, CURLOPT_FILE, packfile);
 482        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
 483        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
 484        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
 485        slot->local = packfile;
 486
 487        /* If there is data present from a previous transfer attempt,
 488           resume where it left off */
 489        prev_posn = ftell(packfile);
 490        if (prev_posn>0) {
 491                if (push_verbosely)
 492                        fprintf(stderr,
 493                                "Resuming fetch of pack %s at byte %ld\n",
 494                                sha1_to_hex(target->sha1), prev_posn);
 495                sprintf(range, "Range: bytes=%ld-", prev_posn);
 496                range_header = curl_slist_append(range_header, range);
 497                curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);
 498        }
 499
 500        /* Try to get the request started, abort the request on error */
 501        request->state = RUN_FETCH_PACKED;
 502        if (!start_active_slot(slot)) {
 503                fprintf(stderr, "Unable to start GET request\n");
 504                remote->can_update_info_refs = 0;
 505                release_request(request);
 506        }
 507}
 508
 509static void start_put(struct transfer_request *request)
 510{
 511        char *hex = sha1_to_hex(request->obj->sha1);
 512        struct active_request_slot *slot;
 513        struct strbuf buf = STRBUF_INIT;
 514        enum object_type type;
 515        char hdr[50];
 516        void *unpacked;
 517        unsigned long len;
 518        int hdrlen;
 519        ssize_t size;
 520        z_stream stream;
 521
 522        unpacked = read_sha1_file(request->obj->sha1, &type, &len);
 523        hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
 524
 525        /* Set it up */
 526        memset(&stream, 0, sizeof(stream));
 527        deflateInit(&stream, zlib_compression_level);
 528        size = deflateBound(&stream, len + hdrlen);
 529        strbuf_init(&request->buffer.buf, size);
 530        request->buffer.posn = 0;
 531
 532        /* Compress it */
 533        stream.next_out = (unsigned char *)request->buffer.buf.buf;
 534        stream.avail_out = size;
 535
 536        /* First header.. */
 537        stream.next_in = (void *)hdr;
 538        stream.avail_in = hdrlen;
 539        while (deflate(&stream, 0) == Z_OK)
 540                /* nothing */;
 541
 542        /* Then the data itself.. */
 543        stream.next_in = unpacked;
 544        stream.avail_in = len;
 545        while (deflate(&stream, Z_FINISH) == Z_OK)
 546                /* nothing */;
 547        deflateEnd(&stream);
 548        free(unpacked);
 549
 550        request->buffer.buf.len = stream.total_out;
 551
 552        strbuf_addstr(&buf, "Destination: ");
 553        append_remote_object_url(&buf, remote->url, hex, 0);
 554        request->dest = strbuf_detach(&buf, NULL);
 555
 556        append_remote_object_url(&buf, remote->url, hex, 0);
 557        strbuf_addstr(&buf, request->lock->token);
 558        request->url = strbuf_detach(&buf, NULL);
 559
 560        slot = get_active_slot();
 561        slot->callback_func = process_response;
 562        slot->callback_data = request;
 563        curl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);
 564        curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.buf.len);
 565        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
 566        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
 567        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
 568        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
 569        curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
 570        curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
 571        curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
 572
 573        if (start_active_slot(slot)) {
 574                request->slot = slot;
 575                request->state = RUN_PUT;
 576        } else {
 577                request->state = ABORTED;
 578                free(request->url);
 579                request->url = NULL;
 580        }
 581}
 582
 583static void start_move(struct transfer_request *request)
 584{
 585        struct active_request_slot *slot;
 586        struct curl_slist *dav_headers = NULL;
 587
 588        slot = get_active_slot();
 589        slot->callback_func = process_response;
 590        slot->callback_data = request;
 591        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); /* undo PUT setup */
 592        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MOVE);
 593        dav_headers = curl_slist_append(dav_headers, request->dest);
 594        dav_headers = curl_slist_append(dav_headers, "Overwrite: T");
 595        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
 596        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
 597        curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
 598
 599        if (start_active_slot(slot)) {
 600                request->slot = slot;
 601                request->state = RUN_MOVE;
 602        } else {
 603                request->state = ABORTED;
 604                free(request->url);
 605                request->url = NULL;
 606        }
 607}
 608
 609static int refresh_lock(struct remote_lock *lock)
 610{
 611        struct active_request_slot *slot;
 612        struct slot_results results;
 613        struct curl_slist *dav_headers;
 614        int rc = 0;
 615
 616        lock->refreshing = 1;
 617
 618        dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF | DAV_HEADER_TIMEOUT);
 619
 620        slot = get_active_slot();
 621        slot->results = &results;
 622        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
 623        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
 624        curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
 625        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);
 626        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
 627
 628        if (start_active_slot(slot)) {
 629                run_active_slot(slot);
 630                if (results.curl_result != CURLE_OK) {
 631                        fprintf(stderr, "LOCK HTTP error %ld\n",
 632                                results.http_code);
 633                } else {
 634                        lock->start_time = time(NULL);
 635                        rc = 1;
 636                }
 637        }
 638
 639        lock->refreshing = 0;
 640        curl_slist_free_all(dav_headers);
 641
 642        return rc;
 643}
 644
 645static void check_locks(void)
 646{
 647        struct remote_lock *lock = remote->locks;
 648        time_t current_time = time(NULL);
 649        int time_remaining;
 650
 651        while (lock) {
 652                time_remaining = lock->start_time + lock->timeout -
 653                        current_time;
 654                if (!lock->refreshing && time_remaining < LOCK_REFRESH) {
 655                        if (!refresh_lock(lock)) {
 656                                fprintf(stderr,
 657                                        "Unable to refresh lock for %s\n",
 658                                        lock->url);
 659                                aborted = 1;
 660                                return;
 661                        }
 662                }
 663                lock = lock->next;
 664        }
 665}
 666
 667static void release_request(struct transfer_request *request)
 668{
 669        struct transfer_request *entry = request_queue_head;
 670
 671        if (request == request_queue_head) {
 672                request_queue_head = request->next;
 673        } else {
 674                while (entry->next != NULL && entry->next != request)
 675                        entry = entry->next;
 676                if (entry->next == request)
 677                        entry->next = entry->next->next;
 678        }
 679
 680        if (request->local_fileno != -1)
 681                close(request->local_fileno);
 682        if (request->local_stream)
 683                fclose(request->local_stream);
 684        free(request->url);
 685        free(request);
 686}
 687
 688static void finish_request(struct transfer_request *request)
 689{
 690        struct stat st;
 691        struct packed_git *target;
 692        struct packed_git **lst;
 693
 694        request->curl_result = request->slot->curl_result;
 695        request->http_code = request->slot->http_code;
 696        request->slot = NULL;
 697
 698        /* Keep locks active */
 699        check_locks();
 700
 701        if (request->headers != NULL)
 702                curl_slist_free_all(request->headers);
 703
 704        /* URL is reused for MOVE after PUT */
 705        if (request->state != RUN_PUT) {
 706                free(request->url);
 707                request->url = NULL;
 708        }
 709
 710        if (request->state == RUN_MKCOL) {
 711                if (request->curl_result == CURLE_OK ||
 712                    request->http_code == 405) {
 713                        remote_dir_exists[request->obj->sha1[0]] = 1;
 714                        start_put(request);
 715                } else {
 716                        fprintf(stderr, "MKCOL %s failed, aborting (%d/%ld)\n",
 717                                sha1_to_hex(request->obj->sha1),
 718                                request->curl_result, request->http_code);
 719                        request->state = ABORTED;
 720                        aborted = 1;
 721                }
 722        } else if (request->state == RUN_PUT) {
 723                if (request->curl_result == CURLE_OK) {
 724                        start_move(request);
 725                } else {
 726                        fprintf(stderr, "PUT %s failed, aborting (%d/%ld)\n",
 727                                sha1_to_hex(request->obj->sha1),
 728                                request->curl_result, request->http_code);
 729                        request->state = ABORTED;
 730                        aborted = 1;
 731                }
 732        } else if (request->state == RUN_MOVE) {
 733                if (request->curl_result == CURLE_OK) {
 734                        if (push_verbosely)
 735                                fprintf(stderr, "    sent %s\n",
 736                                        sha1_to_hex(request->obj->sha1));
 737                        request->obj->flags |= REMOTE;
 738                        release_request(request);
 739                } else {
 740                        fprintf(stderr, "MOVE %s failed, aborting (%d/%ld)\n",
 741                                sha1_to_hex(request->obj->sha1),
 742                                request->curl_result, request->http_code);
 743                        request->state = ABORTED;
 744                        aborted = 1;
 745                }
 746        } else if (request->state == RUN_FETCH_LOOSE) {
 747                fchmod(request->local_fileno, 0444);
 748                close(request->local_fileno); request->local_fileno = -1;
 749
 750                if (request->curl_result != CURLE_OK &&
 751                    request->http_code != 416) {
 752                        if (stat(request->tmpfile, &st) == 0) {
 753                                if (st.st_size == 0)
 754                                        unlink(request->tmpfile);
 755                        }
 756                } else {
 757                        if (request->http_code == 416)
 758                                fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
 759
 760                        git_inflate_end(&request->stream);
 761                        git_SHA1_Final(request->real_sha1, &request->c);
 762                        if (request->zret != Z_STREAM_END) {
 763                                unlink(request->tmpfile);
 764                        } else if (hashcmp(request->obj->sha1, request->real_sha1)) {
 765                                unlink(request->tmpfile);
 766                        } else {
 767                                request->rename =
 768                                        move_temp_to_file(
 769                                                request->tmpfile,
 770                                                request->filename);
 771                                if (request->rename == 0) {
 772                                        request->obj->flags |= (LOCAL | REMOTE);
 773                                }
 774                        }
 775                }
 776
 777                /* Try fetching packed if necessary */
 778                if (request->obj->flags & LOCAL)
 779                        release_request(request);
 780                else
 781                        start_fetch_packed(request);
 782
 783        } else if (request->state == RUN_FETCH_PACKED) {
 784                if (request->curl_result != CURLE_OK) {
 785                        fprintf(stderr, "Unable to get pack file %s\n%s",
 786                                request->url, curl_errorstr);
 787                        remote->can_update_info_refs = 0;
 788                } else {
 789                        off_t pack_size = ftell(request->local_stream);
 790
 791                        fclose(request->local_stream);
 792                        request->local_stream = NULL;
 793                        if (!move_temp_to_file(request->tmpfile,
 794                                               request->filename)) {
 795                                target = (struct packed_git *)request->userData;
 796                                target->pack_size = pack_size;
 797                                lst = &remote->packs;
 798                                while (*lst != target)
 799                                        lst = &((*lst)->next);
 800                                *lst = (*lst)->next;
 801
 802                                if (!verify_pack(target))
 803                                        install_packed_git(target);
 804                                else
 805                                        remote->can_update_info_refs = 0;
 806                        }
 807                }
 808                release_request(request);
 809        }
 810}
 811
 812#ifdef USE_CURL_MULTI
 813static int fill_active_slot(void *unused)
 814{
 815        struct transfer_request *request = request_queue_head;
 816
 817        if (aborted)
 818                return 0;
 819
 820        for (request = request_queue_head; request; request = request->next) {
 821                if (request->state == NEED_FETCH) {
 822                        start_fetch_loose(request);
 823                        return 1;
 824                } else if (pushing && request->state == NEED_PUSH) {
 825                        if (remote_dir_exists[request->obj->sha1[0]] == 1) {
 826                                start_put(request);
 827                        } else {
 828                                start_mkcol(request);
 829                        }
 830                        return 1;
 831                }
 832        }
 833        return 0;
 834}
 835#endif
 836
 837static void get_remote_object_list(unsigned char parent);
 838
 839static void add_fetch_request(struct object *obj)
 840{
 841        struct transfer_request *request;
 842
 843        check_locks();
 844
 845        /*
 846         * Don't fetch the object if it's known to exist locally
 847         * or is already in the request queue
 848         */
 849        if (remote_dir_exists[obj->sha1[0]] == -1)
 850                get_remote_object_list(obj->sha1[0]);
 851        if (obj->flags & (LOCAL | FETCHING))
 852                return;
 853
 854        obj->flags |= FETCHING;
 855        request = xmalloc(sizeof(*request));
 856        request->obj = obj;
 857        request->url = NULL;
 858        request->lock = NULL;
 859        request->headers = NULL;
 860        request->local_fileno = -1;
 861        request->local_stream = NULL;
 862        request->state = NEED_FETCH;
 863        request->next = request_queue_head;
 864        request_queue_head = request;
 865
 866#ifdef USE_CURL_MULTI
 867        fill_active_slots();
 868        step_active_slots();
 869#endif
 870}
 871
 872static int add_send_request(struct object *obj, struct remote_lock *lock)
 873{
 874        struct transfer_request *request = request_queue_head;
 875        struct packed_git *target;
 876
 877        /* Keep locks active */
 878        check_locks();
 879
 880        /*
 881         * Don't push the object if it's known to exist on the remote
 882         * or is already in the request queue
 883         */
 884        if (remote_dir_exists[obj->sha1[0]] == -1)
 885                get_remote_object_list(obj->sha1[0]);
 886        if (obj->flags & (REMOTE | PUSHING))
 887                return 0;
 888        target = find_sha1_pack(obj->sha1, remote->packs);
 889        if (target) {
 890                obj->flags |= REMOTE;
 891                return 0;
 892        }
 893
 894        obj->flags |= PUSHING;
 895        request = xmalloc(sizeof(*request));
 896        request->obj = obj;
 897        request->url = NULL;
 898        request->lock = lock;
 899        request->headers = NULL;
 900        request->local_fileno = -1;
 901        request->local_stream = NULL;
 902        request->state = NEED_PUSH;
 903        request->next = request_queue_head;
 904        request_queue_head = request;
 905
 906#ifdef USE_CURL_MULTI
 907        fill_active_slots();
 908        step_active_slots();
 909#endif
 910
 911        return 1;
 912}
 913
 914static int fetch_index(unsigned char *sha1)
 915{
 916        char *hex = sha1_to_hex(sha1);
 917        char *filename;
 918        char *url;
 919        char tmpfile[PATH_MAX];
 920        long prev_posn = 0;
 921        char range[RANGE_HEADER_SIZE];
 922        struct curl_slist *range_header = NULL;
 923
 924        FILE *indexfile;
 925        struct active_request_slot *slot;
 926        struct slot_results results;
 927
 928        /* Don't use the index if the pack isn't there */
 929        url = xmalloc(strlen(remote->url) + 64);
 930        sprintf(url, "%sobjects/pack/pack-%s.pack", remote->url, hex);
 931        slot = get_active_slot();
 932        slot->results = &results;
 933        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
 934        curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
 935        if (start_active_slot(slot)) {
 936                run_active_slot(slot);
 937                if (results.curl_result != CURLE_OK) {
 938                        free(url);
 939                        return error("Unable to verify pack %s is available",
 940                                     hex);
 941                }
 942        } else {
 943                free(url);
 944                return error("Unable to start request");
 945        }
 946
 947        if (has_pack_index(sha1)) {
 948                free(url);
 949                return 0;
 950        }
 951
 952        if (push_verbosely)
 953                fprintf(stderr, "Getting index for pack %s\n", hex);
 954
 955        sprintf(url, "%sobjects/pack/pack-%s.idx", remote->url, hex);
 956
 957        filename = sha1_pack_index_name(sha1);
 958        snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
 959        indexfile = fopen(tmpfile, "a");
 960        if (!indexfile) {
 961                free(url);
 962                return error("Unable to open local file %s for pack index",
 963                             tmpfile);
 964        }
 965
 966        slot = get_active_slot();
 967        slot->results = &results;
 968        curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
 969        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
 970        curl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);
 971        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
 972        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
 973        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
 974        slot->local = indexfile;
 975
 976        /* If there is data present from a previous transfer attempt,
 977           resume where it left off */
 978        prev_posn = ftell(indexfile);
 979        if (prev_posn>0) {
 980                if (push_verbosely)
 981                        fprintf(stderr,
 982                                "Resuming fetch of index for pack %s at byte %ld\n",
 983                                hex, prev_posn);
 984                sprintf(range, "Range: bytes=%ld-", prev_posn);
 985                range_header = curl_slist_append(range_header, range);
 986                curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);
 987        }
 988
 989        if (start_active_slot(slot)) {
 990                run_active_slot(slot);
 991                if (results.curl_result != CURLE_OK) {
 992                        free(url);
 993                        fclose(indexfile);
 994                        return error("Unable to get pack index %s\n%s", url,
 995                                     curl_errorstr);
 996                }
 997        } else {
 998                free(url);
 999                fclose(indexfile);
1000                return error("Unable to start request");
1001        }
1002
1003        free(url);
1004        fclose(indexfile);
1005
1006        return move_temp_to_file(tmpfile, filename);
1007}
1008
1009static int setup_index(unsigned char *sha1)
1010{
1011        struct packed_git *new_pack;
1012
1013        if (fetch_index(sha1))
1014                return -1;
1015
1016        new_pack = parse_pack_index(sha1);
1017        new_pack->next = remote->packs;
1018        remote->packs = new_pack;
1019        return 0;
1020}
1021
1022static int fetch_indices(void)
1023{
1024        unsigned char sha1[20];
1025        char *url;
1026        struct strbuf buffer = STRBUF_INIT;
1027        char *data;
1028        int i = 0;
1029
1030        struct active_request_slot *slot;
1031        struct slot_results results;
1032
1033        if (push_verbosely)
1034                fprintf(stderr, "Getting pack list\n");
1035
1036        url = xmalloc(strlen(remote->url) + 20);
1037        sprintf(url, "%sobjects/info/packs", remote->url);
1038
1039        slot = get_active_slot();
1040        slot->results = &results;
1041        curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
1042        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
1043        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
1044        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
1045        if (start_active_slot(slot)) {
1046                run_active_slot(slot);
1047                if (results.curl_result != CURLE_OK) {
1048                        strbuf_release(&buffer);
1049                        free(url);
1050                        if (results.http_code == 404)
1051                                return 0;
1052                        else
1053                                return error("%s", curl_errorstr);
1054                }
1055        } else {
1056                strbuf_release(&buffer);
1057                free(url);
1058                return error("Unable to start request");
1059        }
1060        free(url);
1061
1062        data = buffer.buf;
1063        while (i < buffer.len) {
1064                switch (data[i]) {
1065                case 'P':
1066                        i++;
1067                        if (i + 52 < buffer.len &&
1068                            !prefixcmp(data + i, " pack-") &&
1069                            !prefixcmp(data + i + 46, ".pack\n")) {
1070                                get_sha1_hex(data + i + 6, sha1);
1071                                setup_index(sha1);
1072                                i += 51;
1073                                break;
1074                        }
1075                default:
1076                        while (data[i] != '\n')
1077                                i++;
1078                }
1079                i++;
1080        }
1081
1082        strbuf_release(&buffer);
1083        return 0;
1084}
1085
1086static void one_remote_object(const char *hex)
1087{
1088        unsigned char sha1[20];
1089        struct object *obj;
1090
1091        if (get_sha1_hex(hex, sha1) != 0)
1092                return;
1093
1094        obj = lookup_object(sha1);
1095        if (!obj)
1096                obj = parse_object(sha1);
1097
1098        /* Ignore remote objects that don't exist locally */
1099        if (!obj)
1100                return;
1101
1102        obj->flags |= REMOTE;
1103        if (!object_list_contains(objects, obj))
1104                object_list_insert(obj, &objects);
1105}
1106
1107static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed)
1108{
1109        int *lock_flags = (int *)ctx->userData;
1110
1111        if (tag_closed) {
1112                if (!strcmp(ctx->name, DAV_CTX_LOCKENTRY)) {
1113                        if ((*lock_flags & DAV_PROP_LOCKEX) &&
1114                            (*lock_flags & DAV_PROP_LOCKWR)) {
1115                                *lock_flags |= DAV_LOCK_OK;
1116                        }
1117                        *lock_flags &= DAV_LOCK_OK;
1118                } else if (!strcmp(ctx->name, DAV_CTX_LOCKTYPE_WRITE)) {
1119                        *lock_flags |= DAV_PROP_LOCKWR;
1120                } else if (!strcmp(ctx->name, DAV_CTX_LOCKTYPE_EXCLUSIVE)) {
1121                        *lock_flags |= DAV_PROP_LOCKEX;
1122                }
1123        }
1124}
1125
1126static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
1127{
1128        struct remote_lock *lock = (struct remote_lock *)ctx->userData;
1129
1130        if (tag_closed && ctx->cdata) {
1131                if (!strcmp(ctx->name, DAV_ACTIVELOCK_OWNER)) {
1132                        lock->owner = xmalloc(strlen(ctx->cdata) + 1);
1133                        strcpy(lock->owner, ctx->cdata);
1134                } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) {
1135                        if (!prefixcmp(ctx->cdata, "Second-"))
1136                                lock->timeout =
1137                                        strtol(ctx->cdata + 7, NULL, 10);
1138                } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
1139                        lock->token = xmalloc(strlen(ctx->cdata) + 1);
1140                        strcpy(lock->token, ctx->cdata);
1141                }
1142        }
1143}
1144
1145static void one_remote_ref(char *refname);
1146
1147static void
1148xml_start_tag(void *userData, const char *name, const char **atts)
1149{
1150        struct xml_ctx *ctx = (struct xml_ctx *)userData;
1151        const char *c = strchr(name, ':');
1152        int new_len;
1153
1154        if (c == NULL)
1155                c = name;
1156        else
1157                c++;
1158
1159        new_len = strlen(ctx->name) + strlen(c) + 2;
1160
1161        if (new_len > ctx->len) {
1162                ctx->name = xrealloc(ctx->name, new_len);
1163                ctx->len = new_len;
1164        }
1165        strcat(ctx->name, ".");
1166        strcat(ctx->name, c);
1167
1168        free(ctx->cdata);
1169        ctx->cdata = NULL;
1170
1171        ctx->userFunc(ctx, 0);
1172}
1173
1174static void
1175xml_end_tag(void *userData, const char *name)
1176{
1177        struct xml_ctx *ctx = (struct xml_ctx *)userData;
1178        const char *c = strchr(name, ':');
1179        char *ep;
1180
1181        ctx->userFunc(ctx, 1);
1182
1183        if (c == NULL)
1184                c = name;
1185        else
1186                c++;
1187
1188        ep = ctx->name + strlen(ctx->name) - strlen(c) - 1;
1189        *ep = 0;
1190}
1191
1192static void
1193xml_cdata(void *userData, const XML_Char *s, int len)
1194{
1195        struct xml_ctx *ctx = (struct xml_ctx *)userData;
1196        free(ctx->cdata);
1197        ctx->cdata = xmemdupz(s, len);
1198}
1199
1200static struct remote_lock *lock_remote(const char *path, long timeout)
1201{
1202        struct active_request_slot *slot;
1203        struct slot_results results;
1204        struct buffer out_buffer = { STRBUF_INIT, 0 };
1205        struct strbuf in_buffer = STRBUF_INIT;
1206        char *url;
1207        char *ep;
1208        char timeout_header[25];
1209        struct remote_lock *lock = NULL;
1210        struct curl_slist *dav_headers = NULL;
1211        struct xml_ctx ctx;
1212
1213        url = xmalloc(strlen(remote->url) + strlen(path) + 1);
1214        sprintf(url, "%s%s", remote->url, path);
1215
1216        /* Make sure leading directories exist for the remote ref */
1217        ep = strchr(url + strlen(remote->url) + 1, '/');
1218        while (ep) {
1219                char saved_character = ep[1];
1220                ep[1] = '\0';
1221                slot = get_active_slot();
1222                slot->results = &results;
1223                curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
1224                curl_easy_setopt(slot->curl, CURLOPT_URL, url);
1225                curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MKCOL);
1226                curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
1227                if (start_active_slot(slot)) {
1228                        run_active_slot(slot);
1229                        if (results.curl_result != CURLE_OK &&
1230                            results.http_code != 405) {
1231                                fprintf(stderr,
1232                                        "Unable to create branch path %s\n",
1233                                        url);
1234                                free(url);
1235                                return NULL;
1236                        }
1237                } else {
1238                        fprintf(stderr, "Unable to start MKCOL request\n");
1239                        free(url);
1240                        return NULL;
1241                }
1242                ep[1] = saved_character;
1243                ep = strchr(ep + 1, '/');
1244        }
1245
1246        strbuf_addf(&out_buffer.buf, LOCK_REQUEST, git_default_email);
1247
1248        sprintf(timeout_header, "Timeout: Second-%ld", timeout);
1249        dav_headers = curl_slist_append(dav_headers, timeout_header);
1250        dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
1251
1252        slot = get_active_slot();
1253        slot->results = &results;
1254        curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
1255        curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
1256        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1257        curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
1258        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
1259        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
1260        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
1261        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);
1262        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1263
1264        lock = xcalloc(1, sizeof(*lock));
1265        lock->timeout = -1;
1266
1267        if (start_active_slot(slot)) {
1268                run_active_slot(slot);
1269                if (results.curl_result == CURLE_OK) {
1270                        XML_Parser parser = XML_ParserCreate(NULL);
1271                        enum XML_Status result;
1272                        ctx.name = xcalloc(10, 1);
1273                        ctx.len = 0;
1274                        ctx.cdata = NULL;
1275                        ctx.userFunc = handle_new_lock_ctx;
1276                        ctx.userData = lock;
1277                        XML_SetUserData(parser, &ctx);
1278                        XML_SetElementHandler(parser, xml_start_tag,
1279                                              xml_end_tag);
1280                        XML_SetCharacterDataHandler(parser, xml_cdata);
1281                        result = XML_Parse(parser, in_buffer.buf,
1282                                           in_buffer.len, 1);
1283                        free(ctx.name);
1284                        if (result != XML_STATUS_OK) {
1285                                fprintf(stderr, "XML error: %s\n",
1286                                        XML_ErrorString(
1287                                                XML_GetErrorCode(parser)));
1288                                lock->timeout = -1;
1289                        }
1290                        XML_ParserFree(parser);
1291                }
1292        } else {
1293                fprintf(stderr, "Unable to start LOCK request\n");
1294        }
1295
1296        curl_slist_free_all(dav_headers);
1297        strbuf_release(&out_buffer.buf);
1298        strbuf_release(&in_buffer);
1299
1300        if (lock->token == NULL || lock->timeout <= 0) {
1301                free(lock->token);
1302                free(lock->owner);
1303                free(url);
1304                free(lock);
1305                lock = NULL;
1306        } else {
1307                lock->url = url;
1308                lock->start_time = time(NULL);
1309                lock->next = remote->locks;
1310                remote->locks = lock;
1311        }
1312
1313        return lock;
1314}
1315
1316static int unlock_remote(struct remote_lock *lock)
1317{
1318        struct active_request_slot *slot;
1319        struct slot_results results;
1320        struct remote_lock *prev = remote->locks;
1321        struct curl_slist *dav_headers;
1322        int rc = 0;
1323
1324        dav_headers = get_dav_token_headers(lock, DAV_HEADER_LOCK);
1325
1326        slot = get_active_slot();
1327        slot->results = &results;
1328        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
1329        curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
1330        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_UNLOCK);
1331        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1332
1333        if (start_active_slot(slot)) {
1334                run_active_slot(slot);
1335                if (results.curl_result == CURLE_OK)
1336                        rc = 1;
1337                else
1338                        fprintf(stderr, "UNLOCK HTTP error %ld\n",
1339                                results.http_code);
1340        } else {
1341                fprintf(stderr, "Unable to start UNLOCK request\n");
1342        }
1343
1344        curl_slist_free_all(dav_headers);
1345
1346        if (remote->locks == lock) {
1347                remote->locks = lock->next;
1348        } else {
1349                while (prev && prev->next != lock)
1350                        prev = prev->next;
1351                if (prev)
1352                        prev->next = prev->next->next;
1353        }
1354
1355        free(lock->owner);
1356        free(lock->url);
1357        free(lock->token);
1358        free(lock);
1359
1360        return rc;
1361}
1362
1363static void remove_locks(void)
1364{
1365        struct remote_lock *lock = remote->locks;
1366
1367        fprintf(stderr, "Removing remote locks...\n");
1368        while (lock) {
1369                unlock_remote(lock);
1370                lock = lock->next;
1371        }
1372}
1373
1374static void remove_locks_on_signal(int signo)
1375{
1376        remove_locks();
1377        signal(signo, SIG_DFL);
1378        raise(signo);
1379}
1380
1381static void remote_ls(const char *path, int flags,
1382                      void (*userFunc)(struct remote_ls_ctx *ls),
1383                      void *userData);
1384
1385static void process_ls_object(struct remote_ls_ctx *ls)
1386{
1387        unsigned int *parent = (unsigned int *)ls->userData;
1388        char *path = ls->dentry_name;
1389        char *obj_hex;
1390
1391        if (!strcmp(ls->path, ls->dentry_name) && (ls->flags & IS_DIR)) {
1392                remote_dir_exists[*parent] = 1;
1393                return;
1394        }
1395
1396        if (strlen(path) != 49)
1397                return;
1398        path += 8;
1399        obj_hex = xmalloc(strlen(path));
1400        /* NB: path is not null-terminated, can not use strlcpy here */
1401        memcpy(obj_hex, path, 2);
1402        strcpy(obj_hex + 2, path + 3);
1403        one_remote_object(obj_hex);
1404        free(obj_hex);
1405}
1406
1407static void process_ls_ref(struct remote_ls_ctx *ls)
1408{
1409        if (!strcmp(ls->path, ls->dentry_name) && (ls->dentry_flags & IS_DIR)) {
1410                fprintf(stderr, "  %s\n", ls->dentry_name);
1411                return;
1412        }
1413
1414        if (!(ls->dentry_flags & IS_DIR))
1415                one_remote_ref(ls->dentry_name);
1416}
1417
1418static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
1419{
1420        struct remote_ls_ctx *ls = (struct remote_ls_ctx *)ctx->userData;
1421
1422        if (tag_closed) {
1423                if (!strcmp(ctx->name, DAV_PROPFIND_RESP) && ls->dentry_name) {
1424                        if (ls->dentry_flags & IS_DIR) {
1425                                if (ls->flags & PROCESS_DIRS) {
1426                                        ls->userFunc(ls);
1427                                }
1428                                if (strcmp(ls->dentry_name, ls->path) &&
1429                                    ls->flags & RECURSIVE) {
1430                                        remote_ls(ls->dentry_name,
1431                                                  ls->flags,
1432                                                  ls->userFunc,
1433                                                  ls->userData);
1434                                }
1435                        } else if (ls->flags & PROCESS_FILES) {
1436                                ls->userFunc(ls);
1437                        }
1438                } else if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {
1439                        char *path = ctx->cdata;
1440                        if (*ctx->cdata == 'h') {
1441                                path = strstr(path, "//");
1442                                if (path) {
1443                                        path = strchr(path+2, '/');
1444                                }
1445                        }
1446                        if (path) {
1447                                path += remote->path_len;
1448                                ls->dentry_name = xstrdup(path);
1449                        }
1450                } else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
1451                        ls->dentry_flags |= IS_DIR;
1452                }
1453        } else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {
1454                free(ls->dentry_name);
1455                ls->dentry_name = NULL;
1456                ls->dentry_flags = 0;
1457        }
1458}
1459
1460/*
1461 * NEEDSWORK: remote_ls() ignores info/refs on the remote side.  But it
1462 * should _only_ heed the information from that file, instead of trying to
1463 * determine the refs from the remote file system (badly: it does not even
1464 * know about packed-refs).
1465 */
1466static void remote_ls(const char *path, int flags,
1467                      void (*userFunc)(struct remote_ls_ctx *ls),
1468                      void *userData)
1469{
1470        char *url = xmalloc(strlen(remote->url) + strlen(path) + 1);
1471        struct active_request_slot *slot;
1472        struct slot_results results;
1473        struct strbuf in_buffer = STRBUF_INIT;
1474        struct buffer out_buffer = { STRBUF_INIT, 0 };
1475        struct curl_slist *dav_headers = NULL;
1476        struct xml_ctx ctx;
1477        struct remote_ls_ctx ls;
1478
1479        ls.flags = flags;
1480        ls.path = xstrdup(path);
1481        ls.dentry_name = NULL;
1482        ls.dentry_flags = 0;
1483        ls.userData = userData;
1484        ls.userFunc = userFunc;
1485
1486        sprintf(url, "%s%s", remote->url, path);
1487
1488        strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST);
1489
1490        dav_headers = curl_slist_append(dav_headers, "Depth: 1");
1491        dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
1492
1493        slot = get_active_slot();
1494        slot->results = &results;
1495        curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
1496        curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
1497        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1498        curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
1499        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
1500        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
1501        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
1502        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND);
1503        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1504
1505        if (start_active_slot(slot)) {
1506                run_active_slot(slot);
1507                if (results.curl_result == CURLE_OK) {
1508                        XML_Parser parser = XML_ParserCreate(NULL);
1509                        enum XML_Status result;
1510                        ctx.name = xcalloc(10, 1);
1511                        ctx.len = 0;
1512                        ctx.cdata = NULL;
1513                        ctx.userFunc = handle_remote_ls_ctx;
1514                        ctx.userData = &ls;
1515                        XML_SetUserData(parser, &ctx);
1516                        XML_SetElementHandler(parser, xml_start_tag,
1517                                              xml_end_tag);
1518                        XML_SetCharacterDataHandler(parser, xml_cdata);
1519                        result = XML_Parse(parser, in_buffer.buf,
1520                                           in_buffer.len, 1);
1521                        free(ctx.name);
1522
1523                        if (result != XML_STATUS_OK) {
1524                                fprintf(stderr, "XML error: %s\n",
1525                                        XML_ErrorString(
1526                                                XML_GetErrorCode(parser)));
1527                        }
1528                        XML_ParserFree(parser);
1529                }
1530        } else {
1531                fprintf(stderr, "Unable to start PROPFIND request\n");
1532        }
1533
1534        free(ls.path);
1535        free(url);
1536        strbuf_release(&out_buffer.buf);
1537        strbuf_release(&in_buffer);
1538        curl_slist_free_all(dav_headers);
1539}
1540
1541static void get_remote_object_list(unsigned char parent)
1542{
1543        char path[] = "objects/XX/";
1544        static const char hex[] = "0123456789abcdef";
1545        unsigned int val = parent;
1546
1547        path[8] = hex[val >> 4];
1548        path[9] = hex[val & 0xf];
1549        remote_dir_exists[val] = 0;
1550        remote_ls(path, (PROCESS_FILES | PROCESS_DIRS),
1551                  process_ls_object, &val);
1552}
1553
1554static int locking_available(void)
1555{
1556        struct active_request_slot *slot;
1557        struct slot_results results;
1558        struct strbuf in_buffer = STRBUF_INIT;
1559        struct buffer out_buffer = { STRBUF_INIT, 0 };
1560        struct curl_slist *dav_headers = NULL;
1561        struct xml_ctx ctx;
1562        int lock_flags = 0;
1563
1564        strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, remote->url);
1565
1566        dav_headers = curl_slist_append(dav_headers, "Depth: 0");
1567        dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
1568
1569        slot = get_active_slot();
1570        slot->results = &results;
1571        curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
1572        curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
1573        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1574        curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
1575        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
1576        curl_easy_setopt(slot->curl, CURLOPT_URL, remote->url);
1577        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
1578        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND);
1579        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1580
1581        if (start_active_slot(slot)) {
1582                run_active_slot(slot);
1583                if (results.curl_result == CURLE_OK) {
1584                        XML_Parser parser = XML_ParserCreate(NULL);
1585                        enum XML_Status result;
1586                        ctx.name = xcalloc(10, 1);
1587                        ctx.len = 0;
1588                        ctx.cdata = NULL;
1589                        ctx.userFunc = handle_lockprop_ctx;
1590                        ctx.userData = &lock_flags;
1591                        XML_SetUserData(parser, &ctx);
1592                        XML_SetElementHandler(parser, xml_start_tag,
1593                                              xml_end_tag);
1594                        result = XML_Parse(parser, in_buffer.buf,
1595                                           in_buffer.len, 1);
1596                        free(ctx.name);
1597
1598                        if (result != XML_STATUS_OK) {
1599                                fprintf(stderr, "XML error: %s\n",
1600                                        XML_ErrorString(
1601                                                XML_GetErrorCode(parser)));
1602                                lock_flags = 0;
1603                        }
1604                        XML_ParserFree(parser);
1605                        if (!lock_flags)
1606                                error("Error: no DAV locking support on %s",
1607                                      remote->url);
1608
1609                } else {
1610                        error("Cannot access URL %s, return code %d",
1611                              remote->url, results.curl_result);
1612                        lock_flags = 0;
1613                }
1614        } else {
1615                error("Unable to start PROPFIND request on %s", remote->url);
1616        }
1617
1618        strbuf_release(&out_buffer.buf);
1619        strbuf_release(&in_buffer);
1620        curl_slist_free_all(dav_headers);
1621
1622        return lock_flags;
1623}
1624
1625static struct object_list **add_one_object(struct object *obj, struct object_list **p)
1626{
1627        struct object_list *entry = xmalloc(sizeof(struct object_list));
1628        entry->item = obj;
1629        entry->next = *p;
1630        *p = entry;
1631        return &entry->next;
1632}
1633
1634static struct object_list **process_blob(struct blob *blob,
1635                                         struct object_list **p,
1636                                         struct name_path *path,
1637                                         const char *name)
1638{
1639        struct object *obj = &blob->object;
1640
1641        obj->flags |= LOCAL;
1642
1643        if (obj->flags & (UNINTERESTING | SEEN))
1644                return p;
1645
1646        obj->flags |= SEEN;
1647        return add_one_object(obj, p);
1648}
1649
1650static struct object_list **process_tree(struct tree *tree,
1651                                         struct object_list **p,
1652                                         struct name_path *path,
1653                                         const char *name)
1654{
1655        struct object *obj = &tree->object;
1656        struct tree_desc desc;
1657        struct name_entry entry;
1658        struct name_path me;
1659
1660        obj->flags |= LOCAL;
1661
1662        if (obj->flags & (UNINTERESTING | SEEN))
1663                return p;
1664        if (parse_tree(tree) < 0)
1665                die("bad tree object %s", sha1_to_hex(obj->sha1));
1666
1667        obj->flags |= SEEN;
1668        name = xstrdup(name);
1669        p = add_one_object(obj, p);
1670        me.up = path;
1671        me.elem = name;
1672        me.elem_len = strlen(name);
1673
1674        init_tree_desc(&desc, tree->buffer, tree->size);
1675
1676        while (tree_entry(&desc, &entry))
1677                switch (object_type(entry.mode)) {
1678                case OBJ_TREE:
1679                        p = process_tree(lookup_tree(entry.sha1), p, &me, name);
1680                        break;
1681                case OBJ_BLOB:
1682                        p = process_blob(lookup_blob(entry.sha1), p, &me, name);
1683                        break;
1684                default:
1685                        /* Subproject commit - not in this repository */
1686                        break;
1687                }
1688
1689        free(tree->buffer);
1690        tree->buffer = NULL;
1691        return p;
1692}
1693
1694static int get_delta(struct rev_info *revs, struct remote_lock *lock)
1695{
1696        int i;
1697        struct commit *commit;
1698        struct object_list **p = &objects;
1699        int count = 0;
1700
1701        while ((commit = get_revision(revs)) != NULL) {
1702                p = process_tree(commit->tree, p, NULL, "");
1703                commit->object.flags |= LOCAL;
1704                if (!(commit->object.flags & UNINTERESTING))
1705                        count += add_send_request(&commit->object, lock);
1706        }
1707
1708        for (i = 0; i < revs->pending.nr; i++) {
1709                struct object_array_entry *entry = revs->pending.objects + i;
1710                struct object *obj = entry->item;
1711                const char *name = entry->name;
1712
1713                if (obj->flags & (UNINTERESTING | SEEN))
1714                        continue;
1715                if (obj->type == OBJ_TAG) {
1716                        obj->flags |= SEEN;
1717                        p = add_one_object(obj, p);
1718                        continue;
1719                }
1720                if (obj->type == OBJ_TREE) {
1721                        p = process_tree((struct tree *)obj, p, NULL, name);
1722                        continue;
1723                }
1724                if (obj->type == OBJ_BLOB) {
1725                        p = process_blob((struct blob *)obj, p, NULL, name);
1726                        continue;
1727                }
1728                die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
1729        }
1730
1731        while (objects) {
1732                if (!(objects->item->flags & UNINTERESTING))
1733                        count += add_send_request(objects->item, lock);
1734                objects = objects->next;
1735        }
1736
1737        return count;
1738}
1739
1740static int update_remote(unsigned char *sha1, struct remote_lock *lock)
1741{
1742        struct active_request_slot *slot;
1743        struct slot_results results;
1744        struct buffer out_buffer = { STRBUF_INIT, 0 };
1745        struct curl_slist *dav_headers;
1746
1747        dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
1748
1749        strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1));
1750
1751        slot = get_active_slot();
1752        slot->results = &results;
1753        curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
1754        curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
1755        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1756        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
1757        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
1758        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1759        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
1760        curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
1761        curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
1762
1763        if (start_active_slot(slot)) {
1764                run_active_slot(slot);
1765                strbuf_release(&out_buffer.buf);
1766                if (results.curl_result != CURLE_OK) {
1767                        fprintf(stderr,
1768                                "PUT error: curl result=%d, HTTP code=%ld\n",
1769                                results.curl_result, results.http_code);
1770                        /* We should attempt recovery? */
1771                        return 0;
1772                }
1773        } else {
1774                strbuf_release(&out_buffer.buf);
1775                fprintf(stderr, "Unable to start PUT request\n");
1776                return 0;
1777        }
1778
1779        return 1;
1780}
1781
1782static struct ref *local_refs, **local_tail;
1783static struct ref *remote_refs, **remote_tail;
1784
1785static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
1786{
1787        struct ref *ref;
1788        int len = strlen(refname) + 1;
1789        ref = xcalloc(1, sizeof(*ref) + len);
1790        hashcpy(ref->new_sha1, sha1);
1791        memcpy(ref->name, refname, len);
1792        *local_tail = ref;
1793        local_tail = &ref->next;
1794        return 0;
1795}
1796
1797static void one_remote_ref(char *refname)
1798{
1799        struct ref *ref;
1800        struct object *obj;
1801
1802        ref = alloc_ref(refname);
1803
1804        if (http_fetch_ref(remote->url, ref) != 0) {
1805                fprintf(stderr,
1806                        "Unable to fetch ref %s from %s\n",
1807                        refname, remote->url);
1808                free(ref);
1809                return;
1810        }
1811
1812        /*
1813         * Fetch a copy of the object if it doesn't exist locally - it
1814         * may be required for updating server info later.
1815         */
1816        if (remote->can_update_info_refs && !has_sha1_file(ref->old_sha1)) {
1817                obj = lookup_unknown_object(ref->old_sha1);
1818                if (obj) {
1819                        fprintf(stderr, "  fetch %s for %s\n",
1820                                sha1_to_hex(ref->old_sha1), refname);
1821                        add_fetch_request(obj);
1822                }
1823        }
1824
1825        *remote_tail = ref;
1826        remote_tail = &ref->next;
1827}
1828
1829static void get_local_heads(void)
1830{
1831        local_tail = &local_refs;
1832        for_each_ref(one_local_ref, NULL);
1833}
1834
1835static void get_dav_remote_heads(void)
1836{
1837        remote_tail = &remote_refs;
1838        remote_ls("refs/", (PROCESS_FILES | PROCESS_DIRS | RECURSIVE), process_ls_ref, NULL);
1839}
1840
1841static int is_zero_sha1(const unsigned char *sha1)
1842{
1843        int i;
1844
1845        for (i = 0; i < 20; i++) {
1846                if (*sha1++)
1847                        return 0;
1848        }
1849        return 1;
1850}
1851
1852static void unmark_and_free(struct commit_list *list, unsigned int mark)
1853{
1854        while (list) {
1855                struct commit_list *temp = list;
1856                temp->item->object.flags &= ~mark;
1857                list = temp->next;
1858                free(temp);
1859        }
1860}
1861
1862static int ref_newer(const unsigned char *new_sha1,
1863                     const unsigned char *old_sha1)
1864{
1865        struct object *o;
1866        struct commit *old, *new;
1867        struct commit_list *list, *used;
1868        int found = 0;
1869
1870        /* Both new and old must be commit-ish and new is descendant of
1871         * old.  Otherwise we require --force.
1872         */
1873        o = deref_tag(parse_object(old_sha1), NULL, 0);
1874        if (!o || o->type != OBJ_COMMIT)
1875                return 0;
1876        old = (struct commit *) o;
1877
1878        o = deref_tag(parse_object(new_sha1), NULL, 0);
1879        if (!o || o->type != OBJ_COMMIT)
1880                return 0;
1881        new = (struct commit *) o;
1882
1883        if (parse_commit(new) < 0)
1884                return 0;
1885
1886        used = list = NULL;
1887        commit_list_insert(new, &list);
1888        while (list) {
1889                new = pop_most_recent_commit(&list, TMP_MARK);
1890                commit_list_insert(new, &used);
1891                if (new == old) {
1892                        found = 1;
1893                        break;
1894                }
1895        }
1896        unmark_and_free(list, TMP_MARK);
1897        unmark_and_free(used, TMP_MARK);
1898        return found;
1899}
1900
1901static void add_remote_info_ref(struct remote_ls_ctx *ls)
1902{
1903        struct strbuf *buf = (struct strbuf *)ls->userData;
1904        struct object *o;
1905        int len;
1906        char *ref_info;
1907        struct ref *ref;
1908
1909        ref = alloc_ref(ls->dentry_name);
1910
1911        if (http_fetch_ref(remote->url, ref) != 0) {
1912                fprintf(stderr,
1913                        "Unable to fetch ref %s from %s\n",
1914                        ls->dentry_name, remote->url);
1915                aborted = 1;
1916                free(ref);
1917                return;
1918        }
1919
1920        o = parse_object(ref->old_sha1);
1921        if (!o) {
1922                fprintf(stderr,
1923                        "Unable to parse object %s for remote ref %s\n",
1924                        sha1_to_hex(ref->old_sha1), ls->dentry_name);
1925                aborted = 1;
1926                free(ref);
1927                return;
1928        }
1929
1930        len = strlen(ls->dentry_name) + 42;
1931        ref_info = xcalloc(len + 1, 1);
1932        sprintf(ref_info, "%s   %s\n",
1933                sha1_to_hex(ref->old_sha1), ls->dentry_name);
1934        fwrite_buffer(ref_info, 1, len, buf);
1935        free(ref_info);
1936
1937        if (o->type == OBJ_TAG) {
1938                o = deref_tag(o, ls->dentry_name, 0);
1939                if (o) {
1940                        len = strlen(ls->dentry_name) + 45;
1941                        ref_info = xcalloc(len + 1, 1);
1942                        sprintf(ref_info, "%s   %s^{}\n",
1943                                sha1_to_hex(o->sha1), ls->dentry_name);
1944                        fwrite_buffer(ref_info, 1, len, buf);
1945                        free(ref_info);
1946                }
1947        }
1948        free(ref);
1949}
1950
1951static void update_remote_info_refs(struct remote_lock *lock)
1952{
1953        struct buffer buffer = { STRBUF_INIT, 0 };
1954        struct active_request_slot *slot;
1955        struct slot_results results;
1956        struct curl_slist *dav_headers;
1957
1958        remote_ls("refs/", (PROCESS_FILES | RECURSIVE),
1959                  add_remote_info_ref, &buffer.buf);
1960        if (!aborted) {
1961                dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
1962
1963                slot = get_active_slot();
1964                slot->results = &results;
1965                curl_easy_setopt(slot->curl, CURLOPT_INFILE, &buffer);
1966                curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.buf.len);
1967                curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1968                curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
1969                curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
1970                curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1971                curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
1972                curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
1973                curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
1974
1975                if (start_active_slot(slot)) {
1976                        run_active_slot(slot);
1977                        if (results.curl_result != CURLE_OK) {
1978                                fprintf(stderr,
1979                                        "PUT error: curl result=%d, HTTP code=%ld\n",
1980                                        results.curl_result, results.http_code);
1981                        }
1982                }
1983        }
1984        strbuf_release(&buffer.buf);
1985}
1986
1987static int remote_exists(const char *path)
1988{
1989        char *url = xmalloc(strlen(remote->url) + strlen(path) + 1);
1990        struct active_request_slot *slot;
1991        struct slot_results results;
1992        int ret = -1;
1993
1994        sprintf(url, "%s%s", remote->url, path);
1995
1996        slot = get_active_slot();
1997        slot->results = &results;
1998        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
1999        curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
2000
2001        if (start_active_slot(slot)) {
2002                run_active_slot(slot);
2003                if (results.http_code == 404)
2004                        ret = 0;
2005                else if (results.curl_result == CURLE_OK)
2006                        ret = 1;
2007                else
2008                        fprintf(stderr, "HEAD HTTP error %ld\n", results.http_code);
2009        } else {
2010                fprintf(stderr, "Unable to start HEAD request\n");
2011        }
2012
2013        free(url);
2014        return ret;
2015}
2016
2017static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
2018{
2019        char *url;
2020        struct strbuf buffer = STRBUF_INIT;
2021        struct active_request_slot *slot;
2022        struct slot_results results;
2023
2024        url = xmalloc(strlen(remote->url) + strlen(path) + 1);
2025        sprintf(url, "%s%s", remote->url, path);
2026
2027        slot = get_active_slot();
2028        slot->results = &results;
2029        curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
2030        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
2031        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
2032        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
2033        if (start_active_slot(slot)) {
2034                run_active_slot(slot);
2035                if (results.curl_result != CURLE_OK) {
2036                        die("Couldn't get %s for remote symref\n%s",
2037                            url, curl_errorstr);
2038                }
2039        } else {
2040                die("Unable to start remote symref request");
2041        }
2042        free(url);
2043
2044        free(*symref);
2045        *symref = NULL;
2046        hashclr(sha1);
2047
2048        if (buffer.len == 0)
2049                return;
2050
2051        /* If it's a symref, set the refname; otherwise try for a sha1 */
2052        if (!prefixcmp((char *)buffer.buf, "ref: ")) {
2053                *symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6);
2054        } else {
2055                get_sha1_hex(buffer.buf, sha1);
2056        }
2057
2058        strbuf_release(&buffer);
2059}
2060
2061static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha1)
2062{
2063        struct commit *head = lookup_commit(head_sha1);
2064        struct commit *branch = lookup_commit(branch_sha1);
2065        struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
2066
2067        return (merge_bases && !merge_bases->next && merge_bases->item == branch);
2068}
2069
2070static int delete_remote_branch(char *pattern, int force)
2071{
2072        struct ref *refs = remote_refs;
2073        struct ref *remote_ref = NULL;
2074        unsigned char head_sha1[20];
2075        char *symref = NULL;
2076        int match;
2077        int patlen = strlen(pattern);
2078        int i;
2079        struct active_request_slot *slot;
2080        struct slot_results results;
2081        char *url;
2082
2083        /* Find the remote branch(es) matching the specified branch name */
2084        for (match = 0; refs; refs = refs->next) {
2085                char *name = refs->name;
2086                int namelen = strlen(name);
2087                if (namelen < patlen ||
2088                    memcmp(name + namelen - patlen, pattern, patlen))
2089                        continue;
2090                if (namelen != patlen && name[namelen - patlen - 1] != '/')
2091                        continue;
2092                match++;
2093                remote_ref = refs;
2094        }
2095        if (match == 0)
2096                return error("No remote branch matches %s", pattern);
2097        if (match != 1)
2098                return error("More than one remote branch matches %s",
2099                             pattern);
2100
2101        /*
2102         * Remote HEAD must be a symref (not exactly foolproof; a remote
2103         * symlink to a symref will look like a symref)
2104         */
2105        fetch_symref("HEAD", &symref, head_sha1);
2106        if (!symref)
2107                return error("Remote HEAD is not a symref");
2108
2109        /* Remote branch must not be the remote HEAD */
2110        for (i=0; symref && i<MAXDEPTH; i++) {
2111                if (!strcmp(remote_ref->name, symref))
2112                        return error("Remote branch %s is the current HEAD",
2113                                     remote_ref->name);
2114                fetch_symref(symref, &symref, head_sha1);
2115        }
2116
2117        /* Run extra sanity checks if delete is not forced */
2118        if (!force) {
2119                /* Remote HEAD must resolve to a known object */
2120                if (symref)
2121                        return error("Remote HEAD symrefs too deep");
2122                if (is_zero_sha1(head_sha1))
2123                        return error("Unable to resolve remote HEAD");
2124                if (!has_sha1_file(head_sha1))
2125                        return error("Remote HEAD resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", sha1_to_hex(head_sha1));
2126
2127                /* Remote branch must resolve to a known object */
2128                if (is_zero_sha1(remote_ref->old_sha1))
2129                        return error("Unable to resolve remote branch %s",
2130                                     remote_ref->name);
2131                if (!has_sha1_file(remote_ref->old_sha1))
2132                        return error("Remote branch %s resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", remote_ref->name, sha1_to_hex(remote_ref->old_sha1));
2133
2134                /* Remote branch must be an ancestor of remote HEAD */
2135                if (!verify_merge_base(head_sha1, remote_ref->old_sha1)) {
2136                        return error("The branch '%s' is not an ancestor "
2137                                     "of your current HEAD.\n"
2138                                     "If you are sure you want to delete it,"
2139                                     " run:\n\t'git http-push -D %s %s'",
2140                                     remote_ref->name, remote->url, pattern);
2141                }
2142        }
2143
2144        /* Send delete request */
2145        fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name);
2146        if (dry_run)
2147                return 0;
2148        url = xmalloc(strlen(remote->url) + strlen(remote_ref->name) + 1);
2149        sprintf(url, "%s%s", remote->url, remote_ref->name);
2150        slot = get_active_slot();
2151        slot->results = &results;
2152        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
2153        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
2154        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
2155        curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_DELETE);
2156        if (start_active_slot(slot)) {
2157                run_active_slot(slot);
2158                free(url);
2159                if (results.curl_result != CURLE_OK)
2160                        return error("DELETE request failed (%d/%ld)\n",
2161                                     results.curl_result, results.http_code);
2162        } else {
2163                free(url);
2164                return error("Unable to start DELETE request");
2165        }
2166
2167        return 0;
2168}
2169
2170int main(int argc, char **argv)
2171{
2172        struct transfer_request *request;
2173        struct transfer_request *next_request;
2174        int nr_refspec = 0;
2175        char **refspec = NULL;
2176        struct remote_lock *ref_lock = NULL;
2177        struct remote_lock *info_ref_lock = NULL;
2178        struct rev_info revs;
2179        int delete_branch = 0;
2180        int force_delete = 0;
2181        int objects_to_send;
2182        int rc = 0;
2183        int i;
2184        int new_refs;
2185        struct ref *ref;
2186        char *rewritten_url = NULL;
2187
2188        setup_git_directory();
2189
2190        remote = xcalloc(sizeof(*remote), 1);
2191
2192        argv++;
2193        for (i = 1; i < argc; i++, argv++) {
2194                char *arg = *argv;
2195
2196                if (*arg == '-') {
2197                        if (!strcmp(arg, "--all")) {
2198                                push_all = MATCH_REFS_ALL;
2199                                continue;
2200                        }
2201                        if (!strcmp(arg, "--force")) {
2202                                force_all = 1;
2203                                continue;
2204                        }
2205                        if (!strcmp(arg, "--dry-run")) {
2206                                dry_run = 1;
2207                                continue;
2208                        }
2209                        if (!strcmp(arg, "--verbose")) {
2210                                push_verbosely = 1;
2211                                continue;
2212                        }
2213                        if (!strcmp(arg, "-d")) {
2214                                delete_branch = 1;
2215                                continue;
2216                        }
2217                        if (!strcmp(arg, "-D")) {
2218                                delete_branch = 1;
2219                                force_delete = 1;
2220                                continue;
2221                        }
2222                }
2223                if (!remote->url) {
2224                        char *path = strstr(arg, "//");
2225                        remote->url = arg;
2226                        remote->path_len = strlen(arg);
2227                        if (path) {
2228                                remote->path = strchr(path+2, '/');
2229                                if (remote->path)
2230                                        remote->path_len = strlen(remote->path);
2231                        }
2232                        continue;
2233                }
2234                refspec = argv;
2235                nr_refspec = argc - i;
2236                break;
2237        }
2238
2239#ifndef USE_CURL_MULTI
2240        die("git-push is not available for http/https repository when not compiled with USE_CURL_MULTI");
2241#endif
2242
2243        if (!remote->url)
2244                usage(http_push_usage);
2245
2246        if (delete_branch && nr_refspec != 1)
2247                die("You must specify only one branch name when deleting a remote branch");
2248
2249        memset(remote_dir_exists, -1, 256);
2250
2251        http_init(NULL);
2252
2253        no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
2254
2255        if (remote->url && remote->url[strlen(remote->url)-1] != '/') {
2256                rewritten_url = xmalloc(strlen(remote->url)+2);
2257                strcpy(rewritten_url, remote->url);
2258                strcat(rewritten_url, "/");
2259                remote->path = rewritten_url + (remote->path - remote->url);
2260                remote->path_len++;
2261                remote->url = rewritten_url;
2262        }
2263
2264        /* Verify DAV compliance/lock support */
2265        if (!locking_available()) {
2266                rc = 1;
2267                goto cleanup;
2268        }
2269
2270        signal(SIGINT, remove_locks_on_signal);
2271        signal(SIGHUP, remove_locks_on_signal);
2272        signal(SIGQUIT, remove_locks_on_signal);
2273        signal(SIGTERM, remove_locks_on_signal);
2274
2275        /* Check whether the remote has server info files */
2276        remote->can_update_info_refs = 0;
2277        remote->has_info_refs = remote_exists("info/refs");
2278        remote->has_info_packs = remote_exists("objects/info/packs");
2279        if (remote->has_info_refs) {
2280                info_ref_lock = lock_remote("info/refs", LOCK_TIME);
2281                if (info_ref_lock)
2282                        remote->can_update_info_refs = 1;
2283                else {
2284                        fprintf(stderr, "Error: cannot lock existing info/refs\n");
2285                        rc = 1;
2286                        goto cleanup;
2287                }
2288        }
2289        if (remote->has_info_packs)
2290                fetch_indices();
2291
2292        /* Get a list of all local and remote heads to validate refspecs */
2293        get_local_heads();
2294        fprintf(stderr, "Fetching remote heads...\n");
2295        get_dav_remote_heads();
2296
2297        /* Remove a remote branch if -d or -D was specified */
2298        if (delete_branch) {
2299                if (delete_remote_branch(refspec[0], force_delete) == -1)
2300                        fprintf(stderr, "Unable to delete remote branch %s\n",
2301                                refspec[0]);
2302                goto cleanup;
2303        }
2304
2305        /* match them up */
2306        if (!remote_tail)
2307                remote_tail = &remote_refs;
2308        if (match_refs(local_refs, remote_refs, &remote_tail,
2309                       nr_refspec, (const char **) refspec, push_all)) {
2310                rc = -1;
2311                goto cleanup;
2312        }
2313        if (!remote_refs) {
2314                fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
2315                rc = 0;
2316                goto cleanup;
2317        }
2318
2319        new_refs = 0;
2320        for (ref = remote_refs; ref; ref = ref->next) {
2321                char old_hex[60], *new_hex;
2322                const char *commit_argv[4];
2323                int commit_argc;
2324                char *new_sha1_hex, *old_sha1_hex;
2325
2326                if (!ref->peer_ref)
2327                        continue;
2328
2329                if (is_zero_sha1(ref->peer_ref->new_sha1)) {
2330                        if (delete_remote_branch(ref->name, 1) == -1) {
2331                                error("Could not remove %s", ref->name);
2332                                rc = -4;
2333                        }
2334                        new_refs++;
2335                        continue;
2336                }
2337
2338                if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
2339                        if (push_verbosely || 1)
2340                                fprintf(stderr, "'%s': up-to-date\n", ref->name);
2341                        continue;
2342                }
2343
2344                if (!force_all &&
2345                    !is_zero_sha1(ref->old_sha1) &&
2346                    !ref->force) {
2347                        if (!has_sha1_file(ref->old_sha1) ||
2348                            !ref_newer(ref->peer_ref->new_sha1,
2349                                       ref->old_sha1)) {
2350                                /*
2351                                 * We do not have the remote ref, or
2352                                 * we know that the remote ref is not
2353                                 * an ancestor of what we are trying to
2354                                 * push.  Either way this can be losing
2355                                 * commits at the remote end and likely
2356                                 * we were not up to date to begin with.
2357                                 */
2358                                error("remote '%s' is not an ancestor of\n"
2359                                      "local '%s'.\n"
2360                                      "Maybe you are not up-to-date and "
2361                                      "need to pull first?",
2362                                      ref->name,
2363                                      ref->peer_ref->name);
2364                                rc = -2;
2365                                continue;
2366                        }
2367                }
2368                hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
2369                new_refs++;
2370                strcpy(old_hex, sha1_to_hex(ref->old_sha1));
2371                new_hex = sha1_to_hex(ref->new_sha1);
2372
2373                fprintf(stderr, "updating '%s'", ref->name);
2374                if (strcmp(ref->name, ref->peer_ref->name))
2375                        fprintf(stderr, " using '%s'", ref->peer_ref->name);
2376                fprintf(stderr, "\n  from %s\n  to   %s\n", old_hex, new_hex);
2377                if (dry_run)
2378                        continue;
2379
2380                /* Lock remote branch ref */
2381                ref_lock = lock_remote(ref->name, LOCK_TIME);
2382                if (ref_lock == NULL) {
2383                        fprintf(stderr, "Unable to lock remote branch %s\n",
2384                                ref->name);
2385                        rc = 1;
2386                        continue;
2387                }
2388
2389                /* Set up revision info for this refspec */
2390                commit_argc = 3;
2391                new_sha1_hex = xstrdup(sha1_to_hex(ref->new_sha1));
2392                old_sha1_hex = NULL;
2393                commit_argv[1] = "--objects";
2394                commit_argv[2] = new_sha1_hex;
2395                if (!push_all && !is_zero_sha1(ref->old_sha1)) {
2396                        old_sha1_hex = xmalloc(42);
2397                        sprintf(old_sha1_hex, "^%s",
2398                                sha1_to_hex(ref->old_sha1));
2399                        commit_argv[3] = old_sha1_hex;
2400                        commit_argc++;
2401                }
2402                init_revisions(&revs, setup_git_directory());
2403                setup_revisions(commit_argc, commit_argv, &revs, NULL);
2404                revs.edge_hint = 0; /* just in case */
2405                free(new_sha1_hex);
2406                if (old_sha1_hex) {
2407                        free(old_sha1_hex);
2408                        commit_argv[1] = NULL;
2409                }
2410
2411                /* Generate a list of objects that need to be pushed */
2412                pushing = 0;
2413                if (prepare_revision_walk(&revs))
2414                        die("revision walk setup failed");
2415                mark_edges_uninteresting(revs.commits, &revs, NULL);
2416                objects_to_send = get_delta(&revs, ref_lock);
2417                finish_all_active_slots();
2418
2419                /* Push missing objects to remote, this would be a
2420                   convenient time to pack them first if appropriate. */
2421                pushing = 1;
2422                if (objects_to_send)
2423                        fprintf(stderr, "    sending %d objects\n",
2424                                objects_to_send);
2425#ifdef USE_CURL_MULTI
2426                fill_active_slots();
2427                add_fill_function(NULL, fill_active_slot);
2428#endif
2429                do {
2430                        finish_all_active_slots();
2431#ifdef USE_CURL_MULTI
2432                        fill_active_slots();
2433#endif
2434                } while (request_queue_head && !aborted);
2435
2436                /* Update the remote branch if all went well */
2437                if (aborted || !update_remote(ref->new_sha1, ref_lock))
2438                        rc = 1;
2439
2440                if (!rc)
2441                        fprintf(stderr, "    done\n");
2442                unlock_remote(ref_lock);
2443                check_locks();
2444        }
2445
2446        /* Update remote server info if appropriate */
2447        if (remote->has_info_refs && new_refs) {
2448                if (info_ref_lock && remote->can_update_info_refs) {
2449                        fprintf(stderr, "Updating remote server info\n");
2450                        if (!dry_run)
2451                                update_remote_info_refs(info_ref_lock);
2452                } else {
2453                        fprintf(stderr, "Unable to update server info\n");
2454                }
2455        }
2456
2457 cleanup:
2458        free(rewritten_url);
2459        if (info_ref_lock)
2460                unlock_remote(info_ref_lock);
2461        free(remote);
2462
2463        curl_slist_free_all(no_pragma_header);
2464
2465        http_cleanup();
2466
2467        request = request_queue_head;
2468        while (request != NULL) {
2469                next_request = request->next;
2470                release_request(request);
2471                request = next_request;
2472        }
2473
2474        return rc;
2475}