/* 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"));
logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
else
{
- /* 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 */
+ char *target = u->dir;
+
DEBUGP (("changing working directory\n"));
- if (*(u->dir) == '/')
+
+ /* Change working directory. To change to a non-absolute
+ Unix directory, we need to prepend initial directory
+ (con->id) to it. Absolute directories "just work". */
+
+ if (*target != '/')
{
- int pwd_len = strlen (con->id);
- char *result = (char *)alloca (strlen (u->dir) + pwd_len + 10);
- *result = '\0';
- switch (con->rs)
- {
- case ST_VMS:
- {
- char *tmp_dir, *tmpp;
- STRDUP_ALLOCA (tmp_dir, u->dir);
- for (tmpp = tmp_dir; *tmpp; tmpp++)
- if (*tmpp=='/')
- *tmpp = '.';
- strcpy (result, con->id);
- /* pwd ends with ']', we have to get rid of it */
- result[pwd_len - 1]= '\0';
- strcat (result, tmp_dir);
- strcat (result, "]");
- }
- 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, con->id);
- strcat (result, u->dir);
- DEBUGP(("\npwd=\"%s\"", con->id));
- DEBUGP(("\nu->dir=\"%s\"", u->dir));
- break;
- default:
- abort ();
- break;
- }
- if (!opt.server_response)
- logprintf (LOG_VERBOSE, "==> CWD %s ... ", result);
- err = ftp_cwd (&con->rbuf, result);
+ int idlen = strlen (con->id);
+ char *ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
+ /* 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;
}
- else
+
+ /* 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)
{
- if (!opt.server_response)
- logprintf (LOG_VERBOSE, "==> CWD %s ... ", u->dir);
- err = ftp_cwd (&con->rbuf, u->dir);
+ char *tmpp;
+ 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 = '[';
+ for (tmpp = ntarget + 1; *tmpp; tmpp++)
+ if (*tmpp == '/')
+ *tmpp = '.';
+ *tmpp++ = ']';
+ *tmpp = '\0';
+ DEBUGP (("Changed file name to VMS syntax:\n"));
+ DEBUGP ((" Unix: '%s'\n VMS: '%s'\n", target, ntarget));
+ target = ntarget;
}
+
+ if (!opt.server_response)
+ logprintf (LOG_VERBOSE, "==> CWD %s ... ", target);
+ err = ftp_cwd (&con->rbuf, target);
/* FTPRERR, WRITEFAILED, FTPNSFOD */
switch (err)
{
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. */
if (f->type != FT_DIRECTORY)
continue;
odir = u->dir;
- len = 1 + strlen (u->dir) + 1 + strlen (f->name) + 1;
+ len = strlen (u->dir) + 1 + strlen (f->name) + 1;
/* Allocate u->dir off stack, but reallocate only if a larger
string is needed. */
if (len > current_length)
current_container = (char *)alloca (len);
u->dir = current_container;
- sprintf (u->dir, "/%s%s%s", odir + (*odir == '/'),
- (!*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, _("\