#else
# include <strings.h>
#endif
-#include <ctype.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
+#ifndef WINDOWS
+# include <netdb.h> /* for h_errno */
+#endif
#include "wget.h"
#include "utils.h"
extern int errno;
#endif
#ifndef h_errno
+# ifndef __CYGWIN__
extern int h_errno;
+# endif
#endif
/* File where the "ls -al" listing will be saved. */
extern char ftp_last_respline[];
-static enum stype host_type=ST_UNIX;
-static char *pwd;
-static int pwd_len;
-
/* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
the string S, and return the number converted to long, if found, 0
otherwise. */
connection to the server. It always closes the data connection,
and closes the control connection in case of error. */
static uerr_t
-getftp (const struct urlinfo *u, long *len, long restval, ccon *con)
+getftp (struct urlinfo *u, long *len, long restval, ccon *con)
{
int csock, dtsock, res;
uerr_t err;
search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
user = user ? user : opt.ftp_acc;
if (!opt.ftp_pass)
- opt.ftp_pass = xstrdup (ftp_getaddress ());
+ opt.ftp_pass = ftp_getaddress ();
passwd = passwd ? passwd : opt.ftp_pass;
assert (user && passwd);
/* Third: Get the system type */
if (!opt.server_response)
logprintf (LOG_VERBOSE, "==> SYST ... ");
- err = ftp_syst (&con->rbuf, &host_type);
+ err = ftp_syst (&con->rbuf, &con->rs);
/* FTPRERR */
switch (err)
{
if (!opt.server_response)
logprintf (LOG_VERBOSE, "==> PWD ... ");
- err = ftp_pwd(&con->rbuf, &pwd);
- pwd_len = strlen(pwd);
+ err = ftp_pwd(&con->rbuf, &con->id);
/* FTPRERR */
switch (err)
- {
- case FTPRERR || FTPSRVERR :
+ {
+ case FTPRERR:
+ case FTPSRVERR :
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
default:
abort ();
break;
- }
+ }
if (!opt.server_response)
logputs (LOG_VERBOSE, _("done.\n"));
/* Change working directory. If the FTP host runs VMS and
the path specified is absolute, we will have to convert
it to VMS style as VMS does not like leading slashes */
+ DEBUGP (("changing working directory\n"));
if (*(u->dir) == '/')
{
+ int pwd_len = strlen (con->id);
char *result = (char *)alloca (strlen (u->dir) + pwd_len + 10);
*result = '\0';
- switch (host_type)
+ switch (con->rs)
{
case ST_VMS:
{
for (tmpp = tmp_dir; *tmpp; tmpp++)
if (*tmpp=='/')
*tmpp = '.';
- strcpy (result, pwd);
+ strcpy (result, con->id);
/* pwd ends with ']', we have to get rid of it */
result[pwd_len - 1]= '\0';
strcat (result, tmp_dir);
}
break;
case ST_UNIX:
+ case ST_WINNT:
+ case ST_MACOS:
/* pwd_len == 1 means pwd = "/", but u->dir begins with '/'
already */
if (pwd_len > 1)
- strcpy (result, pwd);
+ strcpy (result, con->id);
strcat (result, u->dir);
- /* These look like debugging messages to me. */
-#if 0
- logprintf (LOG_VERBOSE, "\npwd=\"%s\"", pwd);
- logprintf (LOG_VERBOSE, "\nu->dir=\"%s\"", u->dir);
-#endif
+ DEBUGP(("\npwd=\"%s\"", con->id));
+ DEBUGP(("\nu->dir=\"%s\"", u->dir));
break;
default:
abort ();
return err;
break;
case FTPRESTFAIL:
+ /* If `-c' is specified and the file already existed when
+ Wget was started, it would be a bad idea for us to start
+ downloading it from scratch, effectively truncating it. */
+ if (opt.always_rest && (cmd & NO_TRUNCATE))
+ {
+ logprintf (LOG_NOTQUIET,
+ _("\nREST failed; will not truncate `%s'.\n"),
+ u->local);
+ CLOSE (csock);
+ closeport (dtsock);
+ rbuf_uninitialize (&con->rbuf);
+ return CONTNOTSUPPORTED;
+ }
logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n"));
restval = 0L;
break;
res = get_contents (dtsock, fp, len, restval, expected_bytes, &con->rbuf, 0);
con->dltime = elapsed_time ();
tms = time_str (NULL);
- tmrate = rate (*len - restval, con->dltime);
+ tmrate = rate (*len - restval, con->dltime, 0);
/* Close data connection socket. */
closeport (dtsock);
/* Close the local file. */
static uerr_t
ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
{
- static int first_retrieval = 1;
-
- int count, orig_lp;
+ int count, orig_lp, no_truncate;
long restval, len;
char *tms, *tmrate, *locf;
uerr_t err;
orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
+ /* In `-c' is used, check whether the file we're writing to exists
+ before we've done anything. If so, we'll refuse to truncate it
+ if the server doesn't support continued downloads. */
+ no_truncate = 0;
+ if (opt.always_rest)
+ no_truncate = file_exists_p (locf);
+
/* THE loop. */
do
{
/* Increment the pass counter. */
++count;
- /* Wait before the retrieval (unless this is the very first
- retrieval).
- Check if we are retrying or not, wait accordingly - HEH */
- if (!first_retrieval && (opt.wait || (count && opt.waitretry)))
- {
- if (count)
- {
- if (count<opt.waitretry)
- sleep(count);
- else
- sleep(opt.waitretry);
- }
- else
- sleep (opt.wait);
- }
- if (first_retrieval)
- first_retrieval = 0;
+ sleep_between_retrievals (count);
if (con->st & ON_YOUR_OWN)
{
con->cmd = 0;
else
con->cmd |= DO_CWD;
}
+ if (no_truncate)
+ con->cmd |= NO_TRUNCATE;
/* Assume no restarting. */
restval = 0L;
if ((count > 1 || opt.always_rest)
err = getftp (u, &len, restval, con);
/* Time? */
tms = time_str (NULL);
- tmrate = rate (len - restval, con->dltime);
+ tmrate = rate (len - restval, con->dltime, 0);
if (!rbuf_initialized_p (&con->rbuf))
con->st &= ~DONE_CWD;
switch (err)
{
case HOSTERR: case CONREFUSED: case FWRITEERR: case FOPENERR:
- case FTPNSFOD: case FTPLOGINC: case FTPNOPASV:
+ case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
/* Fatal errors, give up. */
return err;
break;
/* Return the directory listing in a reusable format. The directory
is specifed in u->dir. */
-static struct fileinfo *
-ftp_get_listing (struct urlinfo *u, ccon *con)
+uerr_t
+ftp_get_listing (struct urlinfo *u, ccon *con, struct fileinfo **f)
{
- struct fileinfo *f;
uerr_t err;
char *olocal = u->local;
char *list_filename, *ofile;
err = ftp_loop_internal (u, NULL, con);
u->local = olocal;
if (err == RETROK)
- f = ftp_parse_ls (list_filename, host_type);
+ *f = ftp_parse_ls (list_filename, con->rs);
else
- f = NULL;
+ *f = NULL;
if (opt.remove_listing)
{
if (unlink (list_filename))
}
xfree (list_filename);
con->cmd &= ~DO_LIST;
- return f;
+ return err;
}
static uerr_t ftp_retrieve_dirs PARAMS ((struct urlinfo *, struct fileinfo *,
dlthis = 1;
if (opt.timestamping && f->type == FT_PLAINFILE)
- {
+ {
struct stat st;
/* If conversion of HTML files retrieved via FTP is ever implemented,
we'll need to stat() <file>.orig here when -K has been specified.
.orig suffix. */
if (!stat (u->local, &st))
{
+ int eq_size;
+ int cor_val;
/* Else, get it from the file. */
local_size = st.st_size;
tml = st.st_mtime;
- if (local_size == f->size && tml >= f->tstamp)
+ /* Compare file sizes only for servers that tell us correct
+ values. Assumme 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 ;
+ if (f->tstamp <= tml && eq_size)
{
- logprintf (LOG_VERBOSE, _("\
-Server file not newer than local file `%s' -- not retrieving.\n\n"), u->local);
+ /* 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"), u->local);
dlthis = 0;
}
- else if (local_size != f->size)
- {
- if (host_type == ST_VMS)
- {
- logprintf (LOG_VERBOSE, _("\
-Cannot compare sizes, remote system is VMS.\n"));
- dlthis = 0;
- }
- else
- {
- logprintf (LOG_VERBOSE, _("\
-The sizes do not match (local %ld) -- retrieving.\n"), local_size);
- }
- }
- }
+ else if (eq_size)
+ {
+ /* Remote file is newer or sizes cannot be matched */
+ logprintf (LOG_VERBOSE, _("\
+Remote file is newer than local file `%s' -- retrieving.\n\n"),
+ u->local);
+ }
+ else
+ {
+ /* Sizes do not match */
+ logprintf (LOG_VERBOSE, _("\
+The sizes do not match (local %ld) -- retrieving.\n\n"), local_size);
+ }
+ }
} /* opt.timestamping && f->type == FT_PLAINFILE */
switch (f->type)
{
/* Set the time-stamp information to the local file. Symlinks
are not to be stamped because it sets the stamp on the
original. :( */
- if (!opt.dfp
- && !(f->type == FT_SYMLINK && !opt.retr_symlinks)
+ if (!(f->type == FT_SYMLINK && !opt.retr_symlinks)
&& f->tstamp != -1
&& dlthis
&& file_exists_p (u->local))
{
- touch (u->local, f->tstamp);
+ /* #### This code repeats in http.c and ftp.c. Move it to a
+ function! */
+ const char *fl = NULL;
+ if (opt.output_document)
+ {
+ if (opt.od_known_regular)
+ fl = opt.output_document;
+ }
+ else
+ fl = u->local;
+ if (fl)
+ touch (fl, f->tstamp);
}
else if (f->tstamp == -1)
logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), u->local);
if (len > current_length)
current_container = (char *)alloca (len);
u->dir = current_container;
- /* When retrieving recursively, all directories must be
- absolute. This restriction will (hopefully!) be lifted in
- the future. */
sprintf (u->dir, "/%s%s%s", odir + (*odir == '/'),
(!*odir || (*odir == '/' && !* (odir + 1))) ? "" : "/", f->name);
if (!accdir (u->dir, ALLABS))
con->cmd |= LEAVE_PENDING;
- orig = ftp_get_listing (u, con);
+ res = ftp_get_listing (u, con, &orig);
+ if (res != RETROK)
+ return res;
start = orig;
/* First: weed out that do not conform the global rules given in
opt.accepts and opt.rejects. */
*dt = 0;
+ memset (&con, 0, sizeof (con));
+
rbuf_uninitialize (&con.rbuf);
con.st = ON_YOUR_OWN;
+ con.rs = ST_UNIX;
+ con.id = NULL;
res = RETROK; /* in case it's not used */
/* If the file name is empty, the user probably wants a directory
opt.htmlify is 0, of course. :-) */
if (!*u->file && !opt.recursive)
{
- struct fileinfo *f = ftp_get_listing (u, &con);
+ struct fileinfo *f;
+ res = ftp_get_listing (u, &con, &f);
- if (f)
+ if (res == RETROK)
{
if (opt.htmlify)
{
/* If a connection was left, quench it. */
if (rbuf_initialized_p (&con.rbuf))
CLOSE (RBUF_FD (&con.rbuf));
+ FREE_MAYBE (con.id);
+ con.id = NULL;
return res;
}