* Copyright (C) 2010 Bradley M. Kuhn <bkuhn@ebb.org>
* Kuhn's copyrights are licensed GPLv2-or-later. File as a whole remains GPLv2.
*/
+
+//usage:#define wget_trivial_usage
+//usage: IF_FEATURE_WGET_LONG_OPTIONS(
+//usage: "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n"
+//usage: " [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]\n"
+//usage: " [--no-check-certificate] [-U|--user-agent AGENT]"
+//usage: IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..."
+//usage: )
+//usage: IF_NOT_FEATURE_WGET_LONG_OPTIONS(
+//usage: "[-csq] [-O FILE] [-Y on/off] [-P DIR] [-U AGENT]"
+//usage: IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..."
+//usage: )
+//usage:#define wget_full_usage "\n\n"
+//usage: "Retrieve files via HTTP or FTP\n"
+//usage: "\nOptions:"
+//usage: "\n -s Spider mode - only check file existence"
+//usage: "\n -c Continue retrieval of aborted transfer"
+//usage: "\n -q Quiet"
+//usage: "\n -P DIR Save to DIR (default .)"
+//usage: IF_FEATURE_WGET_TIMEOUT(
+//usage: "\n -T SEC Network read timeout is SEC seconds"
+//usage: )
+//usage: "\n -O FILE Save to FILE ('-' for stdout)"
+//usage: "\n -U STR Use STR for User-Agent header"
+//usage: "\n -Y Use proxy ('on' or 'off')"
+
#include "libbb.h"
//#define log_io(...) bb_error_msg(__VA_ARGS__)
#if ENABLE_FEATURE_WGET_TIMEOUT
unsigned timeout_seconds;
#endif
+ int output_fd;
+ int o_flags;
smallint chunked; /* chunked transfer encoding */
smallint got_clen; /* got content-length: from server */
/* Local downloads do benefit from big buffer.
if (flag == PROGRESS_START)
bb_progress_init(&G.pmt, G.curfile);
- bb_progress_update(&G.pmt, G.beg_range, G.transferred,
- G.chunked ? 0 : G.beg_range + G.transferred + G.content_len);
+ bb_progress_update(&G.pmt,
+ G.beg_range,
+ G.transferred,
+ (G.chunked || !G.got_clen) ? 0 : G.beg_range + G.transferred + G.content_len
+ );
if (flag == PROGRESS_END) {
bb_progress_free(&G.pmt);
overlapping_strcpy(scope, cp);
}
-#if 0 /* were needed when we used signal-driven progress bar */
-/* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read,
- * and a short count if an eof or non-interrupt error is encountered. */
-static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream)
-{
- size_t ret;
- char *p = (char*)ptr;
-
- do {
- clearerr(stream);
- errno = 0;
- ret = fread(p, 1, nmemb, stream);
- p += ret;
- nmemb -= ret;
- } while (nmemb && ferror(stream) && errno == EINTR);
-
- return p - (char*)ptr;
-}
-
-/* Read a line or SIZE-1 bytes into S, whichever is less, from STREAM.
- * Returns S, or NULL if an eof or non-interrupt error is encountered. */
-static char *safe_fgets(char *s, int size, FILE *stream)
-{
- char *ret;
-
- do {
- clearerr(stream);
- errno = 0;
- ret = fgets(s, size, stream);
- } while (ret == NULL && ferror(stream) && errno == EINTR);
-
- return ret;
-}
-#endif
-
#if ENABLE_FEATURE_WGET_AUTHENTICATION
/* Base64-encode character string. */
static char *base64enc(const char *str)
return sfp;
}
-static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
+static void NOINLINE retrieve_file_data(FILE *dfp)
{
#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
# if ENABLE_FEATURE_WGET_TIMEOUT
break; /* EOF, not error */
}
- xwrite(output_fd, G.wget_buf, n);
+ xwrite(G.output_fd, G.wget_buf, n);
#if ENABLE_FEATURE_WGET_STATUSBAR
G.transferred += n;
}
/* Draw full bar and free its resources */
- G.chunked = 0; /* makes it show 100% even for chunked download */
+ G.chunked = 0; /* makes it show 100% even for chunked download */
+ G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */
progress_meter(PROGRESS_END);
}
-static int download_one_url(const char *url)
+static void download_one_url(const char *url)
{
bool use_proxy; /* Use proxies if env vars are set */
int redir_limit;
- int output_fd;
len_and_sockaddr *lsa;
FILE *sfp; /* socket to web/ftp server */
FILE *dfp; /* socket to ftp server (data) */
use_proxy = (strcmp(G.proxy_flag, "off") != 0);
if (use_proxy) {
proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
- if (proxy && proxy[0]) {
+ use_proxy = (proxy && proxy[0]);
+ if (use_proxy)
parse_url(proxy, &server);
- } else {
- use_proxy = 0;
- }
}
if (!use_proxy) {
server.port = target.port;
strip_ipv6_scope_id(target.host);
/* If there was no -O FILE, guess output filename */
- output_fd = -1;
fname_out_alloc = NULL;
- if (!G.fname_out) {
+ if (!(option_mask32 & WGET_OPT_OUTNAME)) {
G.fname_out = bb_get_last_path_component_nostrip(target.path);
/* handle "wget http://kernel.org//" */
if (G.fname_out[0] == '/' || !G.fname_out[0])
G.fname_out = (char*)"index.html";
/* -P DIR is considered only if there was no -O FILE */
- if (G.dir_prefix)
- G.fname_out = fname_out_alloc = concat_path_file(G.dir_prefix, G.fname_out);
- } else {
- if (LONE_DASH(G.fname_out)) {
- /* -O - */
- output_fd = 1;
- option_mask32 &= ~WGET_OPT_CONTINUE;
+ else {
+ if (G.dir_prefix)
+ G.fname_out = fname_out_alloc = concat_path_file(G.dir_prefix, G.fname_out);
+ else {
+ /* redirects may free target.path later, need to make a copy */
+ G.fname_out = fname_out_alloc = xstrdup(G.fname_out);
+ }
}
}
#if ENABLE_FEATURE_WGET_STATUSBAR
#endif
/* Determine where to start transfer */
+ G.beg_range = 0;
if (option_mask32 & WGET_OPT_CONTINUE) {
- output_fd = open(G.fname_out, O_WRONLY);
- if (output_fd >= 0) {
- G.beg_range = xlseek(output_fd, 0, SEEK_END);
+ G.output_fd = open(G.fname_out, O_WRONLY);
+ if (G.output_fd >= 0) {
+ G.beg_range = xlseek(G.output_fd, 0, SEEK_END);
}
/* File doesn't exist. We do not create file here yet.
* We are not sure it exists on remote side */
free(s);
}
establish_session:
- G.chunked = G.got_clen = 0;
+ /*G.content_len = 0; - redundant, got_clen = 0 is enough */
+ G.got_clen = 0;
+ G.chunked = 0;
if (use_proxy || !target.is_ftp) {
/*
* HTTP session
parse_url(str, &target);
if (!use_proxy) {
free(server.allocated);
+ server.allocated = NULL;
server.host = target.host;
/* strip_ipv6_scope_id(target.host); - no! */
/* we assume remote never gives us IPv6 addr with scope id */
}
free(lsa);
- free(server.allocated);
- free(target.allocated);
- if (option_mask32 & WGET_OPT_SPIDER) {
- free(fname_out_alloc);
- fclose(sfp);
- return EXIT_SUCCESS;
- }
-
- if (output_fd < 0) {
- int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL;
- /* compat with wget: -O FILE can overwrite */
- if (option_mask32 & WGET_OPT_OUTNAME)
- o_flags = O_WRONLY | O_CREAT | O_TRUNC;
- output_fd = xopen(G.fname_out, o_flags);
+ if (!(option_mask32 & WGET_OPT_SPIDER)) {
+ if (G.output_fd < 0)
+ G.output_fd = xopen(G.fname_out, G.o_flags);
+ retrieve_file_data(dfp);
+ if (!(option_mask32 & WGET_OPT_OUTNAME)) {
+ xclose(G.output_fd);
+ G.output_fd = -1;
+ }
}
- free(fname_out_alloc);
-
- retrieve_file_data(dfp, output_fd);
- xclose(output_fd);
-
if (dfp != sfp) {
/* It's ftp. Close data connection properly */
fclose(dfp);
}
fclose(sfp);
- return EXIT_SUCCESS;
+ free(server.allocated);
+ free(target.allocated);
+ free(fname_out_alloc);
}
int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
;
#endif
- int exitcode;
#if ENABLE_FEATURE_WGET_LONG_OPTIONS
llist_t *headers_llist = NULL;
#endif
}
#endif
- exitcode = 0;
+ G.output_fd = -1;
+ G.o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL;
+ if (G.fname_out) { /* -O FILE ? */
+ if (LONE_DASH(G.fname_out)) { /* -O - ? */
+ G.output_fd = 1;
+ option_mask32 &= ~WGET_OPT_CONTINUE;
+ }
+ /* compat with wget: -O FILE can overwrite */
+ G.o_flags = O_WRONLY | O_CREAT | O_TRUNC;
+ }
+
while (*argv)
- exitcode |= download_one_url(*argv++);
+ download_one_url(*argv++);
- return exitcode;
+ if (G.output_fd >= 0)
+ xclose(G.output_fd);
+
+ return EXIT_SUCCESS;
}