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>

Jeff King committed May 18, 2018 at 18:56 UTC 390c6cbc5e643b6d89869b319b51b5b62a3f5a09
2 files changed +38 -32
http.c
+36 -30
@@ -2087,6 +2087,7 @@ void release_http_pack_request(struct http_pack_request *preq)
2087 preq->packfile = NULL;
2088 }
2089 preq->slot = NULL;
2090 + strbuf_release(&preq->tmpfile);
2091 free(preq->url);
2092 free(preq);
2093 }
@@ -2109,19 +2110,19 @@ int finish_http_pack_request(struct http_pack_request *preq)
2110 lst = &((*lst)->next);
2111 *lst = (*lst)->next;
2112
2112 - if (!strip_suffix(preq->tmpfile, ".pack.temp", &len))
2113 + if (!strip_suffix(preq->tmpfile.buf, ".pack.temp", &len))
2114 die("BUG: pack tmpfile does not end in .pack.temp?");
2114 - tmp_idx = xstrfmt("%.*s.idx.temp", (int)len, preq->tmpfile);
2115 + tmp_idx = xstrfmt("%.*s.idx.temp", (int)len, preq->tmpfile.buf);
2116
2117 argv_array_push(&ip.args, "index-pack");
2118 argv_array_pushl(&ip.args, "-o", tmp_idx, NULL);
2118 - argv_array_push(&ip.args, preq->tmpfile);
2119 + argv_array_push(&ip.args, preq->tmpfile.buf);
2120 ip.git_cmd = 1;
2121 ip.no_stdin = 1;
2122 ip.no_stdout = 1;
2123
2124 if (run_command(&ip)) {
2124 - unlink(preq->tmpfile);
2125 + unlink(preq->tmpfile.buf);
2126 unlink(tmp_idx);
2127 free(tmp_idx);
2128 return -1;
@@ -2129,7 +2130,7 @@ int finish_http_pack_request(struct http_pack_request *preq)
2130
2131 unlink(sha1_pack_index_name(p->sha1));
2132
2132 - if (finalize_object_file(preq->tmpfile, sha1_pack_name(p->sha1))
2133 + if (finalize_object_file(preq->tmpfile.buf, sha1_pack_name(p->sha1))
2134 || finalize_object_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
2135 free(tmp_idx);
2136 return -1;
@@ -2148,6 +2149,7 @@ struct http_pack_request *new_http_pack_request(
2149 struct http_pack_request *preq;
2150
2151 preq = xcalloc(1, sizeof(*preq));
2152 + strbuf_init(&preq->tmpfile, 0);
2153 preq->target = target;
2154
2155 end_url_with_slash(&buf, base_url);
@@ -2155,12 +2157,11 @@ struct http_pack_request *new_http_pack_request(
2157 sha1_to_hex(target->sha1));
2158 preq->url = strbuf_detach(&buf, NULL);
2159
2158 - snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp",
2159 - sha1_pack_name(target->sha1));
2160 - preq->packfile = fopen(preq->tmpfile, "a");
2160 + strbuf_addf(&preq->tmpfile, "%s.temp", sha1_pack_name(target->sha1));
2161 + preq->packfile = fopen(preq->tmpfile.buf, "a");
2162 if (!preq->packfile) {
2163 error("Unable to open local file %s for pack",
2163 - preq->tmpfile);
2164 + preq->tmpfile.buf);
2165 goto abort;
2166 }
2167
@@ -2187,6 +2188,7 @@ struct http_pack_request *new_http_pack_request(
2188 return preq;
2189
2190 abort:
2191 + strbuf_release(&preq->tmpfile);
2192 free(preq->url);
2193 free(preq);
2194 return NULL;
@@ -2237,7 +2239,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
2239 {
2240 char *hex = sha1_to_hex(sha1);
2241 struct strbuf filename = STRBUF_INIT;
2240 - char prevfile[PATH_MAX];
2242 + struct strbuf prevfile = STRBUF_INIT;
2243 int prevlocal;
2244 char prev_buf[PREV_BUF_SIZE];
2245 ssize_t prev_read = 0;
@@ -2245,40 +2247,41 @@ struct http_object_request *new_http_object_request(const char *base_url,
2247 struct http_object_request *freq;
2248
2249 freq = xcalloc(1, sizeof(*freq));
2250 + strbuf_init(&freq->tmpfile, 0);
2251 hashcpy(freq->sha1, sha1);
2252 freq->localfile = -1;
2253
2254 sha1_file_name(&filename, sha1);
2252 - snprintf(freq->tmpfile, sizeof(freq->tmpfile),
2253 - "%s.temp", filename.buf);
2255 + strbuf_addf(&freq->tmpfile, "%s.temp", filename.buf);
2256
2255 - snprintf(prevfile, sizeof(prevfile), "%s.prev", filename.buf);
2256 - unlink_or_warn(prevfile);
2257 - rename(freq->tmpfile, prevfile);
2258 - unlink_or_warn(freq->tmpfile);
2257 + strbuf_addf(&prevfile, "%s.prev", filename.buf);
2258 + unlink_or_warn(prevfile.buf);
2259 + rename(freq->tmpfile.buf, prevfile.buf);
2260 + unlink_or_warn(freq->tmpfile.buf);
2261 strbuf_release(&filename);
2262
2263 if (freq->localfile != -1)
2264 error("fd leakage in start: %d", freq->localfile);
2263 - freq->localfile = open(freq->tmpfile,
2265 + freq->localfile = open(freq->tmpfile.buf,
2266 O_WRONLY | O_CREAT | O_EXCL, 0666);
2267 /*
2268 * This could have failed due to the "lazy directory creation";
2269 * try to mkdir the last path component.
2270 */
2271 if (freq->localfile < 0 && errno == ENOENT) {
2270 - char *dir = strrchr(freq->tmpfile, '/');
2272 + char *dir = strrchr(freq->tmpfile.buf, '/');
2273 if (dir) {
2274 *dir = 0;
2273 - mkdir(freq->tmpfile, 0777);
2275 + mkdir(freq->tmpfile.buf, 0777);
2276 *dir = '/';
2277 }
2276 - freq->localfile = open(freq->tmpfile,
2278 + freq->localfile = open(freq->tmpfile.buf,
2279 O_WRONLY | O_CREAT | O_EXCL, 0666);
2280 }
2281
2282 if (freq->localfile < 0) {
2281 - error_errno("Couldn't create temporary file %s", freq->tmpfile);
2283 + error_errno("Couldn't create temporary file %s",
2284 + freq->tmpfile.buf);
2285 goto abort;
2286 }
2287
@@ -2292,7 +2295,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
2295 * If a previous temp file is present, process what was already
2296 * fetched.
2297 */
2295 - prevlocal = open(prevfile, O_RDONLY);
2298 + prevlocal = open(prevfile.buf, O_RDONLY);
2299 if (prevlocal != -1) {
2300 do {
2301 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,
2312 } while (prev_read > 0);
2313 close(prevlocal);
2314 }
2312 - unlink_or_warn(prevfile);
2315 + unlink_or_warn(prevfile.buf);
2316 + strbuf_release(&prevfile);
2317
2318 /*
2319 * 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,
2328 lseek(freq->localfile, 0, SEEK_SET);
2329 if (ftruncate(freq->localfile, 0) < 0) {
2330 error_errno("Couldn't truncate temporary file %s",
2327 - freq->tmpfile);
2331 + freq->tmpfile.buf);
2332 goto abort;
2333 }
2334 }
@@ -2354,6 +2358,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
2358 return freq;
2359
2360 abort:
2361 + strbuf_release(&prevfile);
2362 free(freq->url);
2363 free(freq);
2364 return NULL;
@@ -2381,25 +2386,25 @@ int finish_http_object_request(struct http_object_request *freq)
2386 if (freq->http_code == 416) {
2387 warning("requested range invalid; we may already have all the data.");
2388 } else if (freq->curl_result != CURLE_OK) {
2384 - if (stat(freq->tmpfile, &st) == 0)
2389 + if (stat(freq->tmpfile.buf, &st) == 0)
2390 if (st.st_size == 0)
2386 - unlink_or_warn(freq->tmpfile);
2391 + unlink_or_warn(freq->tmpfile.buf);
2392 return -1;
2393 }
2394
2395 git_inflate_end(&freq->stream);
2396 git_SHA1_Final(freq->real_sha1, &freq->c);
2397 if (freq->zret != Z_STREAM_END) {
2393 - unlink_or_warn(freq->tmpfile);
2398 + unlink_or_warn(freq->tmpfile.buf);
2399 return -1;
2400 }
2401 if (hashcmp(freq->sha1, freq->real_sha1)) {
2397 - unlink_or_warn(freq->tmpfile);
2402 + unlink_or_warn(freq->tmpfile.buf);
2403 return -1;
2404 }
2405
2406 sha1_file_name(&filename, freq->sha1);
2402 - freq->rename = finalize_object_file(freq->tmpfile, filename.buf);
2407 + freq->rename = finalize_object_file(freq->tmpfile.buf, filename.buf);
2408 strbuf_release(&filename);
2409
2410 return freq->rename;
@@ -2407,7 +2412,7 @@ int finish_http_object_request(struct http_object_request *freq)
2412
2413 void abort_http_object_request(struct http_object_request *freq)
2414 {
2410 - unlink_or_warn(freq->tmpfile);
2415 + unlink_or_warn(freq->tmpfile.buf);
2416
2417 release_http_object_request(freq);
2418 }
@@ -2427,4 +2432,5 @@ void release_http_object_request(struct http_object_request *freq)
2432 release_active_slot(freq->slot);
2433 freq->slot = NULL;
2434 }
2435 + strbuf_release(&freq->tmpfile);
2436 }
http.h
+2 -2
@@ -200,7 +200,7 @@ struct http_pack_request {
200 struct packed_git *target;
201 struct packed_git **lst;
202 FILE *packfile;
203 - char tmpfile[PATH_MAX];
203 + struct strbuf tmpfile;
204 struct active_request_slot *slot;
205 };
206
@@ -212,7 +212,7 @@ extern void release_http_pack_request(struct http_pack_request *preq);
212 /* Helpers for fetching object */
213 struct http_object_request {
214 char *url;
215 - char tmpfile[PATH_MAX];
215 + struct strbuf tmpfile;
216 int localfile;
217 CURLcode curl_result;
218 char errorstr[CURL_ERROR_SIZE];