diff options
| author | Tay Ray Chuan <rctay89@gmail.com> | 2009-06-06 16:43:59 +0800 | 
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2009-06-06 11:03:11 -0700 | 
| commit | b8caac2b8ab6482e7ab59c8ec18f1c3d90e7387d (patch) | |
| tree | 173bbc81d92dc47a6c7bfac672a12fe53f9deb1d /http.c | |
| parent | 9af5abd9939585bb588d537085138563922c6abe (diff) | |
| download | git-b8caac2b8ab6482e7ab59c8ec18f1c3d90e7387d.tar.gz | |
http*: add http_get_info_packs
http-push.c and http-walker.c no longer have to use fetch_index or
setup_index; they simply need to use http_get_info_packs, a new http
method, in their fetch_indices implementations.
Move fetch_index() and rename to fetch_pack_index() in http.c; this
method is not meant to be used outside of http.c. It invokes
end_url_with_slash with base_url; apart from that change, the code is
identical.
Move setup_index() and rename to fetch_and_setup_pack_index() in
http.c; this method is not meant to be used outside of http.c.
Do not immediately set ret to 0 in http-walker.c::fetch_indices();
instead do it in the HTTP_MISSING_TARGET case, to make it clear that
the HTTP_OK and HTTP_MISSING_TARGET cases both return 0.
Signed-off-by: Tay Ray Chuan <rctay89@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'http.c')
| -rw-r--r-- | http.c | 164 | 
1 files changed, 164 insertions, 0 deletions
@@ -790,3 +790,167 @@ int http_fetch_ref(const char *base, struct ref *ref)  	free(url);  	return ret;  } + +/* Helpers for fetching packs */ +static int fetch_pack_index(unsigned char *sha1, const char *base_url) +{ +	int ret = 0; +	char *hex = xstrdup(sha1_to_hex(sha1)); +	char *filename; +	char *url; +	char tmpfile[PATH_MAX]; +	long prev_posn = 0; +	char range[RANGE_HEADER_SIZE]; +	struct strbuf buf = STRBUF_INIT; +	struct curl_slist *range_header = NULL; + +	FILE *indexfile; +	struct active_request_slot *slot; +	struct slot_results results; + +	/* Don't use the index if the pack isn't there */ +	end_url_with_slash(&buf, base_url); +	strbuf_addf(&buf, "objects/pack/pack-%s.pack", hex); +	url = strbuf_detach(&buf, 0); + +	slot = get_active_slot(); +	slot->results = &results; +	curl_easy_setopt(slot->curl, CURLOPT_URL, url); +	curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1); +	if (start_active_slot(slot)) { +		run_active_slot(slot); +		if (results.curl_result != CURLE_OK) { +			ret = error("Unable to verify pack %s is available", +				    hex); +			goto cleanup_pack; +		} +	} else { +		ret = error("Unable to start request"); +		goto cleanup_pack; +	} + +	if (has_pack_index(sha1)) { +		ret = 0; +		goto cleanup_pack; +	} + +	if (http_is_verbose) +		fprintf(stderr, "Getting index for pack %s\n", hex); + +	end_url_with_slash(&buf, base_url); +	strbuf_addf(&buf, "objects/pack/pack-%s.idx", hex); +	url = strbuf_detach(&buf, NULL); + +	filename = sha1_pack_index_name(sha1); +	snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename); +	indexfile = fopen(tmpfile, "a"); +	if (!indexfile) { +		ret = error("Unable to open local file %s for pack index", +			    tmpfile); +		goto cleanup_pack; +	} + +	slot = get_active_slot(); +	slot->results = &results; +	curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0); +	curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); +	curl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile); +	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite); +	curl_easy_setopt(slot->curl, CURLOPT_URL, url); +	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header); +	slot->local = indexfile; + +	/* +	 * If there is data present from a previous transfer attempt, +	 * resume where it left off +	 */ +	prev_posn = ftell(indexfile); +	if (prev_posn>0) { +		if (http_is_verbose) +			fprintf(stderr, +				"Resuming fetch of index for pack %s at byte %ld\n", +				hex, prev_posn); +		sprintf(range, "Range: bytes=%ld-", prev_posn); +		range_header = curl_slist_append(range_header, range); +		curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header); +	} + +	if (start_active_slot(slot)) { +		run_active_slot(slot); +		if (results.curl_result != CURLE_OK) { +			ret = error("Unable to get pack index %s\n%s", +				    url, curl_errorstr); +			goto cleanup_index; +		} +	} else { +		ret = error("Unable to start request"); +		goto cleanup_index; +	} + +	ret = move_temp_to_file(tmpfile, filename); + +cleanup_index: +	fclose(indexfile); +	slot->local = NULL; +cleanup_pack: +	free(hex); +	free(url); +	return ret; +} + +static int fetch_and_setup_pack_index(struct packed_git **packs_head, +	unsigned char *sha1, const char *base_url) +{ +	struct packed_git *new_pack; + +	if (fetch_pack_index(sha1, base_url)) +		return -1; + +	new_pack = parse_pack_index(sha1); +	if (!new_pack) +		return -1; /* parse_pack_index() already issued error message */ +	new_pack->next = *packs_head; +	*packs_head = new_pack; +	return 0; +} + +int http_get_info_packs(const char *base_url, struct packed_git **packs_head) +{ +	int ret = 0, i = 0; +	char *url, *data; +	struct strbuf buf = STRBUF_INIT; +	unsigned char sha1[20]; + +	end_url_with_slash(&buf, base_url); +	strbuf_addstr(&buf, "objects/info/packs"); +	url = strbuf_detach(&buf, NULL); + +	ret = http_get_strbuf(url, &buf, HTTP_NO_CACHE); +	if (ret != HTTP_OK) +		goto cleanup; + +	data = buf.buf; +	while (i < buf.len) { +		switch (data[i]) { +		case 'P': +			i++; +			if (i + 52 <= buf.len && +			    !prefixcmp(data + i, " pack-") && +			    !prefixcmp(data + i + 46, ".pack\n")) { +				get_sha1_hex(data + i + 6, sha1); +				fetch_and_setup_pack_index(packs_head, sha1, +						      base_url); +				i += 51; +				break; +			} +		default: +			while (i < buf.len && data[i] != '\n') +				i++; +		} +		i++; +	} + +cleanup: +	free(url); +	return ret; +}  | 
