]>
Commit | Line | Data |
---|---|---|
6eb7ed54 DB |
1 | #include "cache.h" |
2 | #include "commit.h" | |
30ae764b | 3 | #include "walker.h" |
29508e1e | 4 | #include "http.h" |
7baa3e86 | 5 | |
b3661567 DB |
6 | struct alt_base |
7 | { | |
2afea3bc | 8 | char *base; |
b3661567 DB |
9 | int got_indices; |
10 | struct packed_git *packs; | |
11 | struct alt_base *next; | |
12 | }; | |
13 | ||
e388ab74 | 14 | enum object_request_state { |
1d389ab6 NH |
15 | WAITING, |
16 | ABORTED, | |
17 | ACTIVE, | |
18 | COMPLETE, | |
19 | }; | |
6eb7ed54 | 20 | |
e388ab74 | 21 | struct object_request |
1d389ab6 | 22 | { |
30ae764b | 23 | struct walker *walker; |
1d389ab6 NH |
24 | unsigned char sha1[20]; |
25 | struct alt_base *repo; | |
e388ab74 | 26 | enum object_request_state state; |
5424bc55 | 27 | struct http_object_request *req; |
e388ab74 | 28 | struct object_request *next; |
1d389ab6 NH |
29 | }; |
30 | ||
e388ab74 | 31 | struct alternates_request { |
30ae764b | 32 | struct walker *walker; |
8e29f6a0 | 33 | const char *base; |
acc075a8 | 34 | char *url; |
028c2976 | 35 | struct strbuf *buffer; |
acc075a8 NH |
36 | struct active_request_slot *slot; |
37 | int http_specific; | |
38 | }; | |
39 | ||
30ae764b DB |
40 | struct walker_data { |
41 | const char *url; | |
42 | int got_alternates; | |
43 | struct alt_base *alt; | |
30ae764b DB |
44 | }; |
45 | ||
96f1e58f | 46 | static struct object_request *object_queue_head; |
bc8f2652 | 47 | |
30ae764b | 48 | static void fetch_alternates(struct walker *walker, const char *base); |
1d389ab6 | 49 | |
29508e1e | 50 | static void process_object_response(void *callback_data); |
1d389ab6 | 51 | |
30ae764b DB |
52 | static void start_object_request(struct walker *walker, |
53 | struct object_request *obj_req) | |
1d389ab6 | 54 | { |
1d389ab6 | 55 | struct active_request_slot *slot; |
5424bc55 | 56 | struct http_object_request *req; |
1d389ab6 | 57 | |
5424bc55 TRC |
58 | req = new_http_object_request(obj_req->repo->base, obj_req->sha1); |
59 | if (req == NULL) { | |
e388ab74 | 60 | obj_req->state = ABORTED; |
1d389ab6 NH |
61 | return; |
62 | } | |
5424bc55 | 63 | obj_req->req = req; |
1d389ab6 | 64 | |
5424bc55 | 65 | slot = req->slot; |
29508e1e | 66 | slot->callback_func = process_object_response; |
e388ab74 | 67 | slot->callback_data = obj_req; |
1d389ab6 | 68 | |
a7a8d378 | 69 | /* Try to get the request started, abort the request on error */ |
e388ab74 | 70 | obj_req->state = ACTIVE; |
1d389ab6 | 71 | if (!start_active_slot(slot)) { |
e388ab74 | 72 | obj_req->state = ABORTED; |
5424bc55 | 73 | release_http_object_request(req); |
e388ab74 | 74 | return; |
1d389ab6 | 75 | } |
1d389ab6 NH |
76 | } |
77 | ||
e388ab74 | 78 | static void finish_object_request(struct object_request *obj_req) |
1d389ab6 | 79 | { |
5424bc55 | 80 | if (finish_http_object_request(obj_req->req)) |
1d389ab6 | 81 | return; |
1d389ab6 | 82 | |
5424bc55 | 83 | if (obj_req->req->rename == 0) |
30ae764b | 84 | walker_say(obj_req->walker, "got %s\n", sha1_to_hex(obj_req->sha1)); |
1d389ab6 NH |
85 | } |
86 | ||
29508e1e NH |
87 | static void process_object_response(void *callback_data) |
88 | { | |
e388ab74 NH |
89 | struct object_request *obj_req = |
90 | (struct object_request *)callback_data; | |
30ae764b DB |
91 | struct walker *walker = obj_req->walker; |
92 | struct walker_data *data = walker->data; | |
93 | struct alt_base *alt = data->alt; | |
29508e1e | 94 | |
5424bc55 | 95 | process_http_object_request(obj_req->req); |
e388ab74 | 96 | obj_req->state = COMPLETE; |
29508e1e NH |
97 | |
98 | /* Use alternates if necessary */ | |
5424bc55 | 99 | if (missing_target(obj_req->req)) { |
30ae764b | 100 | fetch_alternates(walker, alt->base); |
e388ab74 NH |
101 | if (obj_req->repo->next != NULL) { |
102 | obj_req->repo = | |
103 | obj_req->repo->next; | |
5424bc55 | 104 | release_http_object_request(obj_req->req); |
30ae764b | 105 | start_object_request(walker, obj_req); |
29508e1e NH |
106 | return; |
107 | } | |
108 | } | |
109 | ||
e388ab74 | 110 | finish_object_request(obj_req); |
29508e1e NH |
111 | } |
112 | ||
e388ab74 | 113 | static void release_object_request(struct object_request *obj_req) |
1d389ab6 | 114 | { |
e388ab74 | 115 | struct object_request *entry = object_queue_head; |
1d389ab6 | 116 | |
5424bc55 TRC |
117 | if (obj_req->req !=NULL && obj_req->req->localfile != -1) |
118 | error("fd leakage in release: %d", obj_req->req->localfile); | |
e388ab74 NH |
119 | if (obj_req == object_queue_head) { |
120 | object_queue_head = obj_req->next; | |
1d389ab6 | 121 | } else { |
e388ab74 | 122 | while (entry->next != NULL && entry->next != obj_req) |
1d389ab6 | 123 | entry = entry->next; |
e388ab74 | 124 | if (entry->next == obj_req) |
1d389ab6 NH |
125 | entry->next = entry->next->next; |
126 | } | |
127 | ||
e388ab74 | 128 | free(obj_req); |
1d389ab6 NH |
129 | } |
130 | ||
a7a8d378 | 131 | #ifdef USE_CURL_MULTI |
30ae764b | 132 | static int fill_active_slot(struct walker *walker) |
1d389ab6 | 133 | { |
45c17412 | 134 | struct object_request *obj_req; |
1d389ab6 | 135 | |
45c17412 | 136 | for (obj_req = object_queue_head; obj_req; obj_req = obj_req->next) { |
e388ab74 NH |
137 | if (obj_req->state == WAITING) { |
138 | if (has_sha1_file(obj_req->sha1)) | |
09db444f | 139 | obj_req->state = COMPLETE; |
45c17412 | 140 | else { |
30ae764b | 141 | start_object_request(walker, obj_req); |
45c17412 DB |
142 | return 1; |
143 | } | |
f1a906a3 | 144 | } |
8fcf7f9a | 145 | } |
45c17412 | 146 | return 0; |
1d389ab6 | 147 | } |
a7a8d378 | 148 | #endif |
1d389ab6 | 149 | |
30ae764b | 150 | static void prefetch(struct walker *walker, unsigned char *sha1) |
1d389ab6 | 151 | { |
e388ab74 NH |
152 | struct object_request *newreq; |
153 | struct object_request *tail; | |
30ae764b | 154 | struct walker_data *data = walker->data; |
1d389ab6 NH |
155 | |
156 | newreq = xmalloc(sizeof(*newreq)); | |
30ae764b | 157 | newreq->walker = walker; |
e702496e | 158 | hashcpy(newreq->sha1, sha1); |
30ae764b | 159 | newreq->repo = data->alt; |
1d389ab6 | 160 | newreq->state = WAITING; |
5424bc55 | 161 | newreq->req = NULL; |
1d389ab6 NH |
162 | newreq->next = NULL; |
163 | ||
e9176745 TRC |
164 | http_is_verbose = walker->get_verbosely; |
165 | ||
e388ab74 NH |
166 | if (object_queue_head == NULL) { |
167 | object_queue_head = newreq; | |
1d389ab6 | 168 | } else { |
e388ab74 | 169 | tail = object_queue_head; |
4c42aa1a | 170 | while (tail->next != NULL) |
1d389ab6 | 171 | tail = tail->next; |
1d389ab6 NH |
172 | tail->next = newreq; |
173 | } | |
29508e1e | 174 | |
a7a8d378 | 175 | #ifdef USE_CURL_MULTI |
29508e1e NH |
176 | fill_active_slots(); |
177 | step_active_slots(); | |
a7a8d378 | 178 | #endif |
1d389ab6 NH |
179 | } |
180 | ||
e388ab74 | 181 | static void process_alternates_response(void *callback_data) |
b3661567 | 182 | { |
e388ab74 NH |
183 | struct alternates_request *alt_req = |
184 | (struct alternates_request *)callback_data; | |
30ae764b DB |
185 | struct walker *walker = alt_req->walker; |
186 | struct walker_data *cdata = walker->data; | |
acc075a8 | 187 | struct active_request_slot *slot = alt_req->slot; |
30ae764b | 188 | struct alt_base *tail = cdata->alt; |
8e29f6a0 | 189 | const char *base = alt_req->base; |
bc8f2652 | 190 | static const char null_byte = '\0'; |
acc075a8 NH |
191 | char *data; |
192 | int i = 0; | |
1d389ab6 | 193 | |
acc075a8 NH |
194 | if (alt_req->http_specific) { |
195 | if (slot->curl_result != CURLE_OK || | |
028c2976 | 196 | !alt_req->buffer->len) { |
acc075a8 NH |
197 | |
198 | /* Try reusing the slot to get non-http alternates */ | |
199 | alt_req->http_specific = 0; | |
200 | sprintf(alt_req->url, "%s/objects/info/alternates", | |
201 | base); | |
202 | curl_easy_setopt(slot->curl, CURLOPT_URL, | |
203 | alt_req->url); | |
204 | active_requests++; | |
205 | slot->in_use = 1; | |
c9826473 NH |
206 | if (slot->finished != NULL) |
207 | (*slot->finished) = 0; | |
a3f583cb | 208 | if (!start_active_slot(slot)) { |
30ae764b | 209 | cdata->got_alternates = -1; |
29508e1e | 210 | slot->in_use = 0; |
c9826473 NH |
211 | if (slot->finished != NULL) |
212 | (*slot->finished) = 1; | |
1d389ab6 | 213 | } |
a3f583cb | 214 | return; |
b3661567 | 215 | } |
acc075a8 | 216 | } else if (slot->curl_result != CURLE_OK) { |
be4a015b | 217 | if (!missing_target(slot)) { |
30ae764b | 218 | cdata->got_alternates = -1; |
acc075a8 NH |
219 | return; |
220 | } | |
b3661567 DB |
221 | } |
222 | ||
29508e1e | 223 | fwrite_buffer(&null_byte, 1, 1, alt_req->buffer); |
028c2976 MH |
224 | alt_req->buffer->len--; |
225 | data = alt_req->buffer->buf; | |
1b0c1e67 | 226 | |
028c2976 | 227 | while (i < alt_req->buffer->len) { |
b3661567 | 228 | int posn = i; |
028c2976 | 229 | while (posn < alt_req->buffer->len && data[posn] != '\n') |
b3661567 DB |
230 | posn++; |
231 | if (data[posn] == '\n') { | |
1b0c1e67 DB |
232 | int okay = 0; |
233 | int serverlen = 0; | |
234 | struct alt_base *newalt; | |
235 | char *target = NULL; | |
b3661567 | 236 | if (data[i] == '/') { |
4c42aa1a TRC |
237 | /* |
238 | * This counts | |
5df1e0d0 JH |
239 | * http://git.host/pub/scm/linux.git/ |
240 | * -----------here^ | |
241 | * so memcpy(dst, base, serverlen) will | |
242 | * copy up to "...git.host". | |
243 | */ | |
244 | const char *colon_ss = strstr(base,"://"); | |
245 | if (colon_ss) { | |
246 | serverlen = (strchr(colon_ss + 3, '/') | |
247 | - base); | |
248 | okay = 1; | |
249 | } | |
1b0c1e67 | 250 | } else if (!memcmp(data + i, "../", 3)) { |
4c42aa1a TRC |
251 | /* |
252 | * Relative URL; chop the corresponding | |
5df1e0d0 JH |
253 | * number of subpath from base (and ../ |
254 | * from data), and concatenate the result. | |
255 | * | |
256 | * The code first drops ../ from data, and | |
257 | * then drops one ../ from data and one path | |
258 | * from base. IOW, one extra ../ is dropped | |
259 | * from data than path is dropped from base. | |
260 | * | |
261 | * This is not wrong. The alternate in | |
262 | * http://git.host/pub/scm/linux.git/ | |
263 | * to borrow from | |
264 | * http://git.host/pub/scm/linus.git/ | |
265 | * is ../../linus.git/objects/. You need | |
266 | * two ../../ to borrow from your direct | |
267 | * neighbour. | |
268 | */ | |
1b0c1e67 DB |
269 | i += 3; |
270 | serverlen = strlen(base); | |
8fcf7f9a | 271 | while (i + 2 < posn && |
1b0c1e67 DB |
272 | !memcmp(data + i, "../", 3)) { |
273 | do { | |
274 | serverlen--; | |
275 | } while (serverlen && | |
276 | base[serverlen - 1] != '/'); | |
277 | i += 3; | |
278 | } | |
a9486b02 | 279 | /* If the server got removed, give up. */ |
8fcf7f9a | 280 | okay = strchr(base, ':') - base + 3 < |
4c42aa1a | 281 | serverlen; |
acc075a8 | 282 | } else if (alt_req->http_specific) { |
1b0c1e67 DB |
283 | char *colon = strchr(data + i, ':'); |
284 | char *slash = strchr(data + i, '/'); | |
285 | if (colon && slash && colon < data + posn && | |
286 | slash < data + posn && colon < slash) { | |
287 | okay = 1; | |
288 | } | |
289 | } | |
5df1e0d0 | 290 | /* skip "objects\n" at end */ |
1b0c1e67 DB |
291 | if (okay) { |
292 | target = xmalloc(serverlen + posn - i - 6); | |
5df1e0d0 JH |
293 | memcpy(target, base, serverlen); |
294 | memcpy(target + serverlen, data + i, | |
295 | posn - i - 7); | |
296 | target[serverlen + posn - i - 7] = 0; | |
30ae764b | 297 | if (walker->get_verbosely) |
8fcf7f9a | 298 | fprintf(stderr, |
b3661567 DB |
299 | "Also look at %s\n", target); |
300 | newalt = xmalloc(sizeof(*newalt)); | |
1d389ab6 | 301 | newalt->next = NULL; |
b3661567 DB |
302 | newalt->base = target; |
303 | newalt->got_indices = 0; | |
304 | newalt->packs = NULL; | |
8d9fbe57 | 305 | |
1d389ab6 NH |
306 | while (tail->next != NULL) |
307 | tail = tail->next; | |
308 | tail->next = newalt; | |
b3661567 DB |
309 | } |
310 | } | |
311 | i = posn + 1; | |
312 | } | |
bc8f2652 | 313 | |
30ae764b | 314 | cdata->got_alternates = 1; |
acc075a8 NH |
315 | } |
316 | ||
30ae764b | 317 | static void fetch_alternates(struct walker *walker, const char *base) |
acc075a8 | 318 | { |
028c2976 | 319 | struct strbuf buffer = STRBUF_INIT; |
acc075a8 | 320 | char *url; |
acc075a8 | 321 | struct active_request_slot *slot; |
cb754fdf | 322 | struct alternates_request alt_req; |
30ae764b | 323 | struct walker_data *cdata = walker->data; |
acc075a8 | 324 | |
4c42aa1a TRC |
325 | /* |
326 | * If another request has already started fetching alternates, | |
327 | * wait for them to arrive and return to processing this request's | |
328 | * curl message | |
329 | */ | |
29508e1e | 330 | #ifdef USE_CURL_MULTI |
30ae764b | 331 | while (cdata->got_alternates == 0) { |
29508e1e | 332 | step_active_slots(); |
acc075a8 | 333 | } |
29508e1e | 334 | #endif |
acc075a8 NH |
335 | |
336 | /* Nothing to do if they've already been fetched */ | |
30ae764b | 337 | if (cdata->got_alternates == 1) |
acc075a8 NH |
338 | return; |
339 | ||
340 | /* Start the fetch */ | |
30ae764b | 341 | cdata->got_alternates = 0; |
acc075a8 | 342 | |
30ae764b | 343 | if (walker->get_verbosely) |
acc075a8 | 344 | fprintf(stderr, "Getting alternates list for %s\n", base); |
8fcf7f9a | 345 | |
acc075a8 NH |
346 | url = xmalloc(strlen(base) + 31); |
347 | sprintf(url, "%s/objects/info/http-alternates", base); | |
348 | ||
4c42aa1a TRC |
349 | /* |
350 | * Use a callback to process the result, since another request | |
351 | * may fail and need to have alternates loaded before continuing | |
352 | */ | |
acc075a8 | 353 | slot = get_active_slot(); |
e388ab74 | 354 | slot->callback_func = process_alternates_response; |
30ae764b | 355 | alt_req.walker = walker; |
acc075a8 NH |
356 | slot->callback_data = &alt_req; |
357 | ||
358 | curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer); | |
29508e1e | 359 | curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); |
acc075a8 NH |
360 | curl_easy_setopt(slot->curl, CURLOPT_URL, url); |
361 | ||
362 | alt_req.base = base; | |
363 | alt_req.url = url; | |
364 | alt_req.buffer = &buffer; | |
365 | alt_req.http_specific = 1; | |
366 | alt_req.slot = slot; | |
367 | ||
368 | if (start_active_slot(slot)) | |
369 | run_active_slot(slot); | |
370 | else | |
30ae764b | 371 | cdata->got_alternates = -1; |
acc075a8 | 372 | |
028c2976 | 373 | strbuf_release(&buffer); |
acc075a8 | 374 | free(url); |
b3661567 DB |
375 | } |
376 | ||
30ae764b | 377 | static int fetch_indices(struct walker *walker, struct alt_base *repo) |
182005b9 | 378 | { |
b8caac2b | 379 | int ret; |
1d389ab6 | 380 | |
b3661567 | 381 | if (repo->got_indices) |
182005b9 DB |
382 | return 0; |
383 | ||
30ae764b | 384 | if (walker->get_verbosely) |
6fd72e39 | 385 | fprintf(stderr, "Getting pack list for %s\n", repo->base); |
8fcf7f9a | 386 | |
b8caac2b TRC |
387 | switch (http_get_info_packs(repo->base, &repo->packs)) { |
388 | case HTTP_OK: | |
389 | case HTTP_MISSING_TARGET: | |
390 | repo->got_indices = 1; | |
391 | ret = 0; | |
392 | break; | |
393 | default: | |
5e3a7691 | 394 | repo->got_indices = 0; |
b8caac2b | 395 | ret = -1; |
b3661567 | 396 | } |
182005b9 | 397 | |
3a462bc9 | 398 | return ret; |
182005b9 DB |
399 | } |
400 | ||
30ae764b | 401 | static int fetch_pack(struct walker *walker, struct alt_base *repo, unsigned char *sha1) |
182005b9 | 402 | { |
182005b9 | 403 | struct packed_git *target; |
49a0f240 | 404 | int ret; |
cb754fdf | 405 | struct slot_results results; |
2264dfa5 | 406 | struct http_pack_request *preq; |
182005b9 | 407 | |
30ae764b | 408 | if (fetch_indices(walker, repo)) |
182005b9 | 409 | return -1; |
b3661567 | 410 | target = find_sha1_pack(sha1, repo->packs); |
182005b9 | 411 | if (!target) |
b3661567 | 412 | return -1; |
182005b9 | 413 | |
30ae764b | 414 | if (walker->get_verbosely) { |
182005b9 DB |
415 | fprintf(stderr, "Getting pack %s\n", |
416 | sha1_to_hex(target->sha1)); | |
417 | fprintf(stderr, " which contains %s\n", | |
418 | sha1_to_hex(sha1)); | |
419 | } | |
420 | ||
2264dfa5 TRC |
421 | preq = new_http_pack_request(target, repo->base); |
422 | if (preq == NULL) | |
423 | goto abort; | |
424 | preq->lst = &repo->packs; | |
425 | preq->slot->results = &results; | |
182005b9 | 426 | |
2264dfa5 TRC |
427 | if (start_active_slot(preq->slot)) { |
428 | run_active_slot(preq->slot); | |
c8568e13 | 429 | if (results.curl_result != CURLE_OK) { |
2264dfa5 TRC |
430 | error("Unable to get pack file %s\n%s", preq->url, |
431 | curl_errorstr); | |
432 | goto abort; | |
1d389ab6 NH |
433 | } |
434 | } else { | |
2264dfa5 TRC |
435 | error("Unable to start request"); |
436 | goto abort; | |
182005b9 DB |
437 | } |
438 | ||
2264dfa5 TRC |
439 | ret = finish_http_pack_request(preq); |
440 | release_http_pack_request(preq); | |
49a0f240 | 441 | if (ret) |
b721e01f | 442 | return ret; |
49a0f240 | 443 | |
182005b9 | 444 | return 0; |
2264dfa5 TRC |
445 | |
446 | abort: | |
447 | return -1; | |
182005b9 DB |
448 | } |
449 | ||
53f31389 MW |
450 | static void abort_object_request(struct object_request *obj_req) |
451 | { | |
53f31389 MW |
452 | release_object_request(obj_req); |
453 | } | |
454 | ||
30ae764b | 455 | static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned char *sha1) |
6eb7ed54 DB |
456 | { |
457 | char *hex = sha1_to_hex(sha1); | |
29508e1e | 458 | int ret = 0; |
e388ab74 | 459 | struct object_request *obj_req = object_queue_head; |
5424bc55 | 460 | struct http_object_request *req; |
1d389ab6 | 461 | |
a89fccd2 | 462 | while (obj_req != NULL && hashcmp(obj_req->sha1, sha1)) |
e388ab74 NH |
463 | obj_req = obj_req->next; |
464 | if (obj_req == NULL) | |
1d389ab6 NH |
465 | return error("Couldn't find request for %s in the queue", hex); |
466 | ||
e388ab74 | 467 | if (has_sha1_file(obj_req->sha1)) { |
5424bc55 TRC |
468 | if (obj_req->req != NULL) |
469 | abort_http_object_request(obj_req->req); | |
53f31389 | 470 | abort_object_request(obj_req); |
11f0dafe NH |
471 | return 0; |
472 | } | |
473 | ||
a7a8d378 | 474 | #ifdef USE_CURL_MULTI |
4c42aa1a | 475 | while (obj_req->state == WAITING) |
29508e1e | 476 | step_active_slots(); |
a7a8d378 | 477 | #else |
30ae764b | 478 | start_object_request(walker, obj_req); |
a7a8d378 | 479 | #endif |
6eb7ed54 | 480 | |
5424bc55 TRC |
481 | /* |
482 | * obj_req->req might change when fetching alternates in the callback | |
483 | * process_object_response; therefore, the "shortcut" variable, req, | |
484 | * is used only after we're done with slots. | |
485 | */ | |
4c42aa1a | 486 | while (obj_req->state == ACTIVE) |
5424bc55 TRC |
487 | run_active_slot(obj_req->req->slot); |
488 | ||
489 | req = obj_req->req; | |
4c42aa1a | 490 | |
5424bc55 TRC |
491 | if (req->localfile != -1) { |
492 | close(req->localfile); | |
493 | req->localfile = -1; | |
313c4714 | 494 | } |
6eb7ed54 | 495 | |
e388ab74 | 496 | if (obj_req->state == ABORTED) { |
29508e1e | 497 | ret = error("Request for %s aborted", hex); |
5424bc55 TRC |
498 | } else if (req->curl_result != CURLE_OK && |
499 | req->http_code != 416) { | |
500 | if (missing_target(req)) | |
e2029eb9 PB |
501 | ret = -1; /* Be silent, it is probably in a pack. */ |
502 | else | |
503 | ret = error("%s (curl_result = %d, http_code = %ld, sha1 = %s)", | |
5424bc55 TRC |
504 | req->errorstr, req->curl_result, |
505 | req->http_code, hex); | |
506 | } else if (req->zret != Z_STREAM_END) { | |
30ae764b | 507 | walker->corrupt_object_found++; |
5424bc55 TRC |
508 | ret = error("File %s (%s) corrupt", hex, req->url); |
509 | } else if (hashcmp(obj_req->sha1, req->real_sha1)) { | |
bd2afde8 | 510 | ret = error("File %s has bad hash", hex); |
5424bc55 | 511 | } else if (req->rename < 0) { |
7b934ec0 | 512 | ret = error("unable to write sha1 filename %s", |
5424bc55 | 513 | req->filename); |
6eb7ed54 | 514 | } |
49a0f240 | 515 | |
5424bc55 | 516 | release_http_object_request(req); |
e388ab74 | 517 | release_object_request(obj_req); |
29508e1e | 518 | return ret; |
6eb7ed54 DB |
519 | } |
520 | ||
30ae764b | 521 | static int fetch(struct walker *walker, unsigned char *sha1) |
b3661567 | 522 | { |
30ae764b DB |
523 | struct walker_data *data = walker->data; |
524 | struct alt_base *altbase = data->alt; | |
1d389ab6 | 525 | |
30ae764b | 526 | if (!fetch_object(walker, altbase, sha1)) |
1d389ab6 | 527 | return 0; |
b3661567 | 528 | while (altbase) { |
30ae764b | 529 | if (!fetch_pack(walker, altbase, sha1)) |
b3661567 | 530 | return 0; |
30ae764b | 531 | fetch_alternates(walker, data->alt->base); |
b3661567 DB |
532 | altbase = altbase->next; |
533 | } | |
bd2afde8 | 534 | return error("Unable to find %s under %s", sha1_to_hex(sha1), |
30ae764b | 535 | data->alt->base); |
b3661567 DB |
536 | } |
537 | ||
c13b2633 | 538 | static int fetch_ref(struct walker *walker, struct ref *ref) |
cd541a68 | 539 | { |
30ae764b | 540 | struct walker_data *data = walker->data; |
c13b2633 | 541 | return http_fetch_ref(data->alt->base, ref); |
cd541a68 DB |
542 | } |
543 | ||
30ae764b DB |
544 | static void cleanup(struct walker *walker) |
545 | { | |
30ae764b | 546 | http_cleanup(); |
30ae764b DB |
547 | } |
548 | ||
9fc6440d | 549 | struct walker *get_http_walker(const char *url, struct remote *remote) |
6eb7ed54 | 550 | { |
9c880b3e | 551 | char *s; |
30ae764b DB |
552 | struct walker_data *data = xmalloc(sizeof(struct walker_data)); |
553 | struct walker *walker = xmalloc(sizeof(struct walker)); | |
6eb7ed54 | 554 | |
9fc6440d | 555 | http_init(remote); |
d402d556 | 556 | |
30ae764b DB |
557 | data->alt = xmalloc(sizeof(*data->alt)); |
558 | data->alt->base = xmalloc(strlen(url) + 1); | |
559 | strcpy(data->alt->base, url); | |
560 | for (s = data->alt->base + strlen(data->alt->base) - 1; *s == '/'; --s) | |
9c880b3e | 561 | *s = 0; |
6eb7ed54 | 562 | |
30ae764b DB |
563 | data->alt->got_indices = 0; |
564 | data->alt->packs = NULL; | |
565 | data->alt->next = NULL; | |
566 | data->got_alternates = -1; | |
fc57b6aa | 567 | |
30ae764b DB |
568 | walker->corrupt_object_found = 0; |
569 | walker->fetch = fetch; | |
570 | walker->fetch_ref = fetch_ref; | |
571 | walker->prefetch = prefetch; | |
572 | walker->cleanup = cleanup; | |
573 | walker->data = data; | |
6eb7ed54 | 574 | |
30ae764b DB |
575 | #ifdef USE_CURL_MULTI |
576 | add_fill_function(walker, (int (*)(void *)) fill_active_slot); | |
577 | #endif | |
8e29f6a0 | 578 | |
30ae764b | 579 | return walker; |
6eb7ed54 | 580 | } |