X-Git-Url: http://sjero.net/git/?a=blobdiff_plain;f=src%2Fftp.c;h=d628ad1d7527c42e0a0c7f99e4718d0709a8f7c9;hb=c3d636db033551ec654fecd7116cf7ecac467fd9;hp=ef611d32df7c936a76577fdaf930100bdcb65d00;hpb=ee6065f581f6fe17d98166d711f1977f56c67bbf;p=wget diff --git a/src/ftp.c b/src/ftp.c index ef611d32..d628ad1d 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -1,5 +1,5 @@ /* File Transfer Protocol support. - Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc. This file is part of Wget. @@ -40,7 +40,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "rbuf.h" #include "retr.h" #include "ftp.h" -#include "html.h" #include "connect.h" #include "host.h" #include "fnmatch.h" @@ -58,6 +57,10 @@ extern int h_errno; 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. */ @@ -241,7 +244,64 @@ Error in server response, closing control connection.\n")); exit (1); break; } - /* Third: Set type to Image (binary). */ + /* Third: Get the system type */ + if (!opt.server_response) + logprintf (LOG_VERBOSE, "==> SYST ... "); + err = ftp_syst (&con->rbuf, &host_type); + /* FTPRERR */ + switch (err) + { + case FTPRERR: + 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 FTPSRVERR: + logputs (LOG_VERBOSE, "\n"); + logputs (LOG_NOTQUIET, + _("Server error, can't determine system type.\n")); + break; + case FTPOK: + /* Everything is OK. */ + break; + default: + abort (); + break; + } + if (!opt.server_response) + logputs (LOG_VERBOSE, _("done. ")); + + /* Fourth: Find the initial ftp directory */ + + if (!opt.server_response) + logprintf (LOG_VERBOSE, "==> PWD ... "); + err = ftp_pwd(&con->rbuf, &pwd); + pwd_len = strlen(pwd); + /* FTPRERR */ + switch (err) + { + case FTPRERR || 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")); + + /* Fifth: Set the FTP type. */ if (!opt.server_response) logprintf (LOG_VERBOSE, "==> TYPE %c ... ", TOUPPER (u->ftp_type)); err = ftp_type (&con->rbuf, TOUPPER (u->ftp_type)); @@ -289,10 +349,55 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, _("==> CWD not needed.\n")); else { - /* Change working directory. */ - if (!opt.server_response) - logprintf (LOG_VERBOSE, "==> CWD %s ... ", u->dir); - err = ftp_cwd (&con->rbuf, u->dir); + /* 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 */ + if (*(u->dir) == '/') + { + char *result = (char *)alloca (strlen (u->dir) + pwd_len + 10); + *result = '\0'; + switch (host_type) + { + case ST_VMS: + { + char *tmp_dir, *tmpp; + STRDUP_ALLOCA (tmp_dir, u->dir); + for (tmpp = tmp_dir; *tmpp; tmpp++) + if (*tmpp=='/') + *tmpp = '.'; + strcpy (result, pwd); + /* 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: + /* pwd_len == 1 means pwd = "/", but u->dir begins with '/' + already */ + if (pwd_len > 1) + strcpy (result, pwd); + 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 + break; + default: + abort (); + break; + } + if (!opt.server_response) + logprintf (LOG_VERBOSE, "==> CWD %s ... ", result); + err = ftp_cwd (&con->rbuf, result); + } + else + { + if (!opt.server_response) + logprintf (LOG_VERBOSE, "==> CWD %s ... ", u->dir); + err = ftp_cwd (&con->rbuf, u->dir); + } /* FTPRERR, WRITEFAILED, FTPNSFOD */ switch (err) { @@ -337,7 +442,7 @@ Error in server response, closing control connection.\n")); /* If anything is to be retrieved, PORT (or PASV) must be sent. */ if (cmd & (DO_LIST | DO_RETR)) { - if (opt.ftp_pasv) + if (opt.ftp_pasv > 0) { char thost[256]; unsigned short tport; @@ -648,6 +753,15 @@ Error in server response, closing control connection.\n")); expected_bytes = ftp_expected_bytes (ftp_last_respline); } /* cmd & DO_LIST */ + /* Some FTP servers return the total length of file after REST + command, others just return the remaining size. */ + if (*len && restval && expected_bytes + && (expected_bytes == *len - restval)) + { + DEBUGP (("Lying FTP server found, adjusting.\n")); + expected_bytes = *len; + } + /* If no transmission was required, then everything is OK. */ if (!(cmd & (DO_LIST | DO_RETR))) return RETRFINISHED; @@ -685,7 +799,16 @@ Error in server response, closing control connection.\n")); } } else - fp = opt.dfp; + { + fp = opt.dfp; + if (!restval) + { + /* This will silently fail for streams that don't correspond + to regular files, but that's OK. */ + rewind (fp); + clearerr (fp); + } + } if (*len) { @@ -704,7 +827,7 @@ Error in server response, closing control connection.\n")); } reset_timer (); /* Get the contents of the document. */ - res = get_contents (dtsock, fp, len, restval, expected_bytes, &con->rbuf); + 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); @@ -969,7 +1092,7 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con) /* If we get out of the switch above without continue'ing, we've successfully downloaded a file. Remember this fact. */ - downloaded_file(ADD_FILE, locf); + downloaded_file(FILE_DOWNLOADED_NORMALLY, locf); if (con->st & ON_YOUR_OWN) { @@ -978,15 +1101,52 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con) } logprintf (LOG_VERBOSE, _("%s (%s) - `%s' saved [%ld]\n\n"), tms, tmrate, locf, len); - logprintf (LOG_NONVERBOSE, "%s URL: %s [%ld] -> \"%s\" [%d]\n", - tms, u->url, len, locf, count); - /* Do not count listings among the downloaded stuff, since they - will get deleted anyway. */ - if (!(con->cmd & DO_LIST)) + if (!opt.verbose && !opt.quiet) { - ++opt.numurls; - opt.downloaded += len; + /* 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 = str_url (u->proxy ? u->proxy : u, 1); + logprintf (LOG_NONVERBOSE, "%s URL: %s [%ld] -> \"%s\" [%d]\n", + tms, hurl, len, locf, count); + free (hurl); } + + if ((con->cmd & DO_LIST)) + /* This is a directory listing file. */ + { + if (!opt.remove_listing) + /* --dont-remove-listing was specified, so do count this towards the + number of bytes and files downloaded. */ + { + downloaded_increase (len); + opt.numurls++; + } + + /* Deletion of listing files is not controlled by --delete-after, but + by the more specific option --dont-remove-listing, and the code + to do this deletion is in another function. */ + } + else + /* This is not a directory listing file. */ + { + /* Unlike directory listing files, don't pretend normal files weren't + downloaded if they're going to be deleted. People seeding proxies, + for instance, may want to know how many bytes and files they've + downloaded through it. */ + downloaded_increase (len); + opt.numurls++; + + if (opt.delete_after) + { + DEBUGP (("Removing file due to --delete-after in" + " ftp_loop_internal():\n")); + logprintf (LOG_VERBOSE, _("Removing %s.\n"), locf); + if (unlink (locf)) + logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno)); + } + } + /* Restore the original leave-pendingness. */ if (orig_lp) con->cmd |= LEAVE_PENDING; @@ -1026,7 +1186,7 @@ ftp_get_listing (struct urlinfo *u, ccon *con) err = ftp_loop_internal (u, NULL, con); u->local = olocal; if (err == RETROK) - f = ftp_parse_ls (list_filename); + f = ftp_parse_ls (list_filename, host_type); else f = NULL; if (opt.remove_listing) @@ -1068,7 +1228,7 @@ ftp_retrieve_list (struct urlinfo *u, struct fileinfo *f, ccon *con) /* Increase the depth. */ ++depth; - if (opt.reclevel && depth > opt.reclevel) + if (opt.reclevel != INFINITE_RECURSION && depth > opt.reclevel) { DEBUGP ((_("Recursion depth %d exceeded max. depth %d.\n"), depth, opt.reclevel)); @@ -1095,7 +1255,7 @@ ftp_retrieve_list (struct urlinfo *u, struct fileinfo *f, ccon *con) while (f) { - if (opt.quota && opt.downloaded > opt.quota) + if (downloaded_exceeds_quota ()) { --depth; return QUOTEXC; @@ -1123,13 +1283,22 @@ ftp_retrieve_list (struct urlinfo *u, struct fileinfo *f, ccon *con) if (local_size == f->size && tml >= f->tstamp) { logprintf (LOG_VERBOSE, _("\ -Server file no newer than local file `%s' -- not retrieving.\n\n"), u->local); +Server file not newer than local file `%s' -- not retrieving.\n\n"), u->local); dlthis = 0; } else if (local_size != f->size) { - logprintf (LOG_VERBOSE, _("\ + 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); + } } } } /* opt.timestamping && f->type == FT_PLAINFILE */ @@ -1221,7 +1390,7 @@ Already have correct symlink %s -> %s\n\n"), else if (f->tstamp == -1) logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), u->local); - if (f->perms && dlthis) + if (f->perms && f->type == FT_PLAINFILE && dlthis) chmod (u->local, f->perms); else DEBUGP (("Unrecognized permissions for %s.\n", u->local)); @@ -1236,7 +1405,8 @@ Already have correct symlink %s -> %s\n\n"), f = f->next; } /* while */ /* We do not want to call ftp_retrieve_dirs here */ - if (opt.recursive && !(opt.reclevel && depth >= opt.reclevel)) + if (opt.recursive && + !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel)) err = ftp_retrieve_dirs (u, orig, con); else if (opt.recursive) DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"), @@ -1260,7 +1430,7 @@ ftp_retrieve_dirs (struct urlinfo *u, struct fileinfo *f, ccon *con) { int len; - if (opt.quota && opt.downloaded > opt.quota) + if (downloaded_exceeds_quota ()) break; if (f->type != FT_DIRECTORY) continue; @@ -1381,7 +1551,7 @@ ftp_retrieve_glob (struct urlinfo *u, ccon *con, int action) } } freefileinfo (start); - if (opt.quota && opt.downloaded > opt.quota) + if (downloaded_exceeds_quota ()) return QUOTEXC; else /* #### Should we return `res' here? */