http-push.c 50.8 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

14
#include <expat.h>
15 16

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

19 20 21 22 23 24 25 26 27
#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

28
#define PREV_BUF_SIZE 4096
29

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

/* 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 已提交
51 52 53
#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 已提交
54 55

/* DAV request body templates */
N
Nick Hengeveld 已提交
56 57
#define PROPFIND_SUPPORTEDLOCK_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:propfind xmlns:D=\"DAV:\">\n<D:prop xmlns:R=\"%s\">\n<D:supportedlock/>\n</D:prop>\n</D:propfind>"
#define PROPFIND_ALL_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:propfind xmlns:D=\"DAV:\">\n<D:allprop/>\n</D:propfind>"
58 59
#define LOCK_REQUEST "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<D:lockinfo xmlns:D=\"DAV:\">\n<D:lockscope><D:exclusive/></D:lockscope>\n<D:locktype><D:write/></D:locktype>\n<D:owner>\n<D:href>mailto:%s</D:href>\n</D:owner>\n</D:lockinfo>"

60 61 62
#define LOCK_TIME 600
#define LOCK_REFRESH 30

63
/* bits #0-15 in revision.h */
N
Nick Hengeveld 已提交
64

65 66 67 68
#define LOCAL    (1u<<16)
#define REMOTE   (1u<<17)
#define FETCHING (1u<<18)
#define PUSHING  (1u<<19)
N
Nick Hengeveld 已提交
69

70 71 72
/* We allow "recursive" symbolic refs. Only within reason, though */
#define MAXDEPTH 5

73 74
static int pushing;
static int aborted;
75
static signed char remote_dir_exists[256];
76

77
static int push_verbosely;
A
Andy Whitcroft 已提交
78
static int push_all = MATCH_REFS_NONE;
79
static int force_all;
80
static int dry_run;
81
static int helper_status;
82

83
static struct object_list *objects;
N
Nick Hengeveld 已提交
84

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

96
static struct repo *repo;
97 98

enum transfer_state {
99 100 101
	NEED_FETCH,
	RUN_FETCH_LOOSE,
	RUN_FETCH_PACKED,
102 103 104 105 106
	NEED_PUSH,
	RUN_MKCOL,
	RUN_PUT,
	RUN_MOVE,
	ABORTED,
107
	COMPLETE
108 109
};

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

126
static struct transfer_request *request_queue_head;
127

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

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

147 148 149 150 151 152 153 154
/* 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)

155
struct remote_ls_ctx {
156 157 158 159 160 161 162
	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 已提交
163 164
};

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

172
static char *xml_entities(const char *s)
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
{
	struct strbuf buf = STRBUF_INIT;
	while (*s) {
		size_t len = strcspn(s, "\"<>&");
		strbuf_add(&buf, s, len);
		s += len;
		switch (*s) {
		case '"':
			strbuf_addstr(&buf, "&quot;");
			break;
		case '<':
			strbuf_addstr(&buf, "&lt;");
			break;
		case '>':
			strbuf_addstr(&buf, "&gt;");
			break;
		case '&':
			strbuf_addstr(&buf, "&amp;");
			break;
192 193
		case 0:
			return strbuf_detach(&buf, NULL);
194 195 196 197 198 199
		}
		s++;
	}
	return strbuf_detach(&buf, NULL);
}

200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
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 已提交
228 229
static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum dav_header_flag options)
{
230 231 232
	struct strbuf buf = STRBUF_INIT;
	struct curl_slist *dav_headers = NULL;

J
Junio C Hamano 已提交
233
	if (options & DAV_HEADER_IF) {
234 235 236 237
		strbuf_addf(&buf, "If: (<%s>)", lock->token);
		dav_headers = curl_slist_append(dav_headers, buf.buf);
		strbuf_reset(&buf);
	}
J
Junio C Hamano 已提交
238
	if (options & DAV_HEADER_LOCK) {
239 240 241 242
		strbuf_addf(&buf, "Lock-Token: <%s>", lock->token);
		dav_headers = curl_slist_append(dav_headers, buf.buf);
		strbuf_reset(&buf);
	}
J
Junio C Hamano 已提交
243
	if (options & DAV_HEADER_TIMEOUT) {
244 245 246 247 248 249 250 251 252
		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;
}

253
static void finish_request(struct transfer_request *request);
254
static void release_request(struct transfer_request *request);
255

256
static void process_response(void *callback_data)
257
{
258 259
	struct transfer_request *request =
		(struct transfer_request *)callback_data;
260

261
	finish_request(request);
262 263
}

J
Junio C Hamano 已提交
264
#ifdef USE_CURL_MULTI
265

266 267 268
static void start_fetch_loose(struct transfer_request *request)
{
	struct active_request_slot *slot;
269
	struct http_object_request *obj_req;
270

271 272
	obj_req = new_http_object_request(repo->url, request->obj->sha1);
	if (obj_req == NULL) {
273 274 275 276
		request->state = ABORTED;
		return;
	}

277
	slot = obj_req->slot;
278 279 280
	slot->callback_func = process_response;
	slot->callback_data = request;
	request->slot = slot;
281
	request->userData = obj_req;
282 283 284 285 286

	/* 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");
287
		repo->can_update_info_refs = 0;
288
		release_http_object_request(obj_req);
289 290 291 292
		release_request(request);
	}
}

J
Junio C Hamano 已提交
293 294 295 296 297
static void start_mkcol(struct transfer_request *request)
{
	char *hex = sha1_to_hex(request->obj->sha1);
	struct active_request_slot *slot;

298
	request->url = get_remote_object_url(repo->url, hex, 1);
J
Junio C Hamano 已提交
299 300 301 302

	slot = get_active_slot();
	slot->callback_func = process_response;
	slot->callback_data = request;
303
	curl_setup_http_get(slot->curl, request->url, DAV_MKCOL);
J
Junio C Hamano 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316
	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

317 318 319 320 321
static void start_fetch_packed(struct transfer_request *request)
{
	struct packed_git *target;

	struct transfer_request *check_request = request_queue_head;
322
	struct http_pack_request *preq;
323

324
	target = find_sha1_pack(request->obj->sha1, repo->packs);
325 326
	if (!target) {
		fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", sha1_to_hex(request->obj->sha1));
327
		repo->can_update_info_refs = 0;
328 329 330 331 332 333 334
		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));

335 336 337 338 339 340 341
	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;
342 343 344 345

	/* Make sure there isn't another open request for this pack */
	while (check_request) {
		if (check_request->state == RUN_FETCH_PACKED &&
346 347
		    !strcmp(check_request->url, preq->url)) {
			release_http_pack_request(preq);
348 349 350 351 352 353
			release_request(request);
			return;
		}
		check_request = check_request->next;
	}

354 355 356 357
	preq->slot->callback_func = process_response;
	preq->slot->callback_data = request;
	request->slot = preq->slot;
	request->userData = preq;
358 359 360

	/* Try to get the request started, abort the request on error */
	request->state = RUN_FETCH_PACKED;
361
	if (!start_active_slot(preq->slot)) {
362
		fprintf(stderr, "Unable to start GET request\n");
363
		release_http_pack_request(preq);
364
		repo->can_update_info_refs = 0;
365 366 367 368
		release_request(request);
	}
}

369 370
static void start_put(struct transfer_request *request)
{
N
Nick Hengeveld 已提交
371
	char *hex = sha1_to_hex(request->obj->sha1);
372
	struct active_request_slot *slot;
373
	struct strbuf buf = STRBUF_INIT;
374
	enum object_type type;
375 376 377 378 379
	char hdr[50];
	void *unpacked;
	unsigned long len;
	int hdrlen;
	ssize_t size;
380
	git_zstream stream;
381

382 383
	unpacked = read_sha1_file(request->obj->sha1, &type, &len);
	hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
384 385 386

	/* Set it up */
	memset(&stream, 0, sizeof(stream));
387
	git_deflate_init(&stream, zlib_compression_level);
J
Junio C Hamano 已提交
388
	size = git_deflate_bound(&stream, len + hdrlen);
M
Mike Hommey 已提交
389 390
	strbuf_init(&request->buffer.buf, size);
	request->buffer.posn = 0;
391 392

	/* Compress it */
M
Mike Hommey 已提交
393
	stream.next_out = (unsigned char *)request->buffer.buf.buf;
394 395 396 397 398
	stream.avail_out = size;

	/* First header.. */
	stream.next_in = (void *)hdr;
	stream.avail_in = hdrlen;
399 400
	while (git_deflate(&stream, 0) == Z_OK)
		; /* nothing */
401 402 403 404

	/* Then the data itself.. */
	stream.next_in = unpacked;
	stream.avail_in = len;
405 406 407
	while (git_deflate(&stream, Z_FINISH) == Z_OK)
		; /* nothing */
	git_deflate_end(&stream);
408 409
	free(unpacked);

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

412
	strbuf_addstr(&buf, "Destination: ");
413
	append_remote_object_url(&buf, repo->url, hex, 0);
414 415
	request->dest = strbuf_detach(&buf, NULL);

416
	append_remote_object_url(&buf, repo->url, hex, 0);
417
	strbuf_add(&buf, request->lock->tmpfile_suffix, 41);
418
	request->url = strbuf_detach(&buf, NULL);
419 420

	slot = get_active_slot();
421 422
	slot->callback_func = process_response;
	slot->callback_data = request;
423 424
	curl_setup_http(slot->curl, request->url, DAV_PUT,
			&request->buffer, fwrite_null);
425 426 427 428 429 430 431

	if (start_active_slot(slot)) {
		request->slot = slot;
		request->state = RUN_PUT;
	} else {
		request->state = ABORTED;
		free(request->url);
N
Nick Hengeveld 已提交
432
		request->url = NULL;
433 434 435 436 437 438 439 440 441
	}
}

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

	slot = get_active_slot();
442 443
	slot->callback_func = process_response;
	slot->callback_data = request;
444
	curl_setup_http_get(slot->curl, request->url, DAV_MOVE);
445 446 447 448 449 450 451 452 453 454
	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 已提交
455
		request->url = NULL;
456 457 458
	}
}

459
static int refresh_lock(struct remote_lock *lock)
460 461
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
462
	struct slot_results results;
463
	struct curl_slist *dav_headers;
464
	int rc = 0;
465

466
	lock->refreshing = 1;
467

468
	dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF | DAV_HEADER_TIMEOUT);
469

470 471
	slot = get_active_slot();
	slot->results = &results;
472
	curl_setup_http_get(slot->curl, lock->url, DAV_LOCK);
473
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
474

475 476 477 478 479 480 481 482 483 484
	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 已提交
485

486 487
	lock->refreshing = 0;
	curl_slist_free_all(dav_headers);
N
Nick Hengeveld 已提交
488

489 490 491
	return rc;
}

492
static void check_locks(void)
493
{
494
	struct remote_lock *lock = repo->locks;
495 496 497 498 499 500 501 502 503 504 505 506 507
	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 已提交
508
			}
509
		}
510
		lock = lock->next;
511
	}
N
Nick Hengeveld 已提交
512
}
513

N
Nick Hengeveld 已提交
514 515 516 517 518 519 520 521 522 523 524 525 526
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;
	}

527
	free(request->url);
N
Nick Hengeveld 已提交
528
	free(request);
529 530
}

531 532
static void finish_request(struct transfer_request *request)
{
533
	struct http_pack_request *preq;
534
	struct http_object_request *obj_req;
535 536

	request->curl_result = request->slot->curl_result;
537 538
	request->http_code = request->slot->http_code;
	request->slot = NULL;
539

N
Nick Hengeveld 已提交
540
	/* Keep locks active */
541
	check_locks();
542

543 544
	if (request->headers != NULL)
		curl_slist_free_all(request->headers);
N
Nick Hengeveld 已提交
545 546 547 548 549

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

N
Nick Hengeveld 已提交
552
	if (request->state == RUN_MKCOL) {
553 554
		if (request->curl_result == CURLE_OK ||
		    request->http_code == 405) {
N
Nick Hengeveld 已提交
555
			remote_dir_exists[request->obj->sha1[0]] = 1;
556 557 558
			start_put(request);
		} else {
			fprintf(stderr, "MKCOL %s failed, aborting (%d/%ld)\n",
N
Nick Hengeveld 已提交
559
				sha1_to_hex(request->obj->sha1),
560 561 562 563 564 565 566 567 568
				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 已提交
569
				sha1_to_hex(request->obj->sha1),
570 571 572 573 574 575
				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 已提交
576 577 578
			if (push_verbosely)
				fprintf(stderr, "    sent %s\n",
					sha1_to_hex(request->obj->sha1));
N
Nick Hengeveld 已提交
579 580
			request->obj->flags |= REMOTE;
			release_request(request);
581 582
		} else {
			fprintf(stderr, "MOVE %s failed, aborting (%d/%ld)\n",
N
Nick Hengeveld 已提交
583
				sha1_to_hex(request->obj->sha1),
584 585 586 587
				request->curl_result, request->http_code);
			request->state = ABORTED;
			aborted = 1;
		}
588
	} else if (request->state == RUN_FETCH_LOOSE) {
589
		obj_req = (struct http_object_request *)request->userData;
590

591 592 593
		if (finish_http_object_request(obj_req) == 0)
			if (obj_req->rename == 0)
				request->obj->flags |= (LOCAL | REMOTE);
594 595

		/* Try fetching packed if necessary */
596 597
		if (request->obj->flags & LOCAL) {
			release_http_object_request(obj_req);
598
			release_request(request);
599
		} else
600 601 602
			start_fetch_packed(request);

	} else if (request->state == RUN_FETCH_PACKED) {
603
		int fail = 1;
604 605 606 607
		if (request->curl_result != CURLE_OK) {
			fprintf(stderr, "Unable to get pack file %s\n%s",
				request->url, curl_errorstr);
		} else {
608 609 610
			preq = (struct http_pack_request *)request->userData;

			if (preq) {
611
				if (finish_http_pack_request(preq) == 0)
612 613
					fail = 0;
				release_http_pack_request(preq);
614 615
			}
		}
616 617
		if (fail)
			repo->can_update_info_refs = 0;
618
		release_request(request);
619 620 621
	}
}

N
Nick Hengeveld 已提交
622
#ifdef USE_CURL_MULTI
623
static int is_running_queue;
624
static int fill_active_slot(void *unused)
625
{
626
	struct transfer_request *request;
627

628
	if (aborted || !is_running_queue)
629
		return 0;
630

631
	for (request = request_queue_head; request; request = request->next) {
632 633
		if (request->state == NEED_FETCH) {
			start_fetch_loose(request);
634
			return 1;
635
		} else if (pushing && request->state == NEED_PUSH) {
N
Nick Hengeveld 已提交
636
			if (remote_dir_exists[request->obj->sha1[0]] == 1) {
637
				start_put(request);
N
Nick Hengeveld 已提交
638
			} else {
639
				start_mkcol(request);
N
Nick Hengeveld 已提交
640
			}
641
			return 1;
642
		}
N
Nick Hengeveld 已提交
643
	}
644
	return 0;
645
}
N
Nick Hengeveld 已提交
646
#endif
647

N
Nick Hengeveld 已提交
648 649
static void get_remote_object_list(unsigned char parent);

650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
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 已提交
675
#ifdef USE_CURL_MULTI
676 677
	fill_active_slots();
	step_active_slots();
N
Nick Hengeveld 已提交
678
#endif
679 680
}

N
Nick Hengeveld 已提交
681
static int add_send_request(struct object *obj, struct remote_lock *lock)
682 683 684 685
{
	struct transfer_request *request = request_queue_head;
	struct packed_git *target;

686 687 688
	/* Keep locks active */
	check_locks();

N
Nick Hengeveld 已提交
689 690 691 692 693 694 695
	/*
	 * 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 已提交
696
		return 0;
697
	target = find_sha1_pack(obj->sha1, repo->packs);
N
Nick Hengeveld 已提交
698 699
	if (target) {
		obj->flags |= REMOTE;
N
Nick Hengeveld 已提交
700
		return 0;
N
Nick Hengeveld 已提交
701
	}
702

N
Nick Hengeveld 已提交
703
	obj->flags |= PUSHING;
704
	request = xmalloc(sizeof(*request));
N
Nick Hengeveld 已提交
705
	request->obj = obj;
706
	request->url = NULL;
N
Nick Hengeveld 已提交
707
	request->lock = lock;
708
	request->headers = NULL;
N
Nick Hengeveld 已提交
709
	request->state = NEED_PUSH;
710 711
	request->next = request_queue_head;
	request_queue_head = request;
712

N
Nick Hengeveld 已提交
713
#ifdef USE_CURL_MULTI
714 715
	fill_active_slots();
	step_active_slots();
N
Nick Hengeveld 已提交
716
#endif
N
Nick Hengeveld 已提交
717 718

	return 1;
719 720
}

721
static int fetch_indices(void)
722
{
T
Tay Ray Chuan 已提交
723
	int ret;
724 725 726

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

T
Tay Ray Chuan 已提交
728 729 730 731 732 733 734
	switch (http_get_info_packs(repo->url, &repo->packs)) {
	case HTTP_OK:
	case HTTP_MISSING_TARGET:
		ret = 0;
		break;
	default:
		ret = -1;
735 736
	}

T
Tay Ray Chuan 已提交
737
	return ret;
738 739
}

N
Nick Hengeveld 已提交
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
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))
758
		object_list_insert(obj, &objects);
N
Nick Hengeveld 已提交
759 760
}

N
Nick Hengeveld 已提交
761
static void handle_lockprop_ctx(struct xml_ctx *ctx, int tag_closed)
N
Nick Hengeveld 已提交
762
{
N
Nick Hengeveld 已提交
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
	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 已提交
778 779
}

N
Nick Hengeveld 已提交
780
static void handle_new_lock_ctx(struct xml_ctx *ctx, int tag_closed)
N
Nick Hengeveld 已提交
781
{
N
Nick Hengeveld 已提交
782
	struct remote_lock *lock = (struct remote_lock *)ctx->userData;
783 784
	git_SHA_CTX sha_ctx;
	unsigned char lock_token_sha1[20];
N
Nick Hengeveld 已提交
785 786 787 788 789 790

	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)) {
791
			if (!prefixcmp(ctx->cdata, "Second-"))
N
Nick Hengeveld 已提交
792 793 794
				lock->timeout =
					strtol(ctx->cdata + 7, NULL, 10);
		} else if (!strcmp(ctx->name, DAV_ACTIVELOCK_TOKEN)) {
795 796
			lock->token = xmalloc(strlen(ctx->cdata) + 1);
			strcpy(lock->token, ctx->cdata);
797 798 799 800 801 802 803

			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 已提交
804
		}
N
Nick Hengeveld 已提交
805 806 807
	}
}

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

N
Nick Hengeveld 已提交
810
static void
N
Nick Hengeveld 已提交
811
xml_start_tag(void *userData, const char *name, const char **atts)
N
Nick Hengeveld 已提交
812
{
N
Nick Hengeveld 已提交
813
	struct xml_ctx *ctx = (struct xml_ctx *)userData;
D
Dennis Stosberg 已提交
814
	const char *c = strchr(name, ':');
N
Nick Hengeveld 已提交
815 816 817 818 819 820 821 822 823 824 825 826
	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 已提交
827
	}
N
Nick Hengeveld 已提交
828 829
	strcat(ctx->name, ".");
	strcat(ctx->name, c);
N
Nick Hengeveld 已提交
830

J
Junio C Hamano 已提交
831 832
	free(ctx->cdata);
	ctx->cdata = NULL;
N
Nick Hengeveld 已提交
833 834

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

837
static void
N
Nick Hengeveld 已提交
838
xml_end_tag(void *userData, const char *name)
839
{
N
Nick Hengeveld 已提交
840
	struct xml_ctx *ctx = (struct xml_ctx *)userData;
D
Dennis Stosberg 已提交
841
	const char *c = strchr(name, ':');
N
Nick Hengeveld 已提交
842
	char *ep;
843

N
Nick Hengeveld 已提交
844 845 846 847 848 849 850 851 852
	ctx->userFunc(ctx, 1);

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

	ep = ctx->name + strlen(ctx->name) - strlen(c) - 1;
	*ep = 0;
853 854 855
}

static void
N
Nick Hengeveld 已提交
856
xml_cdata(void *userData, const XML_Char *s, int len)
857
{
N
Nick Hengeveld 已提交
858
	struct xml_ctx *ctx = (struct xml_ctx *)userData;
J
Junio C Hamano 已提交
859
	free(ctx->cdata);
P
Pierre Habouzit 已提交
860
	ctx->cdata = xmemdupz(s, len);
861 862
}

T
Timo Hirvonen 已提交
863
static struct remote_lock *lock_remote(const char *path, long timeout)
864 865
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
866
	struct slot_results results;
M
Mike Hommey 已提交
867 868
	struct buffer out_buffer = { STRBUF_INIT, 0 };
	struct strbuf in_buffer = STRBUF_INIT;
869
	char *url;
870
	char *ep;
871
	char timeout_header[25];
872
	struct remote_lock *lock = NULL;
873
	struct curl_slist *dav_headers = NULL;
N
Nick Hengeveld 已提交
874
	struct xml_ctx ctx;
875
	char *escaped;
876

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

880
	/* Make sure leading directories exist for the remote ref */
881
	ep = strchr(url + strlen(repo->url) + 1, '/');
882
	while (ep) {
883 884
		char saved_character = ep[1];
		ep[1] = '\0';
885
		slot = get_active_slot();
N
Nick Hengeveld 已提交
886
		slot->results = &results;
887
		curl_setup_http_get(slot->curl, url, DAV_MKCOL);
888 889
		if (start_active_slot(slot)) {
			run_active_slot(slot);
N
Nick Hengeveld 已提交
890 891
			if (results.curl_result != CURLE_OK &&
			    results.http_code != 405) {
892 893 894 895 896 897 898
				fprintf(stderr,
					"Unable to create branch path %s\n",
					url);
				free(url);
				return NULL;
			}
		} else {
N
Nick Hengeveld 已提交
899
			fprintf(stderr, "Unable to start MKCOL request\n");
900 901 902
			free(url);
			return NULL;
		}
903
		ep[1] = saved_character;
904 905 906
		ep = strchr(ep + 1, '/');
	}

907 908 909
	escaped = xml_entities(git_default_email);
	strbuf_addf(&out_buffer.buf, LOCK_REQUEST, escaped);
	free(escaped);
N
Nick Hengeveld 已提交
910

911
	sprintf(timeout_header, "Timeout: Second-%ld", timeout);
912 913 914 915
	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 已提交
916
	slot->results = &results;
917
	curl_setup_http(slot->curl, url, DAV_LOCK, &out_buffer, fwrite_buffer);
918
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
919
	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
920

N
Nick Hengeveld 已提交
921 922
	lock = xcalloc(1, sizeof(*lock));
	lock->timeout = -1;
N
Nick Hengeveld 已提交
923

924 925
	if (start_active_slot(slot)) {
		run_active_slot(slot);
N
Nick Hengeveld 已提交
926
		if (results.curl_result == CURLE_OK) {
M
Mike Hommey 已提交
927 928
			XML_Parser parser = XML_ParserCreate(NULL);
			enum XML_Status result;
N
Nick Hengeveld 已提交
929 930 931 932
			ctx.name = xcalloc(10, 1);
			ctx.len = 0;
			ctx.cdata = NULL;
			ctx.userFunc = handle_new_lock_ctx;
N
Nick Hengeveld 已提交
933
			ctx.userData = lock;
N
Nick Hengeveld 已提交
934 935 936 937
			XML_SetUserData(parser, &ctx);
			XML_SetElementHandler(parser, xml_start_tag,
					      xml_end_tag);
			XML_SetCharacterDataHandler(parser, xml_cdata);
M
Mike Hommey 已提交
938 939
			result = XML_Parse(parser, in_buffer.buf,
					   in_buffer.len, 1);
N
Nick Hengeveld 已提交
940 941 942 943 944
			free(ctx.name);
			if (result != XML_STATUS_OK) {
				fprintf(stderr, "XML error: %s\n",
					XML_ErrorString(
						XML_GetErrorCode(parser)));
N
Nick Hengeveld 已提交
945
				lock->timeout = -1;
N
Nick Hengeveld 已提交
946
			}
M
Mike Hommey 已提交
947
			XML_ParserFree(parser);
948 949
		}
	} else {
N
Nick Hengeveld 已提交
950
		fprintf(stderr, "Unable to start LOCK request\n");
951 952
	}

N
Nick Hengeveld 已提交
953
	curl_slist_free_all(dav_headers);
M
Mike Hommey 已提交
954 955
	strbuf_release(&out_buffer.buf);
	strbuf_release(&in_buffer);
N
Nick Hengeveld 已提交
956

N
Nick Hengeveld 已提交
957
	if (lock->token == NULL || lock->timeout <= 0) {
958 959
		free(lock->token);
		free(lock->owner);
960
		free(url);
N
Nick Hengeveld 已提交
961 962
		free(lock);
		lock = NULL;
N
Nick Hengeveld 已提交
963
	} else {
N
Nick Hengeveld 已提交
964 965
		lock->url = url;
		lock->start_time = time(NULL);
966 967
		lock->next = repo->locks;
		repo->locks = lock;
N
Nick Hengeveld 已提交
968 969
	}

N
Nick Hengeveld 已提交
970
	return lock;
971 972
}

N
Nick Hengeveld 已提交
973
static int unlock_remote(struct remote_lock *lock)
974 975
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
976
	struct slot_results results;
977
	struct remote_lock *prev = repo->locks;
978
	struct curl_slist *dav_headers;
979 980
	int rc = 0;

981
	dav_headers = get_dav_token_headers(lock, DAV_HEADER_LOCK);
982 983

	slot = get_active_slot();
N
Nick Hengeveld 已提交
984
	slot->results = &results;
985
	curl_setup_http_get(slot->curl, lock->url, DAV_UNLOCK);
986 987 988 989
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);

	if (start_active_slot(slot)) {
		run_active_slot(slot);
N
Nick Hengeveld 已提交
990
		if (results.curl_result == CURLE_OK)
991 992
			rc = 1;
		else
993
			fprintf(stderr, "UNLOCK HTTP error %ld\n",
N
Nick Hengeveld 已提交
994
				results.http_code);
995
	} else {
996
		fprintf(stderr, "Unable to start UNLOCK request\n");
997 998 999
	}

	curl_slist_free_all(dav_headers);
1000

1001 1002
	if (repo->locks == lock) {
		repo->locks = lock->next;
1003 1004 1005 1006 1007 1008 1009
	} else {
		while (prev && prev->next != lock)
			prev = prev->next;
		if (prev)
			prev->next = prev->next->next;
	}

1010
	free(lock->owner);
1011 1012 1013
	free(lock->url);
	free(lock->token);
	free(lock);
1014 1015 1016 1017

	return rc;
}

1018 1019
static void remove_locks(void)
{
1020
	struct remote_lock *lock = repo->locks;
1021 1022 1023

	fprintf(stderr, "Removing remote locks...\n");
	while (lock) {
1024
		struct remote_lock *next = lock->next;
1025
		unlock_remote(lock);
1026
		lock = next;
1027 1028 1029 1030 1031 1032
	}
}

static void remove_locks_on_signal(int signo)
{
	remove_locks();
1033
	sigchain_pop(signo);
1034 1035 1036
	raise(signo);
}

1037 1038 1039
static void remote_ls(const char *path, int flags,
		      void (*userFunc)(struct remote_ls_ctx *ls),
		      void *userData);
N
Nick Hengeveld 已提交
1040

1041 1042 1043 1044 1045
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 已提交
1046

1047 1048 1049 1050
	if (!strcmp(ls->path, ls->dentry_name) && (ls->flags & IS_DIR)) {
		remote_dir_exists[*parent] = 1;
		return;
	}
N
Nick Hengeveld 已提交
1051

1052 1053 1054 1055
	if (strlen(path) != 49)
		return;
	path += 8;
	obj_hex = xmalloc(strlen(path));
1056 1057
	/* NB: path is not null-terminated, can not use strlcpy here */
	memcpy(obj_hex, path, 2);
1058 1059 1060 1061
	strcpy(obj_hex + 2, path + 3);
	one_remote_object(obj_hex);
	free(obj_hex);
}
N
Nick Hengeveld 已提交
1062

1063 1064 1065 1066 1067 1068
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 已提交
1069

1070 1071 1072
	if (!(ls->dentry_flags & IS_DIR))
		one_remote_ref(ls->dentry_name);
}
N
Nick Hengeveld 已提交
1073

1074 1075 1076
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 已提交
1077

1078 1079 1080
	if (tag_closed) {
		if (!strcmp(ctx->name, DAV_PROPFIND_RESP) && ls->dentry_name) {
			if (ls->dentry_flags & IS_DIR) {
1081 1082 1083 1084

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

1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
				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 已提交
1097
			}
1098
		} else if (!strcmp(ctx->name, DAV_PROPFIND_NAME) && ctx->cdata) {
1099 1100 1101 1102 1103 1104 1105 1106
			char *path = ctx->cdata;
			if (*ctx->cdata == 'h') {
				path = strstr(path, "//");
				if (path) {
					path = strchr(path+2, '/');
				}
			}
			if (path) {
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
				const char *url = repo->url;
				if (repo->path)
					url = repo->path;
				if (strncmp(path, url, repo->path_len))
					error("Parsed path '%s' does not match url: '%s'\n",
					      path, url);
				else {
					path += repo->path_len;
					ls->dentry_name = xstrdup(path);
				}
1117
			}
1118 1119
		} else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) {
			ls->dentry_flags |= IS_DIR;
N
Nick Hengeveld 已提交
1120
		}
1121
	} else if (!strcmp(ctx->name, DAV_PROPFIND_RESP)) {
J
Junio C Hamano 已提交
1122
		free(ls->dentry_name);
1123 1124
		ls->dentry_name = NULL;
		ls->dentry_flags = 0;
N
Nick Hengeveld 已提交
1125 1126 1127
	}
}

1128 1129 1130 1131 1132 1133
/*
 * 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).
 */
1134 1135 1136
static void remote_ls(const char *path, int flags,
		      void (*userFunc)(struct remote_ls_ctx *ls),
		      void *userData)
N
Nick Hengeveld 已提交
1137
{
1138
	char *url = xmalloc(strlen(repo->url) + strlen(path) + 1);
N
Nick Hengeveld 已提交
1139
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
1140
	struct slot_results results;
M
Mike Hommey 已提交
1141 1142
	struct strbuf in_buffer = STRBUF_INIT;
	struct buffer out_buffer = { STRBUF_INIT, 0 };
N
Nick Hengeveld 已提交
1143 1144
	struct curl_slist *dav_headers = NULL;
	struct xml_ctx ctx;
1145 1146 1147
	struct remote_ls_ctx ls;

	ls.flags = flags;
1148
	ls.path = xstrdup(path);
1149 1150 1151 1152
	ls.dentry_name = NULL;
	ls.dentry_flags = 0;
	ls.userData = userData;
	ls.userFunc = userFunc;
N
Nick Hengeveld 已提交
1153

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

M
Mike Hommey 已提交
1156
	strbuf_addf(&out_buffer.buf, PROPFIND_ALL_REQUEST);
N
Nick Hengeveld 已提交
1157 1158 1159 1160 1161

	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 已提交
1162
	slot->results = &results;
1163 1164
	curl_setup_http(slot->curl, url, DAV_PROPFIND,
			&out_buffer, fwrite_buffer);
N
Nick Hengeveld 已提交
1165
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1166
	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
N
Nick Hengeveld 已提交
1167 1168 1169

	if (start_active_slot(slot)) {
		run_active_slot(slot);
N
Nick Hengeveld 已提交
1170
		if (results.curl_result == CURLE_OK) {
M
Mike Hommey 已提交
1171 1172
			XML_Parser parser = XML_ParserCreate(NULL);
			enum XML_Status result;
N
Nick Hengeveld 已提交
1173 1174 1175
			ctx.name = xcalloc(10, 1);
			ctx.len = 0;
			ctx.cdata = NULL;
1176 1177
			ctx.userFunc = handle_remote_ls_ctx;
			ctx.userData = &ls;
N
Nick Hengeveld 已提交
1178 1179 1180 1181
			XML_SetUserData(parser, &ctx);
			XML_SetElementHandler(parser, xml_start_tag,
					      xml_end_tag);
			XML_SetCharacterDataHandler(parser, xml_cdata);
M
Mike Hommey 已提交
1182 1183
			result = XML_Parse(parser, in_buffer.buf,
					   in_buffer.len, 1);
N
Nick Hengeveld 已提交
1184 1185 1186 1187 1188 1189 1190
			free(ctx.name);

			if (result != XML_STATUS_OK) {
				fprintf(stderr, "XML error: %s\n",
					XML_ErrorString(
						XML_GetErrorCode(parser)));
			}
M
Mike Hommey 已提交
1191
			XML_ParserFree(parser);
N
Nick Hengeveld 已提交
1192 1193
		}
	} else {
1194
		fprintf(stderr, "Unable to start PROPFIND request\n");
N
Nick Hengeveld 已提交
1195 1196
	}

1197
	free(ls.path);
N
Nick Hengeveld 已提交
1198
	free(url);
M
Mike Hommey 已提交
1199 1200
	strbuf_release(&out_buffer.buf);
	strbuf_release(&in_buffer);
N
Nick Hengeveld 已提交
1201 1202 1203
	curl_slist_free_all(dav_headers);
}

1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
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 已提交
1217
static int locking_available(void)
1218 1219
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
1220
	struct slot_results results;
M
Mike Hommey 已提交
1221 1222
	struct strbuf in_buffer = STRBUF_INIT;
	struct buffer out_buffer = { STRBUF_INIT, 0 };
1223
	struct curl_slist *dav_headers = NULL;
N
Nick Hengeveld 已提交
1224 1225
	struct xml_ctx ctx;
	int lock_flags = 0;
1226
	char *escaped;
1227

1228 1229 1230
	escaped = xml_entities(repo->url);
	strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, escaped);
	free(escaped);
1231 1232 1233

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

1235
	slot = get_active_slot();
N
Nick Hengeveld 已提交
1236
	slot->results = &results;
1237 1238
	curl_setup_http(slot->curl, repo->url, DAV_PROPFIND,
			&out_buffer, fwrite_buffer);
1239
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
1240
	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
1241 1242 1243

	if (start_active_slot(slot)) {
		run_active_slot(slot);
N
Nick Hengeveld 已提交
1244
		if (results.curl_result == CURLE_OK) {
M
Mike Hommey 已提交
1245 1246
			XML_Parser parser = XML_ParserCreate(NULL);
			enum XML_Status result;
N
Nick Hengeveld 已提交
1247 1248 1249 1250 1251 1252 1253 1254
			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 已提交
1255 1256
			result = XML_Parse(parser, in_buffer.buf,
					   in_buffer.len, 1);
N
Nick Hengeveld 已提交
1257 1258 1259 1260 1261 1262 1263 1264
			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 已提交
1265
			XML_ParserFree(parser);
1266
			if (!lock_flags)
1267
				error("no DAV locking support on %s",
1268
				      repo->url);
1269 1270 1271

		} else {
			error("Cannot access URL %s, return code %d",
1272
			      repo->url, results.curl_result);
1273
			lock_flags = 0;
1274 1275
		}
	} else {
1276
		error("Unable to start PROPFIND request on %s", repo->url);
1277 1278
	}

M
Mike Hommey 已提交
1279 1280
	strbuf_release(&out_buffer.buf);
	strbuf_release(&in_buffer);
N
Nick Hengeveld 已提交
1281 1282 1283
	curl_slist_free_all(dav_headers);

	return lock_flags;
1284 1285
}

P
Pierre Habouzit 已提交
1286
static struct object_list **add_one_object(struct object *obj, struct object_list **p)
1287 1288 1289 1290 1291 1292 1293 1294
{
	struct object_list *entry = xmalloc(sizeof(struct object_list));
	entry->item = obj;
	entry->next = *p;
	*p = entry;
	return &entry->next;
}

N
Nick Hengeveld 已提交
1295 1296 1297 1298
static struct object_list **process_blob(struct blob *blob,
					 struct object_list **p,
					 struct name_path *path,
					 const char *name)
1299
{
N
Nick Hengeveld 已提交
1300
	struct object *obj = &blob->object;
1301

N
Nick Hengeveld 已提交
1302 1303 1304 1305 1306 1307
	obj->flags |= LOCAL;

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

	obj->flags |= SEEN;
1308
	return add_one_object(obj, p);
N
Nick Hengeveld 已提交
1309 1310 1311 1312 1313 1314 1315 1316
}

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;
1317
	struct tree_desc desc;
1318
	struct name_entry entry;
N
Nick Hengeveld 已提交
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
	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;
1329
	name = xstrdup(name);
1330
	p = add_one_object(obj, p);
N
Nick Hengeveld 已提交
1331 1332 1333
	me.up = path;
	me.elem = name;
	me.elem_len = strlen(name);
1334

1335
	init_tree_desc(&desc, tree->buffer, tree->size);
1336

1337 1338 1339
	while (tree_entry(&desc, &entry))
		switch (object_type(entry.mode)) {
		case OBJ_TREE:
1340
			p = process_tree(lookup_tree(entry.sha1), p, &me, name);
1341 1342
			break;
		case OBJ_BLOB:
1343
			p = process_blob(lookup_blob(entry.sha1), p, &me, name);
1344 1345 1346 1347 1348 1349
			break;
		default:
			/* Subproject commit - not in this repository */
			break;
		}

1350 1351
	free(tree->buffer);
	tree->buffer = NULL;
N
Nick Hengeveld 已提交
1352
	return p;
1353 1354
}

N
Nick Hengeveld 已提交
1355
static int get_delta(struct rev_info *revs, struct remote_lock *lock)
1356
{
1357
	int i;
1358
	struct commit *commit;
1359
	struct object_list **p = &objects;
N
Nick Hengeveld 已提交
1360
	int count = 0;
1361

N
Nick Hengeveld 已提交
1362 1363 1364 1365
	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 已提交
1366
			count += add_send_request(&commit->object, lock);
N
Nick Hengeveld 已提交
1367
	}
1368

1369 1370 1371 1372
	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;
1373

N
Nick Hengeveld 已提交
1374 1375
		if (obj->flags & (UNINTERESTING | SEEN))
			continue;
1376
		if (obj->type == OBJ_TAG) {
N
Nick Hengeveld 已提交
1377
			obj->flags |= SEEN;
1378
			p = add_one_object(obj, p);
N
Nick Hengeveld 已提交
1379
			continue;
1380
		}
1381
		if (obj->type == OBJ_TREE) {
N
Nick Hengeveld 已提交
1382 1383
			p = process_tree((struct tree *)obj, p, NULL, name);
			continue;
1384
		}
1385
		if (obj->type == OBJ_BLOB) {
N
Nick Hengeveld 已提交
1386 1387
			p = process_blob((struct blob *)obj, p, NULL, name);
			continue;
1388
		}
N
Nick Hengeveld 已提交
1389 1390 1391 1392 1393
		die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
	}

	while (objects) {
		if (!(objects->item->flags & UNINTERESTING))
N
Nick Hengeveld 已提交
1394
			count += add_send_request(objects->item, lock);
N
Nick Hengeveld 已提交
1395
		objects = objects->next;
1396
	}
N
Nick Hengeveld 已提交
1397 1398

	return count;
1399 1400
}

N
Nick Hengeveld 已提交
1401
static int update_remote(unsigned char *sha1, struct remote_lock *lock)
1402 1403
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
1404
	struct slot_results results;
M
Mike Hommey 已提交
1405
	struct buffer out_buffer = { STRBUF_INIT, 0 };
1406
	struct curl_slist *dav_headers;
1407

1408
	dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
1409

M
Mike Hommey 已提交
1410
	strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1));
1411 1412

	slot = get_active_slot();
N
Nick Hengeveld 已提交
1413
	slot->results = &results;
1414 1415
	curl_setup_http(slot->curl, lock->url, DAV_PUT,
			&out_buffer, fwrite_null);
1416 1417 1418 1419
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);

	if (start_active_slot(slot)) {
		run_active_slot(slot);
M
Mike Hommey 已提交
1420
		strbuf_release(&out_buffer.buf);
N
Nick Hengeveld 已提交
1421
		if (results.curl_result != CURLE_OK) {
1422 1423
			fprintf(stderr,
				"PUT error: curl result=%d, HTTP code=%ld\n",
N
Nick Hengeveld 已提交
1424
				results.curl_result, results.http_code);
1425 1426 1427 1428
			/* We should attempt recovery? */
			return 0;
		}
	} else {
M
Mike Hommey 已提交
1429
		strbuf_release(&out_buffer.buf);
1430 1431 1432 1433 1434 1435 1436
		fprintf(stderr, "Unable to start PUT request\n");
		return 0;
	}

	return 1;
}

1437
static struct ref *remote_refs;
N
Nick Hengeveld 已提交
1438

1439
static void one_remote_ref(const char *refname)
N
Nick Hengeveld 已提交
1440 1441
{
	struct ref *ref;
1442
	struct object *obj;
N
Nick Hengeveld 已提交
1443

1444
	ref = alloc_ref(refname);
1445

1446
	if (http_fetch_ref(repo->url, ref) != 0) {
N
Nick Hengeveld 已提交
1447 1448
		fprintf(stderr,
			"Unable to fetch ref %s from %s\n",
1449
			refname, repo->url);
1450
		free(ref);
N
Nick Hengeveld 已提交
1451 1452 1453
		return;
	}

1454 1455 1456 1457
	/*
	 * Fetch a copy of the object if it doesn't exist locally - it
	 * may be required for updating server info later.
	 */
1458
	if (repo->can_update_info_refs && !has_sha1_file(ref->old_sha1)) {
1459
		obj = lookup_unknown_object(ref->old_sha1);
1460 1461
		if (obj) {
			fprintf(stderr,	"  fetch %s for %s\n",
1462
				sha1_to_hex(ref->old_sha1), refname);
1463 1464 1465 1466
			add_fetch_request(obj);
		}
	}

1467 1468
	ref->next = remote_refs;
	remote_refs = ref;
N
Nick Hengeveld 已提交
1469 1470 1471 1472
}

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

1476 1477
static void add_remote_info_ref(struct remote_ls_ctx *ls)
{
M
Mike Hommey 已提交
1478
	struct strbuf *buf = (struct strbuf *)ls->userData;
1479 1480 1481
	struct object *o;
	int len;
	char *ref_info;
1482 1483
	struct ref *ref;

1484
	ref = alloc_ref(ls->dentry_name);
1485

1486
	if (http_fetch_ref(repo->url, ref) != 0) {
1487 1488
		fprintf(stderr,
			"Unable to fetch ref %s from %s\n",
1489
			ls->dentry_name, repo->url);
1490
		aborted = 1;
1491
		free(ref);
1492 1493 1494
		return;
	}

1495
	o = parse_object(ref->old_sha1);
1496 1497 1498
	if (!o) {
		fprintf(stderr,
			"Unable to parse object %s for remote ref %s\n",
1499
			sha1_to_hex(ref->old_sha1), ls->dentry_name);
1500
		aborted = 1;
1501
		free(ref);
1502 1503 1504 1505 1506 1507
		return;
	}

	len = strlen(ls->dentry_name) + 42;
	ref_info = xcalloc(len + 1, 1);
	sprintf(ref_info, "%s	%s\n",
1508
		sha1_to_hex(ref->old_sha1), ls->dentry_name);
1509 1510 1511
	fwrite_buffer(ref_info, 1, len, buf);
	free(ref_info);

1512
	if (o->type == OBJ_TAG) {
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
		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);
		}
	}
1523
	free(ref);
1524 1525 1526 1527
}

static void update_remote_info_refs(struct remote_lock *lock)
{
M
Mike Hommey 已提交
1528
	struct buffer buffer = { STRBUF_INIT, 0 };
1529 1530
	struct active_request_slot *slot;
	struct slot_results results;
1531
	struct curl_slist *dav_headers;
1532 1533

	remote_ls("refs/", (PROCESS_FILES | RECURSIVE),
M
Mike Hommey 已提交
1534
		  add_remote_info_ref, &buffer.buf);
1535
	if (!aborted) {
1536
		dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
1537 1538 1539

		slot = get_active_slot();
		slot->results = &results;
1540 1541
		curl_setup_http(slot->curl, lock->url, DAV_PUT,
				&buffer, fwrite_null);
1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552
		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 已提交
1553
	strbuf_release(&buffer.buf);
1554 1555 1556 1557
}

static int remote_exists(const char *path)
{
1558
	char *url = xmalloc(strlen(repo->url) + strlen(path) + 1);
1559
	int ret;
1560

1561
	sprintf(url, "%s%s", repo->url, path);
1562

1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573
	switch (http_get_strbuf(url, NULL, 0)) {
	case HTTP_OK:
		ret = 1;
		break;
	case HTTP_MISSING_TARGET:
		ret = 0;
		break;
	case HTTP_ERROR:
		http_error(url, HTTP_ERROR);
	default:
		ret = -1;
1574
	}
1575 1576
	free(url);
	return ret;
1577 1578
}

T
Timo Hirvonen 已提交
1579
static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
1580 1581
{
	char *url;
M
Mike Hommey 已提交
1582
	struct strbuf buffer = STRBUF_INIT;
1583

1584 1585
	url = xmalloc(strlen(repo->url) + strlen(path) + 1);
	sprintf(url, "%s%s", repo->url, path);
1586

1587 1588 1589
	if (http_get_strbuf(url, &buffer, 0) != HTTP_OK)
		die("Couldn't get %s for remote symref\n%s", url,
		    curl_errorstr);
1590 1591
	free(url);

1592
	free(*symref);
1593
	*symref = NULL;
1594
	hashclr(sha1);
1595

M
Mike Hommey 已提交
1596
	if (buffer.len == 0)
1597 1598 1599
		return;

	/* If it's a symref, set the refname; otherwise try for a sha1 */
M
Mike Hommey 已提交
1600 1601
	if (!prefixcmp((char *)buffer.buf, "ref: ")) {
		*symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6);
1602
	} else {
M
Mike Hommey 已提交
1603
		get_sha1_hex(buffer.buf, sha1);
1604 1605
	}

M
Mike Hommey 已提交
1606
	strbuf_release(&buffer);
1607 1608
}

1609
static int verify_merge_base(unsigned char *head_sha1, struct ref *remote)
1610
{
1611 1612
	struct commit *head = lookup_commit_or_die(head_sha1, "HEAD");
	struct commit *branch = lookup_commit_or_die(remote->old_sha1, remote->name);
1613
	struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
1614

D
David Rientjes 已提交
1615
	return (merge_bases && !merge_bases->next && merge_bases->item == branch);
1616 1617
}

1618
static int delete_remote_branch(const char *pattern, int force)
1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657
{
	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 */
1658
	for (i = 0; symref && i < MAXDEPTH; i++) {
1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669
		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");
1670
		if (is_null_sha1(head_sha1))
1671 1672 1673 1674 1675
			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 */
1676
		if (is_null_sha1(remote_ref->old_sha1))
1677 1678 1679 1680 1681 1682
			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 */
1683
		if (!verify_merge_base(head_sha1, remote_ref)) {
1684 1685 1686 1687
			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'",
1688
				     remote_ref->name, repo->url, pattern);
1689 1690 1691 1692 1693
		}
	}

	/* Send delete request */
	fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name);
1694 1695
	if (dry_run)
		return 0;
1696 1697
	url = xmalloc(strlen(repo->url) + strlen(remote_ref->name) + 1);
	sprintf(url, "%s%s", repo->url, remote_ref->name);
1698 1699
	slot = get_active_slot();
	slot->results = &results;
1700
	curl_setup_http_get(slot->curl, url, DAV_DELETE);
1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714
	if (start_active_slot(slot)) {
		run_active_slot(slot);
		free(url);
		if (results.curl_result != CURLE_OK)
			return error("DELETE request failed (%d/%ld)\n",
				     results.curl_result, results.http_code);
	} else {
		free(url);
		return error("Unable to start DELETE request");
	}

	return 0;
}

1715
static void run_request_queue(void)
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
{
#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
}

1734 1735 1736 1737 1738 1739
int main(int argc, char **argv)
{
	struct transfer_request *request;
	struct transfer_request *next_request;
	int nr_refspec = 0;
	char **refspec = NULL;
1740
	struct remote_lock *ref_lock = NULL;
1741
	struct remote_lock *info_ref_lock = NULL;
N
Nick Hengeveld 已提交
1742
	struct rev_info revs;
1743 1744
	int delete_branch = 0;
	int force_delete = 0;
N
Nick Hengeveld 已提交
1745
	int objects_to_send;
1746 1747
	int rc = 0;
	int i;
1748
	int new_refs;
1749
	struct ref *ref, *local_refs;
1750

1751 1752
	git_extract_argv0_path(argv[0]);

1753
	repo = xcalloc(sizeof(*repo), 1);
1754 1755 1756 1757 1758 1759

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

		if (*arg == '-') {
N
Nick Hengeveld 已提交
1760
			if (!strcmp(arg, "--all")) {
A
Andy Whitcroft 已提交
1761
				push_all = MATCH_REFS_ALL;
1762 1763 1764 1765 1766 1767
				continue;
			}
			if (!strcmp(arg, "--force")) {
				force_all = 1;
				continue;
			}
1768 1769 1770 1771
			if (!strcmp(arg, "--dry-run")) {
				dry_run = 1;
				continue;
			}
1772 1773 1774 1775
			if (!strcmp(arg, "--helper-status")) {
				helper_status = 1;
				continue;
			}
1776 1777
			if (!strcmp(arg, "--verbose")) {
				push_verbosely = 1;
1778
				http_is_verbose = 1;
1779 1780
				continue;
			}
1781 1782 1783 1784 1785 1786 1787 1788 1789
			if (!strcmp(arg, "-d")) {
				delete_branch = 1;
				continue;
			}
			if (!strcmp(arg, "-D")) {
				delete_branch = 1;
				force_delete = 1;
				continue;
			}
1790 1791
			if (!strcmp(arg, "-h"))
				usage(http_push_usage);
1792
		}
1793
		if (!repo->url) {
N
Nick Hengeveld 已提交
1794
			char *path = strstr(arg, "//");
1795 1796
			str_end_url_with_slash(arg, &repo->url);
			repo->path_len = strlen(repo->url);
N
Nick Hengeveld 已提交
1797
			if (path) {
1798 1799 1800
				repo->path = strchr(path+2, '/');
				if (repo->path)
					repo->path_len = strlen(repo->path);
N
Nick Hengeveld 已提交
1801
			}
1802 1803 1804 1805 1806 1807 1808
			continue;
		}
		refspec = argv;
		nr_refspec = argc - i;
		break;
	}

1809 1810 1811 1812
#ifndef USE_CURL_MULTI
	die("git-push is not available for http/https repository when not compiled with USE_CURL_MULTI");
#endif

1813
	if (!repo->url)
N
Nick Hengeveld 已提交
1814 1815
		usage(http_push_usage);

1816 1817 1818
	if (delete_branch && nr_refspec != 1)
		die("You must specify only one branch name when deleting a remote branch");

1819 1820
	setup_git_directory();

N
Nick Hengeveld 已提交
1821
	memset(remote_dir_exists, -1, 256);
1822

1823
	http_init(NULL, repo->url);
1824

1825
#ifdef USE_CURL_MULTI
1826
	is_running_queue = 0;
1827
#endif
1828

1829
	/* Verify DAV compliance/lock support */
N
Nick Hengeveld 已提交
1830
	if (!locking_available()) {
1831 1832 1833 1834
		rc = 1;
		goto cleanup;
	}

1835
	sigchain_push_common(remove_locks_on_signal);
1836

1837
	/* Check whether the remote has server info files */
1838 1839 1840 1841
	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) {
1842 1843
		info_ref_lock = lock_remote("info/refs", LOCK_TIME);
		if (info_ref_lock)
1844
			repo->can_update_info_refs = 1;
1845
		else {
1846
			error("cannot lock existing info/refs");
1847 1848 1849
			rc = 1;
			goto cleanup;
		}
1850
	}
1851
	if (repo->has_info_packs)
1852 1853
		fetch_indices();

N
Nick Hengeveld 已提交
1854
	/* Get a list of all local and remote heads to validate refspecs */
1855
	local_refs = get_local_heads();
N
Nick Hengeveld 已提交
1856 1857
	fprintf(stderr, "Fetching remote heads...\n");
	get_dav_remote_heads();
1858
	run_request_queue();
N
Nick Hengeveld 已提交
1859

1860 1861
	/* Remove a remote branch if -d or -D was specified */
	if (delete_branch) {
1862
		if (delete_remote_branch(refspec[0], force_delete) == -1) {
1863 1864
			fprintf(stderr, "Unable to delete remote branch %s\n",
				refspec[0]);
1865 1866 1867
			if (helper_status)
				printf("error %s cannot remove\n", refspec[0]);
		}
1868 1869 1870
		goto cleanup;
	}

N
Nick Hengeveld 已提交
1871
	/* match them up */
1872 1873
	if (match_push_refs(local_refs, &remote_refs,
			    nr_refspec, (const char **) refspec, push_all)) {
1874 1875 1876
		rc = -1;
		goto cleanup;
	}
N
Nick Hengeveld 已提交
1877 1878
	if (!remote_refs) {
		fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
1879 1880
		if (helper_status)
			printf("error null no match\n");
1881 1882
		rc = 0;
		goto cleanup;
N
Nick Hengeveld 已提交
1883 1884
	}

1885
	new_refs = 0;
N
Nick Hengeveld 已提交
1886 1887
	for (ref = remote_refs; ref; ref = ref->next) {
		char old_hex[60], *new_hex;
1888
		const char *commit_argv[5];
1889 1890 1891
		int commit_argc;
		char *new_sha1_hex, *old_sha1_hex;

N
Nick Hengeveld 已提交
1892 1893
		if (!ref->peer_ref)
			continue;
1894

1895
		if (is_null_sha1(ref->peer_ref->new_sha1)) {
1896 1897
			if (delete_remote_branch(ref->name, 1) == -1) {
				error("Could not remove %s", ref->name);
1898 1899
				if (helper_status)
					printf("error %s cannot remove\n", ref->name);
1900 1901
				rc = -4;
			}
1902 1903
			else if (helper_status)
				printf("ok %s\n", ref->name);
1904 1905 1906 1907
			new_refs++;
			continue;
		}

1908
		if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
1909
			if (push_verbosely)
N
Nick Hengeveld 已提交
1910
				fprintf(stderr, "'%s': up-to-date\n", ref->name);
1911 1912
			if (helper_status)
				printf("ok %s up to date\n", ref->name);
N
Nick Hengeveld 已提交
1913 1914 1915 1916
			continue;
		}

		if (!force_all &&
1917
		    !is_null_sha1(ref->old_sha1) &&
N
Nick Hengeveld 已提交
1918 1919 1920 1921
		    !ref->force) {
			if (!has_sha1_file(ref->old_sha1) ||
			    !ref_newer(ref->peer_ref->new_sha1,
				       ref->old_sha1)) {
1922 1923
				/*
				 * We do not have the remote ref, or
N
Nick Hengeveld 已提交
1924 1925 1926 1927 1928 1929
				 * 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.
				 */
1930 1931 1932
				error("remote '%s' is not an ancestor of\n"
				      "local '%s'.\n"
				      "Maybe you are not up-to-date and "
N
Nick Hengeveld 已提交
1933 1934 1935
				      "need to pull first?",
				      ref->name,
				      ref->peer_ref->name);
1936 1937
				if (helper_status)
					printf("error %s non-fast forward\n", ref->name);
N
Nick Hengeveld 已提交
1938
				rc = -2;
N
Nick Hengeveld 已提交
1939 1940
				continue;
			}
1941
		}
1942
		hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
N
Nick Hengeveld 已提交
1943 1944 1945 1946 1947 1948 1949 1950
		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);
1951 1952 1953
		if (dry_run) {
			if (helper_status)
				printf("ok %s\n", ref->name);
1954
			continue;
1955
		}
1956 1957

		/* Lock remote branch ref */
N
Nick Hengeveld 已提交
1958 1959
		ref_lock = lock_remote(ref->name, LOCK_TIME);
		if (ref_lock == NULL) {
1960
			fprintf(stderr, "Unable to lock remote branch %s\n",
N
Nick Hengeveld 已提交
1961
				ref->name);
1962 1963
			if (helper_status)
				printf("error %s lock error\n", ref->name);
1964 1965 1966 1967
			rc = 1;
			continue;
		}

N
Nick Hengeveld 已提交
1968
		/* Set up revision info for this refspec */
1969
		commit_argc = 3;
1970
		new_sha1_hex = xstrdup(sha1_to_hex(ref->new_sha1));
1971
		old_sha1_hex = NULL;
N
Nick Hengeveld 已提交
1972 1973
		commit_argv[1] = "--objects";
		commit_argv[2] = new_sha1_hex;
1974
		if (!push_all && !is_null_sha1(ref->old_sha1)) {
N
Nick Hengeveld 已提交
1975 1976 1977
			old_sha1_hex = xmalloc(42);
			sprintf(old_sha1_hex, "^%s",
				sha1_to_hex(ref->old_sha1));
N
Nick Hengeveld 已提交
1978
			commit_argv[3] = old_sha1_hex;
N
Nick Hengeveld 已提交
1979
			commit_argc++;
1980
		}
1981
		commit_argv[commit_argc] = NULL;
1982
		init_revisions(&revs, setup_git_directory());
N
Nick Hengeveld 已提交
1983
		setup_revisions(commit_argc, commit_argv, &revs, NULL);
1984
		revs.edge_hint = 0; /* just in case */
N
Nick Hengeveld 已提交
1985 1986 1987 1988
		free(new_sha1_hex);
		if (old_sha1_hex) {
			free(old_sha1_hex);
			commit_argv[1] = NULL;
1989 1990
		}

N
Nick Hengeveld 已提交
1991
		/* Generate a list of objects that need to be pushed */
1992
		pushing = 0;
1993 1994
		if (prepare_revision_walk(&revs))
			die("revision walk setup failed");
1995
		mark_edges_uninteresting(revs.commits, &revs, NULL);
N
Nick Hengeveld 已提交
1996
		objects_to_send = get_delta(&revs, ref_lock);
1997
		finish_all_active_slots();
1998 1999 2000 2001

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

		run_request_queue();
2007 2008

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

N
Nick Hengeveld 已提交
2012 2013
		if (!rc)
			fprintf(stderr, "    done\n");
2014 2015
		if (helper_status)
			printf("%s %s\n", !rc ? "ok" : "error", ref->name);
N
Nick Hengeveld 已提交
2016
		unlock_remote(ref_lock);
2017
		check_locks();
2018 2019
	}

2020
	/* Update remote server info if appropriate */
2021 2022
	if (repo->has_info_refs && new_refs) {
		if (info_ref_lock && repo->can_update_info_refs) {
2023
			fprintf(stderr, "Updating remote server info\n");
2024 2025
			if (!dry_run)
				update_remote_info_refs(info_ref_lock);
2026 2027 2028 2029 2030
		} else {
			fprintf(stderr, "Unable to update server info\n");
		}
	}

2031
 cleanup:
2032 2033
	if (info_ref_lock)
		unlock_remote(info_ref_lock);
2034
	free(repo);
2035

2036
	http_cleanup();
2037 2038 2039 2040 2041 2042 2043 2044 2045 2046

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

	return rc;
}