X-Git-Url: http://sjero.net/git/?p=wget;a=blobdiff_plain;f=src%2Fftp.c;h=2e32c1f03d04b45e9f723706d8e8d7ac1567925d;hp=fed0597c319d5575c04dab6cbdd8f0e6fb416e13;hb=4d7c5e087b2bc82c9f503dff003916d1047903ce;hpb=e911bc29434b7da90446d2ca5304106724d05680 diff --git a/src/ftp.c b/src/ftp.c index fed0597c..2e32c1f0 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -1,12 +1,11 @@ /* File Transfer Protocol support. - Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001 - Free Software Foundation, Inc. + Copyright (C) 1996-2006 Free Software Foundation, Inc. This file is part of GNU Wget. GNU Wget is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or +the Free Software Foundation; either version 3 of the License, or (at your option) any later version. GNU Wget is distributed in the hope that it will be useful, @@ -15,8 +14,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with Wget; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +along with Wget. If not, see . In addition, as a special exception, the Free Software Foundation gives permission to link the code of its release of Wget with the @@ -38,6 +36,7 @@ so, delete this exception statement from your version. */ #endif #include #include +#include #include "wget.h" #include "utils.h" @@ -50,16 +49,9 @@ so, delete this exception statement from your version. */ #include "convert.h" /* for downloaded_file */ #include "recur.h" /* for INFINITE_RECURSION */ -extern LARGE_INT total_downloaded_bytes; - /* File where the "ls -al" listing will be saved. */ #define LIST_FILENAME ".listing" -extern char ftp_last_respline[]; - -extern FILE *output_stream; -extern int output_stream_regular; - typedef struct { int st; /* connection status */ @@ -124,14 +116,14 @@ ftp_do_pasv (int csock, ip_address *addr, int *port) /* If our control connection is over IPv6, then we first try EPSV and then * LPSV if the former is not supported. If the control connection is over * IPv4, we simply issue the good old PASV request. */ - switch (addr->type) + switch (addr->family) { - case IPV4_ADDRESS: + case AF_INET: if (!opt.server_response) logputs (LOG_VERBOSE, "==> PASV ... "); err = ftp_pasv (csock, addr, port); break; - case IPV6_ADDRESS: + case AF_INET6: if (!opt.server_response) logputs (LOG_VERBOSE, "==> EPSV ... "); err = ftp_epsv (csock, addr, port); @@ -167,14 +159,14 @@ ftp_do_port (int csock, int *local_sock) /* If our control connection is over IPv6, then we first try EPRT and then * LPRT if the former is not supported. If the control connection is over * IPv4, we simply issue the good old PORT request. */ - switch (cip.type) + switch (cip.family) { - case IPV4_ADDRESS: + case AF_INET: if (!opt.server_response) logputs (LOG_VERBOSE, "==> PORT ... "); err = ftp_port (csock, local_sock); break; - case IPV6_ADDRESS: + case AF_INET6: if (!opt.server_response) logputs (LOG_VERBOSE, "==> EPRT ... "); err = ftp_eprt (csock, local_sock); @@ -212,20 +204,20 @@ ftp_do_port (int csock, int *local_sock) #endif static void -print_length (wgint size, wgint start, int authoritative) +print_length (wgint size, wgint start, bool authoritative) { - logprintf (LOG_VERBOSE, _("Length: %s"), with_thousand_seps (size)); + logprintf (LOG_VERBOSE, _("Length: %s"), number_to_static_string (size)); if (size >= 1024) logprintf (LOG_VERBOSE, " (%s)", human_readable (size)); if (start > 0) { if (start >= 1024) logprintf (LOG_VERBOSE, _(", %s (%s) remaining"), - with_thousand_seps (size - start), + number_to_static_string (size - start), human_readable (size - start)); else logprintf (LOG_VERBOSE, _(", %s remaining"), - with_thousand_seps (size - start)); + number_to_static_string (size - start)); } logputs (LOG_VERBOSE, !authoritative ? _(" (unauthoritative)\n") : "\n"); } @@ -240,11 +232,12 @@ getftp (struct url *u, wgint *len, wgint restval, ccon *con) uerr_t err = RETROK; /* appease the compiler */ FILE *fp; char *user, *passwd, *respline; - char *tms, *tmrate; + char *tms; + const char *tmrate; int cmd = con->cmd; - int pasv_mode_open = 0; + bool pasv_mode_open = false; wgint expected_bytes = 0; - int rest_failed = 0; + bool rest_failed = false; int flags; wgint rd_size; @@ -585,7 +578,7 @@ Error in server response, closing control connection.\n")); else /* do not CWD */ logputs (LOG_VERBOSE, _("==> CWD not required.\n")); - if ((cmd & DO_RETR) && restval && *len == 0) + if ((cmd & DO_RETR) && *len == 0) { if (opt.verbose) { @@ -598,7 +591,7 @@ Error in server response, closing control connection.\n")); switch (err) { case FTPRERR: - case FTPSRVERR : + case FTPSRVERR: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); @@ -612,7 +605,8 @@ Error in server response, closing control connection.\n")); abort (); } if (!opt.server_response) - logputs (LOG_VERBOSE, _("done.\n")); + logprintf (LOG_VERBOSE, *len ? "%s\n" : _("done.\n"), + number_to_static_string (*len)); } /* If anything is to be retrieved, PORT (or PASV) must be sent. */ @@ -656,8 +650,7 @@ Error in server response, closing control connection.\n")); if (err==FTPOK) { DEBUGP (("trying to connect to %s port %d\n", - pretty_print_address (&passive_addr), - passive_port)); + print_address (&passive_addr), passive_port)); dtsock = connect_to_ip (&passive_addr, passive_port, NULL); if (dtsock < 0) { @@ -665,13 +658,13 @@ Error in server response, closing control connection.\n")); fd_close (csock); con->csock = -1; logprintf (LOG_VERBOSE, _("couldn't connect to %s port %d: %s\n"), - pretty_print_address (&passive_addr), passive_port, + print_address (&passive_addr), passive_port, strerror (save_errno)); return (retryable_socket_connect_error (save_errno) ? CONERROR : CONIMPOSSIBLE); } - pasv_mode_open = 1; /* Flag to avoid accept port */ + pasv_mode_open = true; /* Flag to avoid accept port */ if (!opt.server_response) logputs (LOG_VERBOSE, _("done. ")); } /* err==FTP_OK */ @@ -765,7 +758,7 @@ Error in server response, closing control connection.\n")); return err; case FTPRESTFAIL: logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n")); - rest_failed = 1; + rest_failed = true; break; case FTPOK: break; @@ -927,7 +920,7 @@ Error in server response, closing control connection.\n")); fp = fopen (con->target, "wb"); else { - fp = fopen_excl (con->target, 1); + fp = fopen_excl (con->target, true); if (!fp && errno == EEXIST) { /* We cannot just invent a new name and use it (which is @@ -958,11 +951,11 @@ Error in server response, closing control connection.\n")); if (*len) { - print_length (*len, restval, 1); - expected_bytes = *len; /* for get_contents/show_progress */ + print_length (*len, restval, true); + expected_bytes = *len; /* for fd_read_body's progress bar */ } else if (expected_bytes) - print_length (expected_bytes, restval, 0); + print_length (expected_bytes, restval, false); /* Get the contents of the document. */ flags = 0; @@ -974,47 +967,38 @@ Error in server response, closing control connection.\n")); expected_bytes ? expected_bytes - restval : 0, restval, &rd_size, len, &con->dltime, flags); - tms = time_str (NULL); - tmrate = retr_rate (rd_size, con->dltime, 0); - /* Close data connection socket. */ - fd_close (dtsock); + tms = time_str (time (NULL)); + tmrate = retr_rate (rd_size, con->dltime); + total_download_time += con->dltime; + fd_close (local_sock); /* Close the local file. */ - { - /* Close or flush the file. We have to be careful to check for - error here. Checking the result of fwrite() is not enough -- - errors could go unnoticed! */ - int flush_res; - if (!output_stream || con->cmd & DO_LIST) - flush_res = fclose (fp); - else - flush_res = fflush (fp); - if (flush_res == EOF) - res = -2; - } - - /* If get_contents couldn't write to fp, bail out. */ + if (!output_stream || con->cmd & DO_LIST) + fclose (fp); + + /* If fd_read_body couldn't write to fp, bail out. */ if (res == -2) { logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"), con->target, strerror (errno)); fd_close (csock); con->csock = -1; + fd_close (dtsock); return FWRITEERR; } else if (res == -1) { logprintf (LOG_NOTQUIET, _("%s (%s) - Data connection: %s; "), - tms, tmrate, strerror (errno)); + tms, tmrate, fd_errstr (dtsock)); if (opt.server_response) logputs (LOG_ALWAYS, "\n"); } + fd_close (dtsock); /* Get the server to tell us if everything is retrieved. */ err = ftp_response (csock, &respline); if (err != FTPOK) { - xfree (respline); /* The control connection is decidedly closed. Print the time only if it hasn't already been printed. */ if (res != -1) @@ -1071,6 +1055,9 @@ Error in server response, closing control connection.\n")); no-buffering on opt.lfile. */ while ((line = read_whole_line (fp)) != NULL) { + char *p = strchr (line, '\0'); + while (p > line && (p[-1] == '\n' || p[-1] == '\r')) + *--p = '\0'; logprintf (LOG_ALWAYS, "%s\n", escnonprint (line)); xfree (line); } @@ -1092,7 +1079,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) int count, orig_lp; wgint restval, len = 0; char *tms, *locf; - char *tmrate = NULL; + const char *tmrate = NULL; uerr_t err; struct_stat st; @@ -1162,11 +1149,11 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) restval = 0; /* Get the current time string. */ - tms = time_str (NULL); + tms = time_str (time (NULL)); /* Print fetch message, if opt.verbose. */ if (opt.verbose) { - char *hurl = url_string (u, 1); + char *hurl = url_string (u, true); char tmp[256]; strcpy (tmp, " "); if (count > 1) @@ -1185,7 +1172,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) len = 0; err = getftp (u, &len, restval, con); - if (con->csock != -1) + if (con->csock == -1) con->st &= ~DONE_CWD; else con->st |= DONE_CWD; @@ -1226,9 +1213,9 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) /* Not as great. */ abort (); } - tms = time_str (NULL); + tms = time_str (time (NULL)); if (!opt.spider) - tmrate = retr_rate (len - restval, con->dltime, 0); + tmrate = retr_rate (len - restval, con->dltime); /* If we get out of the switch above without continue'ing, we've successfully downloaded a file. Remember this fact. */ @@ -1247,7 +1234,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) /* Need to hide the password from the URL. The `if' is here so that we don't do the needless allocation every time. */ - char *hurl = url_string (u, 1); + char *hurl = url_string (u, true); logprintf (LOG_NONVERBOSE, "%s URL: %s [%s] -> \"%s\" [%d]\n", tms, hurl, number_to_static_string (len), locf, count); xfree (hurl); @@ -1306,7 +1293,7 @@ Removing file due to --delete-after in ftp_loop_internal():\n")); /* Return the directory listing in a reusable format. The directory is specifed in u->dir. */ -uerr_t +static uerr_t ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f) { uerr_t err; @@ -1366,7 +1353,7 @@ ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con) struct fileinfo *orig; wgint local_size; time_t tml; - int dlthis; + bool dlthis; /* Increase the depth. */ ++depth; @@ -1412,7 +1399,7 @@ ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con) con->target = url_file_name (u); err = RETROK; - dlthis = 1; + dlthis = true; if (opt.timestamping && f->type == FT_PLAINFILE) { struct_stat st; @@ -1423,8 +1410,8 @@ ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con) .orig suffix. */ if (!stat (con->target, &st)) { - int eq_size; - int cor_val; + bool eq_size; + bool cor_val; /* Else, get it from the file. */ local_size = st.st_size; tml = st.st_mtime; @@ -1434,17 +1421,17 @@ ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con) tml++; #endif /* Compare file sizes only for servers that tell us correct - values. Assumme sizes being equal for servers that lie + values. Assume sizes being equal for servers that lie about file size. */ cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT); - eq_size = cor_val ? (local_size == f->size) : 1 ; + eq_size = cor_val ? (local_size == f->size) : true; if (f->tstamp <= tml && eq_size) { /* Remote file is older, file sizes can be compared and are both equal. */ logprintf (LOG_VERBOSE, _("\ Remote file no newer than local file `%s' -- not retrieving.\n"), con->target); - dlthis = 0; + dlthis = false; } else if (eq_size) { @@ -1494,7 +1481,7 @@ The sizes do not match (local %s) -- retrieving.\n\n"), logprintf (LOG_VERBOSE, _("\ Already have correct symlink %s -> %s\n\n"), con->target, escnonprint (f->linkto)); - dlthis = 0; + dlthis = false; break; } } @@ -1633,7 +1620,7 @@ ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con) DEBUGP (("Composing new CWD relative to the initial directory.\n")); DEBUGP ((" odir = '%s'\n f->name = '%s'\n newdir = '%s'\n\n", odir, f->name, newdir)); - if (!accdir (newdir, ALLABS)) + if (!accdir (newdir)) { logprintf (LOG_VERBOSE, _("\ Not descending to `%s' as it is excluded/not-included.\n"), @@ -1659,17 +1646,17 @@ Not descending to `%s' as it is excluded/not-included.\n"), return RETROK; } -/* Return non-zero if S has a leading '/' or contains '../' */ -static int +/* Return true if S has a leading '/' or contains '../' */ +static bool has_insecure_name_p (const char *s) { if (*s == '/') - return 1; + return true; if (strstr (s, "../") != 0) - return 1; + return true; - return 0; + return false; } /* A near-top-level function to retrieve the files in a directory. @@ -1726,12 +1713,14 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action) If we are dealing with a globbing pattern, that is. */ if (*u->file && (action == GLOB_GLOBALL || action == GLOB_GETONE)) { + int (*matcher) (const char *, const char *, int) + = opt.ignore_case ? fnmatch_nocase : fnmatch; int matchres = 0; f = start; while (f) { - matchres = fnmatch (u->file, f->name, 0); + matchres = matcher (u->file, f->name, 0); if (matchres == -1) { logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, @@ -1784,7 +1773,7 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action) of URL. Inherently, its capabilities are limited on what can be encoded into a URL. */ uerr_t -ftp_loop (struct url *u, int *dt, struct url *proxy) +ftp_loop (struct url *u, int *dt, struct url *proxy, bool recursive, bool glob) { ccon con; /* FTP connection */ uerr_t res; @@ -1802,7 +1791,7 @@ ftp_loop (struct url *u, int *dt, struct url *proxy) /* If the file name is empty, the user probably wants a directory index. We'll provide one, properly HTML-ized. Unless opt.htmlify is 0, of course. :-) */ - if (!*u->file && !opt.recursive) + if (!*u->file && !recursive) { struct fileinfo *f; res = ftp_get_listing (u, &con, &f); @@ -1842,8 +1831,8 @@ ftp_loop (struct url *u, int *dt, struct url *proxy) } else { - int ispattern = 0; - if (opt.ftp_glob) + bool ispattern = false; + if (glob) { /* Treat the URL as a pattern if the file name part of the URL path contains wildcards. (Don't check for u->file @@ -1854,7 +1843,7 @@ ftp_loop (struct url *u, int *dt, struct url *proxy) file_part = u->path; ispattern = has_wildcards_p (file_part); } - if (ispattern || opt.recursive || opt.timestamping) + if (ispattern || recursive || opt.timestamping) { /* ftp_retrieve_glob is a catch-all function that gets called if we need globbing, time-stamping or recursion. Its