]> sjero.net Git - wget/blobdiff - src/ftp.c
[svn] Support the SIZE command.
[wget] / src / ftp.c
index c7f9274d02c3c1a63d3e39de5bd0d35ee6115db3..7427d9e8d935da379e24aebd8f40ac03cbf9bda3 100644 (file)
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -1,20 +1,21 @@
 /* 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>
@@ -114,6 +115,7 @@ getftp (struct urlinfo *u, long *len, long restval, ccon *con)
   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;
@@ -132,8 +134,6 @@ getftp (struct urlinfo *u, long *len, long restval, ccon *con)
   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);
 
@@ -298,6 +298,29 @@ Error in server response, closing control connection.\n"));
          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"));
 
@@ -361,19 +384,27 @@ Error in server response, closing control connection.\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 = '[';
@@ -382,6 +413,8 @@ Error in server response, closing control connection.\n"));
                  *tmpp = '.';
              *tmpp++ = ']';
              *tmpp = '\0';
+              DEBUGP (("Changed file name to VMS syntax:\n"));
+              DEBUGP (("  Unix: '%s'\n  VMS: '%s'\n", target, ntarget));
              target = ntarget;
            }
 
@@ -429,6 +462,38 @@ Error in server response, closing control connection.\n"));
   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))
     {
@@ -827,6 +892,7 @@ Error in server response, closing control connection.\n"));
       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)
     {
@@ -836,10 +902,11 @@ Error in server response, closing control connection.\n"));
                   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.  */
@@ -955,7 +1022,7 @@ Error in server response, closing control connection.\n"));
 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;
@@ -986,13 +1053,6 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
 
   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
     {
@@ -1019,8 +1079,7 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
          else
            con->cmd |= DO_CWD;
        }
-      if (no_truncate)
-       con->cmd |= NO_TRUNCATE;
+
       /* Assume no restarting.  */
       restval = 0L;
       if ((count > 1 || opt.always_rest)
@@ -1028,6 +1087,14 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
          && 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.  */
@@ -1051,9 +1118,6 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
       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;
@@ -1091,6 +1155,9 @@ ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
          /* 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. */
@@ -1460,8 +1527,18 @@ ftp_retrieve_dirs (struct urlinfo *u, struct fileinfo *f, ccon *con)
       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, _("\