http: use strbufs instead of fixed buffers
We keep the names of incoming packs and objects in fixed PATH_MAX-size buffers, and snprintf() into them. This is unlikely to end up with truncated filenames, but it is possible (especially on systems where PATH_MAX is shorter than actual paths can be). Let's switch to using strbufs, which makes the question go away entirely. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									468165c1d8
								
							
						
					
					
						commit
						390c6cbc5e
					
				
							
								
								
									
										66
									
								
								http.c
								
								
								
								
							
							
						
						
									
										66
									
								
								http.c
								
								
								
								
							|  | @ -2087,6 +2087,7 @@ void release_http_pack_request(struct http_pack_request *preq) | ||||||
| 		preq->packfile = NULL; | 		preq->packfile = NULL; | ||||||
| 	} | 	} | ||||||
| 	preq->slot = NULL; | 	preq->slot = NULL; | ||||||
|  | 	strbuf_release(&preq->tmpfile); | ||||||
| 	free(preq->url); | 	free(preq->url); | ||||||
| 	free(preq); | 	free(preq); | ||||||
| } | } | ||||||
|  | @ -2109,19 +2110,19 @@ int finish_http_pack_request(struct http_pack_request *preq) | ||||||
| 		lst = &((*lst)->next); | 		lst = &((*lst)->next); | ||||||
| 	*lst = (*lst)->next; | 	*lst = (*lst)->next; | ||||||
|  |  | ||||||
| 	if (!strip_suffix(preq->tmpfile, ".pack.temp", &len)) | 	if (!strip_suffix(preq->tmpfile.buf, ".pack.temp", &len)) | ||||||
| 		die("BUG: pack tmpfile does not end in .pack.temp?"); | 		die("BUG: pack tmpfile does not end in .pack.temp?"); | ||||||
| 	tmp_idx = xstrfmt("%.*s.idx.temp", (int)len, preq->tmpfile); | 	tmp_idx = xstrfmt("%.*s.idx.temp", (int)len, preq->tmpfile.buf); | ||||||
|  |  | ||||||
| 	argv_array_push(&ip.args, "index-pack"); | 	argv_array_push(&ip.args, "index-pack"); | ||||||
| 	argv_array_pushl(&ip.args, "-o", tmp_idx, NULL); | 	argv_array_pushl(&ip.args, "-o", tmp_idx, NULL); | ||||||
| 	argv_array_push(&ip.args, preq->tmpfile); | 	argv_array_push(&ip.args, preq->tmpfile.buf); | ||||||
| 	ip.git_cmd = 1; | 	ip.git_cmd = 1; | ||||||
| 	ip.no_stdin = 1; | 	ip.no_stdin = 1; | ||||||
| 	ip.no_stdout = 1; | 	ip.no_stdout = 1; | ||||||
|  |  | ||||||
| 	if (run_command(&ip)) { | 	if (run_command(&ip)) { | ||||||
| 		unlink(preq->tmpfile); | 		unlink(preq->tmpfile.buf); | ||||||
| 		unlink(tmp_idx); | 		unlink(tmp_idx); | ||||||
| 		free(tmp_idx); | 		free(tmp_idx); | ||||||
| 		return -1; | 		return -1; | ||||||
|  | @ -2129,7 +2130,7 @@ int finish_http_pack_request(struct http_pack_request *preq) | ||||||
|  |  | ||||||
| 	unlink(sha1_pack_index_name(p->sha1)); | 	unlink(sha1_pack_index_name(p->sha1)); | ||||||
|  |  | ||||||
| 	if (finalize_object_file(preq->tmpfile, sha1_pack_name(p->sha1)) | 	if (finalize_object_file(preq->tmpfile.buf, sha1_pack_name(p->sha1)) | ||||||
| 	 || finalize_object_file(tmp_idx, sha1_pack_index_name(p->sha1))) { | 	 || finalize_object_file(tmp_idx, sha1_pack_index_name(p->sha1))) { | ||||||
| 		free(tmp_idx); | 		free(tmp_idx); | ||||||
| 		return -1; | 		return -1; | ||||||
|  | @ -2148,6 +2149,7 @@ struct http_pack_request *new_http_pack_request( | ||||||
| 	struct http_pack_request *preq; | 	struct http_pack_request *preq; | ||||||
|  |  | ||||||
| 	preq = xcalloc(1, sizeof(*preq)); | 	preq = xcalloc(1, sizeof(*preq)); | ||||||
|  | 	strbuf_init(&preq->tmpfile, 0); | ||||||
| 	preq->target = target; | 	preq->target = target; | ||||||
|  |  | ||||||
| 	end_url_with_slash(&buf, base_url); | 	end_url_with_slash(&buf, base_url); | ||||||
|  | @ -2155,12 +2157,11 @@ struct http_pack_request *new_http_pack_request( | ||||||
| 		sha1_to_hex(target->sha1)); | 		sha1_to_hex(target->sha1)); | ||||||
| 	preq->url = strbuf_detach(&buf, NULL); | 	preq->url = strbuf_detach(&buf, NULL); | ||||||
|  |  | ||||||
| 	snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp", | 	strbuf_addf(&preq->tmpfile, "%s.temp", sha1_pack_name(target->sha1)); | ||||||
| 		sha1_pack_name(target->sha1)); | 	preq->packfile = fopen(preq->tmpfile.buf, "a"); | ||||||
| 	preq->packfile = fopen(preq->tmpfile, "a"); |  | ||||||
| 	if (!preq->packfile) { | 	if (!preq->packfile) { | ||||||
| 		error("Unable to open local file %s for pack", | 		error("Unable to open local file %s for pack", | ||||||
| 		      preq->tmpfile); | 		      preq->tmpfile.buf); | ||||||
| 		goto abort; | 		goto abort; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -2187,6 +2188,7 @@ struct http_pack_request *new_http_pack_request( | ||||||
| 	return preq; | 	return preq; | ||||||
|  |  | ||||||
| abort: | abort: | ||||||
|  | 	strbuf_release(&preq->tmpfile); | ||||||
| 	free(preq->url); | 	free(preq->url); | ||||||
| 	free(preq); | 	free(preq); | ||||||
| 	return NULL; | 	return NULL; | ||||||
|  | @ -2237,7 +2239,7 @@ struct http_object_request *new_http_object_request(const char *base_url, | ||||||
| { | { | ||||||
| 	char *hex = sha1_to_hex(sha1); | 	char *hex = sha1_to_hex(sha1); | ||||||
| 	struct strbuf filename = STRBUF_INIT; | 	struct strbuf filename = STRBUF_INIT; | ||||||
| 	char prevfile[PATH_MAX]; | 	struct strbuf prevfile = STRBUF_INIT; | ||||||
| 	int prevlocal; | 	int prevlocal; | ||||||
| 	char prev_buf[PREV_BUF_SIZE]; | 	char prev_buf[PREV_BUF_SIZE]; | ||||||
| 	ssize_t prev_read = 0; | 	ssize_t prev_read = 0; | ||||||
|  | @ -2245,40 +2247,41 @@ struct http_object_request *new_http_object_request(const char *base_url, | ||||||
| 	struct http_object_request *freq; | 	struct http_object_request *freq; | ||||||
|  |  | ||||||
| 	freq = xcalloc(1, sizeof(*freq)); | 	freq = xcalloc(1, sizeof(*freq)); | ||||||
|  | 	strbuf_init(&freq->tmpfile, 0); | ||||||
| 	hashcpy(freq->sha1, sha1); | 	hashcpy(freq->sha1, sha1); | ||||||
| 	freq->localfile = -1; | 	freq->localfile = -1; | ||||||
|  |  | ||||||
| 	sha1_file_name(&filename, sha1); | 	sha1_file_name(&filename, sha1); | ||||||
| 	snprintf(freq->tmpfile, sizeof(freq->tmpfile), | 	strbuf_addf(&freq->tmpfile, "%s.temp", filename.buf); | ||||||
| 		 "%s.temp", filename.buf); |  | ||||||
|  |  | ||||||
| 	snprintf(prevfile, sizeof(prevfile), "%s.prev", filename.buf); | 	strbuf_addf(&prevfile, "%s.prev", filename.buf); | ||||||
| 	unlink_or_warn(prevfile); | 	unlink_or_warn(prevfile.buf); | ||||||
| 	rename(freq->tmpfile, prevfile); | 	rename(freq->tmpfile.buf, prevfile.buf); | ||||||
| 	unlink_or_warn(freq->tmpfile); | 	unlink_or_warn(freq->tmpfile.buf); | ||||||
| 	strbuf_release(&filename); | 	strbuf_release(&filename); | ||||||
|  |  | ||||||
| 	if (freq->localfile != -1) | 	if (freq->localfile != -1) | ||||||
| 		error("fd leakage in start: %d", freq->localfile); | 		error("fd leakage in start: %d", freq->localfile); | ||||||
| 	freq->localfile = open(freq->tmpfile, | 	freq->localfile = open(freq->tmpfile.buf, | ||||||
| 			       O_WRONLY | O_CREAT | O_EXCL, 0666); | 			       O_WRONLY | O_CREAT | O_EXCL, 0666); | ||||||
| 	/* | 	/* | ||||||
| 	 * This could have failed due to the "lazy directory creation"; | 	 * This could have failed due to the "lazy directory creation"; | ||||||
| 	 * try to mkdir the last path component. | 	 * try to mkdir the last path component. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (freq->localfile < 0 && errno == ENOENT) { | 	if (freq->localfile < 0 && errno == ENOENT) { | ||||||
| 		char *dir = strrchr(freq->tmpfile, '/'); | 		char *dir = strrchr(freq->tmpfile.buf, '/'); | ||||||
| 		if (dir) { | 		if (dir) { | ||||||
| 			*dir = 0; | 			*dir = 0; | ||||||
| 			mkdir(freq->tmpfile, 0777); | 			mkdir(freq->tmpfile.buf, 0777); | ||||||
| 			*dir = '/'; | 			*dir = '/'; | ||||||
| 		} | 		} | ||||||
| 		freq->localfile = open(freq->tmpfile, | 		freq->localfile = open(freq->tmpfile.buf, | ||||||
| 				       O_WRONLY | O_CREAT | O_EXCL, 0666); | 				       O_WRONLY | O_CREAT | O_EXCL, 0666); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (freq->localfile < 0) { | 	if (freq->localfile < 0) { | ||||||
| 		error_errno("Couldn't create temporary file %s", freq->tmpfile); | 		error_errno("Couldn't create temporary file %s", | ||||||
|  | 			    freq->tmpfile.buf); | ||||||
| 		goto abort; | 		goto abort; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -2292,7 +2295,7 @@ struct http_object_request *new_http_object_request(const char *base_url, | ||||||
| 	 * If a previous temp file is present, process what was already | 	 * If a previous temp file is present, process what was already | ||||||
| 	 * fetched. | 	 * fetched. | ||||||
| 	 */ | 	 */ | ||||||
| 	prevlocal = open(prevfile, O_RDONLY); | 	prevlocal = open(prevfile.buf, O_RDONLY); | ||||||
| 	if (prevlocal != -1) { | 	if (prevlocal != -1) { | ||||||
| 		do { | 		do { | ||||||
| 			prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE); | 			prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE); | ||||||
|  | @ -2309,7 +2312,8 @@ struct http_object_request *new_http_object_request(const char *base_url, | ||||||
| 		} while (prev_read > 0); | 		} while (prev_read > 0); | ||||||
| 		close(prevlocal); | 		close(prevlocal); | ||||||
| 	} | 	} | ||||||
| 	unlink_or_warn(prevfile); | 	unlink_or_warn(prevfile.buf); | ||||||
|  | 	strbuf_release(&prevfile); | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| 	 * Reset inflate/SHA1 if there was an error reading the previous temp | 	 * Reset inflate/SHA1 if there was an error reading the previous temp | ||||||
|  | @ -2324,7 +2328,7 @@ struct http_object_request *new_http_object_request(const char *base_url, | ||||||
| 			lseek(freq->localfile, 0, SEEK_SET); | 			lseek(freq->localfile, 0, SEEK_SET); | ||||||
| 			if (ftruncate(freq->localfile, 0) < 0) { | 			if (ftruncate(freq->localfile, 0) < 0) { | ||||||
| 				error_errno("Couldn't truncate temporary file %s", | 				error_errno("Couldn't truncate temporary file %s", | ||||||
| 					    freq->tmpfile); | 					    freq->tmpfile.buf); | ||||||
| 				goto abort; | 				goto abort; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | @ -2354,6 +2358,7 @@ struct http_object_request *new_http_object_request(const char *base_url, | ||||||
| 	return freq; | 	return freq; | ||||||
|  |  | ||||||
| abort: | abort: | ||||||
|  | 	strbuf_release(&prevfile); | ||||||
| 	free(freq->url); | 	free(freq->url); | ||||||
| 	free(freq); | 	free(freq); | ||||||
| 	return NULL; | 	return NULL; | ||||||
|  | @ -2381,25 +2386,25 @@ int finish_http_object_request(struct http_object_request *freq) | ||||||
| 	if (freq->http_code == 416) { | 	if (freq->http_code == 416) { | ||||||
| 		warning("requested range invalid; we may already have all the data."); | 		warning("requested range invalid; we may already have all the data."); | ||||||
| 	} else if (freq->curl_result != CURLE_OK) { | 	} else if (freq->curl_result != CURLE_OK) { | ||||||
| 		if (stat(freq->tmpfile, &st) == 0) | 		if (stat(freq->tmpfile.buf, &st) == 0) | ||||||
| 			if (st.st_size == 0) | 			if (st.st_size == 0) | ||||||
| 				unlink_or_warn(freq->tmpfile); | 				unlink_or_warn(freq->tmpfile.buf); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	git_inflate_end(&freq->stream); | 	git_inflate_end(&freq->stream); | ||||||
| 	git_SHA1_Final(freq->real_sha1, &freq->c); | 	git_SHA1_Final(freq->real_sha1, &freq->c); | ||||||
| 	if (freq->zret != Z_STREAM_END) { | 	if (freq->zret != Z_STREAM_END) { | ||||||
| 		unlink_or_warn(freq->tmpfile); | 		unlink_or_warn(freq->tmpfile.buf); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 	if (hashcmp(freq->sha1, freq->real_sha1)) { | 	if (hashcmp(freq->sha1, freq->real_sha1)) { | ||||||
| 		unlink_or_warn(freq->tmpfile); | 		unlink_or_warn(freq->tmpfile.buf); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	sha1_file_name(&filename, freq->sha1); | 	sha1_file_name(&filename, freq->sha1); | ||||||
| 	freq->rename = finalize_object_file(freq->tmpfile, filename.buf); | 	freq->rename = finalize_object_file(freq->tmpfile.buf, filename.buf); | ||||||
| 	strbuf_release(&filename); | 	strbuf_release(&filename); | ||||||
|  |  | ||||||
| 	return freq->rename; | 	return freq->rename; | ||||||
|  | @ -2407,7 +2412,7 @@ int finish_http_object_request(struct http_object_request *freq) | ||||||
|  |  | ||||||
| void abort_http_object_request(struct http_object_request *freq) | void abort_http_object_request(struct http_object_request *freq) | ||||||
| { | { | ||||||
| 	unlink_or_warn(freq->tmpfile); | 	unlink_or_warn(freq->tmpfile.buf); | ||||||
|  |  | ||||||
| 	release_http_object_request(freq); | 	release_http_object_request(freq); | ||||||
| } | } | ||||||
|  | @ -2427,4 +2432,5 @@ void release_http_object_request(struct http_object_request *freq) | ||||||
| 		release_active_slot(freq->slot); | 		release_active_slot(freq->slot); | ||||||
| 		freq->slot = NULL; | 		freq->slot = NULL; | ||||||
| 	} | 	} | ||||||
|  | 	strbuf_release(&freq->tmpfile); | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								http.h
								
								
								
								
							
							
						
						
									
										4
									
								
								http.h
								
								
								
								
							|  | @ -200,7 +200,7 @@ struct http_pack_request { | ||||||
| 	struct packed_git *target; | 	struct packed_git *target; | ||||||
| 	struct packed_git **lst; | 	struct packed_git **lst; | ||||||
| 	FILE *packfile; | 	FILE *packfile; | ||||||
| 	char tmpfile[PATH_MAX]; | 	struct strbuf tmpfile; | ||||||
| 	struct active_request_slot *slot; | 	struct active_request_slot *slot; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -212,7 +212,7 @@ extern void release_http_pack_request(struct http_pack_request *preq); | ||||||
| /* Helpers for fetching object */ | /* Helpers for fetching object */ | ||||||
| struct http_object_request { | struct http_object_request { | ||||||
| 	char *url; | 	char *url; | ||||||
| 	char tmpfile[PATH_MAX]; | 	struct strbuf tmpfile; | ||||||
| 	int localfile; | 	int localfile; | ||||||
| 	CURLcode curl_result; | 	CURLcode curl_result; | ||||||
| 	char errorstr[CURL_ERROR_SIZE]; | 	char errorstr[CURL_ERROR_SIZE]; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Jeff King
						Jeff King