🌐 AI搜索 & 代理 主页
blob: 202fae0ba8b348aeca6ec6c61045f39aa0d1fa66 [file] [log] [blame]
Daniel Barkalow6eb7ed52005-04-24 01:47:231#include "cache.h"
2#include "commit.h"
Junio C Hamano271421c2005-09-30 07:07:393#include "pack.h"
Junio C Hamano215a7ad2005-09-08 00:26:234#include "fetch.h"
Nick Hengeveld29508e12005-11-18 19:02:585#include "http.h"
Johannes Schindelin7baa3e82005-10-15 18:10:466
Nick Hengeveld49a0f242005-09-28 17:14:047#define PREV_BUF_SIZE 4096
8#define RANGE_HEADER_SIZE 30
9
David Rientjes96f1e582006-08-15 17:23:4810static int commits_on_stdin;
Petr Baudis8e29f6a2006-07-27 21:56:2211
Nick Hengeveldacc075a2005-11-12 17:11:3212static int got_alternates = -1;
David Rientjes96f1e582006-08-15 17:23:4813static int corrupt_object_found;
Nick Hengeveld1d389ab2005-10-11 06:22:0114
Sergey Vlasov1db69b52005-09-13 15:38:5815static struct curl_slist *no_pragma_header;
Daniel Barkalow6eb7ed52005-04-24 01:47:2316
Daniel Barkalowb3661562005-09-15 03:26:0817struct alt_base
18{
Gerrit Pape2afea3b2007-03-28 09:46:1519 char *base;
Daniel Barkalowb3661562005-09-15 03:26:0820 int got_indices;
21 struct packed_git *packs;
22 struct alt_base *next;
23};
24
David Rientjes96f1e582006-08-15 17:23:4825static struct alt_base *alt;
Daniel Barkalow6eb7ed52005-04-24 01:47:2326
Nick Hengevelde388ab72005-11-18 19:03:0427enum object_request_state {
Nick Hengeveld1d389ab2005-10-11 06:22:0128 WAITING,
29 ABORTED,
30 ACTIVE,
31 COMPLETE,
32};
Daniel Barkalow6eb7ed52005-04-24 01:47:2333
Nick Hengevelde388ab72005-11-18 19:03:0434struct object_request
Nick Hengeveld1d389ab2005-10-11 06:22:0135{
36 unsigned char sha1[20];
37 struct alt_base *repo;
38 char *url;
39 char filename[PATH_MAX];
40 char tmpfile[PATH_MAX];
41 int local;
Nick Hengevelde388ab72005-11-18 19:03:0442 enum object_request_state state;
Nick Hengeveld1d389ab2005-10-11 06:22:0143 CURLcode curl_result;
44 char errorstr[CURL_ERROR_SIZE];
45 long http_code;
46 unsigned char real_sha1[20];
47 SHA_CTX c;
48 z_stream stream;
49 int zret;
50 int rename;
51 struct active_request_slot *slot;
Nick Hengevelde388ab72005-11-18 19:03:0452 struct object_request *next;
Nick Hengeveld1d389ab2005-10-11 06:22:0153};
54
Nick Hengevelde388ab72005-11-18 19:03:0455struct alternates_request {
Petr Baudis8e29f6a2006-07-27 21:56:2256 const char *base;
Nick Hengeveldacc075a2005-11-12 17:11:3257 char *url;
58 struct buffer *buffer;
59 struct active_request_slot *slot;
60 int http_specific;
61};
62
David Rientjes96f1e582006-08-15 17:23:4863static struct object_request *object_queue_head;
Sergey Vlasovbc8f2652005-10-13 17:49:5364
barkalow@iabervon.org182005b2005-08-01 00:54:1765static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb,
66 void *data)
67{
Brian Gerstbf0f9102005-05-18 12:14:0968 unsigned char expn[4096];
Daniel Barkalow6eb7ed52005-04-24 01:47:2369 size_t size = eltsize * nmemb;
70 int posn = 0;
Nick Hengevelde388ab72005-11-18 19:03:0471 struct object_request *obj_req = (struct object_request *)data;
Daniel Barkalow6eb7ed52005-04-24 01:47:2372 do {
Andy Whitcroft93822c22007-01-08 15:58:2373 ssize_t retval = xwrite(obj_req->local,
Florian Forster1d7f1712006-06-18 15:18:0974 (char *) ptr + posn, size - posn);
Daniel Barkalow6eb7ed52005-04-24 01:47:2375 if (retval < 0)
76 return posn;
77 posn += retval;
78 } while (posn < size);
79
Nick Hengevelde388ab72005-11-18 19:03:0480 obj_req->stream.avail_in = size;
81 obj_req->stream.next_in = ptr;
Daniel Barkalow6eb7ed52005-04-24 01:47:2382 do {
Nick Hengevelde388ab72005-11-18 19:03:0483 obj_req->stream.next_out = expn;
84 obj_req->stream.avail_out = sizeof(expn);
85 obj_req->zret = inflate(&obj_req->stream, Z_SYNC_FLUSH);
86 SHA1_Update(&obj_req->c, expn,
87 sizeof(expn) - obj_req->stream.avail_out);
88 } while (obj_req->stream.avail_in && obj_req->zret == Z_OK);
Nick Hengeveld1d389ab2005-10-11 06:22:0189 data_received++;
Daniel Barkalow6eb7ed52005-04-24 01:47:2390 return size;
91}
92
Junio C Hamanobe4a0152006-09-16 17:58:2093static int missing__target(int code, int result)
94{
95 return /* file:// URL -- do we ever use one??? */
96 (result == CURLE_FILE_COULDNT_READ_FILE) ||
97 /* http:// and https:// URL */
Junio C Hamano4adffc72006-09-16 18:06:0298 (code == 404 && result == CURLE_HTTP_RETURNED_ERROR) ||
99 /* ftp:// URL */
100 (code == 550 && result == CURLE_FTP_COULDNT_RETR_FILE)
Junio C Hamanobe4a0152006-09-16 17:58:20101 ;
102}
103
104#define missing_target(a) missing__target((a)->http_code, (a)->curl_result)
105
Petr Baudis8e29f6a2006-07-27 21:56:22106static void fetch_alternates(const char *base);
Nick Hengeveld1d389ab2005-10-11 06:22:01107
Nick Hengeveld29508e12005-11-18 19:02:58108static void process_object_response(void *callback_data);
Nick Hengeveld1d389ab2005-10-11 06:22:01109
Nick Hengevelde388ab72005-11-18 19:03:04110static void start_object_request(struct object_request *obj_req)
Nick Hengeveld1d389ab2005-10-11 06:22:01111{
Nick Hengevelde388ab72005-11-18 19:03:04112 char *hex = sha1_to_hex(obj_req->sha1);
Nick Hengeveld1d389ab2005-10-11 06:22:01113 char prevfile[PATH_MAX];
114 char *url;
115 char *posn;
116 int prevlocal;
117 unsigned char prev_buf[PREV_BUF_SIZE];
118 ssize_t prev_read = 0;
119 long prev_posn = 0;
120 char range[RANGE_HEADER_SIZE];
121 struct curl_slist *range_header = NULL;
122 struct active_request_slot *slot;
123
Nick Hengevelde388ab72005-11-18 19:03:04124 snprintf(prevfile, sizeof(prevfile), "%s.prev", obj_req->filename);
Nick Hengeveld1d389ab2005-10-11 06:22:01125 unlink(prevfile);
Nick Hengevelde388ab72005-11-18 19:03:04126 rename(obj_req->tmpfile, prevfile);
127 unlink(obj_req->tmpfile);
Nick Hengeveld1d389ab2005-10-11 06:22:01128
Nick Hengevelde388ab72005-11-18 19:03:04129 if (obj_req->local != -1)
130 error("fd leakage in start: %d", obj_req->local);
131 obj_req->local = open(obj_req->tmpfile,
Nick Hengeveld1d389ab2005-10-11 06:22:01132 O_WRONLY | O_CREAT | O_EXCL, 0666);
Junio C Hamanob721e012005-10-11 06:22:01133 /* This could have failed due to the "lazy directory creation";
134 * try to mkdir the last path component.
135 */
Nick Hengevelde388ab72005-11-18 19:03:04136 if (obj_req->local < 0 && errno == ENOENT) {
137 char *dir = strrchr(obj_req->tmpfile, '/');
Junio C Hamanob721e012005-10-11 06:22:01138 if (dir) {
139 *dir = 0;
Nick Hengevelde388ab72005-11-18 19:03:04140 mkdir(obj_req->tmpfile, 0777);
Junio C Hamanob721e012005-10-11 06:22:01141 *dir = '/';
142 }
Nick Hengevelde388ab72005-11-18 19:03:04143 obj_req->local = open(obj_req->tmpfile,
Junio C Hamanob721e012005-10-11 06:22:01144 O_WRONLY | O_CREAT | O_EXCL, 0666);
145 }
146
Nick Hengevelde388ab72005-11-18 19:03:04147 if (obj_req->local < 0) {
148 obj_req->state = ABORTED;
Junio C Hamanobd2afde2006-02-23 01:47:10149 error("Couldn't create temporary file %s for %s: %s",
Nick Hengevelde388ab72005-11-18 19:03:04150 obj_req->tmpfile, obj_req->filename, strerror(errno));
Nick Hengeveld1d389ab2005-10-11 06:22:01151 return;
152 }
153
Nick Hengevelde388ab72005-11-18 19:03:04154 memset(&obj_req->stream, 0, sizeof(obj_req->stream));
Nick Hengeveld1d389ab2005-10-11 06:22:01155
Nick Hengevelde388ab72005-11-18 19:03:04156 inflateInit(&obj_req->stream);
Nick Hengeveld1d389ab2005-10-11 06:22:01157
Nick Hengevelde388ab72005-11-18 19:03:04158 SHA1_Init(&obj_req->c);
Nick Hengeveld1d389ab2005-10-11 06:22:01159
Gerrit Pape2afea3b2007-03-28 09:46:15160 url = xmalloc(strlen(obj_req->repo->base) + 51);
161 obj_req->url = xmalloc(strlen(obj_req->repo->base) + 51);
Nick Hengevelde388ab72005-11-18 19:03:04162 strcpy(url, obj_req->repo->base);
163 posn = url + strlen(obj_req->repo->base);
Gerrit Pape2afea3b2007-03-28 09:46:15164 strcpy(posn, "/objects/");
165 posn += 9;
Nick Hengeveld1d389ab2005-10-11 06:22:01166 memcpy(posn, hex, 2);
167 posn += 2;
168 *(posn++) = '/';
169 strcpy(posn, hex + 2);
Nick Hengevelde388ab72005-11-18 19:03:04170 strcpy(obj_req->url, url);
Nick Hengeveld1d389ab2005-10-11 06:22:01171
172 /* If a previous temp file is present, process what was already
173 fetched. */
174 prevlocal = open(prevfile, O_RDONLY);
175 if (prevlocal != -1) {
176 do {
Andy Whitcroft93d26e42007-01-08 15:58:08177 prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE);
Nick Hengeveld1d389ab2005-10-11 06:22:01178 if (prev_read>0) {
179 if (fwrite_sha1_file(prev_buf,
180 1,
181 prev_read,
Nick Hengevelde388ab72005-11-18 19:03:04182 obj_req) == prev_read) {
Nick Hengeveld1d389ab2005-10-11 06:22:01183 prev_posn += prev_read;
184 } else {
185 prev_read = -1;
186 }
187 }
188 } while (prev_read > 0);
189 close(prevlocal);
190 }
191 unlink(prevfile);
192
193 /* Reset inflate/SHA1 if there was an error reading the previous temp
194 file; also rewind to the beginning of the local file. */
195 if (prev_read == -1) {
Nick Hengevelde388ab72005-11-18 19:03:04196 memset(&obj_req->stream, 0, sizeof(obj_req->stream));
197 inflateInit(&obj_req->stream);
198 SHA1_Init(&obj_req->c);
Nick Hengeveld1d389ab2005-10-11 06:22:01199 if (prev_posn>0) {
200 prev_posn = 0;
Dana Howb5da2462007-04-05 19:05:57201 lseek(obj_req->local, 0, SEEK_SET);
Nick Hengevelde388ab72005-11-18 19:03:04202 ftruncate(obj_req->local, 0);
Nick Hengeveld1d389ab2005-10-11 06:22:01203 }
204 }
205
206 slot = get_active_slot();
Nick Hengeveld29508e12005-11-18 19:02:58207 slot->callback_func = process_object_response;
Nick Hengevelde388ab72005-11-18 19:03:04208 slot->callback_data = obj_req;
209 obj_req->slot = slot;
Nick Hengeveld29508e12005-11-18 19:02:58210
Nick Hengevelde388ab72005-11-18 19:03:04211 curl_easy_setopt(slot->curl, CURLOPT_FILE, obj_req);
Nick Hengeveld1d389ab2005-10-11 06:22:01212 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
Nick Hengevelde388ab72005-11-18 19:03:04213 curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, obj_req->errorstr);
Nick Hengeveld1d389ab2005-10-11 06:22:01214 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
Nick Hengeveld03126002005-10-11 06:22:01215 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
Nick Hengeveld1d389ab2005-10-11 06:22:01216
217 /* If we have successfully processed data from a previous fetch
218 attempt, only fetch the data we don't already have. */
219 if (prev_posn>0) {
220 if (get_verbosely)
221 fprintf(stderr,
222 "Resuming fetch of object %s at byte %ld\n",
223 hex, prev_posn);
224 sprintf(range, "Range: bytes=%ld-", prev_posn);
225 range_header = curl_slist_append(range_header, range);
226 curl_easy_setopt(slot->curl,
227 CURLOPT_HTTPHEADER, range_header);
228 }
229
Nick Hengevelda7a8d372005-10-11 06:22:01230 /* Try to get the request started, abort the request on error */
Nick Hengevelde388ab72005-11-18 19:03:04231 obj_req->state = ACTIVE;
Nick Hengeveld1d389ab2005-10-11 06:22:01232 if (!start_active_slot(slot)) {
Nick Hengevelde388ab72005-11-18 19:03:04233 obj_req->state = ABORTED;
234 obj_req->slot = NULL;
235 close(obj_req->local); obj_req->local = -1;
236 free(obj_req->url);
237 return;
Nick Hengeveld1d389ab2005-10-11 06:22:01238 }
Nick Hengeveld1d389ab2005-10-11 06:22:01239}
240
Nick Hengevelde388ab72005-11-18 19:03:04241static void finish_object_request(struct object_request *obj_req)
Nick Hengeveld1d389ab2005-10-11 06:22:01242{
Nick Hengeveld50496b22005-11-04 01:54:52243 struct stat st;
244
Nick Hengevelde388ab72005-11-18 19:03:04245 fchmod(obj_req->local, 0444);
246 close(obj_req->local); obj_req->local = -1;
Nick Hengeveld1d389ab2005-10-11 06:22:01247
Nick Hengevelde388ab72005-11-18 19:03:04248 if (obj_req->http_code == 416) {
Nick Hengeveld1d389ab2005-10-11 06:22:01249 fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n");
Nick Hengevelde388ab72005-11-18 19:03:04250 } else if (obj_req->curl_result != CURLE_OK) {
251 if (stat(obj_req->tmpfile, &st) == 0)
Nick Hengeveld50496b22005-11-04 01:54:52252 if (st.st_size == 0)
Nick Hengevelde388ab72005-11-18 19:03:04253 unlink(obj_req->tmpfile);
Nick Hengeveld1d389ab2005-10-11 06:22:01254 return;
255 }
256
Nick Hengevelde388ab72005-11-18 19:03:04257 inflateEnd(&obj_req->stream);
258 SHA1_Final(obj_req->real_sha1, &obj_req->c);
259 if (obj_req->zret != Z_STREAM_END) {
260 unlink(obj_req->tmpfile);
Nick Hengeveld1d389ab2005-10-11 06:22:01261 return;
262 }
David Rientjesa89fccd2006-08-17 18:54:57263 if (hashcmp(obj_req->sha1, obj_req->real_sha1)) {
Nick Hengevelde388ab72005-11-18 19:03:04264 unlink(obj_req->tmpfile);
Nick Hengeveld1d389ab2005-10-11 06:22:01265 return;
266 }
Nick Hengevelde388ab72005-11-18 19:03:04267 obj_req->rename =
268 move_temp_to_file(obj_req->tmpfile, obj_req->filename);
Nick Hengeveld1d389ab2005-10-11 06:22:01269
Nick Hengevelde388ab72005-11-18 19:03:04270 if (obj_req->rename == 0)
271 pull_say("got %s\n", sha1_to_hex(obj_req->sha1));
Nick Hengeveld1d389ab2005-10-11 06:22:01272}
273
Nick Hengeveld29508e12005-11-18 19:02:58274static void process_object_response(void *callback_data)
275{
Nick Hengevelde388ab72005-11-18 19:03:04276 struct object_request *obj_req =
277 (struct object_request *)callback_data;
Nick Hengeveld29508e12005-11-18 19:02:58278
Nick Hengevelde388ab72005-11-18 19:03:04279 obj_req->curl_result = obj_req->slot->curl_result;
280 obj_req->http_code = obj_req->slot->http_code;
281 obj_req->slot = NULL;
282 obj_req->state = COMPLETE;
Nick Hengeveld29508e12005-11-18 19:02:58283
284 /* Use alternates if necessary */
Junio C Hamanobe4a0152006-09-16 17:58:20285 if (missing_target(obj_req)) {
Nick Hengeveld29508e12005-11-18 19:02:58286 fetch_alternates(alt->base);
Nick Hengevelde388ab72005-11-18 19:03:04287 if (obj_req->repo->next != NULL) {
288 obj_req->repo =
289 obj_req->repo->next;
290 close(obj_req->local);
291 obj_req->local = -1;
292 start_object_request(obj_req);
Nick Hengeveld29508e12005-11-18 19:02:58293 return;
294 }
295 }
296
Nick Hengevelde388ab72005-11-18 19:03:04297 finish_object_request(obj_req);
Nick Hengeveld29508e12005-11-18 19:02:58298}
299
Nick Hengevelde388ab72005-11-18 19:03:04300static void release_object_request(struct object_request *obj_req)
Nick Hengeveld1d389ab2005-10-11 06:22:01301{
Nick Hengevelde388ab72005-11-18 19:03:04302 struct object_request *entry = object_queue_head;
Nick Hengeveld1d389ab2005-10-11 06:22:01303
Nick Hengevelde388ab72005-11-18 19:03:04304 if (obj_req->local != -1)
305 error("fd leakage in release: %d", obj_req->local);
306 if (obj_req == object_queue_head) {
307 object_queue_head = obj_req->next;
Nick Hengeveld1d389ab2005-10-11 06:22:01308 } else {
Nick Hengevelde388ab72005-11-18 19:03:04309 while (entry->next != NULL && entry->next != obj_req)
Nick Hengeveld1d389ab2005-10-11 06:22:01310 entry = entry->next;
Nick Hengevelde388ab72005-11-18 19:03:04311 if (entry->next == obj_req)
Nick Hengeveld1d389ab2005-10-11 06:22:01312 entry->next = entry->next->next;
313 }
314
Nick Hengevelde388ab72005-11-18 19:03:04315 free(obj_req->url);
316 free(obj_req);
Nick Hengeveld1d389ab2005-10-11 06:22:01317}
318
Nick Hengevelda7a8d372005-10-11 06:22:01319#ifdef USE_CURL_MULTI
Nick Hengeveld29508e12005-11-18 19:02:58320void fill_active_slots(void)
Nick Hengeveld1d389ab2005-10-11 06:22:01321{
Nick Hengevelde388ab72005-11-18 19:03:04322 struct object_request *obj_req = object_queue_head;
Nick Hengeveldf1a906a2005-10-21 19:06:10323 struct active_request_slot *slot = active_queue_head;
Nick Hengeveld1d389ab2005-10-11 06:22:01324 int num_transfers;
325
Nick Hengevelde388ab72005-11-18 19:03:04326 while (active_requests < max_requests && obj_req != NULL) {
327 if (obj_req->state == WAITING) {
328 if (has_sha1_file(obj_req->sha1))
Mark Wooding09db4442006-02-01 11:44:28329 obj_req->state = COMPLETE;
Nick Hengeveld11f0daf2005-10-11 06:22:01330 else
Nick Hengevelde388ab72005-11-18 19:03:04331 start_object_request(obj_req);
Nick Hengeveld1d389ab2005-10-11 06:22:01332 curl_multi_perform(curlm, &num_transfers);
333 }
Nick Hengevelde388ab72005-11-18 19:03:04334 obj_req = obj_req->next;
Nick Hengeveld1d389ab2005-10-11 06:22:01335 }
Nick Hengeveldf1a906a2005-10-21 19:06:10336
337 while (slot != NULL) {
338 if (!slot->in_use && slot->curl != NULL) {
339 curl_easy_cleanup(slot->curl);
340 slot->curl = NULL;
341 }
342 slot = slot->next;
Junio C Hamano8fcf7f92006-02-01 02:15:51343 }
Nick Hengeveld1d389ab2005-10-11 06:22:01344}
Nick Hengevelda7a8d372005-10-11 06:22:01345#endif
Nick Hengeveld1d389ab2005-10-11 06:22:01346
347void prefetch(unsigned char *sha1)
348{
Nick Hengevelde388ab72005-11-18 19:03:04349 struct object_request *newreq;
350 struct object_request *tail;
Nick Hengeveld1d389ab2005-10-11 06:22:01351 char *filename = sha1_file_name(sha1);
352
353 newreq = xmalloc(sizeof(*newreq));
Shawn Pearcee7024962006-08-23 06:49:00354 hashcpy(newreq->sha1, sha1);
Nick Hengeveld1d389ab2005-10-11 06:22:01355 newreq->repo = alt;
356 newreq->url = NULL;
357 newreq->local = -1;
358 newreq->state = WAITING;
359 snprintf(newreq->filename, sizeof(newreq->filename), "%s", filename);
360 snprintf(newreq->tmpfile, sizeof(newreq->tmpfile),
361 "%s.temp", filename);
Nick Hengevelde8dff6b2006-06-07 05:22:35362 newreq->slot = NULL;
Nick Hengeveld1d389ab2005-10-11 06:22:01363 newreq->next = NULL;
364
Nick Hengevelde388ab72005-11-18 19:03:04365 if (object_queue_head == NULL) {
366 object_queue_head = newreq;
Nick Hengeveld1d389ab2005-10-11 06:22:01367 } else {
Nick Hengevelde388ab72005-11-18 19:03:04368 tail = object_queue_head;
Nick Hengeveld1d389ab2005-10-11 06:22:01369 while (tail->next != NULL) {
370 tail = tail->next;
371 }
372 tail->next = newreq;
373 }
Nick Hengeveld29508e12005-11-18 19:02:58374
Nick Hengevelda7a8d372005-10-11 06:22:01375#ifdef USE_CURL_MULTI
Nick Hengeveld29508e12005-11-18 19:02:58376 fill_active_slots();
377 step_active_slots();
Nick Hengevelda7a8d372005-10-11 06:22:01378#endif
Nick Hengeveld1d389ab2005-10-11 06:22:01379}
380
Daniel Barkalowb3661562005-09-15 03:26:08381static int fetch_index(struct alt_base *repo, unsigned char *sha1)
barkalow@iabervon.org182005b2005-08-01 00:54:17382{
Nick Hengeveld1d389ab2005-10-11 06:22:01383 char *hex = sha1_to_hex(sha1);
barkalow@iabervon.org182005b2005-08-01 00:54:17384 char *filename;
385 char *url;
Nick Hengeveld49a0f242005-09-28 17:14:04386 char tmpfile[PATH_MAX];
Nick Hengeveld49a0f242005-09-28 17:14:04387 long prev_posn = 0;
388 char range[RANGE_HEADER_SIZE];
389 struct curl_slist *range_header = NULL;
barkalow@iabervon.org182005b2005-08-01 00:54:17390
391 FILE *indexfile;
Nick Hengeveld1d389ab2005-10-11 06:22:01392 struct active_request_slot *slot;
Nick Hengeveldcb754fd2006-02-01 02:00:37393 struct slot_results results;
barkalow@iabervon.org182005b2005-08-01 00:54:17394
395 if (has_pack_index(sha1))
396 return 0;
397
398 if (get_verbosely)
Nick Hengeveld1d389ab2005-10-11 06:22:01399 fprintf(stderr, "Getting index for pack %s\n", hex);
Junio C Hamano8fcf7f92006-02-01 02:15:51400
Daniel Barkalowb3661562005-09-15 03:26:08401 url = xmalloc(strlen(repo->base) + 64);
Nick Hengeveld1d389ab2005-10-11 06:22:01402 sprintf(url, "%s/objects/pack/pack-%s.idx", repo->base, hex);
Junio C Hamano8fcf7f92006-02-01 02:15:51403
barkalow@iabervon.org182005b2005-08-01 00:54:17404 filename = sha1_pack_index_name(sha1);
Nick Hengeveld49a0f242005-09-28 17:14:04405 snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
406 indexfile = fopen(tmpfile, "a");
barkalow@iabervon.org182005b2005-08-01 00:54:17407 if (!indexfile)
408 return error("Unable to open local file %s for pack index",
409 filename);
410
Nick Hengeveld1d389ab2005-10-11 06:22:01411 slot = get_active_slot();
Nick Hengeveldc8568e12006-01-31 19:06:55412 slot->results = &results;
Nick Hengeveld1d389ab2005-10-11 06:22:01413 curl_easy_setopt(slot->curl, CURLOPT_FILE, indexfile);
414 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
415 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
Nick Hengeveld03126002005-10-11 06:22:01416 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
Nick Hengeveld1d389ab2005-10-11 06:22:01417 slot->local = indexfile;
418
Nick Hengeveld49a0f242005-09-28 17:14:04419 /* If there is data present from a previous transfer attempt,
420 resume where it left off */
421 prev_posn = ftell(indexfile);
422 if (prev_posn>0) {
423 if (get_verbosely)
424 fprintf(stderr,
425 "Resuming fetch of index for pack %s at byte %ld\n",
Nick Hengeveld1d389ab2005-10-11 06:22:01426 hex, prev_posn);
Nick Hengeveld49a0f242005-09-28 17:14:04427 sprintf(range, "Range: bytes=%ld-", prev_posn);
428 range_header = curl_slist_append(range_header, range);
Nick Hengeveld1d389ab2005-10-11 06:22:01429 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);
Nick Hengeveld49a0f242005-09-28 17:14:04430 }
431
Nick Hengeveld1d389ab2005-10-11 06:22:01432 if (start_active_slot(slot)) {
433 run_active_slot(slot);
Nick Hengeveldc8568e12006-01-31 19:06:55434 if (results.curl_result != CURLE_OK) {
Nick Hengeveld1d389ab2005-10-11 06:22:01435 fclose(indexfile);
436 return error("Unable to get pack index %s\n%s", url,
437 curl_errorstr);
438 }
439 } else {
Petr Baudis313c4712005-11-11 23:55:16440 fclose(indexfile);
Nick Hengeveld1d389ab2005-10-11 06:22:01441 return error("Unable to start request");
barkalow@iabervon.org182005b2005-08-01 00:54:17442 }
443
444 fclose(indexfile);
Nick Hengeveld49a0f242005-09-28 17:14:04445
Junio C Hamanob721e012005-10-11 06:22:01446 return move_temp_to_file(tmpfile, filename);
barkalow@iabervon.org182005b2005-08-01 00:54:17447}
448
Daniel Barkalowb3661562005-09-15 03:26:08449static int setup_index(struct alt_base *repo, unsigned char *sha1)
barkalow@iabervon.org182005b2005-08-01 00:54:17450{
451 struct packed_git *new_pack;
452 if (has_pack_file(sha1))
Pavel Roskina9486b02006-07-10 06:57:51453 return 0; /* don't list this as something we can get */
barkalow@iabervon.org182005b2005-08-01 00:54:17454
Daniel Barkalowb3661562005-09-15 03:26:08455 if (fetch_index(repo, sha1))
barkalow@iabervon.org182005b2005-08-01 00:54:17456 return -1;
457
458 new_pack = parse_pack_index(sha1);
Daniel Barkalowb3661562005-09-15 03:26:08459 new_pack->next = repo->packs;
460 repo->packs = new_pack;
barkalow@iabervon.org182005b2005-08-01 00:54:17461 return 0;
462}
463
Nick Hengevelde388ab72005-11-18 19:03:04464static void process_alternates_response(void *callback_data)
Daniel Barkalowb3661562005-09-15 03:26:08465{
Nick Hengevelde388ab72005-11-18 19:03:04466 struct alternates_request *alt_req =
467 (struct alternates_request *)callback_data;
Nick Hengeveldacc075a2005-11-12 17:11:32468 struct active_request_slot *slot = alt_req->slot;
469 struct alt_base *tail = alt;
Petr Baudis8e29f6a2006-07-27 21:56:22470 const char *base = alt_req->base;
Nick Hengeveldacc075a2005-11-12 17:11:32471 static const char null_byte = '\0';
Daniel Barkalowb3661562005-09-15 03:26:08472 char *data;
473 int i = 0;
Nick Hengeveld1d389ab2005-10-11 06:22:01474
Nick Hengeveldacc075a2005-11-12 17:11:32475 if (alt_req->http_specific) {
476 if (slot->curl_result != CURLE_OK ||
477 !alt_req->buffer->posn) {
Junio C Hamanodc1b5ea2005-10-11 06:22:02478
Nick Hengeveldacc075a2005-11-12 17:11:32479 /* Try reusing the slot to get non-http alternates */
480 alt_req->http_specific = 0;
481 sprintf(alt_req->url, "%s/objects/info/alternates",
482 base);
483 curl_easy_setopt(slot->curl, CURLOPT_URL,
484 alt_req->url);
485 active_requests++;
486 slot->in_use = 1;
Nick Hengeveldc9826472006-03-15 16:59:52487 if (slot->finished != NULL)
488 (*slot->finished) = 0;
Mark Woodinga3f583c2006-02-01 11:44:39489 if (!start_active_slot(slot)) {
Nick Hengeveldacc075a2005-11-12 17:11:32490 got_alternates = -1;
Nick Hengeveld29508e12005-11-18 19:02:58491 slot->in_use = 0;
Nick Hengeveldc9826472006-03-15 16:59:52492 if (slot->finished != NULL)
493 (*slot->finished) = 1;
Nick Hengeveld1d389ab2005-10-11 06:22:01494 }
Mark Woodinga3f583c2006-02-01 11:44:39495 return;
Daniel Barkalowb3661562005-09-15 03:26:08496 }
Nick Hengeveldacc075a2005-11-12 17:11:32497 } else if (slot->curl_result != CURLE_OK) {
Junio C Hamanobe4a0152006-09-16 17:58:20498 if (!missing_target(slot)) {
Nick Hengeveldacc075a2005-11-12 17:11:32499 got_alternates = -1;
500 return;
501 }
Daniel Barkalowb3661562005-09-15 03:26:08502 }
503
Nick Hengeveld29508e12005-11-18 19:02:58504 fwrite_buffer(&null_byte, 1, 1, alt_req->buffer);
Nick Hengeveldacc075a2005-11-12 17:11:32505 alt_req->buffer->posn--;
506 data = alt_req->buffer->buffer;
Daniel Barkalow1b0c1e62005-09-18 18:14:19507
Nick Hengeveldacc075a2005-11-12 17:11:32508 while (i < alt_req->buffer->posn) {
Daniel Barkalowb3661562005-09-15 03:26:08509 int posn = i;
Nick Hengeveldacc075a2005-11-12 17:11:32510 while (posn < alt_req->buffer->posn && data[posn] != '\n')
Daniel Barkalowb3661562005-09-15 03:26:08511 posn++;
512 if (data[posn] == '\n') {
Daniel Barkalow1b0c1e62005-09-18 18:14:19513 int okay = 0;
514 int serverlen = 0;
515 struct alt_base *newalt;
516 char *target = NULL;
Daniel Barkalowb3661562005-09-15 03:26:08517 if (data[i] == '/') {
Junio C Hamano5df1e0d2006-09-13 06:53:27518 /* This counts
519 * http://git.host/pub/scm/linux.git/
520 * -----------here^
521 * so memcpy(dst, base, serverlen) will
522 * copy up to "...git.host".
523 */
524 const char *colon_ss = strstr(base,"://");
525 if (colon_ss) {
526 serverlen = (strchr(colon_ss + 3, '/')
527 - base);
528 okay = 1;
529 }
Daniel Barkalow1b0c1e62005-09-18 18:14:19530 } else if (!memcmp(data + i, "../", 3)) {
Junio C Hamano5df1e0d2006-09-13 06:53:27531 /* Relative URL; chop the corresponding
532 * number of subpath from base (and ../
533 * from data), and concatenate the result.
534 *
535 * The code first drops ../ from data, and
536 * then drops one ../ from data and one path
537 * from base. IOW, one extra ../ is dropped
538 * from data than path is dropped from base.
539 *
540 * This is not wrong. The alternate in
541 * http://git.host/pub/scm/linux.git/
542 * to borrow from
543 * http://git.host/pub/scm/linus.git/
544 * is ../../linus.git/objects/. You need
545 * two ../../ to borrow from your direct
546 * neighbour.
547 */
Daniel Barkalow1b0c1e62005-09-18 18:14:19548 i += 3;
549 serverlen = strlen(base);
Junio C Hamano8fcf7f92006-02-01 02:15:51550 while (i + 2 < posn &&
Daniel Barkalow1b0c1e62005-09-18 18:14:19551 !memcmp(data + i, "../", 3)) {
552 do {
553 serverlen--;
554 } while (serverlen &&
555 base[serverlen - 1] != '/');
556 i += 3;
557 }
Pavel Roskina9486b02006-07-10 06:57:51558 /* If the server got removed, give up. */
Junio C Hamano8fcf7f92006-02-01 02:15:51559 okay = strchr(base, ':') - base + 3 <
Daniel Barkalow1b0c1e62005-09-18 18:14:19560 serverlen;
Nick Hengeveldacc075a2005-11-12 17:11:32561 } else if (alt_req->http_specific) {
Daniel Barkalow1b0c1e62005-09-18 18:14:19562 char *colon = strchr(data + i, ':');
563 char *slash = strchr(data + i, '/');
564 if (colon && slash && colon < data + posn &&
565 slash < data + posn && colon < slash) {
566 okay = 1;
567 }
568 }
Junio C Hamano5df1e0d2006-09-13 06:53:27569 /* skip "objects\n" at end */
Daniel Barkalow1b0c1e62005-09-18 18:14:19570 if (okay) {
571 target = xmalloc(serverlen + posn - i - 6);
Junio C Hamano5df1e0d2006-09-13 06:53:27572 memcpy(target, base, serverlen);
573 memcpy(target + serverlen, data + i,
574 posn - i - 7);
575 target[serverlen + posn - i - 7] = 0;
Daniel Barkalowb3661562005-09-15 03:26:08576 if (get_verbosely)
Junio C Hamano8fcf7f92006-02-01 02:15:51577 fprintf(stderr,
Daniel Barkalowb3661562005-09-15 03:26:08578 "Also look at %s\n", target);
579 newalt = xmalloc(sizeof(*newalt));
Nick Hengeveld1d389ab2005-10-11 06:22:01580 newalt->next = NULL;
Daniel Barkalowb3661562005-09-15 03:26:08581 newalt->base = target;
582 newalt->got_indices = 0;
583 newalt->packs = NULL;
Nick Hengeveld8d9fbe52006-04-04 12:33:18584
Nick Hengeveld1d389ab2005-10-11 06:22:01585 while (tail->next != NULL)
586 tail = tail->next;
587 tail->next = newalt;
Daniel Barkalowb3661562005-09-15 03:26:08588 }
589 }
590 i = posn + 1;
591 }
Sergey Vlasovbc8f2652005-10-13 17:49:53592
Nick Hengeveldf7eb2902005-10-21 19:06:20593 got_alternates = 1;
Nick Hengeveldacc075a2005-11-12 17:11:32594}
595
Petr Baudis8e29f6a2006-07-27 21:56:22596static void fetch_alternates(const char *base)
Nick Hengeveldacc075a2005-11-12 17:11:32597{
598 struct buffer buffer;
599 char *url;
600 char *data;
601 struct active_request_slot *slot;
Nick Hengeveldcb754fd2006-02-01 02:00:37602 struct alternates_request alt_req;
Nick Hengeveldacc075a2005-11-12 17:11:32603
604 /* If another request has already started fetching alternates,
605 wait for them to arrive and return to processing this request's
606 curl message */
Nick Hengeveld29508e12005-11-18 19:02:58607#ifdef USE_CURL_MULTI
Nick Hengeveldacc075a2005-11-12 17:11:32608 while (got_alternates == 0) {
Nick Hengeveld29508e12005-11-18 19:02:58609 step_active_slots();
Nick Hengeveldacc075a2005-11-12 17:11:32610 }
Nick Hengeveld29508e12005-11-18 19:02:58611#endif
Nick Hengeveldacc075a2005-11-12 17:11:32612
613 /* Nothing to do if they've already been fetched */
614 if (got_alternates == 1)
615 return;
616
617 /* Start the fetch */
618 got_alternates = 0;
619
620 data = xmalloc(4096);
621 buffer.size = 4096;
622 buffer.posn = 0;
623 buffer.buffer = data;
624
625 if (get_verbosely)
626 fprintf(stderr, "Getting alternates list for %s\n", base);
Junio C Hamano8fcf7f92006-02-01 02:15:51627
Nick Hengeveldacc075a2005-11-12 17:11:32628 url = xmalloc(strlen(base) + 31);
629 sprintf(url, "%s/objects/info/http-alternates", base);
630
631 /* Use a callback to process the result, since another request
632 may fail and need to have alternates loaded before continuing */
633 slot = get_active_slot();
Nick Hengevelde388ab72005-11-18 19:03:04634 slot->callback_func = process_alternates_response;
Nick Hengeveldacc075a2005-11-12 17:11:32635 slot->callback_data = &alt_req;
636
637 curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
Nick Hengeveld29508e12005-11-18 19:02:58638 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
Nick Hengeveldacc075a2005-11-12 17:11:32639 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
640
641 alt_req.base = base;
642 alt_req.url = url;
643 alt_req.buffer = &buffer;
644 alt_req.http_specific = 1;
645 alt_req.slot = slot;
646
647 if (start_active_slot(slot))
648 run_active_slot(slot);
649 else
650 got_alternates = -1;
651
652 free(data);
653 free(url);
Daniel Barkalowb3661562005-09-15 03:26:08654}
655
Daniel Barkalowb3661562005-09-15 03:26:08656static int fetch_indices(struct alt_base *repo)
barkalow@iabervon.org182005b2005-08-01 00:54:17657{
658 unsigned char sha1[20];
659 char *url;
660 struct buffer buffer;
661 char *data;
662 int i = 0;
663
Nick Hengeveld1d389ab2005-10-11 06:22:01664 struct active_request_slot *slot;
Nick Hengeveldcb754fd2006-02-01 02:00:37665 struct slot_results results;
Nick Hengeveld1d389ab2005-10-11 06:22:01666
Daniel Barkalowb3661562005-09-15 03:26:08667 if (repo->got_indices)
barkalow@iabervon.org182005b2005-08-01 00:54:17668 return 0;
669
670 data = xmalloc(4096);
671 buffer.size = 4096;
672 buffer.posn = 0;
673 buffer.buffer = data;
674
675 if (get_verbosely)
Petr Baudis6fd72e32005-11-12 00:49:59676 fprintf(stderr, "Getting pack list for %s\n", repo->base);
Junio C Hamano8fcf7f92006-02-01 02:15:51677
Daniel Barkalowb3661562005-09-15 03:26:08678 url = xmalloc(strlen(repo->base) + 21);
679 sprintf(url, "%s/objects/info/packs", repo->base);
barkalow@iabervon.org182005b2005-08-01 00:54:17680
Nick Hengeveld1d389ab2005-10-11 06:22:01681 slot = get_active_slot();
Nick Hengeveldc8568e12006-01-31 19:06:55682 slot->results = &results;
Nick Hengeveld1d389ab2005-10-11 06:22:01683 curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
Nick Hengeveld29508e12005-11-18 19:02:58684 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
Nick Hengeveld1d389ab2005-10-11 06:22:01685 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
686 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
687 if (start_active_slot(slot)) {
688 run_active_slot(slot);
Nick Hengeveldc8568e12006-01-31 19:06:55689 if (results.curl_result != CURLE_OK) {
Junio C Hamanobe4a0152006-09-16 17:58:20690 if (missing_target(&results)) {
Nick Hengeveld5e3a7692005-11-18 19:03:11691 repo->got_indices = 1;
692 free(buffer.buffer);
693 return 0;
694 } else {
695 repo->got_indices = 0;
696 free(buffer.buffer);
697 return error("%s", curl_errorstr);
698 }
Sergey Vlasovbc8f2652005-10-13 17:49:53699 }
Nick Hengeveld1d389ab2005-10-11 06:22:01700 } else {
Nick Hengeveld5e3a7692005-11-18 19:03:11701 repo->got_indices = 0;
Sergey Vlasovbc8f2652005-10-13 17:49:53702 free(buffer.buffer);
Nick Hengeveld1d389ab2005-10-11 06:22:01703 return error("Unable to start request");
704 }
barkalow@iabervon.org182005b2005-08-01 00:54:17705
Sergey Vlasovbc8f2652005-10-13 17:49:53706 data = buffer.buffer;
Daniel Barkalowb3661562005-09-15 03:26:08707 while (i < buffer.posn) {
barkalow@iabervon.org182005b2005-08-01 00:54:17708 switch (data[i]) {
709 case 'P':
710 i++;
Junio C Hamano455c1612005-12-21 20:10:10711 if (i + 52 <= buffer.posn &&
Junio C Hamanocc44c762007-02-20 09:53:29712 !prefixcmp(data + i, " pack-") &&
Junio C Hamano1968d772007-02-20 09:55:07713 !prefixcmp(data + i + 46, ".pack\n")) {
barkalow@iabervon.org182005b2005-08-01 00:54:17714 get_sha1_hex(data + i + 6, sha1);
Daniel Barkalowb3661562005-09-15 03:26:08715 setup_index(repo, sha1);
barkalow@iabervon.org182005b2005-08-01 00:54:17716 i += 51;
717 break;
718 }
719 default:
Junio C Hamano455c1612005-12-21 20:10:10720 while (i < buffer.posn && data[i] != '\n')
barkalow@iabervon.org182005b2005-08-01 00:54:17721 i++;
722 }
723 i++;
Daniel Barkalowb3661562005-09-15 03:26:08724 }
barkalow@iabervon.org182005b2005-08-01 00:54:17725
Sergey Vlasovbc8f2652005-10-13 17:49:53726 free(buffer.buffer);
Daniel Barkalowb3661562005-09-15 03:26:08727 repo->got_indices = 1;
barkalow@iabervon.org182005b2005-08-01 00:54:17728 return 0;
729}
730
Daniel Barkalowb3661562005-09-15 03:26:08731static int fetch_pack(struct alt_base *repo, unsigned char *sha1)
barkalow@iabervon.org182005b2005-08-01 00:54:17732{
733 char *url;
734 struct packed_git *target;
735 struct packed_git **lst;
736 FILE *packfile;
737 char *filename;
Nick Hengeveld49a0f242005-09-28 17:14:04738 char tmpfile[PATH_MAX];
739 int ret;
740 long prev_posn = 0;
741 char range[RANGE_HEADER_SIZE];
742 struct curl_slist *range_header = NULL;
Nick Hengeveld1d389ab2005-10-11 06:22:01743
744 struct active_request_slot *slot;
Nick Hengeveldcb754fd2006-02-01 02:00:37745 struct slot_results results;
barkalow@iabervon.org182005b2005-08-01 00:54:17746
Daniel Barkalowb3661562005-09-15 03:26:08747 if (fetch_indices(repo))
barkalow@iabervon.org182005b2005-08-01 00:54:17748 return -1;
Daniel Barkalowb3661562005-09-15 03:26:08749 target = find_sha1_pack(sha1, repo->packs);
barkalow@iabervon.org182005b2005-08-01 00:54:17750 if (!target)
Daniel Barkalowb3661562005-09-15 03:26:08751 return -1;
barkalow@iabervon.org182005b2005-08-01 00:54:17752
753 if (get_verbosely) {
754 fprintf(stderr, "Getting pack %s\n",
755 sha1_to_hex(target->sha1));
756 fprintf(stderr, " which contains %s\n",
757 sha1_to_hex(sha1));
758 }
759
Daniel Barkalowb3661562005-09-15 03:26:08760 url = xmalloc(strlen(repo->base) + 65);
barkalow@iabervon.org182005b2005-08-01 00:54:17761 sprintf(url, "%s/objects/pack/pack-%s.pack",
Daniel Barkalowb3661562005-09-15 03:26:08762 repo->base, sha1_to_hex(target->sha1));
barkalow@iabervon.org182005b2005-08-01 00:54:17763
764 filename = sha1_pack_name(target->sha1);
Nick Hengeveld49a0f242005-09-28 17:14:04765 snprintf(tmpfile, sizeof(tmpfile), "%s.temp", filename);
766 packfile = fopen(tmpfile, "a");
barkalow@iabervon.org182005b2005-08-01 00:54:17767 if (!packfile)
768 return error("Unable to open local file %s for pack",
769 filename);
770
Nick Hengeveld1d389ab2005-10-11 06:22:01771 slot = get_active_slot();
Nick Hengeveldc8568e12006-01-31 19:06:55772 slot->results = &results;
Nick Hengeveld1d389ab2005-10-11 06:22:01773 curl_easy_setopt(slot->curl, CURLOPT_FILE, packfile);
774 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
775 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
Nick Hengeveld03126002005-10-11 06:22:01776 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
Nick Hengeveld1d389ab2005-10-11 06:22:01777 slot->local = packfile;
Nick Hengeveld1ddea772005-09-26 17:52:11778
Nick Hengeveld49a0f242005-09-28 17:14:04779 /* If there is data present from a previous transfer attempt,
780 resume where it left off */
781 prev_posn = ftell(packfile);
782 if (prev_posn>0) {
783 if (get_verbosely)
784 fprintf(stderr,
785 "Resuming fetch of pack %s at byte %ld\n",
786 sha1_to_hex(target->sha1), prev_posn);
787 sprintf(range, "Range: bytes=%ld-", prev_posn);
788 range_header = curl_slist_append(range_header, range);
Nick Hengeveld1d389ab2005-10-11 06:22:01789 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, range_header);
Nick Hengeveld49a0f242005-09-28 17:14:04790 }
791
Nick Hengeveld1d389ab2005-10-11 06:22:01792 if (start_active_slot(slot)) {
793 run_active_slot(slot);
Nick Hengeveldc8568e12006-01-31 19:06:55794 if (results.curl_result != CURLE_OK) {
Nick Hengeveld1d389ab2005-10-11 06:22:01795 fclose(packfile);
796 return error("Unable to get pack file %s\n%s", url,
797 curl_errorstr);
798 }
799 } else {
Petr Baudis313c4712005-11-11 23:55:16800 fclose(packfile);
Nick Hengeveld1d389ab2005-10-11 06:22:01801 return error("Unable to start request");
barkalow@iabervon.org182005b2005-08-01 00:54:17802 }
803
Shawn O. Pearce1c23d7942007-01-10 01:04:52804 target->pack_size = ftell(packfile);
barkalow@iabervon.org182005b2005-08-01 00:54:17805 fclose(packfile);
806
Junio C Hamanob721e012005-10-11 06:22:01807 ret = move_temp_to_file(tmpfile, filename);
Nick Hengeveld49a0f242005-09-28 17:14:04808 if (ret)
Junio C Hamanob721e012005-10-11 06:22:01809 return ret;
Nick Hengeveld49a0f242005-09-28 17:14:04810
Daniel Barkalowb3661562005-09-15 03:26:08811 lst = &repo->packs;
barkalow@iabervon.org182005b2005-08-01 00:54:17812 while (*lst != target)
813 lst = &((*lst)->next);
814 *lst = (*lst)->next;
815
Junio C Hamano271421c2005-09-30 07:07:39816 if (verify_pack(target, 0))
817 return -1;
barkalow@iabervon.org182005b2005-08-01 00:54:17818 install_packed_git(target);
819
820 return 0;
821}
822
Mark Wooding53f31382006-02-07 10:07:39823static void abort_object_request(struct object_request *obj_req)
824{
825 if (obj_req->local >= 0) {
826 close(obj_req->local);
827 obj_req->local = -1;
828 }
829 unlink(obj_req->tmpfile);
830 if (obj_req->slot) {
Junio C Hamanoa6080a02007-06-07 07:04:01831 release_active_slot(obj_req->slot);
Mark Wooding53f31382006-02-07 10:07:39832 obj_req->slot = NULL;
833 }
834 release_object_request(obj_req);
835}
836
Peter Hagervalla7928f82005-09-28 12:04:54837static int fetch_object(struct alt_base *repo, unsigned char *sha1)
Daniel Barkalow6eb7ed52005-04-24 01:47:23838{
839 char *hex = sha1_to_hex(sha1);
Nick Hengeveld29508e12005-11-18 19:02:58840 int ret = 0;
Nick Hengevelde388ab72005-11-18 19:03:04841 struct object_request *obj_req = object_queue_head;
Daniel Barkalow6eb7ed52005-04-24 01:47:23842
David Rientjesa89fccd2006-08-17 18:54:57843 while (obj_req != NULL && hashcmp(obj_req->sha1, sha1))
Nick Hengevelde388ab72005-11-18 19:03:04844 obj_req = obj_req->next;
845 if (obj_req == NULL)
Nick Hengeveld1d389ab2005-10-11 06:22:01846 return error("Couldn't find request for %s in the queue", hex);
Junio C Hamano271421c2005-09-30 07:07:39847
Nick Hengevelde388ab72005-11-18 19:03:04848 if (has_sha1_file(obj_req->sha1)) {
Mark Wooding53f31382006-02-07 10:07:39849 abort_object_request(obj_req);
Nick Hengeveld11f0daf2005-10-11 06:22:01850 return 0;
851 }
852
Nick Hengevelda7a8d372005-10-11 06:22:01853#ifdef USE_CURL_MULTI
Nick Hengevelde388ab72005-11-18 19:03:04854 while (obj_req->state == WAITING) {
Nick Hengeveld29508e12005-11-18 19:02:58855 step_active_slots();
Nick Hengeveld49a0f242005-09-28 17:14:04856 }
Nick Hengevelda7a8d372005-10-11 06:22:01857#else
Nick Hengevelde388ab72005-11-18 19:03:04858 start_object_request(obj_req);
Nick Hengevelda7a8d372005-10-11 06:22:01859#endif
Nick Hengeveld49a0f242005-09-28 17:14:04860
Nick Hengevelde388ab72005-11-18 19:03:04861 while (obj_req->state == ACTIVE) {
862 run_active_slot(obj_req->slot);
Nick Hengevelda7a8d372005-10-11 06:22:01863 }
Nick Hengevelde388ab72005-11-18 19:03:04864 if (obj_req->local != -1) {
865 close(obj_req->local); obj_req->local = -1;
Petr Baudis313c4712005-11-11 23:55:16866 }
Nick Hengeveld1d389ab2005-10-11 06:22:01867
Nick Hengevelde388ab72005-11-18 19:03:04868 if (obj_req->state == ABORTED) {
Nick Hengeveld29508e12005-11-18 19:02:58869 ret = error("Request for %s aborted", hex);
Nick Hengevelde388ab72005-11-18 19:03:04870 } else if (obj_req->curl_result != CURLE_OK &&
871 obj_req->http_code != 416) {
Junio C Hamanobe4a0152006-09-16 17:58:20872 if (missing_target(obj_req))
Petr Baudise2029eb2005-10-21 16:18:46873 ret = -1; /* Be silent, it is probably in a pack. */
874 else
875 ret = error("%s (curl_result = %d, http_code = %ld, sha1 = %s)",
Nick Hengevelde388ab72005-11-18 19:03:04876 obj_req->errorstr, obj_req->curl_result,
877 obj_req->http_code, hex);
878 } else if (obj_req->zret != Z_STREAM_END) {
Junio C Hamanobb528072006-03-20 22:07:59879 corrupt_object_found++;
Junio C Hamanobd2afde2006-02-23 01:47:10880 ret = error("File %s (%s) corrupt", hex, obj_req->url);
David Rientjesa89fccd2006-08-17 18:54:57881 } else if (hashcmp(obj_req->sha1, obj_req->real_sha1)) {
Junio C Hamanobd2afde2006-02-23 01:47:10882 ret = error("File %s has bad hash", hex);
Nick Hengevelde388ab72005-11-18 19:03:04883 } else if (obj_req->rename < 0) {
Mark Wooding7b934ec2006-02-01 11:44:35884 ret = error("unable to write sha1 filename %s",
885 obj_req->filename);
Nick Hengeveld1d389ab2005-10-11 06:22:01886 }
887
Nick Hengevelde388ab72005-11-18 19:03:04888 release_object_request(obj_req);
Nick Hengeveld29508e12005-11-18 19:02:58889 return ret;
Daniel Barkalow6eb7ed52005-04-24 01:47:23890}
891
Daniel Barkalowb3661562005-09-15 03:26:08892int fetch(unsigned char *sha1)
893{
894 struct alt_base *altbase = alt;
Nick Hengeveld1d389ab2005-10-11 06:22:01895
896 if (!fetch_object(altbase, sha1))
897 return 0;
Daniel Barkalowb3661562005-09-15 03:26:08898 while (altbase) {
Daniel Barkalowb3661562005-09-15 03:26:08899 if (!fetch_pack(altbase, sha1))
900 return 0;
Nick Hengeveldf7eb2902005-10-21 19:06:20901 fetch_alternates(alt->base);
Daniel Barkalowb3661562005-09-15 03:26:08902 altbase = altbase->next;
903 }
Junio C Hamanobd2afde2006-02-23 01:47:10904 return error("Unable to find %s under %s", sha1_to_hex(sha1),
Nick Hengeveld1d389ab2005-10-11 06:22:01905 alt->base);
Daniel Barkalowb3661562005-09-15 03:26:08906}
907
Junio C Hamano94fa4472005-10-11 06:22:02908static inline int needs_quote(int ch)
909{
Florian Forstercfd432e62006-06-18 15:18:03910 if (((ch >= 'A') && (ch <= 'Z'))
911 || ((ch >= 'a') && (ch <= 'z'))
912 || ((ch >= '0') && (ch <= '9'))
913 || (ch == '/')
914 || (ch == '-')
915 || (ch == '.'))
Junio C Hamano94fa4472005-10-11 06:22:02916 return 0;
Florian Forstercfd432e62006-06-18 15:18:03917 return 1;
Junio C Hamano94fa4472005-10-11 06:22:02918}
919
920static inline int hex(int v)
921{
922 if (v < 10) return '0' + v;
923 else return 'A' + v - 10;
924}
925
926static char *quote_ref_url(const char *base, const char *ref)
927{
928 const char *cp;
929 char *dp, *qref;
930 int len, baselen, ch;
931
932 baselen = strlen(base);
Gerrit Pape2afea3b2007-03-28 09:46:15933 len = baselen + 7; /* "/refs/" + NUL */
Junio C Hamano94fa4472005-10-11 06:22:02934 for (cp = ref; (ch = *cp) != 0; cp++, len++)
935 if (needs_quote(ch))
936 len += 2; /* extra two hex plus replacement % */
937 qref = xmalloc(len);
938 memcpy(qref, base, baselen);
Gerrit Pape2afea3b2007-03-28 09:46:15939 memcpy(qref + baselen, "/refs/", 6);
940 for (cp = ref, dp = qref + baselen + 6; (ch = *cp) != 0; cp++) {
Junio C Hamano94fa4472005-10-11 06:22:02941 if (needs_quote(ch)) {
942 *dp++ = '%';
943 *dp++ = hex((ch >> 4) & 0xF);
944 *dp++ = hex(ch & 0xF);
945 }
946 else
947 *dp++ = ch;
948 }
949 *dp = 0;
950
951 return qref;
952}
953
Daniel Barkalowcd541a62005-06-06 20:38:26954int fetch_ref(char *ref, unsigned char *sha1)
955{
Junio C Hamano94fa4472005-10-11 06:22:02956 char *url;
Daniel Barkalowfa3e0652005-06-22 00:45:49957 char hex[42];
958 struct buffer buffer;
Petr Baudis8e29f6a2006-07-27 21:56:22959 const char *base = alt->base;
Nick Hengeveld1d389ab2005-10-11 06:22:01960 struct active_request_slot *slot;
Nick Hengeveldcb754fd2006-02-01 02:00:37961 struct slot_results results;
Daniel Barkalowfa3e0652005-06-22 00:45:49962 buffer.size = 41;
963 buffer.posn = 0;
964 buffer.buffer = hex;
965 hex[41] = '\0';
Junio C Hamano8fcf7f92006-02-01 02:15:51966
Junio C Hamano94fa4472005-10-11 06:22:02967 url = quote_ref_url(base, ref);
Nick Hengeveld1d389ab2005-10-11 06:22:01968 slot = get_active_slot();
Nick Hengeveldc8568e12006-01-31 19:06:55969 slot->results = &results;
Nick Hengeveld1d389ab2005-10-11 06:22:01970 curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer);
971 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
972 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL);
973 curl_easy_setopt(slot->curl, CURLOPT_URL, url);
974 if (start_active_slot(slot)) {
975 run_active_slot(slot);
Nick Hengeveldc8568e12006-01-31 19:06:55976 if (results.curl_result != CURLE_OK)
Nick Hengeveld1d389ab2005-10-11 06:22:01977 return error("Couldn't get %s for %s\n%s",
978 url, ref, curl_errorstr);
979 } else {
980 return error("Unable to start request");
981 }
Daniel Barkalowfa3e0652005-06-22 00:45:49982
983 hex[40] = '\0';
984 get_sha1_hex(hex, sha1);
985 return 0;
Daniel Barkalowcd541a62005-06-06 20:38:26986}
987
Petr Baudis8e29f6a2006-07-27 21:56:22988int main(int argc, const char **argv)
Daniel Barkalow6eb7ed52005-04-24 01:47:23989{
Petr Baudis8e29f6a2006-07-27 21:56:22990 int commits;
991 const char **write_ref = NULL;
992 char **commit_id;
993 const char *url;
Gerrit Pape9c880b32007-03-28 09:47:35994 char *s;
Daniel Barkalow6eb7ed52005-04-24 01:47:23995 int arg = 1;
Nick Hengeveld7b9ae532005-10-21 19:06:27996 int rc = 0;
Daniel Barkalow6eb7ed52005-04-24 01:47:23997
Junio C Hamano5a327712005-11-26 08:47:59998 setup_git_directory();
Shawn Pearced0740d92006-05-19 07:29:26999 git_config(git_default_config);
Junio C Hamano5a327712005-11-26 08:47:591000
Daniel Barkalow6eb7ed52005-04-24 01:47:231001 while (arg < argc && argv[arg][0] == '-') {
1002 if (argv[arg][1] == 't') {
Daniel Barkalow4250a5e2005-04-30 23:53:561003 get_tree = 1;
Daniel Barkalow6eb7ed52005-04-24 01:47:231004 } else if (argv[arg][1] == 'c') {
Daniel Barkalow4250a5e2005-04-30 23:53:561005 get_history = 1;
Daniel Barkalow6eb7ed52005-04-24 01:47:231006 } else if (argv[arg][1] == 'a') {
Daniel Barkalow4250a5e2005-04-30 23:53:561007 get_all = 1;
1008 get_tree = 1;
1009 get_history = 1;
Junio C Hamanoe78d9772005-05-06 08:37:211010 } else if (argv[arg][1] == 'v') {
1011 get_verbosely = 1;
Daniel Barkalowfa3e0652005-06-22 00:45:491012 } else if (argv[arg][1] == 'w') {
Petr Baudis8e29f6a2006-07-27 21:56:221013 write_ref = &argv[arg + 1];
Daniel Barkalowfa3e0652005-06-22 00:45:491014 arg++;
Daniel Barkalow820eca62005-09-27 01:38:081015 } else if (!strcmp(argv[arg], "--recover")) {
1016 get_recover = 1;
Petr Baudis8e29f6a2006-07-27 21:56:221017 } else if (!strcmp(argv[arg], "--stdin")) {
1018 commits_on_stdin = 1;
Daniel Barkalow6eb7ed52005-04-24 01:47:231019 }
1020 arg++;
1021 }
Petr Baudis8e29f6a2006-07-27 21:56:221022 if (argc < arg + 2 - commits_on_stdin) {
1023 usage("git-http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url");
Daniel Barkalow6eb7ed52005-04-24 01:47:231024 return 1;
1025 }
Petr Baudis8e29f6a2006-07-27 21:56:221026 if (commits_on_stdin) {
1027 commits = pull_targets_stdin(&commit_id, &write_ref);
1028 } else {
1029 commit_id = (char **) &argv[arg++];
1030 commits = 1;
1031 }
1032 url = argv[arg];
Daniel Barkalow6eb7ed52005-04-24 01:47:231033
Nick Hengeveld29508e12005-11-18 19:02:581034 http_init();
Daniel Barkalow6eb7ed52005-04-24 01:47:231035
Sergey Vlasov1db69b52005-09-13 15:38:581036 no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
Darrin Thompson3dcb90f2005-07-13 02:12:401037
Daniel Barkalowb3661562005-09-15 03:26:081038 alt = xmalloc(sizeof(*alt));
Gerrit Pape2afea3b2007-03-28 09:46:151039 alt->base = xmalloc(strlen(url) + 1);
1040 strcpy(alt->base, url);
Gerrit Pape9c880b32007-03-28 09:47:351041 for (s = alt->base + strlen(alt->base) - 1; *s == '/'; --s)
1042 *s = 0;
Daniel Barkalowb3661562005-09-15 03:26:081043 alt->got_indices = 0;
1044 alt->packs = NULL;
1045 alt->next = NULL;
Daniel Barkalow6eb7ed52005-04-24 01:47:231046
Petr Baudis8e29f6a2006-07-27 21:56:221047 if (pull(commits, commit_id, write_ref, url))
Nick Hengeveld7b9ae532005-10-21 19:06:271048 rc = 1;
Daniel Barkalow6eb7ed52005-04-24 01:47:231049
Nick Hengeveld29508e12005-11-18 19:02:581050 http_cleanup();
1051
Sean07001f92006-05-20 22:46:331052 curl_slist_free_all(no_pragma_header);
1053
Petr Baudis8e29f6a2006-07-27 21:56:221054 if (commits_on_stdin)
1055 pull_targets_free(commits, commit_id, write_ref);
1056
Junio C Hamanobb528072006-03-20 22:07:591057 if (corrupt_object_found) {
1058 fprintf(stderr,
1059"Some loose object were found to be corrupt, but they might be just\n"
1060"a false '404 Not Found' error message sent with incorrect HTTP\n"
Junio C Hamanodf391b12007-01-29 00:33:581061"status code. Suggest running git-fsck.\n");
Junio C Hamanobb528072006-03-20 22:07:591062 }
Nick Hengeveld7b9ae532005-10-21 19:06:271063 return rc;
Daniel Barkalow6eb7ed52005-04-24 01:47:231064}