/* File Transfer Protocol support.
- Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001
+ Free Software Foundation, Inc.
-This file is part of Wget.
+This file is part of GNU Wget.
-This program is free software; you can redistribute it and/or modify
+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
(at your option) any later version.
-This program is distributed in the hope that it will be useful,
+GNU Wget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
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 this program; if not, write to the Free Software
+along with Wget; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <config.h>
FILE *fp;
char *user, *passwd, *respline;
char *tms, *tmrate;
+ struct wget_timer *timer;
unsigned char pasv_addr[6];
int cmd = con->cmd;
int passive_mode_open = 0;
passwd = u->passwd;
search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
user = user ? user : opt.ftp_acc;
- if (!opt.ftp_pass)
- opt.ftp_pass = ftp_getaddress ();
passwd = passwd ? passwd : opt.ftp_pass;
assert (user && passwd);
abort ();
break;
}
+ /* VMS will report something like "PUB$DEVICE:[INITIAL.FOLDER]".
+ Convert it to "/INITIAL/FOLDER" */
+ if (con->rs == ST_VMS)
+ {
+ char *path = strchr (con->id, '[');
+ char *pathend = path ? strchr (path + 1, ']') : NULL;
+ if (!path || !pathend)
+ DEBUGP (("Initial VMS directory not in the form [...]!\n"));
+ else
+ {
+ char *idir = con->id;
+ DEBUGP (("Preprocessing the initial VMS directory\n"));
+ DEBUGP ((" old = '%s'\n", con->id));
+ /* We do the conversion in-place by copying the stuff
+ between [ and ] to the beginning, and changing dots
+ to slashes at the same time. */
+ *idir++ = '/';
+ for (++path; path < pathend; path++, idir++)
+ *idir = *path == '.' ? '/' : *path;
+ *idir = '\0';
+ DEBUGP ((" new = '%s'\n\n", con->id));
+ }
+ }
if (!opt.server_response)
logputs (LOG_VERBOSE, _("done.\n"));
{
int idlen = strlen (con->id);
char *ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
- /* pwd_len == 1 means pwd = "/" */
+ /* idlen == 1 means con->id = "/" */
sprintf (ntarget, "%s%s%s", con->id, idlen == 1 ? "" : "/",
target);
+ DEBUGP (("Prepended initial PWD to relative path:\n"));
+ DEBUGP ((" old: '%s'\n new: '%s'\n", target, ntarget));
target = ntarget;
}
- /* If the FTP host runs VMS, we will have to convert it to
- VMS style as VMS does not like leading slashes. "VMS
- style" is [dir.subdir.subsubdir]. */
+ /* If the FTP host runs VMS, we will have to convert the absolute
+ directory path in UNIX notation to absolute directory path in
+ VMS notation as VMS FTP servers do not like UNIX notation of
+ absolute paths. "VMS notation" is [dir.subdir.subsubdir]. */
+
if (con->rs == ST_VMS)
{
char *tmpp;
- char *ntarget = (char *)alloca (strlen (target) + 1);
+ char *ntarget = (char *)alloca (strlen (target) + 2);
+ /* We use a converted initial dir, so directories in
+ TARGET will be separated with slashes, something like
+ "/INITIAL/FOLDER/DIR/SUBDIR". Convert that to
+ "[INITIAL.FOLDER.DIR.SUBDIR]". */
strcpy (ntarget, target);
assert (*ntarget == '/');
*ntarget = '[';
*tmpp = '.';
*tmpp++ = ']';
*tmpp = '\0';
+ DEBUGP (("Changed file name to VMS syntax:\n"));
+ DEBUGP ((" Unix: '%s'\n VMS: '%s'\n", target, ntarget));
target = ntarget;
}
else /* do not CWD */
logputs (LOG_VERBOSE, _("==> CWD not required.\n"));
+ if ((cmd & DO_RETR) && restval && *len == 0)
+ {
+ if (opt.verbose)
+ {
+ if (!opt.server_response)
+ logprintf (LOG_VERBOSE, "==> SIZE %s ... ", u->file);
+ }
+
+ err = ftp_size(&con->rbuf, u->file, len);
+ /* FTPRERR */
+ switch (err)
+ {
+ case FTPRERR:
+ case FTPSRVERR :
+ logputs (LOG_VERBOSE, "\n");
+ logputs (LOG_NOTQUIET, _("\
+Error in server response, closing control connection.\n"));
+ CLOSE (csock);
+ rbuf_uninitialize (&con->rbuf);
+ return err;
+ break;
+ case FTPOK:
+ /* Everything is OK. */
+ break;
+ default:
+ abort ();
+ break;
+ }
+ if (!opt.server_response)
+ logputs (LOG_VERBOSE, _("done.\n"));
+ }
+
/* If anything is to be retrieved, PORT (or PASV) must be sent. */
if (cmd & (DO_LIST | DO_RETR))
{
if (restval)
logprintf (LOG_VERBOSE, _(" [%s to go]"), legible (*len - restval));
logputs (LOG_VERBOSE, "\n");
+ expected_bytes = *len; /* for get_contents/show_progress */
}
else if (expected_bytes)
{
legible (expected_bytes - restval));
logputs (LOG_VERBOSE, _(" (unauthoritative)\n"));
}
- reset_timer ();
+ timer = wtimer_new ();
/* Get the contents of the document. */
res = get_contents (dtsock, fp, len, restval, expected_bytes, &con->rbuf, 0);
- con->dltime = elapsed_time ();
+ con->dltime = wtimer_elapsed (timer);
+ wtimer_delete (timer);
tms = time_str (NULL);
tmrate = rate (*len - restval, con->dltime, 0);
/* Close data connection socket. */
static uerr_t
ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
{
- int count, orig_lp, no_truncate;
+ int count, orig_lp;
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
{
else
con->cmd |= DO_CWD;
}
- if (no_truncate)
- con->cmd |= NO_TRUNCATE;
+
/* Assume no restarting. */
restval = 0L;
if ((count > 1 || opt.always_rest)
&& file_exists_p (locf))
if (stat (locf, &st) == 0 && S_ISREG (st.st_mode))
restval = st.st_size;
+
+ /* In `-c' is used, check whether the file we're writing to
+ exists and is of non-zero length. If so, we'll refuse to
+ truncate it if the server doesn't support continued
+ downloads. */
+ if (opt.always_rest && restval > 0)
+ con->cmd |= NO_TRUNCATE;
+
/* Get the current time string. */
tms = time_str (NULL);
/* Print fetch message, if opt.verbose. */
else
len = 0;
err = getftp (u, &len, restval, con);
- /* Time? */
- tms = time_str (NULL);
- tmrate = rate (len - restval, con->dltime, 0);
if (!rbuf_initialized_p (&con->rbuf))
con->st &= ~DONE_CWD;
/* Not as great. */
abort ();
}
+ /* Time? */
+ tms = time_str (NULL);
+ tmrate = rate (len - restval, con->dltime, 0);
/* If we get out of the switch above without continue'ing, we've
successfully downloaded a file. Remember this fact. */
if (len > current_length)
current_container = (char *)alloca (len);
u->dir = current_container;
- sprintf (u->dir, "%s%s%s", odir,
- (*odir == '/' && !*(odir + 1)) ? "" : "/", f->name);
+ if (*odir == '\0'
+ || (*odir == '/' && *(odir + 1) == '\0'))
+ /* If ODIR is empty or just "/", simply append f->name to
+ ODIR. (In the former case, to preserve u->dir being
+ relative; in the latter case, to avoid double slash.) */
+ sprintf (u->dir, "%s%s", odir, f->name);
+ else
+ /* Else, use a separator. */
+ sprintf (u->dir, "%s/%s", odir, f->name);
+ DEBUGP (("Composing new CWD relative to the initial directory.\n"));
+ DEBUGP ((" odir = '%s'\n f->name = '%s'\n u->dir = '%s'\n\n",
+ odir, f->name, u->dir));
if (!accdir (u->dir, ALLABS))
{
logprintf (LOG_VERBOSE, _("\