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

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

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

84 85 86
struct repo
{
	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 107 108 109 110 111
	NEED_PUSH,
	RUN_MKCOL,
	RUN_PUT,
	RUN_MOVE,
	ABORTED,
	COMPLETE,
};

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

127
static struct transfer_request *request_queue_head;
128

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

N
Nick Hengeveld 已提交
138
struct remote_lock
N
Nick Hengeveld 已提交
139
{
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 158
/* 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)

struct remote_ls_ctx
N
Nick Hengeveld 已提交
159
{
160 161 162 163 164 165 166
	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 已提交
167 168
};

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

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
static char *xml_entities(char *s)
{
	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;
196 197
		case 0:
			return strbuf_detach(&buf, NULL);
198 199 200 201 202 203
		}
		s++;
	}
	return strbuf_detach(&buf, NULL);
}

J
Junio C Hamano 已提交
204 205
static struct curl_slist *get_dav_token_headers(struct remote_lock *lock, enum dav_header_flag options)
{
206 207 208
	struct strbuf buf = STRBUF_INIT;
	struct curl_slist *dav_headers = NULL;

J
Junio C Hamano 已提交
209
	if (options & DAV_HEADER_IF) {
210 211 212 213
		strbuf_addf(&buf, "If: (<%s>)", lock->token);
		dav_headers = curl_slist_append(dav_headers, buf.buf);
		strbuf_reset(&buf);
	}
J
Junio C Hamano 已提交
214
	if (options & DAV_HEADER_LOCK) {
215 216 217 218
		strbuf_addf(&buf, "Lock-Token: <%s>", lock->token);
		dav_headers = curl_slist_append(dav_headers, buf.buf);
		strbuf_reset(&buf);
	}
J
Junio C Hamano 已提交
219
	if (options & DAV_HEADER_TIMEOUT) {
220 221 222 223 224 225 226 227 228
		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;
}

229
static void finish_request(struct transfer_request *request);
230
static void release_request(struct transfer_request *request);
231

232
static void process_response(void *callback_data)
233
{
234 235
	struct transfer_request *request =
		(struct transfer_request *)callback_data;
236

237
	finish_request(request);
238 239
}

J
Junio C Hamano 已提交
240
#ifdef USE_CURL_MULTI
241

242 243 244
static void start_fetch_loose(struct transfer_request *request)
{
	struct active_request_slot *slot;
245
	struct http_object_request *obj_req;
246

247 248
	obj_req = new_http_object_request(repo->url, request->obj->sha1);
	if (obj_req == NULL) {
249 250 251 252
		request->state = ABORTED;
		return;
	}

253
	slot = obj_req->slot;
254 255 256
	slot->callback_func = process_response;
	slot->callback_data = request;
	request->slot = slot;
257
	request->userData = obj_req;
258 259 260 261 262

	/* 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");
263
		repo->can_update_info_refs = 0;
264
		release_http_object_request(obj_req);
265 266 267 268
		release_request(request);
	}
}

J
Junio C Hamano 已提交
269 270 271 272 273
static void start_mkcol(struct transfer_request *request)
{
	char *hex = sha1_to_hex(request->obj->sha1);
	struct active_request_slot *slot;

274
	request->url = get_remote_object_url(repo->url, hex, 1);
J
Junio C Hamano 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295

	slot = get_active_slot();
	slot->callback_func = process_response;
	slot->callback_data = request;
	curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); /* undo PUT setup */
	curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);
	curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, request->errorstr);
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MKCOL);
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);

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

296 297 298 299 300
static void start_fetch_packed(struct transfer_request *request)
{
	struct packed_git *target;

	struct transfer_request *check_request = request_queue_head;
301
	struct http_pack_request *preq;
302

303
	target = find_sha1_pack(request->obj->sha1, repo->packs);
304 305
	if (!target) {
		fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", sha1_to_hex(request->obj->sha1));
306
		repo->can_update_info_refs = 0;
307 308 309 310 311 312 313
		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));

314 315 316 317 318 319 320
	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;
321 322 323 324

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

333 334 335 336
	preq->slot->callback_func = process_response;
	preq->slot->callback_data = request;
	request->slot = preq->slot;
	request->userData = preq;
337 338 339

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

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

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

	/* Set it up */
	memset(&stream, 0, sizeof(stream));
366
	deflateInit(&stream, zlib_compression_level);
367
	size = deflateBound(&stream, len + hdrlen);
M
Mike Hommey 已提交
368 369
	strbuf_init(&request->buffer.buf, size);
	request->buffer.posn = 0;
370 371

	/* Compress it */
M
Mike Hommey 已提交
372
	stream.next_out = (unsigned char *)request->buffer.buf.buf;
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
	stream.avail_out = size;

	/* First header.. */
	stream.next_in = (void *)hdr;
	stream.avail_in = hdrlen;
	while (deflate(&stream, 0) == Z_OK)
		/* nothing */;

	/* Then the data itself.. */
	stream.next_in = unpacked;
	stream.avail_in = len;
	while (deflate(&stream, Z_FINISH) == Z_OK)
		/* nothing */;
	deflateEnd(&stream);
	free(unpacked);

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

391
	strbuf_addstr(&buf, "Destination: ");
392
	append_remote_object_url(&buf, repo->url, hex, 0);
393 394
	request->dest = strbuf_detach(&buf, NULL);

395
	append_remote_object_url(&buf, repo->url, hex, 0);
396
	strbuf_add(&buf, request->lock->tmpfile_suffix, 41);
397
	request->url = strbuf_detach(&buf, NULL);
398 399

	slot = get_active_slot();
400 401
	slot->callback_func = process_response;
	slot->callback_data = request;
402
	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &request->buffer);
M
Mike Hommey 已提交
403
	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, request->buffer.buf.len);
404
	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
405 406 407 408
#ifndef NO_CURL_IOCTL
	curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);
	curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &request->buffer);
#endif
409 410 411 412 413 414 415 416 417 418 419 420 421
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
	curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
	curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
	curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
	curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);

	if (start_active_slot(slot)) {
		request->slot = slot;
		request->state = RUN_PUT;
	} else {
		request->state = ABORTED;
		free(request->url);
N
Nick Hengeveld 已提交
422
		request->url = NULL;
423 424 425 426 427 428 429 430 431
	}
}

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

	slot = get_active_slot();
432 433
	slot->callback_func = process_response;
	slot->callback_data = request;
434 435 436 437 438 439 440 441 442 443 444 445 446 447
	curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); /* undo PUT setup */
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_MOVE);
	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);
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
	curl_easy_setopt(slot->curl, CURLOPT_URL, request->url);

	if (start_active_slot(slot)) {
		request->slot = slot;
		request->state = RUN_MOVE;
	} else {
		request->state = ABORTED;
		free(request->url);
N
Nick Hengeveld 已提交
448
		request->url = NULL;
449 450 451
	}
}

452
static int refresh_lock(struct remote_lock *lock)
453 454
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
455
	struct slot_results results;
456
	struct curl_slist *dav_headers;
457
	int rc = 0;
458

459
	lock->refreshing = 1;
460

461
	dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF | DAV_HEADER_TIMEOUT);
462

463 464 465 466 467 468 469
	slot = get_active_slot();
	slot->results = &results;
	curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
	curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
470

471 472 473 474 475 476 477 478 479 480
	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 已提交
481

482 483
	lock->refreshing = 0;
	curl_slist_free_all(dav_headers);
N
Nick Hengeveld 已提交
484

485 486 487
	return rc;
}

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

N
Nick Hengeveld 已提交
510 511 512 513 514 515 516 517 518 519 520 521 522
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;
	}

523
	free(request->url);
N
Nick Hengeveld 已提交
524
	free(request);
525 526
}

527 528
static void finish_request(struct transfer_request *request)
{
529
	struct http_pack_request *preq;
530
	struct http_object_request *obj_req;
531 532

	request->curl_result = request->slot->curl_result;
533 534
	request->http_code = request->slot->http_code;
	request->slot = NULL;
535

N
Nick Hengeveld 已提交
536
	/* Keep locks active */
537
	check_locks();
538

539 540
	if (request->headers != NULL)
		curl_slist_free_all(request->headers);
N
Nick Hengeveld 已提交
541 542 543 544 545

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

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

587 588 589
		if (finish_http_object_request(obj_req) == 0)
			if (obj_req->rename == 0)
				request->obj->flags |= (LOCAL | REMOTE);
590 591

		/* Try fetching packed if necessary */
592 593
		if (request->obj->flags & LOCAL) {
			release_http_object_request(obj_req);
594
			release_request(request);
595
		} else
596 597 598
			start_fetch_packed(request);

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

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

N
Nick Hengeveld 已提交
618
#ifdef USE_CURL_MULTI
619
static int is_running_queue;
620
static int fill_active_slot(void *unused)
621
{
622
	struct transfer_request *request;
623

624
	if (aborted || !is_running_queue)
625
		return 0;
626

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

N
Nick Hengeveld 已提交
644 645
static void get_remote_object_list(unsigned char parent);

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

N
Nick Hengeveld 已提交
677
static int add_send_request(struct object *obj, struct remote_lock *lock)
678 679 680 681
{
	struct transfer_request *request = request_queue_head;
	struct packed_git *target;

682 683 684
	/* Keep locks active */
	check_locks();

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

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

N
Nick Hengeveld 已提交
709
#ifdef USE_CURL_MULTI
710 711
	fill_active_slots();
	step_active_slots();
N
Nick Hengeveld 已提交
712
#endif
N
Nick Hengeveld 已提交
713 714

	return 1;
715 716
}

717
static int fetch_indices(void)
718
{
T
Tay Ray Chuan 已提交
719
	int ret;
720 721 722

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

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

T
Tay Ray Chuan 已提交
733
	return ret;
734 735
}

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

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

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

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

			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 已提交
800
		}
N
Nick Hengeveld 已提交
801 802 803
	}
}

N
Nick Hengeveld 已提交
804 805
static void one_remote_ref(char *refname);

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

J
Junio C Hamano 已提交
827 828
	free(ctx->cdata);
	ctx->cdata = NULL;
N
Nick Hengeveld 已提交
829 830

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

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

N
Nick Hengeveld 已提交
840 841 842 843 844 845 846 847 848
	ctx->userFunc(ctx, 1);

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

	ep = ctx->name + strlen(ctx->name) - strlen(c) - 1;
	*ep = 0;
849 850 851
}

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

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

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

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

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

910
	sprintf(timeout_header, "Timeout: Second-%ld", timeout);
911 912 913 914
	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 已提交
915
	slot->results = &results;
916
	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
M
Mike Hommey 已提交
917
	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
918
	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
919 920 921 922
#ifndef NO_CURL_IOCTL
	curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);
	curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);
#endif
N
Nick Hengeveld 已提交
923
	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
924
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
925 926 927 928 929
	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
	curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);

N
Nick Hengeveld 已提交
930 931
	lock = xcalloc(1, sizeof(*lock));
	lock->timeout = -1;
N
Nick Hengeveld 已提交
932

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

N
Nick Hengeveld 已提交
962
	curl_slist_free_all(dav_headers);
M
Mike Hommey 已提交
963 964
	strbuf_release(&out_buffer.buf);
	strbuf_release(&in_buffer);
N
Nick Hengeveld 已提交
965

N
Nick Hengeveld 已提交
966
	if (lock->token == NULL || lock->timeout <= 0) {
967 968
		free(lock->token);
		free(lock->owner);
969
		free(url);
N
Nick Hengeveld 已提交
970 971
		free(lock);
		lock = NULL;
N
Nick Hengeveld 已提交
972
	} else {
N
Nick Hengeveld 已提交
973 974
		lock->url = url;
		lock->start_time = time(NULL);
975 976
		lock->next = repo->locks;
		repo->locks = lock;
N
Nick Hengeveld 已提交
977 978
	}

N
Nick Hengeveld 已提交
979
	return lock;
980 981
}

N
Nick Hengeveld 已提交
982
static int unlock_remote(struct remote_lock *lock)
983 984
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
985
	struct slot_results results;
986
	struct remote_lock *prev = repo->locks;
987
	struct curl_slist *dav_headers;
988 989
	int rc = 0;

990
	dav_headers = get_dav_token_headers(lock, DAV_HEADER_LOCK);
991 992

	slot = get_active_slot();
N
Nick Hengeveld 已提交
993
	slot->results = &results;
994
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
995
	curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
996 997 998 999 1000
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_UNLOCK);
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);

	if (start_active_slot(slot)) {
		run_active_slot(slot);
N
Nick Hengeveld 已提交
1001
		if (results.curl_result == CURLE_OK)
1002 1003
			rc = 1;
		else
1004
			fprintf(stderr, "UNLOCK HTTP error %ld\n",
N
Nick Hengeveld 已提交
1005
				results.http_code);
1006
	} else {
1007
		fprintf(stderr, "Unable to start UNLOCK request\n");
1008 1009 1010
	}

	curl_slist_free_all(dav_headers);
1011

1012 1013
	if (repo->locks == lock) {
		repo->locks = lock->next;
1014 1015 1016 1017 1018 1019 1020
	} else {
		while (prev && prev->next != lock)
			prev = prev->next;
		if (prev)
			prev->next = prev->next->next;
	}

1021
	free(lock->owner);
1022 1023 1024
	free(lock->url);
	free(lock->token);
	free(lock);
1025 1026 1027 1028

	return rc;
}

1029 1030
static void remove_locks(void)
{
1031
	struct remote_lock *lock = repo->locks;
1032 1033 1034

	fprintf(stderr, "Removing remote locks...\n");
	while (lock) {
1035
		struct remote_lock *next = lock->next;
1036
		unlock_remote(lock);
1037
		lock = next;
1038 1039 1040 1041 1042 1043
	}
}

static void remove_locks_on_signal(int signo)
{
	remove_locks();
1044
	sigchain_pop(signo);
1045 1046 1047
	raise(signo);
}

1048 1049 1050
static void remote_ls(const char *path, int flags,
		      void (*userFunc)(struct remote_ls_ctx *ls),
		      void *userData);
N
Nick Hengeveld 已提交
1051

1052 1053 1054 1055 1056
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 已提交
1057

1058 1059 1060 1061
	if (!strcmp(ls->path, ls->dentry_name) && (ls->flags & IS_DIR)) {
		remote_dir_exists[*parent] = 1;
		return;
	}
N
Nick Hengeveld 已提交
1062

1063 1064 1065 1066
	if (strlen(path) != 49)
		return;
	path += 8;
	obj_hex = xmalloc(strlen(path));
1067 1068
	/* NB: path is not null-terminated, can not use strlcpy here */
	memcpy(obj_hex, path, 2);
1069 1070 1071 1072
	strcpy(obj_hex + 2, path + 3);
	one_remote_object(obj_hex);
	free(obj_hex);
}
N
Nick Hengeveld 已提交
1073

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

1081 1082 1083
	if (!(ls->dentry_flags & IS_DIR))
		one_remote_ref(ls->dentry_name);
}
N
Nick Hengeveld 已提交
1084

1085 1086 1087
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 已提交
1088

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

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

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

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

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

	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 已提交
1161
	slot->results = &results;
N
Nick Hengeveld 已提交
1162
	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
M
Mike Hommey 已提交
1163
	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
N
Nick Hengeveld 已提交
1164
	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1165 1166 1167 1168
#ifndef NO_CURL_IOCTL
	curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);
	curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);
#endif
N
Nick Hengeveld 已提交
1169 1170 1171 1172 1173 1174 1175 1176 1177
	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
	curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND);
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);

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

			if (result != XML_STATUS_OK) {
				fprintf(stderr, "XML error: %s\n",
					XML_ErrorString(
						XML_GetErrorCode(parser)));
			}
M
Mike Hommey 已提交
1199
			XML_ParserFree(parser);
N
Nick Hengeveld 已提交
1200 1201
		}
	} else {
1202
		fprintf(stderr, "Unable to start PROPFIND request\n");
N
Nick Hengeveld 已提交
1203 1204
	}

1205
	free(ls.path);
N
Nick Hengeveld 已提交
1206
	free(url);
M
Mike Hommey 已提交
1207 1208
	strbuf_release(&out_buffer.buf);
	strbuf_release(&in_buffer);
N
Nick Hengeveld 已提交
1209 1210 1211
	curl_slist_free_all(dav_headers);
}

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

1236 1237 1238
	escaped = xml_entities(repo->url);
	strbuf_addf(&out_buffer.buf, PROPFIND_SUPPORTEDLOCK_REQUEST, escaped);
	free(escaped);
1239 1240 1241

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

1243
	slot = get_active_slot();
N
Nick Hengeveld 已提交
1244
	slot->results = &results;
1245
	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
M
Mike Hommey 已提交
1246
	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
1247
	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1248 1249 1250 1251
#ifndef NO_CURL_IOCTL
	curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);
	curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);
#endif
1252
	curl_easy_setopt(slot->curl, CURLOPT_FILE, &in_buffer);
1253
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
1254
	curl_easy_setopt(slot->curl, CURLOPT_URL, repo->url);
1255 1256 1257 1258 1259 1260
	curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PROPFIND);
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);

	if (start_active_slot(slot)) {
		run_active_slot(slot);
N
Nick Hengeveld 已提交
1261
		if (results.curl_result == CURLE_OK) {
M
Mike Hommey 已提交
1262 1263
			XML_Parser parser = XML_ParserCreate(NULL);
			enum XML_Status result;
N
Nick Hengeveld 已提交
1264 1265 1266 1267 1268 1269 1270 1271
			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 已提交
1272 1273
			result = XML_Parse(parser, in_buffer.buf,
					   in_buffer.len, 1);
N
Nick Hengeveld 已提交
1274 1275 1276 1277 1278 1279 1280 1281
			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 已提交
1282
			XML_ParserFree(parser);
1283
			if (!lock_flags)
1284
				error("no DAV locking support on %s",
1285
				      repo->url);
1286 1287 1288

		} else {
			error("Cannot access URL %s, return code %d",
1289
			      repo->url, results.curl_result);
1290
			lock_flags = 0;
1291 1292
		}
	} else {
1293
		error("Unable to start PROPFIND request on %s", repo->url);
1294 1295
	}

M
Mike Hommey 已提交
1296 1297
	strbuf_release(&out_buffer.buf);
	strbuf_release(&in_buffer);
N
Nick Hengeveld 已提交
1298 1299 1300
	curl_slist_free_all(dav_headers);

	return lock_flags;
1301 1302
}

P
Pierre Habouzit 已提交
1303
static struct object_list **add_one_object(struct object *obj, struct object_list **p)
1304 1305 1306 1307 1308 1309 1310 1311
{
	struct object_list *entry = xmalloc(sizeof(struct object_list));
	entry->item = obj;
	entry->next = *p;
	*p = entry;
	return &entry->next;
}

N
Nick Hengeveld 已提交
1312 1313 1314 1315
static struct object_list **process_blob(struct blob *blob,
					 struct object_list **p,
					 struct name_path *path,
					 const char *name)
1316
{
N
Nick Hengeveld 已提交
1317
	struct object *obj = &blob->object;
1318

N
Nick Hengeveld 已提交
1319 1320 1321 1322 1323 1324
	obj->flags |= LOCAL;

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

	obj->flags |= SEEN;
1325
	return add_one_object(obj, p);
N
Nick Hengeveld 已提交
1326 1327 1328 1329 1330 1331 1332 1333
}

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;
1334
	struct tree_desc desc;
1335
	struct name_entry entry;
N
Nick Hengeveld 已提交
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
	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;
1346
	name = xstrdup(name);
1347
	p = add_one_object(obj, p);
N
Nick Hengeveld 已提交
1348 1349 1350
	me.up = path;
	me.elem = name;
	me.elem_len = strlen(name);
1351

1352
	init_tree_desc(&desc, tree->buffer, tree->size);
1353

1354 1355 1356
	while (tree_entry(&desc, &entry))
		switch (object_type(entry.mode)) {
		case OBJ_TREE:
1357
			p = process_tree(lookup_tree(entry.sha1), p, &me, name);
1358 1359
			break;
		case OBJ_BLOB:
1360
			p = process_blob(lookup_blob(entry.sha1), p, &me, name);
1361 1362 1363 1364 1365 1366
			break;
		default:
			/* Subproject commit - not in this repository */
			break;
		}

1367 1368
	free(tree->buffer);
	tree->buffer = NULL;
N
Nick Hengeveld 已提交
1369
	return p;
1370 1371
}

N
Nick Hengeveld 已提交
1372
static int get_delta(struct rev_info *revs, struct remote_lock *lock)
1373
{
1374
	int i;
1375
	struct commit *commit;
1376
	struct object_list **p = &objects;
N
Nick Hengeveld 已提交
1377
	int count = 0;
1378

N
Nick Hengeveld 已提交
1379 1380 1381 1382
	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 已提交
1383
			count += add_send_request(&commit->object, lock);
N
Nick Hengeveld 已提交
1384
	}
1385

1386 1387 1388 1389
	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;
1390

N
Nick Hengeveld 已提交
1391 1392
		if (obj->flags & (UNINTERESTING | SEEN))
			continue;
1393
		if (obj->type == OBJ_TAG) {
N
Nick Hengeveld 已提交
1394
			obj->flags |= SEEN;
1395
			p = add_one_object(obj, p);
N
Nick Hengeveld 已提交
1396
			continue;
1397
		}
1398
		if (obj->type == OBJ_TREE) {
N
Nick Hengeveld 已提交
1399 1400
			p = process_tree((struct tree *)obj, p, NULL, name);
			continue;
1401
		}
1402
		if (obj->type == OBJ_BLOB) {
N
Nick Hengeveld 已提交
1403 1404
			p = process_blob((struct blob *)obj, p, NULL, name);
			continue;
1405
		}
N
Nick Hengeveld 已提交
1406 1407 1408 1409 1410
		die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
	}

	while (objects) {
		if (!(objects->item->flags & UNINTERESTING))
N
Nick Hengeveld 已提交
1411
			count += add_send_request(objects->item, lock);
N
Nick Hengeveld 已提交
1412
		objects = objects->next;
1413
	}
N
Nick Hengeveld 已提交
1414 1415

	return count;
1416 1417
}

N
Nick Hengeveld 已提交
1418
static int update_remote(unsigned char *sha1, struct remote_lock *lock)
1419 1420
{
	struct active_request_slot *slot;
N
Nick Hengeveld 已提交
1421
	struct slot_results results;
M
Mike Hommey 已提交
1422
	struct buffer out_buffer = { STRBUF_INIT, 0 };
1423
	struct curl_slist *dav_headers;
1424

1425
	dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
1426

M
Mike Hommey 已提交
1427
	strbuf_addf(&out_buffer.buf, "%s\n", sha1_to_hex(sha1));
1428 1429

	slot = get_active_slot();
N
Nick Hengeveld 已提交
1430
	slot->results = &results;
1431
	curl_easy_setopt(slot->curl, CURLOPT_INFILE, &out_buffer);
M
Mike Hommey 已提交
1432
	curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, out_buffer.buf.len);
1433
	curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1434 1435 1436 1437
#ifndef NO_CURL_IOCTL
	curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);
	curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &out_buffer);
#endif
1438 1439 1440 1441 1442
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
	curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
	curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
1443
	curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);
1444 1445 1446

	if (start_active_slot(slot)) {
		run_active_slot(slot);
M
Mike Hommey 已提交
1447
		strbuf_release(&out_buffer.buf);
N
Nick Hengeveld 已提交
1448
		if (results.curl_result != CURLE_OK) {
1449 1450
			fprintf(stderr,
				"PUT error: curl result=%d, HTTP code=%ld\n",
N
Nick Hengeveld 已提交
1451
				results.curl_result, results.http_code);
1452 1453 1454 1455
			/* We should attempt recovery? */
			return 0;
		}
	} else {
M
Mike Hommey 已提交
1456
		strbuf_release(&out_buffer.buf);
1457 1458 1459 1460 1461 1462 1463
		fprintf(stderr, "Unable to start PUT request\n");
		return 0;
	}

	return 1;
}

1464
static struct ref *remote_refs;
N
Nick Hengeveld 已提交
1465 1466 1467 1468

static void one_remote_ref(char *refname)
{
	struct ref *ref;
1469
	struct object *obj;
N
Nick Hengeveld 已提交
1470

1471
	ref = alloc_ref(refname);
1472

1473
	if (http_fetch_ref(repo->url, ref) != 0) {
N
Nick Hengeveld 已提交
1474 1475
		fprintf(stderr,
			"Unable to fetch ref %s from %s\n",
1476
			refname, repo->url);
1477
		free(ref);
N
Nick Hengeveld 已提交
1478 1479 1480
		return;
	}

1481 1482 1483 1484
	/*
	 * Fetch a copy of the object if it doesn't exist locally - it
	 * may be required for updating server info later.
	 */
1485
	if (repo->can_update_info_refs && !has_sha1_file(ref->old_sha1)) {
1486
		obj = lookup_unknown_object(ref->old_sha1);
1487 1488
		if (obj) {
			fprintf(stderr,	"  fetch %s for %s\n",
1489
				sha1_to_hex(ref->old_sha1), refname);
1490 1491 1492 1493
			add_fetch_request(obj);
		}
	}

1494 1495
	ref->next = remote_refs;
	remote_refs = ref;
N
Nick Hengeveld 已提交
1496 1497 1498 1499
}

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

1503 1504
static void add_remote_info_ref(struct remote_ls_ctx *ls)
{
M
Mike Hommey 已提交
1505
	struct strbuf *buf = (struct strbuf *)ls->userData;
1506 1507 1508
	struct object *o;
	int len;
	char *ref_info;
1509 1510
	struct ref *ref;

1511
	ref = alloc_ref(ls->dentry_name);
1512

1513
	if (http_fetch_ref(repo->url, ref) != 0) {
1514 1515
		fprintf(stderr,
			"Unable to fetch ref %s from %s\n",
1516
			ls->dentry_name, repo->url);
1517
		aborted = 1;
1518
		free(ref);
1519 1520 1521
		return;
	}

1522
	o = parse_object(ref->old_sha1);
1523 1524 1525
	if (!o) {
		fprintf(stderr,
			"Unable to parse object %s for remote ref %s\n",
1526
			sha1_to_hex(ref->old_sha1), ls->dentry_name);
1527
		aborted = 1;
1528
		free(ref);
1529 1530 1531 1532 1533 1534
		return;
	}

	len = strlen(ls->dentry_name) + 42;
	ref_info = xcalloc(len + 1, 1);
	sprintf(ref_info, "%s	%s\n",
1535
		sha1_to_hex(ref->old_sha1), ls->dentry_name);
1536 1537 1538
	fwrite_buffer(ref_info, 1, len, buf);
	free(ref_info);

1539
	if (o->type == OBJ_TAG) {
1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
		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);
		}
	}
1550
	free(ref);
1551 1552 1553 1554
}

static void update_remote_info_refs(struct remote_lock *lock)
{
M
Mike Hommey 已提交
1555
	struct buffer buffer = { STRBUF_INIT, 0 };
1556 1557
	struct active_request_slot *slot;
	struct slot_results results;
1558
	struct curl_slist *dav_headers;
1559 1560

	remote_ls("refs/", (PROCESS_FILES | RECURSIVE),
M
Mike Hommey 已提交
1561
		  add_remote_info_ref, &buffer.buf);
1562
	if (!aborted) {
1563
		dav_headers = get_dav_token_headers(lock, DAV_HEADER_IF);
1564 1565 1566 1567

		slot = get_active_slot();
		slot->results = &results;
		curl_easy_setopt(slot->curl, CURLOPT_INFILE, &buffer);
M
Mike Hommey 已提交
1568
		curl_easy_setopt(slot->curl, CURLOPT_INFILESIZE, buffer.buf.len);
1569
		curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, fread_buffer);
1570 1571 1572 1573
#ifndef NO_CURL_IOCTL
		curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);
		curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, &buffer);
#endif
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589
		curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
		curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_PUT);
		curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);
		curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 1);
		curl_easy_setopt(slot->curl, CURLOPT_PUT, 1);
		curl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);

		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 已提交
1590
	strbuf_release(&buffer.buf);
1591 1592 1593 1594
}

static int remote_exists(const char *path)
{
1595
	char *url = xmalloc(strlen(repo->url) + strlen(path) + 1);
1596
	int ret;
1597

1598
	sprintf(url, "%s%s", repo->url, path);
1599

1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610
	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;
1611
	}
1612 1613
	free(url);
	return ret;
1614 1615
}

T
Timo Hirvonen 已提交
1616
static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
1617 1618
{
	char *url;
M
Mike Hommey 已提交
1619
	struct strbuf buffer = STRBUF_INIT;
1620

1621 1622
	url = xmalloc(strlen(repo->url) + strlen(path) + 1);
	sprintf(url, "%s%s", repo->url, path);
1623

1624 1625 1626
	if (http_get_strbuf(url, &buffer, 0) != HTTP_OK)
		die("Couldn't get %s for remote symref\n%s", url,
		    curl_errorstr);
1627 1628
	free(url);

1629
	free(*symref);
1630
	*symref = NULL;
1631
	hashclr(sha1);
1632

M
Mike Hommey 已提交
1633
	if (buffer.len == 0)
1634 1635 1636
		return;

	/* If it's a symref, set the refname; otherwise try for a sha1 */
M
Mike Hommey 已提交
1637 1638
	if (!prefixcmp((char *)buffer.buf, "ref: ")) {
		*symref = xmemdupz((char *)buffer.buf + 5, buffer.len - 6);
1639
	} else {
M
Mike Hommey 已提交
1640
		get_sha1_hex(buffer.buf, sha1);
1641 1642
	}

M
Mike Hommey 已提交
1643
	strbuf_release(&buffer);
1644 1645 1646 1647
}

static int verify_merge_base(unsigned char *head_sha1, unsigned char *branch_sha1)
{
1648 1649 1650
	struct commit *head = lookup_commit(head_sha1);
	struct commit *branch = lookup_commit(branch_sha1);
	struct commit_list *merge_bases = get_merge_bases(head, branch, 1);
1651

D
David Rientjes 已提交
1652
	return (merge_bases && !merge_bases->next && merge_bases->item == branch);
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706
}

static int delete_remote_branch(char *pattern, int force)
{
	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 */
	for (i=0; symref && i<MAXDEPTH; i++) {
		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");
1707
		if (is_null_sha1(head_sha1))
1708 1709 1710 1711 1712
			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 */
1713
		if (is_null_sha1(remote_ref->old_sha1))
1714 1715 1716 1717 1718 1719 1720
			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 */
		if (!verify_merge_base(head_sha1, remote_ref->old_sha1)) {
1721 1722 1723 1724
			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'",
1725
				     remote_ref->name, repo->url, pattern);
1726 1727 1728 1729 1730
		}
	}

	/* Send delete request */
	fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name);
1731 1732
	if (dry_run)
		return 0;
1733 1734
	url = xmalloc(strlen(repo->url) + strlen(remote_ref->name) + 1);
	sprintf(url, "%s%s", repo->url, remote_ref->name);
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754
	slot = get_active_slot();
	slot->results = &results;
	curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);
	curl_easy_setopt(slot->curl, CURLOPT_URL, url);
	curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_DELETE);
	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;
}

1755
static void run_request_queue(void)
1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
{
#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
}

1774 1775 1776 1777 1778 1779
int main(int argc, char **argv)
{
	struct transfer_request *request;
	struct transfer_request *next_request;
	int nr_refspec = 0;
	char **refspec = NULL;
1780
	struct remote_lock *ref_lock = NULL;
1781
	struct remote_lock *info_ref_lock = NULL;
N
Nick Hengeveld 已提交
1782
	struct rev_info revs;
1783 1784
	int delete_branch = 0;
	int force_delete = 0;
N
Nick Hengeveld 已提交
1785
	int objects_to_send;
1786 1787
	int rc = 0;
	int i;
1788
	int new_refs;
1789
	struct ref *ref, *local_refs;
1790
	struct remote *remote;
1791
	char *rewritten_url = NULL;
1792

1793 1794
	git_extract_argv0_path(argv[0]);

1795
	setup_git_directory();
1796

1797
	repo = xcalloc(sizeof(*repo), 1);
1798 1799 1800 1801 1802 1803

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

		if (*arg == '-') {
N
Nick Hengeveld 已提交
1804
			if (!strcmp(arg, "--all")) {
A
Andy Whitcroft 已提交
1805
				push_all = MATCH_REFS_ALL;
1806 1807 1808 1809 1810 1811
				continue;
			}
			if (!strcmp(arg, "--force")) {
				force_all = 1;
				continue;
			}
1812 1813 1814 1815
			if (!strcmp(arg, "--dry-run")) {
				dry_run = 1;
				continue;
			}
1816 1817
			if (!strcmp(arg, "--verbose")) {
				push_verbosely = 1;
1818
				http_is_verbose = 1;
1819 1820
				continue;
			}
1821 1822 1823 1824 1825 1826 1827 1828 1829
			if (!strcmp(arg, "-d")) {
				delete_branch = 1;
				continue;
			}
			if (!strcmp(arg, "-D")) {
				delete_branch = 1;
				force_delete = 1;
				continue;
			}
1830
		}
1831
		if (!repo->url) {
N
Nick Hengeveld 已提交
1832
			char *path = strstr(arg, "//");
1833 1834
			repo->url = arg;
			repo->path_len = strlen(arg);
N
Nick Hengeveld 已提交
1835
			if (path) {
1836 1837 1838
				repo->path = strchr(path+2, '/');
				if (repo->path)
					repo->path_len = strlen(repo->path);
N
Nick Hengeveld 已提交
1839
			}
1840 1841 1842 1843 1844 1845 1846
			continue;
		}
		refspec = argv;
		nr_refspec = argc - i;
		break;
	}

1847 1848 1849 1850
#ifndef USE_CURL_MULTI
	die("git-push is not available for http/https repository when not compiled with USE_CURL_MULTI");
#endif

1851
	if (!repo->url)
N
Nick Hengeveld 已提交
1852 1853
		usage(http_push_usage);

1854 1855 1856
	if (delete_branch && nr_refspec != 1)
		die("You must specify only one branch name when deleting a remote branch");

N
Nick Hengeveld 已提交
1857
	memset(remote_dir_exists, -1, 256);
1858

1859 1860 1861 1862 1863 1864 1865 1866
	/*
	 * Create a minimum remote by hand to give to http_init(),
	 * primarily to allow it to look at the URL.
	 */
	remote = xcalloc(sizeof(*remote), 1);
	ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
	remote->url[remote->url_nr++] = repo->url;
	http_init(remote);
1867

1868 1869 1870
	if (repo->url && repo->url[strlen(repo->url)-1] != '/') {
		rewritten_url = xmalloc(strlen(repo->url)+2);
		strcpy(rewritten_url, repo->url);
1871
		strcat(rewritten_url, "/");
1872 1873 1874
		repo->path = rewritten_url + (repo->path - repo->url);
		repo->path_len++;
		repo->url = rewritten_url;
1875 1876
	}

1877
#ifdef USE_CURL_MULTI
1878
	is_running_queue = 0;
1879
#endif
1880

1881
	/* Verify DAV compliance/lock support */
N
Nick Hengeveld 已提交
1882
	if (!locking_available()) {
1883 1884 1885 1886
		rc = 1;
		goto cleanup;
	}

1887
	sigchain_push_common(remove_locks_on_signal);
1888

1889
	/* Check whether the remote has server info files */
1890 1891 1892 1893
	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) {
1894 1895
		info_ref_lock = lock_remote("info/refs", LOCK_TIME);
		if (info_ref_lock)
1896
			repo->can_update_info_refs = 1;
1897
		else {
1898
			error("cannot lock existing info/refs");
1899 1900 1901
			rc = 1;
			goto cleanup;
		}
1902
	}
1903
	if (repo->has_info_packs)
1904 1905
		fetch_indices();

N
Nick Hengeveld 已提交
1906
	/* Get a list of all local and remote heads to validate refspecs */
1907
	local_refs = get_local_heads();
N
Nick Hengeveld 已提交
1908 1909
	fprintf(stderr, "Fetching remote heads...\n");
	get_dav_remote_heads();
1910
	run_request_queue();
N
Nick Hengeveld 已提交
1911

1912 1913 1914 1915 1916 1917 1918 1919
	/* Remove a remote branch if -d or -D was specified */
	if (delete_branch) {
		if (delete_remote_branch(refspec[0], force_delete) == -1)
			fprintf(stderr, "Unable to delete remote branch %s\n",
				refspec[0]);
		goto cleanup;
	}

N
Nick Hengeveld 已提交
1920
	/* match them up */
1921
	if (match_refs(local_refs, &remote_refs,
1922 1923 1924 1925
		       nr_refspec, (const char **) refspec, push_all)) {
		rc = -1;
		goto cleanup;
	}
N
Nick Hengeveld 已提交
1926 1927
	if (!remote_refs) {
		fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
1928 1929
		rc = 0;
		goto cleanup;
N
Nick Hengeveld 已提交
1930 1931
	}

1932
	new_refs = 0;
N
Nick Hengeveld 已提交
1933 1934
	for (ref = remote_refs; ref; ref = ref->next) {
		char old_hex[60], *new_hex;
1935
		const char *commit_argv[5];
1936 1937 1938
		int commit_argc;
		char *new_sha1_hex, *old_sha1_hex;

N
Nick Hengeveld 已提交
1939 1940
		if (!ref->peer_ref)
			continue;
1941

1942
		if (is_null_sha1(ref->peer_ref->new_sha1)) {
1943 1944 1945 1946 1947 1948 1949 1950
			if (delete_remote_branch(ref->name, 1) == -1) {
				error("Could not remove %s", ref->name);
				rc = -4;
			}
			new_refs++;
			continue;
		}

1951
		if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
N
Nick Hengeveld 已提交
1952 1953 1954 1955 1956 1957
			if (push_verbosely || 1)
				fprintf(stderr, "'%s': up-to-date\n", ref->name);
			continue;
		}

		if (!force_all &&
1958
		    !is_null_sha1(ref->old_sha1) &&
N
Nick Hengeveld 已提交
1959 1960 1961 1962
		    !ref->force) {
			if (!has_sha1_file(ref->old_sha1) ||
			    !ref_newer(ref->peer_ref->new_sha1,
				       ref->old_sha1)) {
1963 1964
				/*
				 * We do not have the remote ref, or
N
Nick Hengeveld 已提交
1965 1966 1967 1968 1969 1970
				 * 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.
				 */
1971 1972 1973
				error("remote '%s' is not an ancestor of\n"
				      "local '%s'.\n"
				      "Maybe you are not up-to-date and "
N
Nick Hengeveld 已提交
1974 1975 1976
				      "need to pull first?",
				      ref->name,
				      ref->peer_ref->name);
N
Nick Hengeveld 已提交
1977
				rc = -2;
N
Nick Hengeveld 已提交
1978 1979
				continue;
			}
1980
		}
1981
		hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
N
Nick Hengeveld 已提交
1982 1983 1984 1985 1986 1987 1988 1989
		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);
1990 1991
		if (dry_run)
			continue;
1992 1993

		/* Lock remote branch ref */
N
Nick Hengeveld 已提交
1994 1995
		ref_lock = lock_remote(ref->name, LOCK_TIME);
		if (ref_lock == NULL) {
1996
			fprintf(stderr, "Unable to lock remote branch %s\n",
N
Nick Hengeveld 已提交
1997
				ref->name);
1998 1999 2000 2001
			rc = 1;
			continue;
		}

N
Nick Hengeveld 已提交
2002
		/* Set up revision info for this refspec */
2003
		commit_argc = 3;
2004
		new_sha1_hex = xstrdup(sha1_to_hex(ref->new_sha1));
2005
		old_sha1_hex = NULL;
N
Nick Hengeveld 已提交
2006 2007
		commit_argv[1] = "--objects";
		commit_argv[2] = new_sha1_hex;
2008
		if (!push_all && !is_null_sha1(ref->old_sha1)) {
N
Nick Hengeveld 已提交
2009 2010 2011
			old_sha1_hex = xmalloc(42);
			sprintf(old_sha1_hex, "^%s",
				sha1_to_hex(ref->old_sha1));
N
Nick Hengeveld 已提交
2012
			commit_argv[3] = old_sha1_hex;
N
Nick Hengeveld 已提交
2013
			commit_argc++;
2014
		}
2015
		commit_argv[commit_argc] = NULL;
2016
		init_revisions(&revs, setup_git_directory());
N
Nick Hengeveld 已提交
2017
		setup_revisions(commit_argc, commit_argv, &revs, NULL);
2018
		revs.edge_hint = 0; /* just in case */
N
Nick Hengeveld 已提交
2019 2020 2021 2022
		free(new_sha1_hex);
		if (old_sha1_hex) {
			free(old_sha1_hex);
			commit_argv[1] = NULL;
2023 2024
		}

N
Nick Hengeveld 已提交
2025
		/* Generate a list of objects that need to be pushed */
2026
		pushing = 0;
2027 2028
		if (prepare_revision_walk(&revs))
			die("revision walk setup failed");
2029
		mark_edges_uninteresting(revs.commits, &revs, NULL);
N
Nick Hengeveld 已提交
2030
		objects_to_send = get_delta(&revs, ref_lock);
2031
		finish_all_active_slots();
2032 2033 2034 2035

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

		run_request_queue();
2041 2042

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

N
Nick Hengeveld 已提交
2046 2047 2048
		if (!rc)
			fprintf(stderr, "    done\n");
		unlock_remote(ref_lock);
2049
		check_locks();
2050 2051
	}

2052
	/* Update remote server info if appropriate */
2053 2054
	if (repo->has_info_refs && new_refs) {
		if (info_ref_lock && repo->can_update_info_refs) {
2055
			fprintf(stderr, "Updating remote server info\n");
2056 2057
			if (!dry_run)
				update_remote_info_refs(info_ref_lock);
2058 2059 2060 2061 2062
		} else {
			fprintf(stderr, "Unable to update server info\n");
		}
	}

2063
 cleanup:
2064
	free(rewritten_url);
2065 2066
	if (info_ref_lock)
		unlock_remote(info_ref_lock);
2067
	free(repo);
2068

2069
	http_cleanup();
2070 2071 2072 2073 2074 2075 2076 2077 2078 2079

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

	return rc;
}