/* 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 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, write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
In addition, as a special exception, the Free Software Foundation
gives permission to link the code of its release of Wget with the
#include <stdio.h>
#include <stdlib.h>
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-#endif
+#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
-#include <sys/types.h>
#include <assert.h>
#include <errno.h>
+#include <time.h>
#include "wget.h"
#include "utils.h"
#include "convert.h" /* for downloaded_file */
#include "recur.h" /* for INFINITE_RECURSION */
-#ifndef errno
-extern int errno;
-#endif
-
-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 */
/* 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);
/* 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);
#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));
}
- if (!authoritative)
- logputs (LOG_VERBOSE, _(" (unauthoritative)\n"));
+ logputs (LOG_VERBOSE, !authoritative ? _(" (unauthoritative)\n") : "\n");
}
/* Retrieves a file with denoted parameters through opening an FTP
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;
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)
{
switch (err)
{
case FTPRERR:
- case FTPSRVERR :
+ case FTPSRVERR:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
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. */
if (cmd & (DO_LIST | DO_RETR))
{
- if (opt.ftp_pasv > 0)
+ if (opt.ftp_pasv)
{
ip_address passive_addr;
int passive_port;
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)
{
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 */
return err;
case FTPRESTFAIL:
logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n"));
- rest_failed = 1;
+ rest_failed = true;
break;
case FTPOK:
break;
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
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;
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)
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);
}
int count, orig_lp;
wgint restval, len = 0;
char *tms, *locf;
- char *tmrate = NULL;
+ const char *tmrate = NULL;
uerr_t err;
struct_stat st;
if (opt.noclobber && file_exists_p (con->target))
{
logprintf (LOG_VERBOSE,
- _("File `%s' already there, not retrieving.\n"), con->target);
+ _("File `%s' already there; not retrieving.\n"), con->target);
/* If the file is there, we suppose it's retrieved OK. */
return RETROK;
}
}
/* Decide whether or not to restart. */
- restval = 0;
- if (count > 1)
- restval = len; /* start where the previous run left off */
- else if (opt.always_rest
- && stat (locf, &st) == 0
- && S_ISREG (st.st_mode))
+ if (opt.always_rest
+ && stat (locf, &st) == 0
+ && S_ISREG (st.st_mode))
+ /* When -c is used, continue from on-disk size. (Can't use
+ hstat.len even if count>1 because we don't want a failed
+ first attempt to clobber existing data.) */
restval = st.st_size;
+ else if (count > 1)
+ restval = len; /* start where the previous run left off */
+ else
+ 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)
/* 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. */
/* 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);
/* 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;
return err;
}
-static uerr_t ftp_retrieve_dirs PARAMS ((struct url *, struct fileinfo *,
- ccon *));
-static uerr_t ftp_retrieve_glob PARAMS ((struct url *, ccon *, int));
-static struct fileinfo *delelement PARAMS ((struct fileinfo *,
- struct fileinfo **));
-static void freefileinfo PARAMS ((struct fileinfo *f));
+static uerr_t ftp_retrieve_dirs (struct url *, struct fileinfo *, ccon *);
+static uerr_t ftp_retrieve_glob (struct url *, ccon *, int);
+static struct fileinfo *delelement (struct fileinfo *, struct fileinfo **);
+static void freefileinfo (struct fileinfo *f);
/* Retrieve a list of files given in struct fileinfo linked list. If
a file is a symbolic link, do not retrieve it, but rather try to
struct fileinfo *orig;
wgint local_size;
time_t tml;
- int dlthis;
+ bool dlthis;
/* Increase the depth. */
++depth;
con->target = url_file_name (u);
err = RETROK;
- dlthis = 1;
+ dlthis = true;
if (opt.timestamping && f->type == FT_PLAINFILE)
{
struct_stat st;
.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;
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)
{
logprintf (LOG_VERBOSE, _("\
Already have correct symlink %s -> %s\n\n"),
con->target, escnonprint (f->linkto));
- dlthis = 0;
+ dlthis = false;
break;
}
}
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"),
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.
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,
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;
/* 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);
}
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
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