http-push.c 50.5 KB
Newer Older
1 2 3 4
#include "cache.h"
#include "commit.h"
#include "tag.h"
#include "blob.h"
5
#include "http.h"
N
Nick Hengeveld 已提交
6
#include "refs.h"
7
#include "diff.h"
N
Nick Hengeveld 已提交
8
#include "revision.h"
9
#include "exec_cmd.h"
10
#include "remote.h"
11
#include "list-objects.h"
12
#include "sigchain.h"
13

M
Matt Kraai 已提交
14 15 16
#ifdef EXPAT_NEEDS_XMLPARSE_H
#include <xmlparse.h>
#else
17
#include <expat.h>
M
Matt Kraai 已提交
18
#endif
19 20

static const char http_push_usage[] =
S
Stephan Beyer 已提交
21
"git http-push [--all] [--dry-run] [--force] [--verbose] <remote> [<head>...]\n";
22

23 24 25 26 27 28 29 30 31
#ifndef XML_STATUS_OK
enum XML_Status {
  XML_STATUS_OK = 1,
  XML_STATUS_ERROR = 0
};
#define XML_STATUS_OK    1
#define XML_STATUS_ERROR 0
#endif

32
#define PREV_BUF_SIZE 4096
33

N
Nick Hengeveld 已提交
34
/* DAV methods */
35 36 37 38 39 40
#define DAV_LOCK "LOCK"
#define DAV_MKCOL "MKCOL"
#define DAV_MOVE "MOVE"
#define DAV_PROPFIND "PROPFIND"
#define DAV_PUT "PUT"
#define DAV_UNLOCK "UNLOCK"
41
#define DAV_DELETE "DELETE"
N
Nick Hengeveld 已提交
42 43 44 45 46 47 48 49 50 51 52 53 54

/* DAV lock flags */
#define DAV_PROP_LOCKWR (1u << 0)
#define DAV_PROP_LOCKEX (1u << 1)
#define DAV_LOCK_OK (1u << 2)

/* DAV XML properties */
#define DAV_CTX_LOCKENTRY ".multistatus.response.propstat.prop.supportedlock.lockentry"
#define DAV_CTX_LOCKTYPE_WRITE ".multistatus.response.propstat.prop.supportedlock.lockentry.locktype.write"
#define DAV_CTX_LOCKTYPE_EXCLUSIVE ".multistatus.response.propstat.prop.supportedlock.lockentry.lockscope.exclusive"
#define DAV_ACTIVELOCK_OWNER ".prop.lockdiscovery.activelock.owner.href"
#define DAV_ACTIVELOCK_TIMEOUT ".prop.lockdiscovery.activelock.timeout"
#define DAV_ACTIVELOCK_TOKEN ".prop.lockdiscovery.activelock.locktoken.href"
N
Nick Hengeveld 已提交
55 56 57
#define DAV_PROPFIND_RESP ".multistatus.response"
#define DAV_PROPFIND_NAME ".multistatus.response.href"
#define DAV_PROPFIND_COLLECTION ".multistatus.response.propstat.prop.resourcetype.collection"
N
Nick Hengeveld 已提交
58 59

/* DAV request body templates */
N
Nick Hengeveld 已提交
60 61
#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>"
#define PROPFIND_ALL_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:propfind xmlns:D=\"DAV:\">\n<D:allprop/>\n</D:propfind>"
62 63
#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>"

64 65 66
#define LOCK_TIME 600
#define LOCK_REFRESH 30

67
/* Remember to update object flag allocation in object.h */
68 69 70 71
#define LOCAL    (1u<<16)
#define REMOTE   (1u<<17)
#define FETCHING (1u<<18)
#define PUSHING  (1u<<19)
N
Nick Hengeveld 已提交
72

73 74 75
/* We allow "recursive" symbolic refs. Only within reason, though */
#define MAXDEPTH 5

76 77
static int pushing;
static int aborted;
78
static signed char remote_dir_exists[256];
79

80
static int push_verbosely;
A
Andy Whitcroft 已提交
81
static int push_all = MATCH_REFS_NONE;
82
static int force_all;
83
static int dry_run;
84
static int helper_status;
85

86
static struct object_list *objects;
N
Nick Hengeveld 已提交
87

88
struct repo {
89
	char *url;
90
	char *path;
N
Nick Hengeveld 已提交
91
	int path_len;
92 93 94
	int has_info_refs;
	int can_update_info_refs;
	int has_info_packs;
95
	struct packed_git *packs;
96
	struct remote_lock *locks;
97 98
};

99
static struct repo *repo;
100 101

enum transfer_state {
102 103 104
	NEED_FETCH,
	RUN_FETCH_LOOSE,
	RUN_FETCH_PACKED,
105 106 107 108 109
	NEED_PUSH,
	RUN_MKCOL,
	RUN_PUT,
	RUN_MOVE,
	ABORTED,
110
	COMPLETE
111 112
};

113
struct transfer_request {
N
Nick Hengeveld 已提交
114
	struct object *obj;
115 116
	char *url;
	char *dest;
N
Nick Hengeveld 已提交
117
	struct remote_lock *lock;
118 119 120 121 122 123
	struct curl_slist *headers;
	struct buffer buffer;
	enum transfer_state state;
	CURLcode curl_result;
	char errorstr[CURL_ERROR_SIZE];
	long http_code;
124
	void *userData;
125 126 127 128
	struct active_request_slot *slot;
	struct transfer_request *next;
};

129
static struct transfer_request *request_queue_head;
130

131
struct xml_ctx {
N
Nick Hengeveld 已提交
132 133 134 135 136 137 138
	char *name;
	int len;
	char *cdata;
	void (*userFunc)(struct xml_ctx *ctx, int tag_closed);
	void *userData;
};

139
struct remote_lock {
140
	char *url;
N
Nick Hengeveld 已提交
141
	char *owner;
142
	char *token;
143
	char tmpfile_suffix[41];
N
Nick Hengeveld 已提交
144 145
	time_t start_time;
	long timeout;
146
	int refreshing;
N
Nick Hengeveld 已提交
147 148 149
	struct remote_lock *next;
};

150 151 152 153 154 155 156 157
/* Flags that control remote_ls processing */
#define PROCESS_FILES (1u << 0)
#define PROCESS_DIRS  (1u << 1)
#define RECURSIVE     (1u << 2)

/* Flags that remote_ls passes to callback functions */
#define IS_DIR (1u << 0)

158
struct remote_ls_ctx {
159 160 161 162 163 164 165
	char *path;
	void (*userFunc)(struct remote_ls_ctx *ls);
	void *userData;
	int flags;
	char *dentry_name;
	int dentry_flags;
	struct remote_ls_ctx *parent;
N
Nick Hengeveld 已提交
166 167
};

168 169 170 171 172 173 174
/* get_dav_token_headers options */
enum dav_header_flag {
	DAV_HEADER_IF = (1u << 0),
	DAV_HEADER_LOCK = (1u << 1),
	DAV_HEADER_TIMEOUT = (1u << 2)
};

175
static char *xml_entities(const char *s)
176 177
{
	struct strbuf buf = STRBUF_INIT;
178
	strbuf_addstr_xml_quoted(&buf, s);
179 180 181
	return strbuf_detach(&buf, NULL);
}

182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
static void curl_setup_http_get(CURL *curl, const char *url,
		const char *custom_req)
{
	curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
	curl_easy_setopt(curl, CURLOPT_URL, url);
	curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, custom_req);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite_null);
}

static void curl_setup_http(CURL *curl, const char *url,
		const char *custom_req, struct buffer *buffer,
		curl_write_callback write_fn)
{
	curl_easy_setopt(curl, CURLOPT_PUT, 1);
	curl_easy_setopt(curl, CURLOPT_URL, url);
	curl_easy_setopt(curl, CURLOPT_INFILE, buffer);
	curl_easy_setopt(curl, CURLOPT_INFILESIZE, buffer->buf.len);
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
#ifndef NO_CURL_IOCTL
	curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);
	curl_easy_setopt(curl, CURLOPT_IOCTLDATA, &buffer);
#endif
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_fn);
	curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
	curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, custom_req);
	curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
}

J
Junio C Hamano 已提交
210 211
static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum dav_header_flag options)
{
212 213 214
	struct strbuf buf = STRBUF_INIT;
	struct curl_slist *dav_headers = NULL;

J
Junio C Hamano 已提交
215
	if (options & DAV_HEADER_IF) {
216 217 218 219
		strbuf_addf(&buf, "If: (<%s>)", lock->token);
		dav_headers = curl_slist_append(dav_headers, buf.buf);
		strbuf_reset(&buf);
	}
J
Junio C Hamano 已提交
220
	if (options & DAV_HEADER_LOCK) {
221 222 223 224
		strbuf_addf(&buf, "Lock-Token: <%s>", lock->token);
		dav_headers = curl_slist_append(dav_headers, buf.buf);
		strbuf_reset(&buf);
	}
J
Junio C Hamano 已提交
225
	if (options & DAV_HEADER_TIMEOUT) {
226 227 228 229 230 231 232 233 234
		strbuf_addf(&buf, "Timeout: Second-%ld", lock->timeout);
		dav_headers = curl_slist_append(dav_headers, buf.buf);
		strbuf_reset(&buf);
	}
	strbuf_release(&buf);

	return dav_headers;
}

235
static void finish_request(struct transfer_request *request);
236
static void release_request(struct transfer_request *request);
237

238
static void process_response(void *callback_data)
239
{
240 241
	struct transfer_request *request =
		(struct transfer_request *)callback_data;
242

243
	finish_request(request);
244 245
}

J
Junio C Hamano 已提交
246
#ifdef USE_CURL_MULTI
247

248 249 250
static void start_fetch_loose(struct transfer_request *request)
{
	struct active_request_slot *slot;
251
	struct http_object_request *obj_req;
252

253 254
	obj_req = new_http_object_request(repo->url, request->obj->sha1);
	if (obj_req == NULL) {
255 256 257 258
		request->state = ABORTED;
		return;
	}

259
	slot = obj_req->slot;
260 261 262
	slot->callback_func = process_response;
	slot->callback_data = request;
	request->slot = slot;
263
	request->userData = obj_req;
264 265 266 267 268

	/* Try to get the request started, abort the request on error */
	request->state = RUN_FETCH_LOOSE;
	if (!start_active_slot(slot)) {
		fprintf(stderr, "Unable to start GET request\n");
269
		repo->can_update_info_refs = 0;
270
		release_http_object_request(obj_req);
271 272 273 274
		release_request(request);
	}
}

J
Junio C Hamano 已提交
275 276 277 278 279
static void start_mkcol(struct transfer_request *request)
{
	char *hex = sha1_to_hex(request->obj->sha1);
	struct active_request_slot *slot;

280
	request->url = get_remote_object_url(repo->url, hex, 1);
J
Junio C Hamano 已提交
281 282 283 284

	slot = get_active_slot();
	slot->callback_func = process_response;
	slot->callback_data = request;
285
	curl_setup_http_get(slot->curl, request->url, DAV_MKCOL);
J
Junio C Hamano 已提交
286 287 288 289 290 291 292 293 294 295 296 297 298
	curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);

	if (start_active_slot(slot)) {
		request->slot = slot;
		request->state = RUN_MKCOL;
	} else {
		request->state = ABORTED;
		free(request->url);
		request->url = NULL;
	}
}
#endif

299 300 301 302 303
static void start_fetch_packed(struct transfer_request *request)
{
	struct packed_git *target;

	struct transfer_request *check_request = request_queue_head;
304
	struct http_pack_request *preq;
305

306
	target = find_sha1_pack(request->obj->sha1, repo->packs);
307 308
	if (!target) {
		fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", sha1_to_hex(request->obj->sha1));
309
		repo->can_update_info_refs = 0;
310 311 312 313 314 315 316
		release_request(request);
		return;
	}

	fprintf(stderr,	"Fetching pack %s\n", sha1_to_hex(target->sha1));
	fprintf(stderr, " which contains %s\n", sha1_to_hex(request->obj->sha1));

317 318 319 320 321 322 323
	preq = new_http_pack_request(target, repo->url);
	if (preq == NULL) {
		release_http_pack_request(preq);
		repo->can_update_info_refs = 0;
		return;
	}
	preq->lst = &repo->packs;
324 325 326 327

	/* Make sure there isn't another open request for this pack */
	while (check_request) {
		if (check_request->state == RUN_FETCH_PACKED &&
328 329
		    !strcmp(check_request->url, preq->url)) {
			release_http_pack_request(preq);
330 331 332 333 334 335
			release_request(request);
			return;
		}
		check_request = check_request->next;
	}

336 337 338 339
	preq->slot->callback_func = process_response;
	preq->slot->callback_data = request;
	request->slot = preq->slot;
	request->userData = preq;
340 341 342

	/* Try to get the request started, abort the request on error */
	request->state = RUN_FETCH_PACKED;
343
	if (!start_active_slot(preq->slot)) {
344
		fprintf(stderr, "Unable to start GET request\n");
345
		release_http_pack_request(preq);
346
		repo->can_update_info_refs = 0;
347 348 349 350
		release_request(request);
	}
}

351 352
static void start_put(struct transfer_request *request)
{
N
Nick Hengeveld 已提交
353
	char *hex = sha1_to_hex(request->obj->sha1);
354
	struct active_request_slot *slot;
355
	struct strbuf buf = STRBUF_INIT;
356
	enum object_type type;
357 358 359 360 361
	char hdr[50];
	void *unpacked;
	unsigned long len;
	int hdrlen;
	ssize_t size;
362
	git_zstream stream;
363

364 365
	unpacked = read_sha1_file(request->obj->sha1, &type, &len);
	hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
366 367 368

	/* Set it up */
	memset(&stream, 0, sizeof(stream));
369
	git_deflate_init(&stream, zlib_compression_level);
J
Junio C Hamano 已提交
370
	size = git_deflate_bound(&stream, len + hdrlen);
M
Mike Hommey 已提交
371 372
	strbuf_init(&request->buffer.buf, size);
	request->buffer.posn = 0;
373 374

	/* Compress it */
M
Mike Hommey 已提交
375
	stream.next_out = (unsigned char *)request->buffer.buf.buf;
376 377 378 379 380
	stream.avail_out = size;

	/* First header.. */
	stream.next_in = (void *)hdr;
	stream.avail_in = hdrlen;
381 382
	while (git_deflate(&stream, 0) == Z_OK)
		; /* nothing */
383 384 385 386

	/* Then the data itself.. */
	stream.next_in = unpacked;
	stream.avail_in = len;
387 388 389
	while (git_deflate(&stream, Z_FINISH) == Z_OK)
		; /* nothing */
	git_deflate_end(&stream);
390 391
	free(unpacked);

M
Mike Hommey 已提交
392
	request->buffer.buf.len = stream.total_out;
393

394
	strbuf_addstr(&buf, "Destination: ");
395
	append_remote_object_url(&buf, repo->url, hex, 0);
396 397
	request->dest = strbuf_detach(&buf, NULL);

398
	append_remote_object_url(&buf, repo->url, hex, 0);
399
	strbuf_add(&buf, request->lock->tmpfile_suffix, 41);
400
	request->url = strbuf_detach(&buf, NULL);
401 402

	slot = get_active_slot();
403 404
	slot->callback_func = process_response;
	slot->callback_data = request;
405 406
	curl_setup_http(slot->curl, request->url, DAV_PUT,
			&request->buffer, fwrite_null);
407 408 409 410 411 412 413

	if (start_active_slot(slot)) {
		request->slot = slot;
		request->state = RUN_PUT;
	} else {
		request->state = ABORTED;
		free(request->url);
N
Nick Hengeveld 已提交
414
		request->url = NULL;
415 416 417 418 419 420 421 422 423
	}
}

static void start_move(struct transfer_request *request)
{
	struct active_request_slot *slot;
	struct curl_slist *dav_headers = NULL;

	slot = get_active_slot();
424 425
	slot->callback_func = process_response;
	slot->callback_data = request;
426
	curl_setup_http_get(slot->curl, request->url, DAV_MOVE);
427 428 429 430 431 432 433 434 435 436
	dav_headers = curl_slist_append(dav_headers, request->dest);
	dav_headers = curl_slist_append(dav_headers, "Overwrite: T");
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);

	if (start_active_slot(slot)) {
		request->slot = slot;
		request->state = RUN_MOVE;
	} else {
		request->state = ABORTED;
		free(request->url);
N
Nick Hengeveld 已提交
437
		request->url = NULL;
438 439 440
	}
}

441
static int refresh_lock(struct remote_lock *lock)
442 443
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
444
	struct slot_results results;
445
	struct curl_slist *dav_headers;
446
	int rc = 0;
447

448
	lock->refreshing = 1;
449

450
	dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF | DAV_HEADER_TIMEOUT);
451

452 453
	slot = get_active_slot();
	slot->results = &results;
454
	curl_setup_http_get(slot->curl, lock->url, DAV_LOCK);
455
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
456

457 458 459 460 461 462 463 464 465 466
	if (start_active_slot(slot)) {
		run_active_slot(slot);
		if (results.curl_result != CURLE_OK) {
			fprintf(stderr, "LOCK HTTP error %ld\n",
				results.http_code);
		} else {
			lock->start_time = time(NULL);
			rc = 1;
		}
	}
N
Nick Hengeveld 已提交
467

468 469
	lock->refreshing = 0;
	curl_slist_free_all(dav_headers);
N
Nick Hengeveld 已提交
470

471 472 473
	return rc;
}

474
static void check_locks(void)
475
{
476
	struct remote_lock *lock = repo->locks;
477 478 479 480 481 482 483 484 485 486 487 488 489
	time_t current_time = time(NULL);
	int time_remaining;

	while (lock) {
		time_remaining = lock->start_time + lock->timeout -
			current_time;
		if (!lock->refreshing && time_remaining < LOCK_REFRESH) {
			if (!refresh_lock(lock)) {
				fprintf(stderr,
					"Unable to refresh lock for %s\n",
					lock->url);
				aborted = 1;
				return;
N
Nick Hengeveld 已提交
490
			}
491
		}
492
		lock = lock->next;
493
	}
N
Nick Hengeveld 已提交
494
}
495

N
Nick Hengeveld 已提交
496 497 498 499 500 501 502 503 504 505 506 507 508
static void release_request(struct transfer_request *request)
{
	struct transfer_request *entry = request_queue_head;

	if (request == request_queue_head) {
		request_queue_head = request->next;
	} else {
		while (entry->next != NULL && entry->next != request)
			entry = entry->next;
		if (entry->next == request)
			entry->next = entry->next->next;
	}

509
	free(request->url);
N
Nick Hengeveld 已提交
510
	free(request);
511 512
}

513 514
static void finish_request(struct transfer_request *request)
{
515
	struct http_pack_request *preq;
516
	struct http_object_request *obj_req;
517 518

	request->curl_result = request->slot->curl_result;
519 520
	request->http_code = request->slot->http_code;
	request->slot = NULL;
521

N
Nick Hengeveld 已提交
522
	/* Keep locks active */
523
	check_locks();
524

525 526
	if (request->headers != NULL)
		curl_slist_free_all(request->headers);
N
Nick Hengeveld 已提交
527 528 529 530 531

	/* URL is reused for MOVE after PUT */
	if (request->state != RUN_PUT) {
		free(request->url);
		request->url = NULL;
N
Nick Hengeveld 已提交
532
	}
N
Nick Hengeveld 已提交
533

N
Nick Hengeveld 已提交
534
	if (request->state == RUN_MKCOL) {
535 536
		if (request->curl_result == CURLE_OK ||
		    request->http_code == 405) {
N
Nick Hengeveld 已提交
537
			remote_dir_exists[request->obj->sha1[0]] = 1;
538 539 540
			start_put(request);
		} else {
			fprintf(stderr, "MKCOL %s failed, aborting (%d/%ld)\n",
N
Nick Hengeveld 已提交
541
				sha1_to_hex(request->obj->sha1),
542 543 544 545 546 547 548 549 550
				request->curl_result, request->http_code);
			request->state = ABORTED;
			aborted = 1;
		}
	} else if (request->state == RUN_PUT) {
		if (request->curl_result == CURLE_OK) {
			start_move(request);
		} else {
			fprintf(stderr,	"PUT %s failed, aborting (%d/%ld)\n",
N
Nick Hengeveld 已提交
551
				sha1_to_hex(request->obj->sha1),
552 553 554 555 556 557
				request->curl_result, request->http_code);
			request->state = ABORTED;
			aborted = 1;
		}
	} else if (request->state == RUN_MOVE) {
		if (request->curl_result == CURLE_OK) {
N
Nick Hengeveld 已提交
558 559 560
			if (push_verbosely)
				fprintf(stderr, "    sent %s\n",
					sha1_to_hex(request->obj->sha1));
N
Nick Hengeveld 已提交
561 562
			request->obj->flags |= REMOTE;
			release_request(request);
563 564
		} else {
			fprintf(stderr, "MOVE %s failed, aborting (%d/%ld)\n",
N
Nick Hengeveld 已提交
565
				sha1_to_hex(request->obj->sha1),
566 567 568 569
				request->curl_result, request->http_code);
			request->state = ABORTED;
			aborted = 1;
		}
570
	} else if (request->state == RUN_FETCH_LOOSE) {
571
		obj_req = (struct http_object_request *)request->userData;
572

573 574 575
		if (finish_http_object_request(obj_req) == 0)
			if (obj_req->rename == 0)
				request->obj->flags |= (LOCAL | REMOTE);
576 577

		/* Try fetching packed if necessary */
578 579
		if (request->obj->flags & LOCAL) {
			release_http_object_request(obj_req);
580
			release_request(request);
581
		} else
582 583 584
			start_fetch_packed(request);

	} else if (request->state == RUN_FETCH_PACKED) {
585
		int fail = 1;
586 587 588 589
		if (request->curl_result != CURLE_OK) {
			fprintf(stderr, "Unable to get pack file %s\n%s",
				request->url, curl_errorstr);
		} else {
590 591 592
			preq = (struct http_pack_request *)request->userData;

			if (preq) {
593
				if (finish_http_pack_request(preq) == 0)
594 595
					fail = 0;
				release_http_pack_request(preq);
596 597
			}
		}
598 599
		if (fail)
			repo->can_update_info_refs = 0;
600
		release_request(request);
601 602 603
	}
}

N
Nick Hengeveld 已提交
604
#ifdef USE_CURL_MULTI
605
static int is_running_queue;
606
static int fill_active_slot(void *unused)
607
{
608
	struct transfer_request *request;
609

610
	if (aborted || !is_running_queue)
611
		return 0;
612

613
	for (request = request_queue_head; request; request = request->next) {
614 615
		if (request->state == NEED_FETCH) {
			start_fetch_loose(request);
616
			return 1;
617
		} else if (pushing && request->state == NEED_PUSH) {
N
Nick Hengeveld 已提交
618
			if (remote_dir_exists[request->obj->sha1[0]] == 1) {
619
				start_put(request);
N
Nick Hengeveld 已提交
620
			} else {
621
				start_mkcol(request);
N
Nick Hengeveld 已提交
622
			}
623
			return 1;
624
		}
N
Nick Hengeveld 已提交
625
	}
626
	return 0;
627
}
N
Nick Hengeveld 已提交
628
#endif
629

N
Nick Hengeveld 已提交
630 631
static void get_remote_object_list(unsigned char parent);

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
static void add_fetch_request(struct object *obj)
{
	struct transfer_request *request;

	check_locks();

	/*
	 * Don't fetch the object if it's known to exist locally
	 * or is already in the request queue
	 */
	if (remote_dir_exists[obj->sha1[0]] == -1)
		get_remote_object_list(obj->sha1[0]);
	if (obj->flags & (LOCAL | FETCHING))
		return;

	obj->flags |= FETCHING;
	request = xmalloc(sizeof(*request));
	request->obj = obj;
	request->url = NULL;
	request->lock = NULL;
	request->headers = NULL;
	request->state = NEED_FETCH;
	request->next = request_queue_head;
	request_queue_head = request;

N
Nick Hengeveld 已提交
657
#ifdef USE_CURL_MULTI
658 659
	fill_active_slots();
	step_active_slots();
N
Nick Hengeveld 已提交
660
#endif
661 662
}

N
Nick Hengeveld 已提交
663
static int add_send_request(struct object *obj, struct remote_lock *lock)
664
{
665
	struct transfer_request *request;
666 667
	struct packed_git *target;

668 669 670
	/* Keep locks active */
	check_locks();

N
Nick Hengeveld 已提交
671 672 673 674 675 676 677
	/*
	 * Don't push the object if it's known to exist on the remote
	 * or is already in the request queue
	 */
	if (remote_dir_exists[obj->sha1[0]] == -1)
		get_remote_object_list(obj->sha1[0]);
	if (obj->flags & (REMOTE | PUSHING))
N
Nick Hengeveld 已提交
678
		return 0;
679
	target = find_sha1_pack(obj->sha1, repo->packs);
N
Nick Hengeveld 已提交
680 681
	if (target) {
		obj->flags |= REMOTE;
N
Nick Hengeveld 已提交
682
		return 0;
N
Nick Hengeveld 已提交
683
	}
684

N
Nick Hengeveld 已提交
685
	obj->flags |= PUSHING;
686
	request = xmalloc(sizeof(*request));
N
Nick Hengeveld 已提交
687
	request->obj = obj;
688
	request->url = NULL;
N
Nick Hengeveld 已提交
689
	request->lock = lock;
690
	request->headers = NULL;
N
Nick Hengeveld 已提交
691
	request->state = NEED_PUSH;
692 693
	request->next = request_queue_head;
	request_queue_head = request;
694

N
Nick Hengeveld 已提交
695
#ifdef USE_CURL_MULTI
696 697
	fill_active_slots();
	step_active_slots();
N
Nick Hengeveld 已提交
698
#endif
N
Nick Hengeveld 已提交
699 700

	return 1;
701 702
}

703
static int fetch_indices(void)
704
{
T
Tay Ray Chuan 已提交
705
	int ret;
706 707 708

	if (push_verbosely)
		fprintf(stderr, "Getting pack list\n");
N
Nick Hengeveld 已提交
709

T
Tay Ray Chuan 已提交
710 711 712 713 714 715 716
	switch (http_get_info_packs(repo->url, &repo->packs)) {
	case HTTP_OK:
	case HTTP_MISSING_TARGET:
		ret = 0;
		break;
	default:
		ret = -1;
717 718
	}

T
Tay Ray Chuan 已提交
719
	return ret;
720 721
}

N
Nick Hengeveld 已提交
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
static void one_remote_object(const char *hex)
{
	unsigned char sha1[20];
	struct object *obj;

	if (get_sha1_hex(hex, sha1) != 0)
		return;

	obj = lookup_object(sha1);
	if (!obj)
		obj = parse_object(sha1);

	/* Ignore remote objects that don't exist locally */
	if (!obj)
		return;

	obj->flags |= REMOTE;
	if (!object_list_contains(objects, obj))
740
		object_list_insert(obj, &objects);
N
Nick Hengeveld 已提交
741 742
}

N
Nick Hengeveld 已提交
743
static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed)
N
Nick Hengeveld 已提交
744
{
N
Nick Hengeveld 已提交
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
	int *lock_flags = (int *)ctx->userData;

	if (tag_closed) {
		if (!strcmp(ctx->name, DAV_CTX_LOCKENTRY)) {
			if ((*lock_flags & DAV_PROP_LOCKEX) &&
			    (*lock_flags & DAV_PROP_LOCKWR)) {
				*lock_flags |= DAV_LOCK_OK;
			}
			*lock_flags &= DAV_LOCK_OK;
		} else if (!strcmp(ctx->name, DAV_CTX_LOCKTYPE_WRITE)) {
			*lock_flags |= DAV_PROP_LOCKWR;
		} else if (!strcmp(ctx->name, DAV_CTX_LOCKTYPE_EXCLUSIVE)) {
			*lock_flags |= DAV_PROP_LOCKEX;
		}
	}
N
Nick Hengeveld 已提交
760 761
}

N
Nick Hengeveld 已提交
762
static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
N
Nick Hengeveld 已提交
763
{
N
Nick Hengeveld 已提交
764
	struct remote_lock *lock = (struct remote_lock *)ctx->userData;
765 766
	git_SHA_CTX sha_ctx;
	unsigned char lock_token_sha1[20];
N
Nick Hengeveld 已提交
767 768 769 770 771 772

	if (tag_closed && ctx->cdata) {
		if (!strcmp(ctx->name, DAV_ACTIVELOCK_OWNER)) {
			lock->owner = xmalloc(strlen(ctx->cdata) + 1);
			strcpy(lock->owner, ctx->cdata);
		} else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TIMEOUT)) {
773
			if (starts_with(ctx->cdata, "Second-"))
N
Nick Hengeveld 已提交
774 775 776
				lock->timeout =
					strtol(ctx->cdata + 7, NULL, 10);
		} else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
777 778
			lock->token = xmalloc(strlen(ctx->cdata) + 1);
			strcpy(lock->token, ctx->cdata);
779 780 781 782 783 784 785

			git_SHA1_Init(&sha_ctx);
			git_SHA1_Update(&sha_ctx, lock->token, strlen(lock->token));
			git_SHA1_Final(lock_token_sha1, &sha_ctx);

			lock->tmpfile_suffix[0] = '_';
			memcpy(lock->tmpfile_suffix + 1, sha1_to_hex(lock_token_sha1), 40);
N
Nick Hengeveld 已提交
786
		}
N
Nick Hengeveld 已提交
787 788 789
	}
}

790
static void one_remote_ref(const char *refname);
N
Nick Hengeveld 已提交
791

N
Nick Hengeveld 已提交
792
static void
N
Nick Hengeveld 已提交
793
xml_start_tag(void *userData, const char *name, const char **atts)
N
Nick Hengeveld 已提交
794
{
N
Nick Hengeveld 已提交
795
	struct xml_ctx *ctx = (struct xml_ctx *)userData;
D
Dennis Stosberg 已提交
796
	const char *c = strchr(name, ':');
N
Nick Hengeveld 已提交
797 798 799 800 801 802 803 804 805 806 807 808
	int new_len;

	if (c == NULL)
		c = name;
	else
		c++;

	new_len = strlen(ctx->name) + strlen(c) + 2;

	if (new_len > ctx->len) {
		ctx->name = xrealloc(ctx->name, new_len);
		ctx->len = new_len;
N
Nick Hengeveld 已提交
809
	}
N
Nick Hengeveld 已提交
810 811
	strcat(ctx->name, ".");
	strcat(ctx->name, c);
N
Nick Hengeveld 已提交
812

J
Junio C Hamano 已提交
813 814
	free(ctx->cdata);
	ctx->cdata = NULL;
N
Nick Hengeveld 已提交
815 816

	ctx->userFunc(ctx, 0);
N
Nick Hengeveld 已提交
817 818
}

819
static void
N
Nick Hengeveld 已提交
820
xml_end_tag(void *userData, const char *name)
821
{
N
Nick Hengeveld 已提交
822
	struct xml_ctx *ctx = (struct xml_ctx *)userData;
D
Dennis Stosberg 已提交
823
	const char *c = strchr(name, ':');
N
Nick Hengeveld 已提交
824
	char *ep;
825

N
Nick Hengeveld 已提交
826 827 828 829 830 831 832 833 834
	ctx->userFunc(ctx, 1);

	if (c == NULL)
		c = name;
	else
		c++;

	ep = ctx->name + strlen(ctx->name) - strlen(c) - 1;
	*ep = 0;
835 836 837
}

static void
N
Nick Hengeveld 已提交
838
xml_cdata(void *userData, const XML_Char *s, int len)
839
{
N
Nick Hengeveld 已提交
840
	struct xml_ctx *ctx = (struct xml_ctx *)userData;
J
Junio C Hamano 已提交
841
	free(ctx->cdata);
P
Pierre Habouzit 已提交
842
	ctx->cdata = xmemdupz(s, len);
843 844
}

T
Timo Hirvonen 已提交
845
static struct remote_lock *lock_remote(const char *path, long timeout)
846 847
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
848
	struct slot_results results;
M
Mike Hommey 已提交
849 850
	struct buffer out_buffer = { STRBUF_INIT, 0 };
	struct strbuf in_buffer = STRBUF_INIT;
851
	char *url;
852
	char *ep;
853
	char timeout_header[25];
854
	struct remote_lock *lock = NULL;
855
	struct curl_slist *dav_headers = NULL;
N
Nick Hengeveld 已提交
856
	struct xml_ctx ctx;
857
	char *escaped;
858

859 860
	url = xmalloc(strlen(repo->url) + strlen(path) + 1);
	sprintf(url, "%s%s", repo->url, path);
N
Nick Hengeveld 已提交
861

862
	/* Make sure leading directories exist for the remote ref */
863
	ep = strchr(url + strlen(repo->url) + 1, '/');
864
	while (ep) {
865 866
		char saved_character = ep[1];
		ep[1] = '\0';
867
		slot = get_active_slot();
N
Nick Hengeveld 已提交
868
		slot->results = &results;
869
		curl_setup_http_get(slot->curl, url, DAV_MKCOL);
870 871
		if (start_active_slot(slot)) {
			run_active_slot(slot);
N
Nick Hengeveld 已提交
872 873
			if (results.curl_result != CURLE_OK &&
			    results.http_code != 405) {
874 875 876 877 878 879 880
				fprintf(stderr,
					"Unable to create branch path %s\n",
					url);
				free(url);
				return NULL;
			}
		} else {
N
Nick Hengeveld 已提交
881
			fprintf(stderr, "Unable to start MKCOL request\n");
882 883 884
			free(url);
			return NULL;
		}
885
		ep[1] = saved_character;
886 887 888
		ep = strchr(ep + 1, '/');
	}

889
	escaped = xml_entities(ident_default_email());
890 891
	strbuf_addf(&out_buffer.buf, LOCK_REQUEST, escaped);
	free(escaped);
N
Nick Hengeveld 已提交
892

893
	sprintf(timeout_header, "Timeout: Second-%ld", timeout);
894 895 896 897
	dav_headers = curl_slist_append(dav_headers, timeout_header);
	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");

	slot = get_active_slot();
N
Nick Hengeveld 已提交
898
	slot->results = &results;
899
	curl_setup_http(slot->curl, url, DAV_LOCK, &out_buffer, fwrite_buffer);
900
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
901
	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
902

N
Nick Hengeveld 已提交
903 904
	lock = xcalloc(1, sizeof(*lock));
	lock->timeout = -1;
N
Nick Hengeveld 已提交
905

906 907
	if (start_active_slot(slot)) {
		run_active_slot(slot);
N
Nick Hengeveld 已提交
908
		if (results.curl_result == CURLE_OK) {
M
Mike Hommey 已提交
909 910
			XML_Parser parser = XML_ParserCreate(NULL);
			enum XML_Status result;
N
Nick Hengeveld 已提交
911 912 913 914
			ctx.name = xcalloc(10, 1);
			ctx.len = 0;
			ctx.cdata = NULL;
			ctx.userFunc = handle_new_lock_ctx;
N
Nick Hengeveld 已提交
915
			ctx.userData = lock;
N
Nick Hengeveld 已提交
916 917 918 919
			XML_SetUserData(parser, &ctx);
			XML_SetElementHandler(parser, xml_start_tag,
					      xml_end_tag);
			XML_SetCharacterDataHandler(parser, xml_cdata);
M
Mike Hommey 已提交
920 921
			result = XML_Parse(parser, in_buffer.buf,
					   in_buffer.len, 1);
N
Nick Hengeveld 已提交
922 923 924 925 926
			free(ctx.name);
			if (result != XML_STATUS_OK) {
				fprintf(stderr, "XML error: %s\n",
					XML_ErrorString(
						XML_GetErrorCode(parser)));
N
Nick Hengeveld 已提交
927
				lock->timeout = -1;
N
Nick Hengeveld 已提交
928
			}
M
Mike Hommey 已提交
929
			XML_ParserFree(parser);
930 931
		}
	} else {
N
Nick Hengeveld 已提交
932
		fprintf(stderr, "Unable to start LOCK request\n");
933 934
	}

N
Nick Hengeveld 已提交
935
	curl_slist_free_all(dav_headers);
M
Mike Hommey 已提交
936 937
	strbuf_release(&out_buffer.buf);
	strbuf_release(&in_buffer);
N
Nick Hengeveld 已提交
938

N
Nick Hengeveld 已提交
939
	if (lock->token == NULL || lock->timeout <= 0) {
940 941
		free(lock->token);
		free(lock->owner);
942
		free(url);
N
Nick Hengeveld 已提交
943 944
		free(lock);
		lock = NULL;
N
Nick Hengeveld 已提交
945
	} else {
N
Nick Hengeveld 已提交
946 947
		lock->url = url;
		lock->start_time = time(NULL);
948 949
		lock->next = repo->locks;
		repo->locks = lock;
N
Nick Hengeveld 已提交
950 951
	}

N
Nick Hengeveld 已提交
952
	return lock;
953 954
}

N
Nick Hengeveld 已提交
955
static int unlock_remote(struct remote_lock *lock)
956 957
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
958
	struct slot_results results;
959
	struct remote_lock *prev = repo->locks;
960
	struct curl_slist *dav_headers;
961 962
	int rc = 0;

963
	dav_headers = get_dav_token_headers(lock, DAV_HEADER_LOCK);
964 965

	slot = get_active_slot();
N
Nick Hengeveld 已提交
966
	slot->results = &results;
967
	curl_setup_http_get(slot->curl, lock->url, DAV_UNLOCK);
968 969 970 971
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);

	if (start_active_slot(slot)) {
		run_active_slot(slot);
N
Nick Hengeveld 已提交
972
		if (results.curl_result == CURLE_OK)
973 974
			rc = 1;
		else
975
			fprintf(stderr, "UNLOCK HTTP error %ld\n",
N
Nick Hengeveld 已提交
976
				results.http_code);
977
	} else {
978
		fprintf(stderr, "Unable to start UNLOCK request\n");
979 980 981
	}

	curl_slist_free_all(dav_headers);
982

983 984
	if (repo->locks == lock) {
		repo->locks = lock->next;
985 986 987 988 989 990 991
	} else {
		while (prev && prev->next != lock)
			prev = prev->next;
		if (prev)
			prev->next = prev->next->next;
	}

992
	free(lock->owner);
993 994 995
	free(lock->url);
	free(lock->token);
	free(lock);
996 997 998 999

	return rc;
}

1000 1001
static void remove_locks(void)
{
1002
	struct remote_lock *lock = repo->locks;
1003 1004 1005

	fprintf(stderr, "Removing remote locks...\n");
	while (lock) {
1006
		struct remote_lock *next = lock->next;
1007
		unlock_remote(lock);
1008
		lock = next;
1009 1010 1011 1012 1013 1014
	}
}

static void remove_locks_on_signal(int signo)
{
	remove_locks();
1015
	sigchain_pop(signo);
1016 1017 1018
	raise(signo);
}

1019 1020 1021
static void remote_ls(const char *path, int flags,
		      void (*userFunc)(struct remote_ls_ctx *ls),
		      void *userData);
N
Nick Hengeveld 已提交
1022

1023 1024 1025 1026 1027
static void process_ls_object(struct remote_ls_ctx *ls)
{
	unsigned int *parent = (unsigned int *)ls->userData;
	char *path = ls->dentry_name;
	char *obj_hex;
N
Nick Hengeveld 已提交
1028

1029 1030 1031 1032
	if (!strcmp(ls->path, ls->dentry_name) && (ls->flags & IS_DIR)) {
		remote_dir_exists[*parent] = 1;
		return;
	}
N
Nick Hengeveld 已提交
1033

1034 1035 1036 1037
	if (strlen(path) != 49)
		return;
	path += 8;
	obj_hex = xmalloc(strlen(path));
1038 1039
	/* NB: path is not null-terminated, can not use strlcpy here */
	memcpy(obj_hex, path, 2);
1040 1041 1042 1043
	strcpy(obj_hex + 2, path + 3);
	one_remote_object(obj_hex);
	free(obj_hex);
}
N
Nick Hengeveld 已提交
1044

1045 1046 1047 1048 1049 1050
static void process_ls_ref(struct remote_ls_ctx *ls)
{
	if (!strcmp(ls->path, ls->dentry_name) && (ls->dentry_flags & IS_DIR)) {
		fprintf(stderr, "  %s\n", ls->dentry_name);
		return;
	}
N
Nick Hengeveld 已提交
1051

1052 1053 1054
	if (!(ls->dentry_flags & IS_DIR))
		one_remote_ref(ls->dentry_name);
}
N
Nick Hengeveld 已提交
1055

1056 1057 1058
static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed)
{
	struct remote_ls_ctx *ls = (struct remote_ls_ctx *)ctx->userData;
N
Nick Hengeveld 已提交
1059

1060 1061 1062
	if (tag_closed) {
		if (!strcmp(ctx->name, DAV_PROPFIND_RESP) && ls->dentry_name) {
			if (ls->dentry_flags & IS_DIR) {
1063 1064 1065 1066

				/* ensure collection names end with slash */
				str_end_url_with_slash(ls->dentry_name, &ls->dentry_name);

1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
				if (ls->flags & PROCESS_DIRS) {
					ls->userFunc(ls);
				}
				if (strcmp(ls->dentry_name, ls->path) &&
				    ls->flags & RECURSIVE) {
					remote_ls(ls->dentry_name,
						  ls->flags,
						  ls->userFunc,
						  ls->userData);
				}
			} else if (ls->flags & PROCESS_FILES) {
				ls->userFunc(ls);
N
Nick Hengeveld 已提交
1079
			}
1080
		} else if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {
1081 1082 1083 1084 1085 1086 1087 1088
			char *path = ctx->cdata;
			if (*ctx->cdata == 'h') {
				path = strstr(path, "//");
				if (path) {
					path = strchr(path+2, '/');
				}
			}
			if (path) {
1089 1090 1091 1092
				const char *url = repo->url;
				if (repo->path)
					url = repo->path;
				if (strncmp(path, url, repo->path_len))
1093
					error("Parsed path '%s' does not match url: '%s'",
1094 1095 1096 1097 1098
					      path, url);
				else {
					path += repo->path_len;
					ls->dentry_name = xstrdup(path);
				}
1099
			}
1100 1101
		} else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
			ls->dentry_flags |= IS_DIR;
N
Nick Hengeveld 已提交
1102
		}
1103
	} else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {
J
Junio C Hamano 已提交
1104
		free(ls->dentry_name);
1105 1106
		ls->dentry_name = NULL;
		ls->dentry_flags = 0;
N
Nick Hengeveld 已提交
1107 1108 1109
	}
}

1110 1111 1112 1113 1114 1115
/*
 * NEEDSWORK: remote_ls() ignores info/refs on the remote side.  But it
 * should _only_ heed the information from that file, instead of trying to
 * determine the refs from the remote file system (badly: it does not even
 * know about packed-refs).
 */
1116 1117 1118
static void remote_ls(const char *path, int flags,
		      void (*userFunc)(struct remote_ls_ctx *ls),
		      void *userData)
N
Nick Hengeveld 已提交
1119
{
1120
	char *url = xmalloc(strlen(repo->url) + strlen(path) + 1);
N
Nick Hengeveld 已提交
1121
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
1122
	struct slot_results results;
M
Mike Hommey 已提交
1123 1124
	struct strbuf in_buffer = STRBUF_INIT;
	struct buffer out_buffer = { STRBUF_INIT, 0 };
N
Nick Hengeveld 已提交
1125 1126
	struct curl_slist *dav_headers = NULL;
	struct xml_ctx ctx;
1127 1128 1129
	struct remote_ls_ctx ls;

	ls.flags = flags;
1130
	ls.path = xstrdup(path);
1131 1132 1133 1134
	ls.dentry_name = NULL;
	ls.dentry_flags = 0;
	ls.userData = userData;
	ls.userFunc = userFunc;
N
Nick Hengeveld 已提交
1135

1136
	sprintf(url, "%s%s", repo->url, path);
N
Nick Hengeveld 已提交
1137

M
Mike Hommey 已提交
1138
	strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST);
N
Nick Hengeveld 已提交
1139 1140 1141 1142 1143

	dav_headers = curl_slist_append(dav_headers, "Depth: 1");
	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");

	slot = get_active_slot();
N
Nick Hengeveld 已提交
1144
	slot->results = &results;
1145 1146
	curl_setup_http(slot->curl, url, DAV_PROPFIND,
			&out_buffer, fwrite_buffer);
N
Nick Hengeveld 已提交
1147
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1148
	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
N
Nick Hengeveld 已提交
1149 1150 1151

	if (start_active_slot(slot)) {
		run_active_slot(slot);
N
Nick Hengeveld 已提交
1152
		if (results.curl_result == CURLE_OK) {
M
Mike Hommey 已提交
1153 1154
			XML_Parser parser = XML_ParserCreate(NULL);
			enum XML_Status result;
N
Nick Hengeveld 已提交
1155 1156 1157
			ctx.name = xcalloc(10, 1);
			ctx.len = 0;
			ctx.cdata = NULL;
1158 1159
			ctx.userFunc = handle_remote_ls_ctx;
			ctx.userData = &ls;
N
Nick Hengeveld 已提交
1160 1161 1162 1163
			XML_SetUserData(parser, &ctx);
			XML_SetElementHandler(parser, xml_start_tag,
					      xml_end_tag);
			XML_SetCharacterDataHandler(parser, xml_cdata);
M
Mike Hommey 已提交
1164 1165
			result = XML_Parse(parser, in_buffer.buf,
					   in_buffer.len, 1);
N
Nick Hengeveld 已提交
1166 1167 1168 1169 1170 1171 1172
			free(ctx.name);

			if (result != XML_STATUS_OK) {
				fprintf(stderr, "XML error: %s\n",
					XML_ErrorString(
						XML_GetErrorCode(parser)));
			}
M
Mike Hommey 已提交
1173
			XML_ParserFree(parser);
N
Nick Hengeveld 已提交
1174 1175
		}
	} else {
1176
		fprintf(stderr, "Unable to start PROPFIND request\n");
N
Nick Hengeveld 已提交
1177 1178
	}

1179
	free(ls.path);
N
Nick Hengeveld 已提交
1180
	free(url);
M
Mike Hommey 已提交
1181 1182
	strbuf_release(&out_buffer.buf);
	strbuf_release(&in_buffer);
N
Nick Hengeveld 已提交
1183 1184 1185
	curl_slist_free_all(dav_headers);
}

1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
static void get_remote_object_list(unsigned char parent)
{
	char path[] = "objects/XX/";
	static const char hex[] = "0123456789abcdef";
	unsigned int val = parent;

	path[8] = hex[val >> 4];
	path[9] = hex[val & 0xf];
	remote_dir_exists[val] = 0;
	remote_ls(path, (PROCESS_FILES | PROCESS_DIRS),
		  process_ls_object, &val);
}

N
Nick Hengeveld 已提交
1199
static int locking_available(void)
1200 1201
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
1202
	struct slot_results results;
M
Mike Hommey 已提交
1203 1204
	struct strbuf in_buffer = STRBUF_INIT;
	struct buffer out_buffer = { STRBUF_INIT, 0 };
1205
	struct curl_slist *dav_headers = NULL;
N
Nick Hengeveld 已提交
1206 1207
	struct xml_ctx ctx;
	int lock_flags = 0;
1208
	char *escaped;
1209

1210 1211 1212
	escaped = xml_entities(repo->url);
	strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, escaped);
	free(escaped);
1213 1214 1215

	dav_headers = curl_slist_append(dav_headers, "Depth: 0");
	dav_headers = curl_slist_append(dav_headers, "Content-Type: text/xml");
N
Nick Hengeveld 已提交
1216

1217
	slot = get_active_slot();
N
Nick Hengeveld 已提交
1218
	slot->results = &results;
1219 1220
	curl_setup_http(slot->curl, repo->url, DAV_PROPFIND,
			&out_buffer, fwrite_buffer);
1221
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1222
	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
1223 1224 1225

	if (start_active_slot(slot)) {
		run_active_slot(slot);
N
Nick Hengeveld 已提交
1226
		if (results.curl_result == CURLE_OK) {
M
Mike Hommey 已提交
1227 1228
			XML_Parser parser = XML_ParserCreate(NULL);
			enum XML_Status result;
N
Nick Hengeveld 已提交
1229 1230 1231 1232 1233 1234 1235 1236
			ctx.name = xcalloc(10, 1);
			ctx.len = 0;
			ctx.cdata = NULL;
			ctx.userFunc = handle_lockprop_ctx;
			ctx.userData = &lock_flags;
			XML_SetUserData(parser, &ctx);
			XML_SetElementHandler(parser, xml_start_tag,
					      xml_end_tag);
M
Mike Hommey 已提交
1237 1238
			result = XML_Parse(parser, in_buffer.buf,
					   in_buffer.len, 1);
N
Nick Hengeveld 已提交
1239 1240 1241 1242 1243 1244 1245 1246
			free(ctx.name);

			if (result != XML_STATUS_OK) {
				fprintf(stderr, "XML error: %s\n",
					XML_ErrorString(
						XML_GetErrorCode(parser)));
				lock_flags = 0;
			}
M
Mike Hommey 已提交
1247
			XML_ParserFree(parser);
1248
			if (!lock_flags)
1249
				error("no DAV locking support on %s",
1250
				      repo->url);
1251 1252 1253

		} else {
			error("Cannot access URL %s, return code %d",
1254
			      repo->url, results.curl_result);
1255
			lock_flags = 0;
1256 1257
		}
	} else {
1258
		error("Unable to start PROPFIND request on %s", repo->url);
1259 1260
	}

M
Mike Hommey 已提交
1261 1262
	strbuf_release(&out_buffer.buf);
	strbuf_release(&in_buffer);
N
Nick Hengeveld 已提交
1263 1264 1265
	curl_slist_free_all(dav_headers);

	return lock_flags;
1266 1267
}

P
Pierre Habouzit 已提交
1268
static struct object_list **add_one_object(struct object *obj, struct object_list **p)
1269 1270 1271 1272 1273 1274 1275 1276
{
	struct object_list *entry = xmalloc(sizeof(struct object_list));
	entry->item = obj;
	entry->next = *p;
	*p = entry;
	return &entry->next;
}

N
Nick Hengeveld 已提交
1277 1278 1279 1280
static struct object_list **process_blob(struct blob *blob,
					 struct object_list **p,
					 struct name_path *path,
					 const char *name)
1281
{
N
Nick Hengeveld 已提交
1282
	struct object *obj = &blob->object;
1283

N
Nick Hengeveld 已提交
1284 1285 1286 1287 1288 1289
	obj->flags |= LOCAL;

	if (obj->flags & (UNINTERESTING | SEEN))
		return p;

	obj->flags |= SEEN;
1290
	return add_one_object(obj, p);
N
Nick Hengeveld 已提交
1291 1292 1293 1294 1295 1296 1297 1298
}

static struct object_list **process_tree(struct tree *tree,
					 struct object_list **p,
					 struct name_path *path,
					 const char *name)
{
	struct object *obj = &tree->object;
1299
	struct tree_desc desc;
1300
	struct name_entry entry;
N
Nick Hengeveld 已提交
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
	struct name_path me;

	obj->flags |= LOCAL;

	if (obj->flags & (UNINTERESTING | SEEN))
		return p;
	if (parse_tree(tree) < 0)
		die("bad tree object %s", sha1_to_hex(obj->sha1));

	obj->flags |= SEEN;
1311
	name = xstrdup(name);
1312
	p = add_one_object(obj, p);
N
Nick Hengeveld 已提交
1313 1314 1315
	me.up = path;
	me.elem = name;
	me.elem_len = strlen(name);
1316

1317
	init_tree_desc(&desc, tree->buffer, tree->size);
1318

1319 1320 1321
	while (tree_entry(&desc, &entry))
		switch (object_type(entry.mode)) {
		case OBJ_TREE:
1322
			p = process_tree(lookup_tree(entry.sha1), p, &me, name);
1323 1324
			break;
		case OBJ_BLOB:
1325
			p = process_blob(lookup_blob(entry.sha1), p, &me, name);
1326 1327 1328 1329 1330 1331
			break;
		default:
			/* Subproject commit - not in this repository */
			break;
		}

1332
	free_tree_buffer(tree);
N
Nick Hengeveld 已提交
1333
	return p;
1334 1335
}

N
Nick Hengeveld 已提交
1336
static int get_delta(struct rev_info *revs, struct remote_lock *lock)
1337
{
1338
	int i;
1339
	struct commit *commit;
1340
	struct object_list **p = &objects;
N
Nick Hengeveld 已提交
1341
	int count = 0;
1342

N
Nick Hengeveld 已提交
1343 1344 1345 1346
	while ((commit = get_revision(revs)) != NULL) {
		p = process_tree(commit->tree, p, NULL, "");
		commit->object.flags |= LOCAL;
		if (!(commit->object.flags & UNINTERESTING))
N
Nick Hengeveld 已提交
1347
			count += add_send_request(&commit->object, lock);
N
Nick Hengeveld 已提交
1348
	}
1349

1350 1351 1352 1353
	for (i = 0; i < revs->pending.nr; i++) {
		struct object_array_entry *entry = revs->pending.objects + i;
		struct object *obj = entry->item;
		const char *name = entry->name;
1354

N
Nick Hengeveld 已提交
1355 1356
		if (obj->flags & (UNINTERESTING | SEEN))
			continue;
1357
		if (obj->type == OBJ_TAG) {
N
Nick Hengeveld 已提交
1358
			obj->flags |= SEEN;
1359
			p = add_one_object(obj, p);
N
Nick Hengeveld 已提交
1360
			continue;
1361
		}
1362
		if (obj->type == OBJ_TREE) {
N
Nick Hengeveld 已提交
1363 1364
			p = process_tree((struct tree *)obj, p, NULL, name);
			continue;
1365
		}
1366
		if (obj->type == OBJ_BLOB) {
N
Nick Hengeveld 已提交
1367 1368
			p = process_blob((struct blob *)obj, p, NULL, name);
			continue;
1369
		}
N
Nick Hengeveld 已提交
1370 1371 1372 1373 1374
		die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
	}

	while (objects) {
		if (!(objects->item->flags & UNINTERESTING))
N
Nick Hengeveld 已提交
1375
			count += add_send_request(objects->item, lock);
N
Nick Hengeveld 已提交
1376
		objects = objects->next;
1377
	}
N
Nick Hengeveld 已提交
1378 1379

	return count;
1380 1381
}

N
Nick Hengeveld 已提交
1382
static int update_remote(unsigned char *sha1, struct remote_lock *lock)
1383 1384
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
1385
	struct slot_results results;
M
Mike Hommey 已提交
1386
	struct buffer out_buffer = { STRBUF_INIT, 0 };
1387
	struct curl_slist *dav_headers;
1388

1389
	dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
1390

M
Mike Hommey 已提交
1391
	strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1));
1392 1393

	slot = get_active_slot();
N
Nick Hengeveld 已提交
1394
	slot->results = &results;
1395 1396
	curl_setup_http(slot->curl, lock->url, DAV_PUT,
			&out_buffer, fwrite_null);
1397 1398 1399 1400
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);

	if (start_active_slot(slot)) {
		run_active_slot(slot);
M
Mike Hommey 已提交
1401
		strbuf_release(&out_buffer.buf);
N
Nick Hengeveld 已提交
1402
		if (results.curl_result != CURLE_OK) {
1403 1404
			fprintf(stderr,
				"PUT error: curl result=%d, HTTP code=%ld\n",
N
Nick Hengeveld 已提交
1405
				results.curl_result, results.http_code);
1406 1407 1408 1409
			/* We should attempt recovery? */
			return 0;
		}
	} else {
M
Mike Hommey 已提交
1410
		strbuf_release(&out_buffer.buf);
1411 1412 1413 1414 1415 1416 1417
		fprintf(stderr, "Unable to start PUT request\n");
		return 0;
	}

	return 1;
}

1418
static struct ref *remote_refs;
N
Nick Hengeveld 已提交
1419

1420
static void one_remote_ref(const char *refname)
N
Nick Hengeveld 已提交
1421 1422
{
	struct ref *ref;
1423
	struct object *obj;
N
Nick Hengeveld 已提交
1424

1425
	ref = alloc_ref(refname);
1426

1427
	if (http_fetch_ref(repo->url, ref) != 0) {
N
Nick Hengeveld 已提交
1428 1429
		fprintf(stderr,
			"Unable to fetch ref %s from %s\n",
1430
			refname, repo->url);
1431
		free(ref);
N
Nick Hengeveld 已提交
1432 1433 1434
		return;
	}

1435 1436 1437 1438
	/*
	 * Fetch a copy of the object if it doesn't exist locally - it
	 * may be required for updating server info later.
	 */
1439
	if (repo->can_update_info_refs && !has_sha1_file(ref->old_sha1)) {
1440
		obj = lookup_unknown_object(ref->old_sha1);
1441 1442
		if (obj) {
			fprintf(stderr,	"  fetch %s for %s\n",
1443
				sha1_to_hex(ref->old_sha1), refname);
1444 1445 1446 1447
			add_fetch_request(obj);
		}
	}

1448 1449
	ref->next = remote_refs;
	remote_refs = ref;
N
Nick Hengeveld 已提交
1450 1451 1452 1453
}

static void get_dav_remote_heads(void)
{
1454
	remote_ls("refs/", (PROCESS_FILES | PROCESS_DIRS | RECURSIVE), process_ls_ref, NULL);
N
Nick Hengeveld 已提交
1455 1456
}

1457 1458
static void add_remote_info_ref(struct remote_ls_ctx *ls)
{
M
Mike Hommey 已提交
1459
	struct strbuf *buf = (struct strbuf *)ls->userData;
1460 1461 1462
	struct object *o;
	int len;
	char *ref_info;
1463 1464
	struct ref *ref;

1465
	ref = alloc_ref(ls->dentry_name);
1466

1467
	if (http_fetch_ref(repo->url, ref) != 0) {
1468 1469
		fprintf(stderr,
			"Unable to fetch ref %s from %s\n",
1470
			ls->dentry_name, repo->url);
1471
		aborted = 1;
1472
		free(ref);
1473 1474 1475
		return;
	}

1476
	o = parse_object(ref->old_sha1);
1477 1478 1479
	if (!o) {
		fprintf(stderr,
			"Unable to parse object %s for remote ref %s\n",
1480
			sha1_to_hex(ref->old_sha1), ls->dentry_name);
1481
		aborted = 1;
1482
		free(ref);
1483 1484 1485 1486 1487 1488
		return;
	}

	len = strlen(ls->dentry_name) + 42;
	ref_info = xcalloc(len + 1, 1);
	sprintf(ref_info, "%s	%s\n",
1489
		sha1_to_hex(ref->old_sha1), ls->dentry_name);
1490 1491 1492
	fwrite_buffer(ref_info, 1, len, buf);
	free(ref_info);

1493
	if (o->type == OBJ_TAG) {
1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
		o = deref_tag(o, ls->dentry_name, 0);
		if (o) {
			len = strlen(ls->dentry_name) + 45;
			ref_info = xcalloc(len + 1, 1);
			sprintf(ref_info, "%s	%s^{}\n",
				sha1_to_hex(o->sha1), ls->dentry_name);
			fwrite_buffer(ref_info, 1, len, buf);
			free(ref_info);
		}
	}
1504
	free(ref);
1505 1506 1507 1508
}

static void update_remote_info_refs(struct remote_lock *lock)
{
M
Mike Hommey 已提交
1509
	struct buffer buffer = { STRBUF_INIT, 0 };
1510 1511
	struct active_request_slot *slot;
	struct slot_results results;
1512
	struct curl_slist *dav_headers;
1513 1514

	remote_ls("refs/", (PROCESS_FILES | RECURSIVE),
M
Mike Hommey 已提交
1515
		  add_remote_info_ref, &buffer.buf);
1516
	if (!aborted) {
1517
		dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
1518 1519 1520

		slot = get_active_slot();
		slot->results = &results;
1521 1522
		curl_setup_http(slot->curl, lock->url, DAV_PUT,
				&buffer, fwrite_null);
1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533
		curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);

		if (start_active_slot(slot)) {
			run_active_slot(slot);
			if (results.curl_result != CURLE_OK) {
				fprintf(stderr,
					"PUT error: curl result=%d, HTTP code=%ld\n",
					results.curl_result, results.http_code);
			}
		}
	}
M
Mike Hommey 已提交
1534
	strbuf_release(&buffer.buf);
1535 1536 1537 1538
}

static int remote_exists(const char *path)
{
1539
	char *url = xmalloc(strlen(repo->url) + strlen(path) + 1);
1540
	int ret;
1541

1542
	sprintf(url, "%s%s", repo->url, path);
1543

J
Jeff King 已提交
1544
	switch (http_get_strbuf(url, NULL, NULL)) {
1545 1546 1547 1548 1549 1550 1551
	case HTTP_OK:
		ret = 1;
		break;
	case HTTP_MISSING_TARGET:
		ret = 0;
		break;
	case HTTP_ERROR:
J
Jeff King 已提交
1552
		error("unable to access '%s': %s", url, curl_errorstr);
1553 1554
	default:
		ret = -1;
1555
	}
1556 1557
	free(url);
	return ret;
1558 1559
}

T
Timo Hirvonen 已提交
1560
static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
1561 1562
{
	char *url;
M
Mike Hommey 已提交
1563
	struct strbuf buffer = STRBUF_INIT;
1564

1565 1566
	url = xmalloc(strlen(repo->url) + strlen(path) + 1);
	sprintf(url, "%s%s", repo->url, path);
1567

J
Jeff King 已提交
1568
	if (http_get_strbuf(url, &buffer, NULL) != HTTP_OK)
1569 1570
		die("Couldn't get %s for remote symref\n%s", url,
		    curl_errorstr);
1571 1572
	free(url);

1573
	free(*symref);
1574
	*symref = NULL;
1575
	hashclr(sha1);
1576

M
Mike Hommey 已提交
1577
	if (buffer.len == 0)
1578 1579 1580
		return;

	/* If it's a symref, set the refname; otherwise try for a sha1 */
1581
	if (starts_with((char *)buffer.buf, "ref: ")) {
M
Mike Hommey 已提交
1582
		*symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6);
1583
	} else {
M
Mike Hommey 已提交
1584
		get_sha1_hex(buffer.buf, sha1);
1585 1586
	}

M
Mike Hommey 已提交
1587
	strbuf_release(&buffer);
1588 1589
}

1590
static int verify_merge_base(unsigned char *head_sha1, struct ref *remote)
1591
{
1592 1593
	struct commit *head = lookup_commit_or_die(head_sha1, "HEAD");
	struct commit *branch = lookup_commit_or_die(remote->old_sha1, remote->name);
1594

1595
	return in_merge_bases(branch, head);
1596 1597
}

1598
static int delete_remote_branch(const char *pattern, int force)
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637
{
	struct ref *refs = remote_refs;
	struct ref *remote_ref = NULL;
	unsigned char head_sha1[20];
	char *symref = NULL;
	int match;
	int patlen = strlen(pattern);
	int i;
	struct active_request_slot *slot;
	struct slot_results results;
	char *url;

	/* Find the remote branch(es) matching the specified branch name */
	for (match = 0; refs; refs = refs->next) {
		char *name = refs->name;
		int namelen = strlen(name);
		if (namelen < patlen ||
		    memcmp(name + namelen - patlen, pattern, patlen))
			continue;
		if (namelen != patlen && name[namelen - patlen - 1] != '/')
			continue;
		match++;
		remote_ref = refs;
	}
	if (match == 0)
		return error("No remote branch matches %s", pattern);
	if (match != 1)
		return error("More than one remote branch matches %s",
			     pattern);

	/*
	 * Remote HEAD must be a symref (not exactly foolproof; a remote
	 * symlink to a symref will look like a symref)
	 */
	fetch_symref("HEAD", &symref, head_sha1);
	if (!symref)
		return error("Remote HEAD is not a symref");

	/* Remote branch must not be the remote HEAD */
1638
	for (i = 0; symref && i < MAXDEPTH; i++) {
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
		if (!strcmp(remote_ref->name, symref))
			return error("Remote branch %s is the current HEAD",
				     remote_ref->name);
		fetch_symref(symref, &symref, head_sha1);
	}

	/* Run extra sanity checks if delete is not forced */
	if (!force) {
		/* Remote HEAD must resolve to a known object */
		if (symref)
			return error("Remote HEAD symrefs too deep");
1650
		if (is_null_sha1(head_sha1))
1651 1652 1653 1654 1655
			return error("Unable to resolve remote HEAD");
		if (!has_sha1_file(head_sha1))
			return error("Remote HEAD resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", sha1_to_hex(head_sha1));

		/* Remote branch must resolve to a known object */
1656
		if (is_null_sha1(remote_ref->old_sha1))
1657 1658 1659 1660 1661 1662
			return error("Unable to resolve remote branch %s",
				     remote_ref->name);
		if (!has_sha1_file(remote_ref->old_sha1))
			return error("Remote branch %s resolves to object %s\nwhich does not exist locally, perhaps you need to fetch?", remote_ref->name, sha1_to_hex(remote_ref->old_sha1));

		/* Remote branch must be an ancestor of remote HEAD */
1663
		if (!verify_merge_base(head_sha1, remote_ref)) {
1664 1665 1666 1667
			return error("The branch '%s' is not an ancestor "
				     "of your current HEAD.\n"
				     "If you are sure you want to delete it,"
				     " run:\n\t'git http-push -D %s %s'",
1668
				     remote_ref->name, repo->url, pattern);
1669 1670 1671 1672 1673
		}
	}

	/* Send delete request */
	fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name);
1674 1675
	if (dry_run)
		return 0;
1676 1677
	url = xmalloc(strlen(repo->url) + strlen(remote_ref->name) + 1);
	sprintf(url, "%s%s", repo->url, remote_ref->name);
1678 1679
	slot = get_active_slot();
	slot->results = &results;
1680
	curl_setup_http_get(slot->curl, url, DAV_DELETE);
1681 1682 1683 1684
	if (start_active_slot(slot)) {
		run_active_slot(slot);
		free(url);
		if (results.curl_result != CURLE_OK)
1685
			return error("DELETE request failed (%d/%ld)",
1686 1687 1688 1689 1690 1691 1692 1693 1694
				     results.curl_result, results.http_code);
	} else {
		free(url);
		return error("Unable to start DELETE request");
	}

	return 0;
}

1695
static void run_request_queue(void)
1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713
{
#ifdef USE_CURL_MULTI
	is_running_queue = 1;
	fill_active_slots();
	add_fill_function(NULL, fill_active_slot);
#endif
	do {
		finish_all_active_slots();
#ifdef USE_CURL_MULTI
		fill_active_slots();
#endif
	} while (request_queue_head && !aborted);

#ifdef USE_CURL_MULTI
	is_running_queue = 0;
#endif
}

1714 1715 1716 1717 1718 1719
int main(int argc, char **argv)
{
	struct transfer_request *request;
	struct transfer_request *next_request;
	int nr_refspec = 0;
	char **refspec = NULL;
1720
	struct remote_lock *ref_lock = NULL;
1721
	struct remote_lock *info_ref_lock = NULL;
N
Nick Hengeveld 已提交
1722
	struct rev_info revs;
1723 1724
	int delete_branch = 0;
	int force_delete = 0;
N
Nick Hengeveld 已提交
1725
	int objects_to_send;
1726 1727
	int rc = 0;
	int i;
1728
	int new_refs;
1729
	struct ref *ref, *local_refs;
1730

1731 1732
	git_setup_gettext();

1733 1734
	git_extract_argv0_path(argv[0]);

1735
	repo = xcalloc(1, sizeof(*repo));
1736 1737 1738 1739 1740 1741

	argv++;
	for (i = 1; i < argc; i++, argv++) {
		char *arg = *argv;

		if (*arg == '-') {
N
Nick Hengeveld 已提交
1742
			if (!strcmp(arg, "--all")) {
A
Andy Whitcroft 已提交
1743
				push_all = MATCH_REFS_ALL;
1744 1745 1746 1747 1748 1749
				continue;
			}
			if (!strcmp(arg, "--force")) {
				force_all = 1;
				continue;
			}
1750 1751 1752 1753
			if (!strcmp(arg, "--dry-run")) {
				dry_run = 1;
				continue;
			}
1754 1755 1756 1757
			if (!strcmp(arg, "--helper-status")) {
				helper_status = 1;
				continue;
			}
1758 1759
			if (!strcmp(arg, "--verbose")) {
				push_verbosely = 1;
1760
				http_is_verbose = 1;
1761 1762
				continue;
			}
1763 1764 1765 1766 1767 1768 1769 1770 1771
			if (!strcmp(arg, "-d")) {
				delete_branch = 1;
				continue;
			}
			if (!strcmp(arg, "-D")) {
				delete_branch = 1;
				force_delete = 1;
				continue;
			}
1772 1773
			if (!strcmp(arg, "-h"))
				usage(http_push_usage);
1774
		}
1775
		if (!repo->url) {
N
Nick Hengeveld 已提交
1776
			char *path = strstr(arg, "//");
1777 1778
			str_end_url_with_slash(arg, &repo->url);
			repo->path_len = strlen(repo->url);
N
Nick Hengeveld 已提交
1779
			if (path) {
1780 1781 1782
				repo->path = strchr(path+2, '/');
				if (repo->path)
					repo->path_len = strlen(repo->path);
N
Nick Hengeveld 已提交
1783
			}
1784 1785 1786 1787 1788 1789 1790
			continue;
		}
		refspec = argv;
		nr_refspec = argc - i;
		break;
	}

1791 1792 1793 1794
#ifndef USE_CURL_MULTI
	die("git-push is not available for http/https repository when not compiled with USE_CURL_MULTI");
#endif

1795
	if (!repo->url)
N
Nick Hengeveld 已提交
1796 1797
		usage(http_push_usage);

1798 1799 1800
	if (delete_branch && nr_refspec != 1)
		die("You must specify only one branch name when deleting a remote branch");

1801 1802
	setup_git_directory();

N
Nick Hengeveld 已提交
1803
	memset(remote_dir_exists, -1, 256);
1804

J
Jeff King 已提交
1805
	http_init(NULL, repo->url, 1);
1806

1807
#ifdef USE_CURL_MULTI
1808
	is_running_queue = 0;
1809
#endif
1810

1811
	/* Verify DAV compliance/lock support */
N
Nick Hengeveld 已提交
1812
	if (!locking_available()) {
1813 1814 1815 1816
		rc = 1;
		goto cleanup;
	}

1817
	sigchain_push_common(remove_locks_on_signal);
1818

1819
	/* Check whether the remote has server info files */
1820 1821 1822 1823
	repo->can_update_info_refs = 0;
	repo->has_info_refs = remote_exists("info/refs");
	repo->has_info_packs = remote_exists("objects/info/packs");
	if (repo->has_info_refs) {
1824 1825
		info_ref_lock = lock_remote("info/refs", LOCK_TIME);
		if (info_ref_lock)
1826
			repo->can_update_info_refs = 1;
1827
		else {
1828
			error("cannot lock existing info/refs");
1829 1830 1831
			rc = 1;
			goto cleanup;
		}
1832
	}
1833
	if (repo->has_info_packs)
1834 1835
		fetch_indices();

N
Nick Hengeveld 已提交
1836
	/* Get a list of all local and remote heads to validate refspecs */
1837
	local_refs = get_local_heads();
N
Nick Hengeveld 已提交
1838 1839
	fprintf(stderr, "Fetching remote heads...\n");
	get_dav_remote_heads();
1840
	run_request_queue();
N
Nick Hengeveld 已提交
1841

1842 1843
	/* Remove a remote branch if -d or -D was specified */
	if (delete_branch) {
1844
		if (delete_remote_branch(refspec[0], force_delete) == -1) {
1845 1846
			fprintf(stderr, "Unable to delete remote branch %s\n",
				refspec[0]);
1847 1848 1849
			if (helper_status)
				printf("error %s cannot remove\n", refspec[0]);
		}
1850 1851 1852
		goto cleanup;
	}

N
Nick Hengeveld 已提交
1853
	/* match them up */
1854 1855
	if (match_push_refs(local_refs, &remote_refs,
			    nr_refspec, (const char **) refspec, push_all)) {
1856 1857 1858
		rc = -1;
		goto cleanup;
	}
N
Nick Hengeveld 已提交
1859 1860
	if (!remote_refs) {
		fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
1861 1862
		if (helper_status)
			printf("error null no match\n");
1863 1864
		rc = 0;
		goto cleanup;
N
Nick Hengeveld 已提交
1865 1866
	}

1867
	new_refs = 0;
N
Nick Hengeveld 已提交
1868 1869
	for (ref = remote_refs; ref; ref = ref->next) {
		char old_hex[60], *new_hex;
1870
		const char *commit_argv[5];
1871 1872 1873
		int commit_argc;
		char *new_sha1_hex, *old_sha1_hex;

N
Nick Hengeveld 已提交
1874 1875
		if (!ref->peer_ref)
			continue;
1876

1877
		if (is_null_sha1(ref->peer_ref->new_sha1)) {
1878 1879
			if (delete_remote_branch(ref->name, 1) == -1) {
				error("Could not remove %s", ref->name);
1880 1881
				if (helper_status)
					printf("error %s cannot remove\n", ref->name);
1882 1883
				rc = -4;
			}
1884 1885
			else if (helper_status)
				printf("ok %s\n", ref->name);
1886 1887 1888 1889
			new_refs++;
			continue;
		}

1890
		if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
1891
			if (push_verbosely)
N
Nick Hengeveld 已提交
1892
				fprintf(stderr, "'%s': up-to-date\n", ref->name);
1893 1894
			if (helper_status)
				printf("ok %s up to date\n", ref->name);
N
Nick Hengeveld 已提交
1895 1896 1897 1898
			continue;
		}

		if (!force_all &&
1899
		    !is_null_sha1(ref->old_sha1) &&
N
Nick Hengeveld 已提交
1900 1901 1902 1903
		    !ref->force) {
			if (!has_sha1_file(ref->old_sha1) ||
			    !ref_newer(ref->peer_ref->new_sha1,
				       ref->old_sha1)) {
1904 1905
				/*
				 * We do not have the remote ref, or
N
Nick Hengeveld 已提交
1906 1907 1908 1909 1910 1911
				 * we know that the remote ref is not
				 * an ancestor of what we are trying to
				 * push.  Either way this can be losing
				 * commits at the remote end and likely
				 * we were not up to date to begin with.
				 */
1912 1913 1914
				error("remote '%s' is not an ancestor of\n"
				      "local '%s'.\n"
				      "Maybe you are not up-to-date and "
N
Nick Hengeveld 已提交
1915 1916 1917
				      "need to pull first?",
				      ref->name,
				      ref->peer_ref->name);
1918 1919
				if (helper_status)
					printf("error %s non-fast forward\n", ref->name);
N
Nick Hengeveld 已提交
1920
				rc = -2;
N
Nick Hengeveld 已提交
1921 1922
				continue;
			}
1923
		}
1924
		hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
N
Nick Hengeveld 已提交
1925 1926 1927 1928 1929 1930 1931 1932
		new_refs++;
		strcpy(old_hex, sha1_to_hex(ref->old_sha1));
		new_hex = sha1_to_hex(ref->new_sha1);

		fprintf(stderr, "updating '%s'", ref->name);
		if (strcmp(ref->name, ref->peer_ref->name))
			fprintf(stderr, " using '%s'", ref->peer_ref->name);
		fprintf(stderr, "\n  from %s\n  to   %s\n", old_hex, new_hex);
1933 1934 1935
		if (dry_run) {
			if (helper_status)
				printf("ok %s\n", ref->name);
1936
			continue;
1937
		}
1938 1939

		/* Lock remote branch ref */
N
Nick Hengeveld 已提交
1940 1941
		ref_lock = lock_remote(ref->name, LOCK_TIME);
		if (ref_lock == NULL) {
1942
			fprintf(stderr, "Unable to lock remote branch %s\n",
N
Nick Hengeveld 已提交
1943
				ref->name);
1944 1945
			if (helper_status)
				printf("error %s lock error\n", ref->name);
1946 1947 1948 1949
			rc = 1;
			continue;
		}

N
Nick Hengeveld 已提交
1950
		/* Set up revision info for this refspec */
1951
		commit_argc = 3;
1952
		new_sha1_hex = xstrdup(sha1_to_hex(ref->new_sha1));
1953
		old_sha1_hex = NULL;
N
Nick Hengeveld 已提交
1954 1955
		commit_argv[1] = "--objects";
		commit_argv[2] = new_sha1_hex;
1956
		if (!push_all && !is_null_sha1(ref->old_sha1)) {
N
Nick Hengeveld 已提交
1957 1958 1959
			old_sha1_hex = xmalloc(42);
			sprintf(old_sha1_hex, "^%s",
				sha1_to_hex(ref->old_sha1));
N
Nick Hengeveld 已提交
1960
			commit_argv[3] = old_sha1_hex;
N
Nick Hengeveld 已提交
1961
			commit_argc++;
1962
		}
1963
		commit_argv[commit_argc] = NULL;
1964
		init_revisions(&revs, setup_git_directory());
N
Nick Hengeveld 已提交
1965
		setup_revisions(commit_argc, commit_argv, &revs, NULL);
1966
		revs.edge_hint = 0; /* just in case */
N
Nick Hengeveld 已提交
1967 1968 1969 1970
		free(new_sha1_hex);
		if (old_sha1_hex) {
			free(old_sha1_hex);
			commit_argv[1] = NULL;
1971 1972
		}

N
Nick Hengeveld 已提交
1973
		/* Generate a list of objects that need to be pushed */
1974
		pushing = 0;
1975 1976
		if (prepare_revision_walk(&revs))
			die("revision walk setup failed");
1977
		mark_edges_uninteresting(&revs, NULL);
N
Nick Hengeveld 已提交
1978
		objects_to_send = get_delta(&revs, ref_lock);
1979
		finish_all_active_slots();
1980 1981 1982 1983

		/* Push missing objects to remote, this would be a
		   convenient time to pack them first if appropriate. */
		pushing = 1;
N
Nick Hengeveld 已提交
1984 1985 1986
		if (objects_to_send)
			fprintf(stderr, "    sending %d objects\n",
				objects_to_send);
1987 1988

		run_request_queue();
1989 1990

		/* Update the remote branch if all went well */
1991
		if (aborted || !update_remote(ref->new_sha1, ref_lock))
N
Nick Hengeveld 已提交
1992
			rc = 1;
1993

N
Nick Hengeveld 已提交
1994 1995
		if (!rc)
			fprintf(stderr, "    done\n");
1996 1997
		if (helper_status)
			printf("%s %s\n", !rc ? "ok" : "error", ref->name);
N
Nick Hengeveld 已提交
1998
		unlock_remote(ref_lock);
1999
		check_locks();
2000 2001
	}

2002
	/* Update remote server info if appropriate */
2003 2004
	if (repo->has_info_refs && new_refs) {
		if (info_ref_lock && repo->can_update_info_refs) {
2005
			fprintf(stderr, "Updating remote server info\n");
2006 2007
			if (!dry_run)
				update_remote_info_refs(info_ref_lock);
2008 2009 2010 2011 2012
		} else {
			fprintf(stderr, "Unable to update server info\n");
		}
	}

2013
 cleanup:
2014 2015
	if (info_ref_lock)
		unlock_remote(info_ref_lock);
2016
	free(repo);
2017

2018
	http_cleanup();
2019 2020 2021 2022 2023 2024 2025 2026 2027 2028

	request = request_queue_head;
	while (request != NULL) {
		next_request = request->next;
		release_request(request);
		request = next_request;
	}

	return rc;
}