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