diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-09-26 09:22:12 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-09-26 09:22:12 +0000 |
commit | a552eeb498e0270ae9c87ef707865a764df99fb6 (patch) | |
tree | 1a385f7c6f1eab36fb66278e48840fe7fdc0b882 /networking/wget.c | |
parent | 3312c989e6a145dc38e5bb874e713aa92b2b0698 (diff) | |
download | busybox-w32-a552eeb498e0270ae9c87ef707865a764df99fb6.tar.gz busybox-w32-a552eeb498e0270ae9c87ef707865a764df99fb6.tar.bz2 busybox-w32-a552eeb498e0270ae9c87ef707865a764df99fb6.zip |
wget: add (configurable) large file support. Run tested.
Diffstat (limited to 'networking/wget.c')
-rw-r--r-- | networking/wget.c | 116 |
1 files changed, 63 insertions, 53 deletions
diff --git a/networking/wget.c b/networking/wget.c index 4b55b93f4..0eb8cd610 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -6,8 +6,28 @@ | |||
6 | * | 6 | * |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* We want libc to give us xxx64 functions also */ | ||
10 | /* http://www.unix.org/version2/whatsnew/lfs20mar.html */ | ||
11 | #define _LARGEFILE64_SOURCE 1 | ||
12 | |||
9 | #include "busybox.h" | 13 | #include "busybox.h" |
10 | #include <getopt.h> | 14 | #include <getopt.h> /* for struct option */ |
15 | |||
16 | #ifdef CONFIG_LFS | ||
17 | # define FILEOFF_TYPE off64_t | ||
18 | # define FILEOFF_FMT "%lld" | ||
19 | # define LSEEK lseek64 | ||
20 | # define STRTOOFF strtoll | ||
21 | # define SAFE_STRTOOFF safe_strtoll | ||
22 | /* stat64 etc as needed... */ | ||
23 | #else | ||
24 | # define FILEOFF_TYPE off_t | ||
25 | # define FILEOFF_FMT "%ld" | ||
26 | # define LSEEK lseek | ||
27 | # define STRTOOFF strtol | ||
28 | # define SAFE_STRTOOFF safe_strtol | ||
29 | /* Do we need to undefine O_LARGEFILE? */ | ||
30 | #endif | ||
11 | 31 | ||
12 | struct host_info { | 32 | struct host_info { |
13 | char *host; | 33 | char *host; |
@@ -23,13 +43,13 @@ static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc); | |||
23 | static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf); | 43 | static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf); |
24 | 44 | ||
25 | /* Globals (can be accessed from signal handlers */ | 45 | /* Globals (can be accessed from signal handlers */ |
26 | static off_t filesize; /* content-length of the file */ | 46 | static FILEOFF_TYPE filesize; /* content-length of the file */ |
27 | static int chunked; /* chunked transfer encoding */ | 47 | static int chunked; /* chunked transfer encoding */ |
28 | #ifdef CONFIG_FEATURE_WGET_STATUSBAR | 48 | #ifdef CONFIG_FEATURE_WGET_STATUSBAR |
29 | static void progressmeter(int flag); | 49 | static void progressmeter(int flag); |
30 | static char *curfile; /* Name of current file being transferred. */ | 50 | static char *curfile; /* Name of current file being transferred. */ |
31 | static struct timeval start; /* Time a transfer started. */ | 51 | static struct timeval start; /* Time a transfer started. */ |
32 | static off_t transferred; /* Number of bytes transferred so far. */ | 52 | static FILEOFF_TYPE transferred; /* Number of bytes transferred so far. */ |
33 | /* For progressmeter() -- number of seconds before xfer considered "stalled" */ | 53 | /* For progressmeter() -- number of seconds before xfer considered "stalled" */ |
34 | enum { | 54 | enum { |
35 | STALLTIME = 5 | 55 | STALLTIME = 5 |
@@ -78,20 +98,20 @@ static char *base64enc(unsigned char *p, char *buf, int len) | |||
78 | } | 98 | } |
79 | #endif | 99 | #endif |
80 | 100 | ||
81 | #define WGET_OPT_CONTINUE 1 | 101 | #define WGET_OPT_CONTINUE 1 |
82 | #define WGET_OPT_QUIET 2 | 102 | #define WGET_OPT_QUIET 2 |
83 | #define WGET_OPT_PASSIVE 4 | 103 | #define WGET_OPT_PASSIVE 4 |
84 | #define WGET_OPT_OUTNAME 8 | 104 | #define WGET_OPT_OUTNAME 8 |
85 | #define WGET_OPT_HEADER 16 | 105 | #define WGET_OPT_HEADER 16 |
86 | #define WGET_OPT_PREFIX 32 | 106 | #define WGET_OPT_PREFIX 32 |
87 | #define WGET_OPT_PROXY 64 | 107 | #define WGET_OPT_PROXY 64 |
88 | #define WGET_OPT_USER_AGENT 128 | 108 | #define WGET_OPT_USER_AGENT 128 |
89 | 109 | ||
90 | #if ENABLE_FEATURE_WGET_LONG_OPTIONS | 110 | #if ENABLE_FEATURE_WGET_LONG_OPTIONS |
91 | static const struct option wget_long_options[] = { | 111 | static const struct option wget_long_options[] = { |
92 | { "continue", 0, NULL, 'c' }, | 112 | { "continue", 0, NULL, 'c' }, |
93 | { "quiet", 0, NULL, 'q' }, | 113 | { "quiet", 0, NULL, 'q' }, |
94 | { "passive-ftp", 0, NULL, 139 }, | 114 | { "passive-ftp", 0, NULL, 139 }, /* FIXME: what is this - 139?? */ |
95 | { "output-document", 1, NULL, 'O' }, | 115 | { "output-document", 1, NULL, 'O' }, |
96 | { "header", 1, NULL, 131 }, | 116 | { "header", 1, NULL, 131 }, |
97 | { "directory-prefix",1, NULL, 'P' }, | 117 | { "directory-prefix",1, NULL, 'P' }, |
@@ -116,17 +136,15 @@ int wget_main(int argc, char **argv) | |||
116 | struct sockaddr_in s_in; | 136 | struct sockaddr_in s_in; |
117 | llist_t *headers_llist = NULL; | 137 | llist_t *headers_llist = NULL; |
118 | 138 | ||
119 | FILE *sfp = NULL; /* socket to web/ftp server */ | 139 | FILE *sfp = NULL; /* socket to web/ftp server */ |
120 | FILE *dfp = NULL; /* socket to ftp server (data) */ | 140 | FILE *dfp = NULL; /* socket to ftp server (data) */ |
121 | char *fname_out = NULL; /* where to direct output (-O) */ | 141 | char *fname_out = NULL; /* where to direct output (-O) */ |
122 | int do_continue = 0; /* continue a prev transfer (-c) */ | 142 | FILEOFF_TYPE beg_range = 0; /* range at which continue begins */ |
123 | off64_t beg_range = 0; /* range at which continue begins */ | 143 | int got_clen = 0; /* got content-length: from server */ |
124 | int got_clen = 0; /* got content-length: from server */ | ||
125 | int output_fd = -1; | 144 | int output_fd = -1; |
126 | int quiet_flag = FALSE; /* Be verry, verry quiet... */ | 145 | int use_proxy = 1; /* Use proxies if env vars are set */ |
127 | int use_proxy = 1; /* Use proxies if env vars are set */ | 146 | char *proxy_flag = "on"; /* Use proxies if env vars are set */ |
128 | char *proxy_flag = "on"; /* Use proxies if env vars are set */ | 147 | char *user_agent = "Wget"; /* Content of the "User-Agent" header field */ |
129 | char *user_agent = "Wget"; /* Content of the "User-Agent" header field */ | ||
130 | 148 | ||
131 | /* | 149 | /* |
132 | * Crack command line. | 150 | * Crack command line. |
@@ -138,12 +156,6 @@ int wget_main(int argc, char **argv) | |||
138 | opt = bb_getopt_ulflags(argc, argv, "cq\213O:\203:P:Y:U:", | 156 | opt = bb_getopt_ulflags(argc, argv, "cq\213O:\203:P:Y:U:", |
139 | &fname_out, &headers_llist, | 157 | &fname_out, &headers_llist, |
140 | &dir_prefix, &proxy_flag, &user_agent); | 158 | &dir_prefix, &proxy_flag, &user_agent); |
141 | if (opt & WGET_OPT_CONTINUE) { | ||
142 | ++do_continue; | ||
143 | } | ||
144 | if (opt & WGET_OPT_QUIET) { | ||
145 | quiet_flag = TRUE; | ||
146 | } | ||
147 | if (strcmp(proxy_flag, "off") == 0) { | 159 | if (strcmp(proxy_flag, "off") == 0) { |
148 | /* Use the proxy if necessary. */ | 160 | /* Use the proxy if necessary. */ |
149 | use_proxy = 0; | 161 | use_proxy = 0; |
@@ -205,7 +217,7 @@ int wget_main(int argc, char **argv) | |||
205 | curfile = bb_get_last_path_component(fname_out); | 217 | curfile = bb_get_last_path_component(fname_out); |
206 | #endif | 218 | #endif |
207 | } | 219 | } |
208 | if (do_continue && !fname_out) | 220 | if ((opt & WGET_OPT_CONTINUE) && !fname_out) |
209 | bb_error_msg_and_die("cannot specify continue (-c) without a filename (-O)"); | 221 | bb_error_msg_and_die("cannot specify continue (-c) without a filename (-O)"); |
210 | 222 | ||
211 | /* | 223 | /* |
@@ -213,13 +225,13 @@ int wget_main(int argc, char **argv) | |||
213 | */ | 225 | */ |
214 | if (!strcmp(fname_out, "-")) { | 226 | if (!strcmp(fname_out, "-")) { |
215 | output_fd = 1; | 227 | output_fd = 1; |
216 | quiet_flag = TRUE; | 228 | opt |= WGET_OPT_QUIET; |
217 | do_continue = 0; | 229 | opt &= ~WGET_OPT_CONTINUE; |
218 | } else if (do_continue) { | 230 | } else if (opt & WGET_OPT_CONTINUE) { |
219 | output_fd = open(fname_out, O_WRONLY|O_LARGEFILE); | 231 | output_fd = open(fname_out, O_WRONLY|O_LARGEFILE); |
220 | if (output_fd >= 0) { | 232 | if (output_fd >= 0) { |
221 | beg_range = lseek64(output_fd, 0, SEEK_END); | 233 | beg_range = LSEEK(output_fd, 0, SEEK_END); |
222 | if (beg_range == (off64_t)-1) | 234 | if (beg_range == (FILEOFF_TYPE)-1) |
223 | bb_perror_msg_and_die("lseek64"); | 235 | bb_perror_msg_and_die("lseek64"); |
224 | } | 236 | } |
225 | /* File doesn't exist. We do not create file here yet. | 237 | /* File doesn't exist. We do not create file here yet. |
@@ -231,7 +243,7 @@ int wget_main(int argc, char **argv) | |||
231 | * and we want to connect to only one IP... */ | 243 | * and we want to connect to only one IP... */ |
232 | bb_lookup_host(&s_in, server.host); | 244 | bb_lookup_host(&s_in, server.host); |
233 | s_in.sin_port = server.port; | 245 | s_in.sin_port = server.port; |
234 | if (quiet_flag == FALSE) { | 246 | if (!(opt & WGET_OPT_QUIET)) { |
235 | printf("Connecting to %s[%s]:%d\n", | 247 | printf("Connecting to %s[%s]:%d\n", |
236 | server.host, inet_ntoa(s_in.sin_addr), ntohs(server.port)); | 248 | server.host, inet_ntoa(s_in.sin_addr), ntohs(server.port)); |
237 | } | 249 | } |
@@ -283,7 +295,7 @@ int wget_main(int argc, char **argv) | |||
283 | #endif | 295 | #endif |
284 | 296 | ||
285 | if (beg_range) | 297 | if (beg_range) |
286 | fprintf(sfp, "Range: bytes=%lld-\r\n", (long long)beg_range); | 298 | fprintf(sfp, "Range: bytes="FILEOFF_FMT"-\r\n", beg_range); |
287 | if(extra_headers_left < sizeof(extra_headers)) | 299 | if(extra_headers_left < sizeof(extra_headers)) |
288 | fputs(extra_headers,sfp); | 300 | fputs(extra_headers,sfp); |
289 | fprintf(sfp,"Connection: close\r\n\r\n"); | 301 | fprintf(sfp,"Connection: close\r\n\r\n"); |
@@ -325,11 +337,9 @@ read_response: | |||
325 | */ | 337 | */ |
326 | while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) { | 338 | while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) { |
327 | if (strcasecmp(buf, "content-length") == 0) { | 339 | if (strcasecmp(buf, "content-length") == 0) { |
328 | unsigned long value; | 340 | if (SAFE_STRTOOFF(s, &filesize) || filesize < 0) { |
329 | if (safe_strtoul(s, &value)) { | ||
330 | bb_error_msg_and_die("content-length %s is garbage", s); | 341 | bb_error_msg_and_die("content-length %s is garbage", s); |
331 | } | 342 | } |
332 | filesize = value; | ||
333 | got_clen = 1; | 343 | got_clen = 1; |
334 | continue; | 344 | continue; |
335 | } | 345 | } |
@@ -395,11 +405,9 @@ read_response: | |||
395 | * Querying file size | 405 | * Querying file size |
396 | */ | 406 | */ |
397 | if (ftpcmd("SIZE ", target.path, sfp, buf) == 213) { | 407 | if (ftpcmd("SIZE ", target.path, sfp, buf) == 213) { |
398 | unsigned long value; | 408 | if (SAFE_STRTOOFF(buf+4, &filesize) || filesize < 0) { |
399 | if (safe_strtoul(buf+4, &value)) { | ||
400 | bb_error_msg_and_die("SIZE value is garbage"); | 409 | bb_error_msg_and_die("SIZE value is garbage"); |
401 | } | 410 | } |
402 | filesize = value; | ||
403 | got_clen = 1; | 411 | got_clen = 1; |
404 | } | 412 | } |
405 | 413 | ||
@@ -417,7 +425,7 @@ read_response: | |||
417 | dfp = open_socket(&s_in); | 425 | dfp = open_socket(&s_in); |
418 | 426 | ||
419 | if (beg_range) { | 427 | if (beg_range) { |
420 | sprintf(buf, "REST %lld", (long long)beg_range); | 428 | sprintf(buf, "REST "FILEOFF_FMT, beg_range); |
421 | if (ftpcmd(buf, NULL, sfp, buf) == 350) | 429 | if (ftpcmd(buf, NULL, sfp, buf) == 350) |
422 | filesize -= beg_range; | 430 | filesize -= beg_range; |
423 | } | 431 | } |
@@ -432,17 +440,18 @@ read_response: | |||
432 | */ | 440 | */ |
433 | if (chunked) { | 441 | if (chunked) { |
434 | fgets(buf, sizeof(buf), dfp); | 442 | fgets(buf, sizeof(buf), dfp); |
435 | filesize = strtol(buf, (char **) NULL, 16); | 443 | filesize = STRTOOFF(buf, (char **) NULL, 16); |
444 | /* FIXME: error check?? */ | ||
436 | } | 445 | } |
437 | 446 | ||
438 | if (quiet_flag == FALSE) | 447 | if (!(opt & WGET_OPT_QUIET)) |
439 | progressmeter(-1); | 448 | progressmeter(-1); |
440 | 449 | ||
441 | do { | 450 | do { |
442 | while (filesize > 0 || !got_clen) { | 451 | while (filesize > 0 || !got_clen) { |
443 | unsigned rdsz = sizeof(buf); | 452 | unsigned rdsz = sizeof(buf); |
444 | if (filesize < sizeof(buf) && (chunked || got_clen)) | 453 | if (filesize < sizeof(buf) && (chunked || got_clen)) |
445 | rdsz = filesize; | 454 | rdsz = (unsigned)filesize; |
446 | n = safe_fread(buf, 1, rdsz, dfp); | 455 | n = safe_fread(buf, 1, rdsz, dfp); |
447 | if (n <= 0) | 456 | if (n <= 0) |
448 | break; | 457 | break; |
@@ -462,7 +471,8 @@ read_response: | |||
462 | if (chunked) { | 471 | if (chunked) { |
463 | safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */ | 472 | safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */ |
464 | safe_fgets(buf, sizeof(buf), dfp); | 473 | safe_fgets(buf, sizeof(buf), dfp); |
465 | filesize = strtol(buf, (char **) NULL, 16); | 474 | filesize = STRTOOFF(buf, (char **) NULL, 16); |
475 | /* FIXME: error check? */ | ||
466 | if (filesize == 0) { | 476 | if (filesize == 0) { |
467 | chunked = 0; /* all done! */ | 477 | chunked = 0; /* all done! */ |
468 | } | 478 | } |
@@ -473,7 +483,7 @@ read_response: | |||
473 | } | 483 | } |
474 | } while (chunked); | 484 | } while (chunked); |
475 | 485 | ||
476 | if (quiet_flag == FALSE) | 486 | if (!(opt & WGET_OPT_QUIET)) |
477 | progressmeter(1); | 487 | progressmeter(1); |
478 | 488 | ||
479 | if ((use_proxy == 0) && target.is_ftp) { | 489 | if ((use_proxy == 0) && target.is_ftp) { |
@@ -662,10 +672,10 @@ static void | |||
662 | progressmeter(int flag) | 672 | progressmeter(int flag) |
663 | { | 673 | { |
664 | static struct timeval lastupdate; | 674 | static struct timeval lastupdate; |
665 | static off_t lastsize, totalsize; | 675 | static FILEOFF_TYPE lastsize, totalsize; |
666 | 676 | ||
667 | struct timeval now, td, tvwait; | 677 | struct timeval now, td, tvwait; |
668 | off_t abbrevsize; | 678 | FILEOFF_TYPE abbrevsize; |
669 | int elapsed, ratio, barlength, i; | 679 | int elapsed, ratio, barlength, i; |
670 | char buf[256]; | 680 | char buf[256]; |
671 | 681 | ||