Decide whether to build http-push in the Makefile
[git/git.git] / http-push.c
CommitLineData
58e60dd2
NH
1#include "cache.h"
2#include "commit.h"
3#include "pack.h"
4#include "fetch.h"
5#include "tag.h"
6#include "blob.h"
29508e1e
NH
7#include "http.h"
8
bee8e79d 9#include <expat.h>
58e60dd2
NH
10
11static const char http_push_usage[] =
12"git-http-push [--complete] [--force] [--verbose] <url> <ref> [<ref>...]\n";
13
92e2eb9c
JS
14#ifndef XML_STATUS_OK
15enum XML_Status {
16 XML_STATUS_OK = 1,
17 XML_STATUS_ERROR = 0
18};
19#define XML_STATUS_OK 1
20#define XML_STATUS_ERROR 0
21#endif
22
58e60dd2
NH
23#define RANGE_HEADER_SIZE 30
24
acf59575 25/* DAV methods */
58e60dd2
NH
26#define DAV_LOCK "LOCK"
27#define DAV_MKCOL "MKCOL"
28#define DAV_MOVE "MOVE"
29#define DAV_PROPFIND "PROPFIND"
30#define DAV_PUT "PUT"
31#define DAV_UNLOCK "UNLOCK"
acf59575
NH
32
33/* DAV lock flags */
34#define DAV_PROP_LOCKWR (1u << 0)
35#define DAV_PROP_LOCKEX (1u << 1)
36#define DAV_LOCK_OK (1u << 2)
37
38/* DAV XML properties */
39#define DAV_CTX_LOCKENTRY ".multistatus.response.propstat.prop.supportedlock.lockentry"
40#define DAV_CTX_LOCKTYPE_WRITE ".multistatus.response.propstat.prop.supportedlock.lockentry.locktype.write"
41#define DAV_CTX_LOCKTYPE_EXCLUSIVE ".multistatus.response.propstat.prop.supportedlock.lockentry.lockscope.exclusive"
42#define DAV_ACTIVELOCK_OWNER ".prop.lockdiscovery.activelock.owner.href"
43#define DAV_ACTIVELOCK_TIMEOUT ".prop.lockdiscovery.activelock.timeout"
44#define DAV_ACTIVELOCK_TOKEN ".prop.lockdiscovery.activelock.locktoken.href"
45
46/* DAV request body templates */
58e60dd2
NH
47#define PROPFIND_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>"
48#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>"
49
75187c9d
NH
50#define LOCK_TIME 600
51#define LOCK_REFRESH 30
52
58e60dd2
NH
53static int pushing = 0;
54static int aborted = 0;
0dd276b8 55static char remote_dir_exists[256];
58e60dd2 56
58e60dd2
NH
57static struct curl_slist *no_pragma_header;
58static struct curl_slist *default_headers;
58e60dd2
NH
59
60static int push_verbosely = 0;
61static int push_all = 0;
62static int force_all = 0;
63
58e60dd2
NH
64struct repo
65{
66 char *url;
67 struct packed_git *packs;
68};
69
70static struct repo *remote = NULL;
71
72enum transfer_state {
73 NEED_CHECK,
74 RUN_HEAD,
75 NEED_PUSH,
76 RUN_MKCOL,
77 RUN_PUT,
78 RUN_MOVE,
79 ABORTED,
80 COMPLETE,
81};
82
83struct transfer_request
84{
85 unsigned char sha1[20];
86 char *url;
87 char *dest;
26349b2e 88 struct active_lock *lock;
58e60dd2
NH
89 struct curl_slist *headers;
90 struct buffer buffer;
91 char filename[PATH_MAX];
92 char tmpfile[PATH_MAX];
93 enum transfer_state state;
94 CURLcode curl_result;
95 char errorstr[CURL_ERROR_SIZE];
96 long http_code;
97 unsigned char real_sha1[20];
98 SHA_CTX c;
99 z_stream stream;
100 int zret;
101 int rename;
102 struct active_request_slot *slot;
103 struct transfer_request *next;
104};
105
58e60dd2 106static struct transfer_request *request_queue_head = NULL;
58e60dd2 107
acf59575
NH
108struct xml_ctx
109{
110 char *name;
111 int len;
112 char *cdata;
113 void (*userFunc)(struct xml_ctx *ctx, int tag_closed);
114 void *userData;
115};
116
26349b2e
NH
117struct active_lock
118{
75187c9d 119 char *url;
26349b2e 120 char *owner;
75187c9d 121 char *token;
26349b2e
NH
122 time_t start_time;
123 long timeout;
75187c9d 124 int refreshing;
26349b2e
NH
125};
126
29508e1e 127static void finish_request(struct transfer_request *request);
58e60dd2 128
29508e1e 129static void process_response(void *callback_data)
58e60dd2 130{
29508e1e
NH
131 struct transfer_request *request =
132 (struct transfer_request *)callback_data;
58e60dd2 133
29508e1e 134 finish_request(request);
58e60dd2
NH
135}
136
137static void start_check(struct transfer_request *request)
138{
139 char *hex = sha1_to_hex(request->sha1);
140 struct active_request_slot *slot;
141 char *posn;
142
143 request->url = xmalloc(strlen(remote->url) + 55);
144 strcpy(request->url, remote->url);
145 posn = request->url + strlen(remote->url);
146 strcpy(posn, "objects/");
147 posn += 8;
148 memcpy(posn, hex, 2);
149 posn += 2;
150 *(posn++) = '/';
151 strcpy(posn, hex + 2);
152
153 slot = get_active_slot();
29508e1e
NH
154 slot->callback_func = process_response;
155 slot->callback_data = request;
58e60dd2
NH
156 curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
157 curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
158 curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
159
160 if (start_active_slot(slot)) {
161 request->slot = slot;
162 request->state = RUN_HEAD;
163 } else {
164 request->state = ABORTED;
165 free(request->url);
7b899967 166 request->url = NULL;
58e60dd2
NH
167 }
168}
169
170static void start_mkcol(struct transfer_request *request)
171{
172 char *hex = sha1_to_hex(request->sha1);
173 struct active_request_slot *slot;
174 char *posn;
175
176 request->url = xmalloc(strlen(remote->url) + 13);
177 strcpy(request->url, remote->url);
178 posn = request->url + strlen(remote->url);
179 strcpy(posn, "objects/");
180 posn += 8;
181 memcpy(posn, hex, 2);
182 posn += 2;
183 strcpy(posn, "/");
184
185 slot = get_active_slot();
29508e1e
NH
186 slot->callback_func = process_response;
187 slot->callback_data = request;
58e60dd2
NH
188 curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); /* undo PUT setup */
189 curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
190 curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
191 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MKCOL);
192 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
193
194 if (start_active_slot(slot)) {
195 request->slot = slot;
196 request->state = RUN_MKCOL;
197 } else {
198 request->state = ABORTED;
199 free(request->url);
7b899967 200 request->url = NULL;
58e60dd2
NH
201 }
202}
203
204static void start_put(struct transfer_request *request)
205{
206 char *hex = sha1_to_hex(request->sha1);
207 struct active_request_slot *slot;
208 char *posn;
209 char type[20];
210 char hdr[50];
211 void *unpacked;
212 unsigned long len;
213 int hdrlen;
214 ssize_t size;
215 z_stream stream;
216
217 unpacked = read_sha1_file(request->sha1, type, &len);
218 hdrlen = sprintf(hdr, "%s %lu", type, len) + 1;
219
220 /* Set it up */
221 memset(&stream, 0, sizeof(stream));
222 deflateInit(&stream, Z_BEST_COMPRESSION);
223 size = deflateBound(&stream, len + hdrlen);
224 request->buffer.buffer = xmalloc(size);
225
226 /* Compress it */
227 stream.next_out = request->buffer.buffer;
228 stream.avail_out = size;
229
230 /* First header.. */
231 stream.next_in = (void *)hdr;
232 stream.avail_in = hdrlen;
233 while (deflate(&stream, 0) == Z_OK)
234 /* nothing */;
235
236 /* Then the data itself.. */
237 stream.next_in = unpacked;
238 stream.avail_in = len;
239 while (deflate(&stream, Z_FINISH) == Z_OK)
240 /* nothing */;
241 deflateEnd(&stream);
242 free(unpacked);
243
244 request->buffer.size = stream.total_out;
245 request->buffer.posn = 0;
246
58e60dd2 247 request->url = xmalloc(strlen(remote->url) +
26349b2e 248 strlen(request->lock->token) + 51);
58e60dd2
NH
249 strcpy(request->url, remote->url);
250 posn = request->url + strlen(remote->url);
251 strcpy(posn, "objects/");
252 posn += 8;
253 memcpy(posn, hex, 2);
254 posn += 2;
255 *(posn++) = '/';
256 strcpy(posn, hex + 2);
257 request->dest = xmalloc(strlen(request->url) + 14);
258 sprintf(request->dest, "Destination: %s", request->url);
259 posn += 38;
260 *(posn++) = '.';
26349b2e 261 strcpy(posn, request->lock->token);
58e60dd2
NH
262
263 slot = get_active_slot();
29508e1e
NH
264 slot->callback_func = process_response;
265 slot->callback_data = request;
58e60dd2
NH
266 curl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);
267 curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.size);
268 curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
269 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
270 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
271 curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
272 curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
273 curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
274 curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
275
276 if (start_active_slot(slot)) {
277 request->slot = slot;
278 request->state = RUN_PUT;
279 } else {
280 request->state = ABORTED;
281 free(request->url);
7b899967 282 request->url = NULL;
58e60dd2
NH
283 }
284}
285
286static void start_move(struct transfer_request *request)
287{
288 struct active_request_slot *slot;
289 struct curl_slist *dav_headers = NULL;
290
291 slot = get_active_slot();
29508e1e
NH
292 slot->callback_func = process_response;
293 slot->callback_data = request;
58e60dd2
NH
294 curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); /* undo PUT setup */
295 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MOVE);
296 dav_headers = curl_slist_append(dav_headers, request->dest);
297 dav_headers = curl_slist_append(dav_headers, "Overwrite: T");
298 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
299 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
300 curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
301
302 if (start_active_slot(slot)) {
303 request->slot = slot;
304 request->state = RUN_MOVE;
305 } else {
306 request->state = ABORTED;
307 free(request->url);
7b899967 308 request->url = NULL;
58e60dd2
NH
309 }
310}
311
f4f440a0 312static int refresh_lock(struct active_lock *lock)
75187c9d
NH
313{
314 struct active_request_slot *slot;
315 char *if_header;
316 char timeout_header[25];
317 struct curl_slist *dav_headers = NULL;
318 int rc = 0;
319
320 lock->refreshing = 1;
321
322 if_header = xmalloc(strlen(lock->token) + 25);
323 sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
324 sprintf(timeout_header, "Timeout: Second-%ld", lock->timeout);
325 dav_headers = curl_slist_append(dav_headers, if_header);
326 dav_headers = curl_slist_append(dav_headers, timeout_header);
327
328 slot = get_active_slot();
329 curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
330 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
331 curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
332 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);
333 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
334
335 if (start_active_slot(slot)) {
336 run_active_slot(slot);
337 if (slot->curl_result != CURLE_OK) {
338 fprintf(stderr, "Got HTTP error %ld\n", slot->http_code);
339 } else {
340 lock->start_time = time(NULL);
341 rc = 1;
342 }
343 }
344
345 lock->refreshing = 0;
346 curl_slist_free_all(dav_headers);
347 free(if_header);
348
349 return rc;
350}
351
58e60dd2
NH
352static void finish_request(struct transfer_request *request)
353{
75187c9d
NH
354 time_t current_time = time(NULL);
355 int time_remaining;
356
58e60dd2
NH
357 request->curl_result = request->slot->curl_result;
358 request->http_code = request->slot->http_code;
359 request->slot = NULL;
75187c9d
NH
360
361 /* Refresh the lock if it is close to timing out */
362 time_remaining = request->lock->start_time + request->lock->timeout
363 - current_time;
364 if (time_remaining < LOCK_REFRESH && !request->lock->refreshing) {
365 if (!refresh_lock(request->lock)) {
366 fprintf(stderr, "Unable to refresh remote lock\n");
367 aborted = 1;
368 }
369 }
370
58e60dd2
NH
371 if (request->headers != NULL)
372 curl_slist_free_all(request->headers);
7b899967
NH
373
374 /* URL is reused for MOVE after PUT */
375 if (request->state != RUN_PUT) {
376 free(request->url);
377 request->url = NULL;
378 }
379
58e60dd2
NH
380 if (request->state == RUN_HEAD) {
381 if (request->http_code == 404) {
382 request->state = NEED_PUSH;
383 } else if (request->curl_result == CURLE_OK) {
0dd276b8 384 remote_dir_exists[request->sha1[0]] = 1;
58e60dd2
NH
385 request->state = COMPLETE;
386 } else {
387 fprintf(stderr, "HEAD %s failed, aborting (%d/%ld)\n",
388 sha1_to_hex(request->sha1),
389 request->curl_result, request->http_code);
390 request->state = ABORTED;
391 aborted = 1;
392 }
393 } else if (request->state == RUN_MKCOL) {
394 if (request->curl_result == CURLE_OK ||
395 request->http_code == 405) {
0dd276b8 396 remote_dir_exists[request->sha1[0]] = 1;
58e60dd2
NH
397 start_put(request);
398 } else {
399 fprintf(stderr, "MKCOL %s failed, aborting (%d/%ld)\n",
400 sha1_to_hex(request->sha1),
401 request->curl_result, request->http_code);
402 request->state = ABORTED;
403 aborted = 1;
404 }
405 } else if (request->state == RUN_PUT) {
406 if (request->curl_result == CURLE_OK) {
407 start_move(request);
408 } else {
409 fprintf(stderr, "PUT %s failed, aborting (%d/%ld)\n",
410 sha1_to_hex(request->sha1),
411 request->curl_result, request->http_code);
412 request->state = ABORTED;
413 aborted = 1;
414 }
415 } else if (request->state == RUN_MOVE) {
416 if (request->curl_result == CURLE_OK) {
417 if (push_verbosely)
418 fprintf(stderr,
419 "sent %s\n",
420 sha1_to_hex(request->sha1));
421 request->state = COMPLETE;
422 } else {
423 fprintf(stderr, "MOVE %s failed, aborting (%d/%ld)\n",
424 sha1_to_hex(request->sha1),
425 request->curl_result, request->http_code);
426 request->state = ABORTED;
427 aborted = 1;
428 }
429 }
430}
431
432static void release_request(struct transfer_request *request)
433{
434 struct transfer_request *entry = request_queue_head;
435
436 if (request == request_queue_head) {
437 request_queue_head = request->next;
438 } else {
439 while (entry->next != NULL && entry->next != request)
440 entry = entry->next;
441 if (entry->next == request)
442 entry->next = entry->next->next;
443 }
444
7b899967
NH
445 if (request->url != NULL)
446 free(request->url);
58e60dd2
NH
447 free(request);
448}
449
29508e1e 450void fill_active_slots(void)
58e60dd2
NH
451{
452 struct transfer_request *request = request_queue_head;
453 struct active_request_slot *slot = active_queue_head;
454 int num_transfers;
455
456 if (aborted)
457 return;
458
459 while (active_requests < max_requests && request != NULL) {
460 if (!pushing && request->state == NEED_CHECK) {
461 start_check(request);
462 curl_multi_perform(curlm, &num_transfers);
463 } else if (pushing && request->state == NEED_PUSH) {
0dd276b8
NH
464 if (remote_dir_exists[request->sha1[0]])
465 start_put(request);
466 else
467 start_mkcol(request);
58e60dd2
NH
468 curl_multi_perform(curlm, &num_transfers);
469 }
470 request = request->next;
471 }
472
473 while (slot != NULL) {
474 if (!slot->in_use && slot->curl != NULL) {
475 curl_easy_cleanup(slot->curl);
476 slot->curl = NULL;
477 }
478 slot = slot->next;
479 }
480}
58e60dd2 481
f4f440a0 482static void add_request(unsigned char *sha1, struct active_lock *lock)
58e60dd2
NH
483{
484 struct transfer_request *request = request_queue_head;
58e60dd2
NH
485 struct packed_git *target;
486
487 while (request != NULL && memcmp(request->sha1, sha1, 20))
488 request = request->next;
489 if (request != NULL)
490 return;
491
492 target = find_sha1_pack(sha1, remote->packs);
493 if (target)
494 return;
495
496 request = xmalloc(sizeof(*request));
497 memcpy(request->sha1, sha1, 20);
498 request->url = NULL;
26349b2e 499 request->lock = lock;
58e60dd2
NH
500 request->headers = NULL;
501 request->state = NEED_CHECK;
c17fb6ee
NH
502 request->next = request_queue_head;
503 request_queue_head = request;
29508e1e
NH
504
505 fill_active_slots();
506 step_active_slots();
58e60dd2
NH
507}
508
509static int fetch_index(unsigned char *sha1)
510{
511 char *hex = sha1_to_hex(sha1);
512 char *filename;
513 char *url;
514 char tmpfile[PATH_MAX];
515 long prev_posn = 0;
516 char range[RANGE_HEADER_SIZE];
517 struct curl_slist *range_header = NULL;
518
519 FILE *indexfile;
520 struct active_request_slot *slot;
521
c17fb6ee
NH
522 /* Don't use the index if the pack isn't there */
523 url = xmalloc(strlen(remote->url) + 65);
524 sprintf(url, "%s/objects/pack/pack-%s.pack", remote->url, hex);
525 slot = get_active_slot();
526 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
527 curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1);
528 if (start_active_slot(slot)) {
529 run_active_slot(slot);
530 if (slot->curl_result != CURLE_OK) {
531 free(url);
532 return error("Unable to verify pack %s is available",
533 hex);
534 }
535 } else {
536 return error("Unable to start request");
537 }
538
58e60dd2
NH
539 if (has_pack_index(sha1))
540 return 0;
541
542 if (push_verbosely)
543 fprintf(stderr, "Getting index for pack %s\n", hex);
544
58e60dd2
NH
545 sprintf(url, "%s/objects/pack/pack-%s.idx", remote->url, hex);
546
547 filename = sha1_pack_index_name(sha1);
548 snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
549 indexfile = fopen(tmpfile, "a");
550 if (!indexfile)
551 return error("Unable to open local file %s for pack index",
552 filename);
553
554 slot = get_active_slot();
c17fb6ee
NH
555 curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
556 curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
58e60dd2
NH
557 curl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);
558 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
559 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
560 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
561 slot->local = indexfile;
562
563 /* If there is data present from a previous transfer attempt,
564 resume where it left off */
565 prev_posn = ftell(indexfile);
566 if (prev_posn>0) {
567 if (push_verbosely)
568 fprintf(stderr,
569 "Resuming fetch of index for pack %s at byte %ld\n",
570 hex, prev_posn);
571 sprintf(range, "Range: bytes=%ld-", prev_posn);
572 range_header = curl_slist_append(range_header, range);
573 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);
574 }
575
576 if (start_active_slot(slot)) {
577 run_active_slot(slot);
578 if (slot->curl_result != CURLE_OK) {
579 free(url);
580 fclose(indexfile);
581 return error("Unable to get pack index %s\n%s", url,
582 curl_errorstr);
583 }
584 } else {
585 free(url);
7b899967 586 fclose(indexfile);
58e60dd2
NH
587 return error("Unable to start request");
588 }
589
590 free(url);
591 fclose(indexfile);
592
593 return move_temp_to_file(tmpfile, filename);
594}
595
596static int setup_index(unsigned char *sha1)
597{
598 struct packed_git *new_pack;
58e60dd2
NH
599
600 if (fetch_index(sha1))
601 return -1;
602
603 new_pack = parse_pack_index(sha1);
604 new_pack->next = remote->packs;
605 remote->packs = new_pack;
606 return 0;
607}
608
f4f440a0 609static int fetch_indices(void)
58e60dd2
NH
610{
611 unsigned char sha1[20];
612 char *url;
613 struct buffer buffer;
614 char *data;
615 int i = 0;
616
617 struct active_request_slot *slot;
618
619 data = xmalloc(4096);
620 memset(data, 0, 4096);
621 buffer.size = 4096;
622 buffer.posn = 0;
623 buffer.buffer = data;
624
625 if (push_verbosely)
626 fprintf(stderr, "Getting pack list\n");
627
628 url = xmalloc(strlen(remote->url) + 21);
629 sprintf(url, "%s/objects/info/packs", remote->url);
630
631 slot = get_active_slot();
632 curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
29508e1e 633 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
58e60dd2
NH
634 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
635 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
636 if (start_active_slot(slot)) {
637 run_active_slot(slot);
638 if (slot->curl_result != CURLE_OK) {
639 free(buffer.buffer);
640 free(url);
641 if (slot->http_code == 404)
642 return 0;
643 else
644 return error("%s", curl_errorstr);
645 }
646 } else {
647 free(buffer.buffer);
648 free(url);
649 return error("Unable to start request");
650 }
651 free(url);
652
653 data = buffer.buffer;
654 while (i < buffer.posn) {
655 switch (data[i]) {
656 case 'P':
657 i++;
658 if (i + 52 < buffer.posn &&
659 !strncmp(data + i, " pack-", 6) &&
660 !strncmp(data + i + 46, ".pack\n", 6)) {
661 get_sha1_hex(data + i + 6, sha1);
662 setup_index(sha1);
663 i += 51;
664 break;
665 }
666 default:
667 while (data[i] != '\n')
668 i++;
669 }
670 i++;
671 }
672
673 free(buffer.buffer);
674 return 0;
675}
676
677static inline int needs_quote(int ch)
678{
679 switch (ch) {
680 case '/': case '-': case '.':
681 case 'A'...'Z': case 'a'...'z': case '0'...'9':
682 return 0;
683 default:
684 return 1;
685 }
686}
687
688static inline int hex(int v)
689{
690 if (v < 10) return '0' + v;
691 else return 'A' + v - 10;
692}
693
694static char *quote_ref_url(const char *base, const char *ref)
695{
696 const char *cp;
697 char *dp, *qref;
698 int len, baselen, ch;
699
700 baselen = strlen(base);
701 len = baselen + 12; /* "refs/heads/" + NUL */
702 for (cp = ref; (ch = *cp) != 0; cp++, len++)
703 if (needs_quote(ch))
704 len += 2; /* extra two hex plus replacement % */
705 qref = xmalloc(len);
706 memcpy(qref, base, baselen);
707 memcpy(qref + baselen, "refs/heads/", 11);
708 for (cp = ref, dp = qref + baselen + 11; (ch = *cp) != 0; cp++) {
709 if (needs_quote(ch)) {
710 *dp++ = '%';
711 *dp++ = hex((ch >> 4) & 0xF);
712 *dp++ = hex(ch & 0xF);
713 }
714 else
715 *dp++ = ch;
716 }
717 *dp = 0;
718
719 return qref;
720}
721
722int fetch_ref(char *ref, unsigned char *sha1)
723{
724 char *url;
725 char hex[42];
726 struct buffer buffer;
727 char *base = remote->url;
728 struct active_request_slot *slot;
729 buffer.size = 41;
730 buffer.posn = 0;
731 buffer.buffer = hex;
732 hex[41] = '\0';
733
734 url = quote_ref_url(base, ref);
735 slot = get_active_slot();
736 curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
29508e1e 737 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
58e60dd2
NH
738 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
739 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
740 if (start_active_slot(slot)) {
741 run_active_slot(slot);
742 if (slot->curl_result != CURLE_OK)
743 return error("Couldn't get %s for %s\n%s",
744 url, ref, curl_errorstr);
745 } else {
746 return error("Unable to start request");
747 }
748
749 hex[40] = '\0';
750 get_sha1_hex(hex, sha1);
751 return 0;
752}
753
acf59575 754static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed)
26349b2e 755{
acf59575
NH
756 int *lock_flags = (int *)ctx->userData;
757
758 if (tag_closed) {
759 if (!strcmp(ctx->name, DAV_CTX_LOCKENTRY)) {
760 if ((*lock_flags & DAV_PROP_LOCKEX) &&
761 (*lock_flags & DAV_PROP_LOCKWR)) {
762 *lock_flags |= DAV_LOCK_OK;
763 }
764 *lock_flags &= DAV_LOCK_OK;
765 } else if (!strcmp(ctx->name, DAV_CTX_LOCKTYPE_WRITE)) {
766 *lock_flags |= DAV_PROP_LOCKWR;
767 } else if (!strcmp(ctx->name, DAV_CTX_LOCKTYPE_EXCLUSIVE)) {
768 *lock_flags |= DAV_PROP_LOCKEX;
769 }
770 }
26349b2e
NH
771}
772
acf59575 773static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
26349b2e 774{
acf59575
NH
775 struct active_lock *lock = (struct active_lock *)ctx->userData;
776
777 if (tag_closed && ctx->cdata) {
778 if (!strcmp(ctx->name, DAV_ACTIVELOCK_OWNER)) {
779 lock->owner = xmalloc(strlen(ctx->cdata) + 1);
780 strcpy(lock->owner, ctx->cdata);
781 } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) {
782 if (!strncmp(ctx->cdata, "Second-", 7))
783 lock->timeout =
784 strtol(ctx->cdata + 7, NULL, 10);
785 } else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
786 if (!strncmp(ctx->cdata, "opaquelocktoken:", 16)) {
787 lock->token = xmalloc(strlen(ctx->cdata - 15));
788 strcpy(lock->token, ctx->cdata + 16);
789 }
790 }
26349b2e
NH
791 }
792}
793
794static void
acf59575 795xml_start_tag(void *userData, const char *name, const char **atts)
26349b2e 796{
acf59575
NH
797 struct xml_ctx *ctx = (struct xml_ctx *)userData;
798 const char *c = index(name, ':');
799 int new_len;
800
801 if (c == NULL)
802 c = name;
803 else
804 c++;
805
806 new_len = strlen(ctx->name) + strlen(c) + 2;
807
808 if (new_len > ctx->len) {
809 ctx->name = xrealloc(ctx->name, new_len);
810 ctx->len = new_len;
26349b2e 811 }
acf59575
NH
812 strcat(ctx->name, ".");
813 strcat(ctx->name, c);
26349b2e 814
acf59575
NH
815 if (ctx->cdata) {
816 free(ctx->cdata);
817 ctx->cdata = NULL;
818 }
819
820 ctx->userFunc(ctx, 0);
26349b2e
NH
821}
822
58e60dd2 823static void
acf59575 824xml_end_tag(void *userData, const char *name)
58e60dd2 825{
acf59575
NH
826 struct xml_ctx *ctx = (struct xml_ctx *)userData;
827 const char *c = index(name, ':');
828 char *ep;
58e60dd2 829
acf59575
NH
830 ctx->userFunc(ctx, 1);
831
832 if (c == NULL)
833 c = name;
834 else
835 c++;
836
837 ep = ctx->name + strlen(ctx->name) - strlen(c) - 1;
838 *ep = 0;
58e60dd2
NH
839}
840
841static void
acf59575 842xml_cdata(void *userData, const XML_Char *s, int len)
58e60dd2 843{
acf59575
NH
844 struct xml_ctx *ctx = (struct xml_ctx *)userData;
845 if (ctx->cdata)
846 free(ctx->cdata);
847 ctx->cdata = xcalloc(len+1, 1);
848 strncpy(ctx->cdata, s, len);
58e60dd2
NH
849}
850
f4f440a0 851static struct active_lock *lock_remote(char *file, long timeout)
58e60dd2
NH
852{
853 struct active_request_slot *slot;
854 struct buffer out_buffer;
26349b2e 855 struct buffer in_buffer;
58e60dd2 856 char *out_data;
26349b2e 857 char *in_data;
58e60dd2 858 char *url;
0772b9a6 859 char *ep;
58e60dd2 860 char timeout_header[25];
acf59575 861 struct active_lock *new_lock = NULL;
26349b2e
NH
862 XML_Parser parser = XML_ParserCreate(NULL);
863 enum XML_Status result;
58e60dd2 864 struct curl_slist *dav_headers = NULL;
acf59575 865 struct xml_ctx ctx;
58e60dd2 866
0772b9a6
NH
867 url = xmalloc(strlen(remote->url) + strlen(file) + 1);
868 sprintf(url, "%s%s", remote->url, file);
869
870 /* Make sure leading directories exist for the remote ref */
871 ep = strchr(url + strlen(remote->url) + 11, '/');
872 while (ep) {
873 *ep = 0;
874 slot = get_active_slot();
875 curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
876 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
877 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MKCOL);
878 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
879 if (start_active_slot(slot)) {
880 run_active_slot(slot);
881 if (slot->curl_result != CURLE_OK &&
882 slot->http_code != 405) {
883 fprintf(stderr,
884 "Unable to create branch path %s\n",
885 url);
886 free(url);
887 return NULL;
888 }
889 } else {
890 fprintf(stderr, "Unable to start request\n");
891 free(url);
892 return NULL;
893 }
894 *ep = '/';
895 ep = strchr(ep + 1, '/');
896 }
897
58e60dd2
NH
898 out_buffer.size = strlen(LOCK_REQUEST) + strlen(git_default_email) - 2;
899 out_data = xmalloc(out_buffer.size + 1);
900 snprintf(out_data, out_buffer.size + 1, LOCK_REQUEST, git_default_email);
901 out_buffer.posn = 0;
902 out_buffer.buffer = out_data;
903
26349b2e
NH
904 in_buffer.size = 4096;
905 in_data = xmalloc(in_buffer.size);
906 in_buffer.posn = 0;
907 in_buffer.buffer = in_data;
908
75187c9d 909 sprintf(timeout_header, "Timeout: Second-%ld", timeout);
58e60dd2
NH
910 dav_headers = curl_slist_append(dav_headers, timeout_header);
911 dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
912
913 slot = get_active_slot();
914 curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
915 curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
916 curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
26349b2e 917 curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
29508e1e 918 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
58e60dd2
NH
919 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
920 curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
921 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);
922 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
923
acf59575
NH
924 new_lock = xcalloc(1, sizeof(*new_lock));
925 new_lock->owner = NULL;
926 new_lock->token = NULL;
927 new_lock->timeout = -1;
928 new_lock->refreshing = 0;
929
58e60dd2
NH
930 if (start_active_slot(slot)) {
931 run_active_slot(slot);
acf59575
NH
932 if (slot->curl_result == CURLE_OK) {
933 ctx.name = xcalloc(10, 1);
934 ctx.len = 0;
935 ctx.cdata = NULL;
936 ctx.userFunc = handle_new_lock_ctx;
937 ctx.userData = new_lock;
938 XML_SetUserData(parser, &ctx);
939 XML_SetElementHandler(parser, xml_start_tag,
940 xml_end_tag);
941 XML_SetCharacterDataHandler(parser, xml_cdata);
942 result = XML_Parse(parser, in_buffer.buffer,
943 in_buffer.posn, 1);
944 free(ctx.name);
945 if (result != XML_STATUS_OK) {
946 fprintf(stderr, "XML error: %s\n",
947 XML_ErrorString(
948 XML_GetErrorCode(parser)));
949 new_lock->timeout = -1;
950 }
58e60dd2
NH
951 }
952 } else {
58e60dd2
NH
953 fprintf(stderr, "Unable to start request\n");
954 }
955
acf59575 956 curl_slist_free_all(dav_headers);
0772b9a6 957 free(out_data);
26349b2e 958 free(in_data);
26349b2e
NH
959
960 if (new_lock->token == NULL || new_lock->timeout <= 0) {
961 if (new_lock->token != NULL)
962 free(new_lock->token);
963 if (new_lock->owner != NULL)
964 free(new_lock->owner);
75187c9d 965 free(url);
26349b2e 966 free(new_lock);
acf59575
NH
967 new_lock = NULL;
968 } else {
969 new_lock->url = url;
970 new_lock->start_time = time(NULL);
26349b2e
NH
971 }
972
26349b2e 973 return new_lock;
58e60dd2
NH
974}
975
f4f440a0 976static int unlock_remote(struct active_lock *lock)
58e60dd2
NH
977{
978 struct active_request_slot *slot;
58e60dd2
NH
979 char *lock_token_header;
980 struct curl_slist *dav_headers = NULL;
981 int rc = 0;
982
26349b2e 983 lock_token_header = xmalloc(strlen(lock->token) + 31);
58e60dd2 984 sprintf(lock_token_header, "Lock-Token: <opaquelocktoken:%s>",
26349b2e 985 lock->token);
58e60dd2
NH
986 dav_headers = curl_slist_append(dav_headers, lock_token_header);
987
988 slot = get_active_slot();
989 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
75187c9d 990 curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
58e60dd2
NH
991 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_UNLOCK);
992 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
993
994 if (start_active_slot(slot)) {
995 run_active_slot(slot);
996 if (slot->curl_result == CURLE_OK)
997 rc = 1;
998 else
999 fprintf(stderr, "Got HTTP error %ld\n",
1000 slot->http_code);
1001 } else {
1002 fprintf(stderr, "Unable to start request\n");
1003 }
1004
1005 curl_slist_free_all(dav_headers);
1006 free(lock_token_header);
75187c9d
NH
1007
1008 if (lock->owner != NULL)
1009 free(lock->owner);
1010 free(lock->url);
acf59575 1011/* Freeing the token causes a segfault...
75187c9d 1012 free(lock->token);
acf59575 1013*/
75187c9d 1014 free(lock);
58e60dd2
NH
1015
1016 return rc;
1017}
1018
acf59575 1019static int locking_available(void)
58e60dd2
NH
1020{
1021 struct active_request_slot *slot;
1022 struct buffer in_buffer;
1023 struct buffer out_buffer;
1024 char *in_data;
1025 char *out_data;
1026 XML_Parser parser = XML_ParserCreate(NULL);
1027 enum XML_Status result;
58e60dd2 1028 struct curl_slist *dav_headers = NULL;
acf59575
NH
1029 struct xml_ctx ctx;
1030 int lock_flags = 0;
58e60dd2
NH
1031
1032 out_buffer.size = strlen(PROPFIND_REQUEST) + strlen(remote->url) - 2;
1033 out_data = xmalloc(out_buffer.size + 1);
1034 snprintf(out_data, out_buffer.size + 1, PROPFIND_REQUEST, remote->url);
1035 out_buffer.posn = 0;
1036 out_buffer.buffer = out_data;
1037
1038 in_buffer.size = 4096;
1039 in_data = xmalloc(in_buffer.size);
1040 in_buffer.posn = 0;
1041 in_buffer.buffer = in_data;
1042
1043 dav_headers = curl_slist_append(dav_headers, "Depth: 0");
1044 dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
1045
1046 slot = get_active_slot();
1047 curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
1048 curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
1049 curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1050 curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
29508e1e 1051 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
58e60dd2
NH
1052 curl_easy_setopt(slot->curl, CURLOPT_URL, remote->url);
1053 curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
1054 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND);
1055 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1056
1057 if (start_active_slot(slot)) {
1058 run_active_slot(slot);
acf59575
NH
1059 if (slot->curl_result == CURLE_OK) {
1060 ctx.name = xcalloc(10, 1);
1061 ctx.len = 0;
1062 ctx.cdata = NULL;
1063 ctx.userFunc = handle_lockprop_ctx;
1064 ctx.userData = &lock_flags;
1065 XML_SetUserData(parser, &ctx);
1066 XML_SetElementHandler(parser, xml_start_tag,
1067 xml_end_tag);
1068 result = XML_Parse(parser, in_buffer.buffer,
1069 in_buffer.posn, 1);
1070 free(ctx.name);
1071
1072 if (result != XML_STATUS_OK) {
1073 fprintf(stderr, "XML error: %s\n",
1074 XML_ErrorString(
1075 XML_GetErrorCode(parser)));
1076 lock_flags = 0;
1077 }
58e60dd2 1078 }
58e60dd2 1079 } else {
acf59575 1080 fprintf(stderr, "Unable to start request\n");
58e60dd2
NH
1081 }
1082
acf59575
NH
1083 free(out_data);
1084 free(in_buffer.buffer);
1085 curl_slist_free_all(dav_headers);
1086
1087 return lock_flags;
58e60dd2
NH
1088}
1089
f4f440a0 1090static int is_ancestor(unsigned char *sha1, struct commit *commit)
58e60dd2
NH
1091{
1092 struct commit_list *parents;
1093
1094 if (parse_commit(commit))
1095 return 0;
1096 parents = commit->parents;
1097 for (; parents; parents = parents->next) {
1098 if (!memcmp(sha1, parents->item->object.sha1, 20)) {
1099 return 1;
1100 } else if (parents->item->object.type == commit_type) {
1101 if (is_ancestor(
1102 sha1,
1103 (struct commit *)&parents->item->object
1104 ))
1105 return 1;
1106 }
1107 }
1108 return 0;
1109}
1110
f4f440a0
PH
1111static void get_delta(unsigned char *sha1, struct object *obj,
1112 struct active_lock *lock)
58e60dd2
NH
1113{
1114 struct commit *commit;
1115 struct commit_list *parents;
1116 struct tree *tree;
1117 struct tree_entry_list *entry;
1118
1119 if (sha1 && !memcmp(sha1, obj->sha1, 20))
1120 return;
1121
1122 if (aborted)
1123 return;
1124
1125 if (obj->type == commit_type) {
1126 if (push_verbosely)
1127 fprintf(stderr, "walk %s\n", sha1_to_hex(obj->sha1));
26349b2e 1128 add_request(obj->sha1, lock);
58e60dd2
NH
1129 commit = (struct commit *)obj;
1130 if (parse_commit(commit)) {
1131 fprintf(stderr, "Error parsing commit %s\n",
1132 sha1_to_hex(obj->sha1));
1133 aborted = 1;
1134 return;
1135 }
1136 parents = commit->parents;
1137 for (; parents; parents = parents->next)
1138 if (sha1 == NULL ||
1139 memcmp(sha1, parents->item->object.sha1, 20))
1140 get_delta(sha1, &parents->item->object,
26349b2e
NH
1141 lock);
1142 get_delta(sha1, &commit->tree->object, lock);
58e60dd2
NH
1143 } else if (obj->type == tree_type) {
1144 if (push_verbosely)
1145 fprintf(stderr, "walk %s\n", sha1_to_hex(obj->sha1));
26349b2e 1146 add_request(obj->sha1, lock);
58e60dd2
NH
1147 tree = (struct tree *)obj;
1148 if (parse_tree(tree)) {
1149 fprintf(stderr, "Error parsing tree %s\n",
1150 sha1_to_hex(obj->sha1));
1151 aborted = 1;
1152 return;
1153 }
1154 entry = tree->entries;
1155 tree->entries = NULL;
1156 while (entry) {
1157 struct tree_entry_list *next = entry->next;
26349b2e 1158 get_delta(sha1, entry->item.any, lock);
58e60dd2
NH
1159 free(entry->name);
1160 free(entry);
1161 entry = next;
1162 }
1163 } else if (obj->type == blob_type || obj->type == tag_type) {
26349b2e 1164 add_request(obj->sha1, lock);
58e60dd2
NH
1165 }
1166}
1167
f4f440a0 1168static int update_remote(unsigned char *sha1, struct active_lock *lock)
58e60dd2
NH
1169{
1170 struct active_request_slot *slot;
58e60dd2
NH
1171 char *out_data;
1172 char *if_header;
1173 struct buffer out_buffer;
1174 struct curl_slist *dav_headers = NULL;
1175 int i;
1176
26349b2e
NH
1177 if_header = xmalloc(strlen(lock->token) + 25);
1178 sprintf(if_header, "If: (<opaquelocktoken:%s>)", lock->token);
58e60dd2
NH
1179 dav_headers = curl_slist_append(dav_headers, if_header);
1180
1181 out_buffer.size = 41;
1182 out_data = xmalloc(out_buffer.size + 1);
1183 i = snprintf(out_data, out_buffer.size + 1, "%s\n", sha1_to_hex(sha1));
1184 if (i != out_buffer.size) {
1185 fprintf(stderr, "Unable to initialize PUT request body\n");
1186 return 0;
1187 }
1188 out_buffer.posn = 0;
1189 out_buffer.buffer = out_data;
1190
1191 slot = get_active_slot();
1192 curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
1193 curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.size);
1194 curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1195 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
1196 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
1197 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1198 curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
1199 curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
75187c9d 1200 curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
58e60dd2
NH
1201
1202 if (start_active_slot(slot)) {
1203 run_active_slot(slot);
1204 free(out_data);
1205 free(if_header);
58e60dd2
NH
1206 if (slot->curl_result != CURLE_OK) {
1207 fprintf(stderr,
1208 "PUT error: curl result=%d, HTTP code=%ld\n",
1209 slot->curl_result, slot->http_code);
1210 /* We should attempt recovery? */
1211 return 0;
1212 }
1213 } else {
1214 free(out_data);
1215 free(if_header);
58e60dd2
NH
1216 fprintf(stderr, "Unable to start PUT request\n");
1217 return 0;
1218 }
1219
1220 return 1;
1221}
1222
1223int main(int argc, char **argv)
1224{
58e60dd2
NH
1225 struct transfer_request *request;
1226 struct transfer_request *next_request;
1227 int nr_refspec = 0;
1228 char **refspec = NULL;
1229 int do_remote_update;
1230 int new_branch;
1231 int force_this;
1232 char *local_ref;
1233 unsigned char local_sha1[20];
1234 struct object *local_object = NULL;
1235 char *remote_ref = NULL;
1236 unsigned char remote_sha1[20];
26349b2e 1237 struct active_lock *remote_lock;
58e60dd2 1238 char *remote_path = NULL;
58e60dd2
NH
1239 int rc = 0;
1240 int i;
1241
1242 setup_ident();
1243
1244 remote = xmalloc(sizeof(*remote));
1245 remote->url = NULL;
1246 remote->packs = NULL;
1247
1248 argv++;
1249 for (i = 1; i < argc; i++, argv++) {
1250 char *arg = *argv;
1251
1252 if (*arg == '-') {
1253 if (!strcmp(arg, "--complete")) {
1254 push_all = 1;
1255 continue;
1256 }
1257 if (!strcmp(arg, "--force")) {
1258 force_all = 1;
1259 continue;
1260 }
1261 if (!strcmp(arg, "--verbose")) {
1262 push_verbosely = 1;
1263 continue;
1264 }
1265 usage(http_push_usage);
1266 }
1267 if (!remote->url) {
1268 remote->url = arg;
1269 continue;
1270 }
1271 refspec = argv;
1272 nr_refspec = argc - i;
1273 break;
1274 }
1275
0dd276b8
NH
1276 memset(remote_dir_exists, 0, 256);
1277
29508e1e 1278 http_init();
58e60dd2
NH
1279
1280 no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
1281 default_headers = curl_slist_append(default_headers, "Range:");
1282 default_headers = curl_slist_append(default_headers, "Destination:");
1283 default_headers = curl_slist_append(default_headers, "If:");
1284 default_headers = curl_slist_append(default_headers,
1285 "Pragma: no-cache");
1286
58e60dd2 1287 /* Verify DAV compliance/lock support */
acf59575 1288 if (!locking_available()) {
58e60dd2
NH
1289 fprintf(stderr, "Error: no DAV locking support on remote repo %s\n", remote->url);
1290 rc = 1;
1291 goto cleanup;
1292 }
1293
1294 /* Process each refspec */
1295 for (i = 0; i < nr_refspec; i++) {
1296 char *ep;
1297 force_this = 0;
1298 do_remote_update = 0;
1299 new_branch = 0;
1300 local_ref = refspec[i];
1301 if (*local_ref == '+') {
1302 force_this = 1;
1303 local_ref++;
1304 }
1305 ep = strchr(local_ref, ':');
1306 if (ep) {
1307 remote_ref = ep + 1;
1308 *ep = 0;
1309 }
1310 else
1311 remote_ref = local_ref;
1312
1313 /* Lock remote branch ref */
1314 if (remote_path)
1315 free(remote_path);
1316 remote_path = xmalloc(strlen(remote_ref) + 12);
1317 sprintf(remote_path, "refs/heads/%s", remote_ref);
75187c9d 1318 remote_lock = lock_remote(remote_path, LOCK_TIME);
58e60dd2
NH
1319 if (remote_lock == NULL) {
1320 fprintf(stderr, "Unable to lock remote branch %s\n",
1321 remote_ref);
1322 rc = 1;
1323 continue;
1324 }
1325
1326 /* Resolve local and remote refs */
1327 if (fetch_ref(remote_ref, remote_sha1) != 0) {
1328 fprintf(stderr,
1329 "Remote branch %s does not exist on %s\n",
1330 remote_ref, remote->url);
1331 new_branch = 1;
1332 }
1333 if (get_sha1(local_ref, local_sha1) != 0) {
1334 fprintf(stderr, "Error resolving local branch %s\n",
1335 local_ref);
1336 rc = 1;
1337 goto unlock;
1338 }
1339
1340 /* Find relationship between local and remote */
1341 local_object = parse_object(local_sha1);
1342 if (!local_object) {
1343 fprintf(stderr, "Unable to parse local object %s\n",
1344 sha1_to_hex(local_sha1));
1345 rc = 1;
1346 goto unlock;
1347 } else if (new_branch) {
1348 do_remote_update = 1;
1349 } else {
1350 if (!memcmp(local_sha1, remote_sha1, 20)) {
1351 fprintf(stderr,
1352 "* %s: same as branch '%s' of %s\n",
1353 local_ref, remote_ref, remote->url);
1354 } else if (is_ancestor(remote_sha1,
1355 (struct commit *)local_object)) {
1356 fprintf(stderr,
1357 "Remote %s will fast-forward to local %s\n",
1358 remote_ref, local_ref);
1359 do_remote_update = 1;
1360 } else if (force_all || force_this) {
1361 fprintf(stderr,
1362 "* %s on %s does not fast forward to local branch '%s', overwriting\n",
1363 remote_ref, remote->url, local_ref);
1364 do_remote_update = 1;
1365 } else {
1366 fprintf(stderr,
1367 "* %s on %s does not fast forward to local branch '%s'\n",
1368 remote_ref, remote->url, local_ref);
1369 rc = 1;
1370 goto unlock;
1371 }
1372 }
1373
1374 /* Generate and check list of required objects */
1375 pushing = 0;
1376 if (do_remote_update || push_all)
1377 fetch_indices();
1378 get_delta(push_all ? NULL : remote_sha1,
1379 local_object, remote_lock);
29508e1e 1380 finish_all_active_slots();
58e60dd2
NH
1381
1382 /* Push missing objects to remote, this would be a
1383 convenient time to pack them first if appropriate. */
1384 pushing = 1;
29508e1e
NH
1385 fill_active_slots();
1386 finish_all_active_slots();
58e60dd2
NH
1387
1388 /* Update the remote branch if all went well */
1389 if (do_remote_update) {
75187c9d 1390 if (!aborted && update_remote(local_sha1,
58e60dd2
NH
1391 remote_lock)) {
1392 fprintf(stderr, "%s remote branch %s\n",
1393 new_branch ? "Created" : "Updated",
1394 remote_ref);
1395 } else {
1396 fprintf(stderr,
1397 "Unable to %s remote branch %s\n",
1398 new_branch ? "create" : "update",
1399 remote_ref);
1400 rc = 1;
1401 goto unlock;
1402 }
1403 }
1404
1405 unlock:
75187c9d 1406 unlock_remote(remote_lock);
58e60dd2 1407 free(remote_path);
58e60dd2
NH
1408 }
1409
1410 cleanup:
1411 free(remote);
1412
1413 curl_slist_free_all(no_pragma_header);
1414 curl_slist_free_all(default_headers);
1415
29508e1e 1416 http_cleanup();
58e60dd2
NH
1417
1418 request = request_queue_head;
1419 while (request != NULL) {
1420 next_request = request->next;
1421 release_request(request);
58e60dd2
NH
1422 request = next_request;
1423 }
1424
58e60dd2
NH
1425 return rc;
1426}