9 #if LIBCURL_VERSION_NUM < 0x070704
10 #define curl_global_cleanup() do { /* nothing */ } while(0)
12 #if LIBCURL_VERSION_NUM < 0x070800
13 #define curl_global_init(a) do { /* nothing */ } while(0)
17 static struct curl_slist
*no_pragma_header
;
19 static char *initial_base
;
25 struct packed_git
*packs
;
26 struct alt_base
*next
;
29 struct alt_base
*alt
= NULL
;
32 static z_stream stream
;
37 static int curl_ssl_verify
;
46 static size_t fwrite_buffer(void *ptr
, size_t eltsize
, size_t nmemb
,
47 struct buffer
*buffer
)
49 size_t size
= eltsize
* nmemb
;
50 if (size
> buffer
->size
- buffer
->posn
)
51 size
= buffer
->size
- buffer
->posn
;
52 memcpy(buffer
->buffer
+ buffer
->posn
, ptr
, size
);
57 static size_t fwrite_sha1_file(void *ptr
, size_t eltsize
, size_t nmemb
,
60 unsigned char expn
[4096];
61 size_t size
= eltsize
* nmemb
;
64 ssize_t retval
= write(local
, ptr
+ posn
, size
- posn
);
68 } while (posn
< size
);
70 stream
.avail_in
= size
;
73 stream
.next_out
= expn
;
74 stream
.avail_out
= sizeof(expn
);
75 zret
= inflate(&stream
, Z_SYNC_FLUSH
);
76 SHA1_Update(&c
, expn
, sizeof(expn
) - stream
.avail_out
);
77 } while (stream
.avail_in
&& zret
== Z_OK
);
81 void prefetch(unsigned char *sha1
)
85 static int got_alternates
= 0;
87 static int fetch_index(struct alt_base
*repo
, unsigned char *sha1
)
94 if (has_pack_index(sha1
))
98 fprintf(stderr
, "Getting index for pack %s\n",
101 url
= xmalloc(strlen(repo
->base
) + 64);
102 sprintf(url
, "%s/objects/pack/pack-%s.idx",
103 repo
->base
, sha1_to_hex(sha1
));
105 filename
= sha1_pack_index_name(sha1
);
106 indexfile
= fopen(filename
, "w");
108 return error("Unable to open local file %s for pack index",
111 curl_easy_setopt(curl
, CURLOPT_FILE
, indexfile
);
112 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, fwrite
);
113 curl_easy_setopt(curl
, CURLOPT_URL
, url
);
114 curl_easy_setopt(curl
, CURLOPT_HTTPHEADER
, no_pragma_header
);
116 if (curl_easy_perform(curl
)) {
118 return error("Unable to get pack index %s", url
);
125 static int setup_index(struct alt_base
*repo
, unsigned char *sha1
)
127 struct packed_git
*new_pack
;
128 if (has_pack_file(sha1
))
129 return 0; // don't list this as something we can get
131 if (fetch_index(repo
, sha1
))
134 new_pack
= parse_pack_index(sha1
);
135 new_pack
->next
= repo
->packs
;
136 repo
->packs
= new_pack
;
140 static int fetch_alternates(char *base
)
143 struct buffer buffer
;
149 data
= xmalloc(4096);
152 buffer
.buffer
= data
;
155 fprintf(stderr
, "Getting alternates list\n");
157 url
= xmalloc(strlen(base
) + 31);
158 sprintf(url
, "%s/objects/info/http-alternates", base
);
160 curl_easy_setopt(curl
, CURLOPT_FILE
, &buffer
);
161 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, fwrite_buffer
);
162 curl_easy_setopt(curl
, CURLOPT_URL
, url
);
164 if (curl_easy_perform(curl
) || !buffer
.posn
) {
165 sprintf(url
, "%s/objects/info/alternates", base
);
167 curl_easy_setopt(curl
, CURLOPT_FILE
, &buffer
);
168 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, fwrite_buffer
);
169 curl_easy_setopt(curl
, CURLOPT_URL
, url
);
171 if (curl_easy_perform(curl
)) {
176 while (i
< buffer
.posn
) {
178 while (posn
< buffer
.posn
&& data
[posn
] != '\n')
180 if (data
[posn
] == '\n') {
181 if (data
[i
] == '/') {
182 int serverlen
= strchr(base
+ 8, '/') - base
;
183 // skip 'objects' at end
185 xmalloc(serverlen
+ posn
- i
- 6);
186 struct alt_base
*newalt
;
187 strncpy(target
, base
, serverlen
);
188 strncpy(target
+ serverlen
, data
+ i
,
190 target
[serverlen
+ posn
- i
- 7] = '\0';
193 "Also look at %s\n", target
);
194 newalt
= xmalloc(sizeof(*newalt
));
196 newalt
->base
= target
;
197 newalt
->got_indices
= 0;
198 newalt
->packs
= NULL
;
210 static int fetch_indices(struct alt_base
*repo
)
212 unsigned char sha1
[20];
214 struct buffer buffer
;
218 if (repo
->got_indices
)
221 data
= xmalloc(4096);
224 buffer
.buffer
= data
;
227 fprintf(stderr
, "Getting pack list\n");
229 url
= xmalloc(strlen(repo
->base
) + 21);
230 sprintf(url
, "%s/objects/info/packs", repo
->base
);
232 curl_easy_setopt(curl
, CURLOPT_FILE
, &buffer
);
233 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, fwrite_buffer
);
234 curl_easy_setopt(curl
, CURLOPT_URL
, url
);
235 curl_easy_setopt(curl
, CURLOPT_HTTPHEADER
, NULL
);
237 if (curl_easy_perform(curl
)) {
238 return error("Unable to get pack index %s", url
);
241 while (i
< buffer
.posn
) {
245 if (i
+ 52 < buffer
.posn
&&
246 !strncmp(data
+ i
, " pack-", 6) &&
247 !strncmp(data
+ i
+ 46, ".pack\n", 6)) {
248 get_sha1_hex(data
+ i
+ 6, sha1
);
249 setup_index(repo
, sha1
);
254 while (data
[i
] != '\n')
260 repo
->got_indices
= 1;
264 static int fetch_pack(struct alt_base
*repo
, unsigned char *sha1
)
267 struct packed_git
*target
;
268 struct packed_git
**lst
;
272 if (fetch_indices(repo
))
274 target
= find_sha1_pack(sha1
, repo
->packs
);
279 fprintf(stderr
, "Getting pack %s\n",
280 sha1_to_hex(target
->sha1
));
281 fprintf(stderr
, " which contains %s\n",
285 url
= xmalloc(strlen(repo
->base
) + 65);
286 sprintf(url
, "%s/objects/pack/pack-%s.pack",
287 repo
->base
, sha1_to_hex(target
->sha1
));
289 filename
= sha1_pack_name(target
->sha1
);
290 packfile
= fopen(filename
, "w");
292 return error("Unable to open local file %s for pack",
295 curl_easy_setopt(curl
, CURLOPT_FILE
, packfile
);
296 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, fwrite
);
297 curl_easy_setopt(curl
, CURLOPT_URL
, url
);
298 curl_easy_setopt(curl
, CURLOPT_HTTPHEADER
, no_pragma_header
);
300 if (curl_easy_perform(curl
)) {
302 return error("Unable to get pack file %s", url
);
308 while (*lst
!= target
)
309 lst
= &((*lst
)->next
);
312 install_packed_git(target
);
317 int fetch_object(struct alt_base
*repo
, unsigned char *sha1
)
319 char *hex
= sha1_to_hex(sha1
);
320 char *filename
= sha1_file_name(sha1
);
321 unsigned char real_sha1
[20];
325 local
= open(filename
, O_WRONLY
| O_CREAT
| O_EXCL
, 0666);
328 return error("Couldn't open local object %s\n", filename
);
330 memset(&stream
, 0, sizeof(stream
));
332 inflateInit(&stream
);
336 curl_easy_setopt(curl
, CURLOPT_FAILONERROR
, 1);
337 curl_easy_setopt(curl
, CURLOPT_FILE
, NULL
);
338 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, fwrite_sha1_file
);
339 curl_easy_setopt(curl
, CURLOPT_HTTPHEADER
, no_pragma_header
);
341 url
= xmalloc(strlen(repo
->base
) + 50);
342 strcpy(url
, repo
->base
);
343 posn
= url
+ strlen(repo
->base
);
344 strcpy(posn
, "objects/");
346 memcpy(posn
, hex
, 2);
349 strcpy(posn
, hex
+ 2);
351 curl_easy_setopt(curl
, CURLOPT_URL
, url
);
353 if (curl_easy_perform(curl
)) {
360 SHA1_Final(real_sha1
, &c
);
361 if (zret
!= Z_STREAM_END
) {
363 return error("File %s (%s) corrupt\n", hex
, url
);
365 if (memcmp(sha1
, real_sha1
, 20)) {
367 return error("File %s has bad hash\n", hex
);
370 pull_say("got %s\n", hex
);
374 int fetch(unsigned char *sha1
)
376 struct alt_base
*altbase
= alt
;
378 if (!fetch_object(altbase
, sha1
))
380 if (!fetch_pack(altbase
, sha1
))
382 if (fetch_alternates(altbase
->base
) > 0) {
386 altbase
= altbase
->next
;
388 return error("Unable to find %s under %s\n", sha1_to_hex(sha1
),
392 int fetch_ref(char *ref
, unsigned char *sha1
)
396 struct buffer buffer
;
397 char *base
= initial_base
;
403 curl_easy_setopt(curl
, CURLOPT_FILE
, &buffer
);
404 curl_easy_setopt(curl
, CURLOPT_WRITEFUNCTION
, fwrite_buffer
);
405 curl_easy_setopt(curl
, CURLOPT_HTTPHEADER
, NULL
);
407 url
= xmalloc(strlen(base
) + 6 + strlen(ref
));
409 posn
= url
+ strlen(base
);
410 strcpy(posn
, "refs/");
414 curl_easy_setopt(curl
, CURLOPT_URL
, url
);
416 if (curl_easy_perform(curl
))
417 return error("Couldn't get %s for %s\n", url
, ref
);
420 get_sha1_hex(hex
, sha1
);
424 int main(int argc
, char **argv
)
430 while (arg
< argc
&& argv
[arg
][0] == '-') {
431 if (argv
[arg
][1] == 't') {
433 } else if (argv
[arg
][1] == 'c') {
435 } else if (argv
[arg
][1] == 'a') {
439 } else if (argv
[arg
][1] == 'v') {
441 } else if (argv
[arg
][1] == 'w') {
442 write_ref
= argv
[arg
+ 1];
447 if (argc
< arg
+ 2) {
448 usage("git-http-fetch [-c] [-t] [-a] [-d] [-v] [--recover] [-w ref] commit-id url");
451 commit_id
= argv
[arg
];
454 curl_global_init(CURL_GLOBAL_ALL
);
456 curl
= curl_easy_init();
457 no_pragma_header
= curl_slist_append(no_pragma_header
, "Pragma:");
459 curl_ssl_verify
= getenv("GIT_SSL_NO_VERIFY") ? 0 : 1;
460 curl_easy_setopt(curl
, CURLOPT_SSL_VERIFYPEER
, curl_ssl_verify
);
461 #if LIBCURL_VERSION_NUM >= 0x070907
462 curl_easy_setopt(curl
, CURLOPT_NETRC
, CURL_NETRC_OPTIONAL
);
465 alt
= xmalloc(sizeof(*alt
));
467 alt
->got_indices
= 0;
475 curl_slist_free_all(no_pragma_header
);
476 curl_global_cleanup();