]> sjero.net Git - wget/blobdiff - src/ftp.c
[svn] Renamed xread/xwrite/xclose to fd_read/fd_write/fd_close. The "x" prefix is
[wget] / src / ftp.c
index 69065490dda04d65cad29be4d108fd743a389094..873556aaeb9b2c4b0ebf9c3d60670281e45cceaa 100644 (file)
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -54,6 +54,7 @@ so, delete this exception statement from your version.  */
 #include "host.h"
 #include "netrc.h"
 #include "convert.h"           /* for downloaded_file */
+#include "recur.h"             /* for INFINITE_RECURSION */
 
 #ifndef errno
 extern int errno;
@@ -122,22 +123,6 @@ ftp_expected_bytes (const char *s)
 }
 
 #ifdef ENABLE_IPV6
-static int
-getfamily (int fd)
-{
-  struct sockaddr_storage ss;
-  struct sockaddr *sa = (struct sockaddr *)&ss;
-  socklen_t len = sizeof (ss);
-
-  assert (fd >= 0);
-
-  if (getpeername (fd, sa, &len) < 0)
-    /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
-    abort ();
-
-  return sa->sa_family;
-}
-
 /* 
  * This function sets up a passive data connection with the FTP server.
  * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
@@ -146,16 +131,24 @@ static uerr_t
 ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
 {
   uerr_t err;
-  int family;
 
-  family = getfamily (rbuf->fd);
-  assert (family == AF_INET || family == AF_INET6);
+  /* We need to determine the address family and need to call
+     getpeername, so while we're at it, store the address to ADDR.
+     ftp_pasv and ftp_lpsv can simply override it.  */
+  if (!socket_ip_address (RBUF_FD (rbuf), addr, ENDPOINT_PEER))
+    abort ();
 
   /* If our control connection is over IPv6, then we first try EPSV and then 
    * LPSV if the former is not supported. If the control connection is over 
    * IPv4, we simply issue the good old PASV request. */
-  if (family == AF_INET6)
+  switch (addr->type)
     {
+    case IPV4_ADDRESS:
+      if (!opt.server_response)
+        logputs (LOG_VERBOSE, "==> PASV ... ");
+      err = ftp_pasv (rbuf, addr, port);
+      break;
+    case IPV6_ADDRESS:
       if (!opt.server_response)
         logputs (LOG_VERBOSE, "==> EPSV ... ");
       err = ftp_epsv (rbuf, addr, port);
@@ -167,12 +160,9 @@ ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
             logputs (LOG_VERBOSE, "==> LPSV ... ");
           err = ftp_lpsv (rbuf, addr, port);
         }
-    }
-  else 
-    {
-      if (!opt.server_response)
-        logputs (LOG_VERBOSE, "==> PASV ... ");
-      err = ftp_pasv (rbuf, addr, port);
+      break;
+    default:
+      abort ();
     }
 
   return err;
@@ -186,19 +176,25 @@ static uerr_t
 ftp_do_port (struct rbuf *rbuf, int *local_sock)
 {
   uerr_t err;
-  int family;
+  ip_address cip;
 
   assert (rbuf != NULL);
   assert (rbuf_initialized_p (rbuf));
 
-  family = getfamily (rbuf->fd);
-  assert (family == AF_INET || family == AF_INET6);
+  if (!socket_ip_address (RBUF_FD (rbuf), &cip, ENDPOINT_PEER))
+    abort ();
 
   /* If our control connection is over IPv6, then we first try EPRT and then 
    * LPRT if the former is not supported. If the control connection is over 
    * IPv4, we simply issue the good old PORT request. */
-  if (family == AF_INET6)
+  switch (cip.type)
     {
+    case IPV4_ADDRESS:
+      if (!opt.server_response)
+        logputs (LOG_VERBOSE, "==> PORT ... ");
+      err = ftp_port (rbuf, local_sock);
+      break;
+    case IPV6_ADDRESS:
       if (!opt.server_response)
         logputs (LOG_VERBOSE, "==> EPRT ... ");
       err = ftp_eprt (rbuf, local_sock);
@@ -210,14 +206,10 @@ ftp_do_port (struct rbuf *rbuf, int *local_sock)
             logputs (LOG_VERBOSE, "==> LPRT ... ");
           err = ftp_lprt (rbuf, local_sock);
         }
+      break;
+    default:
+      abort ();
     }
-  else 
-    {
-      if (!opt.server_response)
-        logputs (LOG_VERBOSE, "==> PORT ... ");
-      err = ftp_port (rbuf, local_sock);
-    }
-
   return err;
 }
 #else
@@ -299,7 +291,8 @@ getftp (struct url *u, long *len, long restval, ccon *con)
       if (csock == E_HOST)
        return HOSTERR;
       else if (csock < 0)
-       return CONNECT_ERROR (errno);
+       return (retryable_socket_connect_error (errno)
+               ? CONERROR : CONIMPOSSIBLE);
 
       if (cmd & LEAVE_PENDING)
        rbuf_initialize (&con->rbuf, csock);
@@ -326,14 +319,14 @@ getftp (struct url *u, long *len, long restval, ccon *con)
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
        case FTPSRVERR:
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("Error in server greeting.\n"));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -341,21 +334,21 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET,
                   _("Write failed, closing control connection.\n"));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
        case FTPLOGREFUSED:
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("The server refuses login.\n"));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return FTPLOGREFUSED;
          break;
        case FTPLOGINC:
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("Login incorrect.\n"));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return FTPLOGINC;
          break;
@@ -379,7 +372,7 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -410,13 +403,13 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
        case FTPSRVERR :
          /* PWD unsupported -- assume "/". */
-         FREE_MAYBE (con->id);
+         xfree_null (con->id);
          con->id = xstrdup ("/");
          break;
        case FTPOK:
@@ -464,7 +457,7 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -472,7 +465,7 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET,
                   _("Write failed, closing control connection.\n"));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -481,7 +474,7 @@ Error in server response, closing control connection.\n"));
          logprintf (LOG_NOTQUIET,
                     _("Unknown type `%c', closing control connection.\n"),
                     type_char);
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return err;
        case FTPOK:
@@ -579,7 +572,7 @@ Error in server response, closing control connection.\n"));
              logputs (LOG_VERBOSE, "\n");
              logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-             CLOSE (csock);
+             fd_close (csock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -587,7 +580,7 @@ Error in server response, closing control connection.\n"));
              logputs (LOG_VERBOSE, "\n");
              logputs (LOG_NOTQUIET,
                       _("Write failed, closing control connection.\n"));
-             CLOSE (csock);
+             fd_close (csock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -595,7 +588,7 @@ Error in server response, closing control connection.\n"));
              logputs (LOG_VERBOSE, "\n");
              logprintf (LOG_NOTQUIET, _("No such directory `%s'.\n\n"),
                         u->dir);
-             CLOSE (csock);
+             fd_close (csock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -630,7 +623,7 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -660,7 +653,7 @@ Error in server response, closing control connection.\n"));
              logputs (LOG_VERBOSE, "\n");
              logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-             CLOSE (csock);
+             fd_close (csock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -668,7 +661,7 @@ Error in server response, closing control connection.\n"));
              logputs (LOG_VERBOSE, "\n");
              logputs (LOG_NOTQUIET,
                       _("Write failed, closing control connection.\n"));
-             CLOSE (csock);
+             fd_close (csock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -696,12 +689,13 @@ Error in server response, closing control connection.\n"));
              if (dtsock < 0)
                {
                  int save_errno = errno;
-                 CLOSE (csock);
+                 fd_close (csock);
                  rbuf_uninitialize (&con->rbuf);
                  logprintf (LOG_VERBOSE, _("couldn't connect to %s port %hu: %s\n"),
                             pretty_print_address (&passive_addr), passive_port,
                             strerror (save_errno));
-                 return CONNECT_ERROR (save_errno);
+                 return (retryable_socket_connect_error (save_errno)
+                         ? CONERROR : CONIMPOSSIBLE);
                }
 
              pasv_mode_open = 1;  /* Flag to avoid accept port */
@@ -713,17 +707,17 @@ Error in server response, closing control connection.\n"));
       if (!pasv_mode_open)   /* Try to use a port command if PASV failed */
        {
          err = ftp_do_port (&con->rbuf, &local_sock);
-         /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR,
-            LISTENERR), HOSTERR, FTPPORTERR */
+         /* FTPRERR, WRITEFAILED, bindport (FTPSYSERR), HOSTERR,
+            FTPPORTERR */
          switch (err)
            {
            case FTPRERR:
              logputs (LOG_VERBOSE, "\n");
              logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-             CLOSE (csock);
-             CLOSE (dtsock);
-             CLOSE (local_sock);
+             fd_close (csock);
+             fd_close (dtsock);
+             fd_close (local_sock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -731,36 +725,34 @@ Error in server response, closing control connection.\n"));
              logputs (LOG_VERBOSE, "\n");
              logputs (LOG_NOTQUIET,
                       _("Write failed, closing control connection.\n"));
-             CLOSE (csock);
-             CLOSE (dtsock);
-             CLOSE (local_sock);
+             fd_close (csock);
+             fd_close (dtsock);
+             fd_close (local_sock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
            case CONSOCKERR:
              logputs (LOG_VERBOSE, "\n");
              logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
-             CLOSE (csock);
-             CLOSE (dtsock);
-             CLOSE (local_sock);
+             fd_close (csock);
+             fd_close (dtsock);
+             fd_close (local_sock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
-           case CONPORTERR: case BINDERR: case LISTENERR:
-             /* What now?  These problems are local...  */
+           case FTPSYSERR:
              logputs (LOG_VERBOSE, "\n");
              logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
                         strerror (errno));
-             CLOSE (dtsock);
-             CLOSE (local_sock);
+             fd_close (dtsock);
              return err;
              break;
            case FTPPORTERR:
              logputs (LOG_VERBOSE, "\n");
              logputs (LOG_NOTQUIET, _("Invalid PORT.\n"));
-             CLOSE (csock);
-             CLOSE (dtsock);
-             CLOSE (local_sock);
+             fd_close (csock);
+             fd_close (dtsock);
+             fd_close (local_sock);
              rbuf_uninitialize (&con->rbuf);
              return err;
              break;
@@ -790,9 +782,9 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-         CLOSE (csock);
-         CLOSE (dtsock);
-         CLOSE (local_sock);
+         fd_close (csock);
+         fd_close (dtsock);
+         fd_close (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -800,9 +792,9 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET,
                   _("Write failed, closing control connection.\n"));
-         CLOSE (csock);
-         CLOSE (dtsock);
-         CLOSE (local_sock);
+         fd_close (csock);
+         fd_close (dtsock);
+         fd_close (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -815,9 +807,9 @@ Error in server response, closing control connection.\n"));
              logprintf (LOG_NOTQUIET,
                         _("\nREST failed; will not truncate `%s'.\n"),
                         con->target);
-             CLOSE (csock);
-             CLOSE (dtsock);
-             CLOSE (local_sock);
+             fd_close (csock);
+             fd_close (dtsock);
+             fd_close (local_sock);
              rbuf_uninitialize (&con->rbuf);
              return CONTNOTSUPPORTED;
            }
@@ -843,9 +835,9 @@ Error in server response, closing control connection.\n"));
         request.  */
       if (opt.spider)
        {
-         CLOSE (csock);
-         CLOSE (dtsock);
-         CLOSE (local_sock);
+         fd_close (csock);
+         fd_close (dtsock);
+         fd_close (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return RETRFINISHED;
        }
@@ -868,9 +860,9 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-         CLOSE (csock);
-         CLOSE (dtsock);
-         CLOSE (local_sock);
+         fd_close (csock);
+         fd_close (dtsock);
+         fd_close (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -878,17 +870,17 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET,
                   _("Write failed, closing control connection.\n"));
-         CLOSE (csock);
-         CLOSE (dtsock);
-         CLOSE (local_sock);
+         fd_close (csock);
+         fd_close (dtsock);
+         fd_close (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
        case FTPNSFOD:
          logputs (LOG_VERBOSE, "\n");
          logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"), u->file);
-         CLOSE (dtsock);
-         CLOSE (local_sock);
+         fd_close (dtsock);
+         fd_close (local_sock);
          return err;
          break;
        case FTPOK:
@@ -919,9 +911,9 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET, _("\
 Error in server response, closing control connection.\n"));
-         CLOSE (csock);
-         CLOSE (dtsock);
-         CLOSE (local_sock);
+         fd_close (csock);
+         fd_close (dtsock);
+         fd_close (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -929,9 +921,9 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logputs (LOG_NOTQUIET,
                   _("Write failed, closing control connection.\n"));
-         CLOSE (csock);
-         CLOSE (dtsock);
-         CLOSE (local_sock);
+         fd_close (csock);
+         fd_close (dtsock);
+         fd_close (local_sock);
          rbuf_uninitialize (&con->rbuf);
          return err;
          break;
@@ -939,8 +931,8 @@ Error in server response, closing control connection.\n"));
          logputs (LOG_VERBOSE, "\n");
          logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"),
                     ".");
-         CLOSE (dtsock);
-         CLOSE (local_sock);
+         fd_close (dtsock);
+         fd_close (local_sock);
          return err;
          break;
        case FTPOK:
@@ -971,10 +963,10 @@ Error in server response, closing control connection.\n"));
   if (!pasv_mode_open)  /* we are not using pasive mode so we need
                              to accept */
     {
-      /* Open the data transmission socket by calling acceptport().  */
-      err = acceptport (local_sock, &dtsock);
-      /* Possible errors: ACCEPTERR.  */
-      if (err == ACCEPTERR)
+      /* Wait for the server to connect to the address we're waiting
+        at.  */
+      dtsock = accept_connection (local_sock);
+      if (dtsock < 0)
        {
          logprintf (LOG_NOTQUIET, "accept: %s\n", strerror (errno));
          return err;
@@ -994,10 +986,10 @@ Error in server response, closing control connection.\n"));
       if (!fp)
        {
          logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno));
-         CLOSE (csock);
+         fd_close (csock);
          rbuf_uninitialize (&con->rbuf);
-         CLOSE (dtsock);
-         CLOSE (local_sock);
+         fd_close (dtsock);
+         fd_close (local_sock);
          return FOPENERR;
        }
     }
@@ -1044,8 +1036,8 @@ Error in server response, closing control connection.\n"));
   tms = time_str (NULL);
   tmrate = retr_rate (*len - restval, con->dltime, 0);
   /* Close data connection socket.  */
-  CLOSE (dtsock);
-  CLOSE (local_sock);
+  fd_close (dtsock);
+  fd_close (local_sock);
   /* Close the local file.  */
   {
     /* Close or flush the file.  We have to be careful to check for
@@ -1065,7 +1057,7 @@ Error in server response, closing control connection.\n"));
     {
       logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
                 con->target, strerror (errno));
-      CLOSE (csock);
+      fd_close (csock);
       rbuf_uninitialize (&con->rbuf);
       return FWRITEERR;
     }
@@ -1093,7 +1085,7 @@ Error in server response, closing control connection.\n"));
         return FTPRETRINT, since there is a possibility that the
         whole file was retrieved nevertheless (but that is for
         ftp_loop_internal to decide).  */
-      CLOSE (csock);
+      fd_close (csock);
       rbuf_uninitialize (&con->rbuf);
       return FTPRETRINT;
     } /* err != FTPOK */
@@ -1122,7 +1114,7 @@ Error in server response, closing control connection.\n"));
     {
       /* I should probably send 'QUIT' and check for a reply, but this
         is faster.  #### Is it OK, though?  */
-      CLOSE (csock);
+      fd_close (csock);
       rbuf_uninitialize (&con->rbuf);
     }
   /* If it was a listing, and opt.server_response is true,
@@ -1269,8 +1261,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con)
          return err;
          break;
        case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
-       case WRITEFAILED: case FTPUNKNOWNTYPE: case CONPORTERR:
-       case BINDERR: case LISTENERR: case ACCEPTERR:
+       case WRITEFAILED: case FTPUNKNOWNTYPE: case FTPSYSERR:
        case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV:
          printwhat (count, opt.ntry);
          /* non-fatal errors */
@@ -1303,7 +1294,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con)
 
       if (con->st & ON_YOUR_OWN)
        {
-         CLOSE (RBUF_FD (&con->rbuf));
+         fd_close (RBUF_FD (&con->rbuf));
          rbuf_uninitialize (&con->rbuf);
        }
       if (!opt.spider)
@@ -1365,7 +1356,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con)
 
   if (rbuf_initialized_p (&con->rbuf) && (con->st & ON_YOUR_OWN))
     {
-      CLOSE (RBUF_FD (&con->rbuf));
+      fd_close (RBUF_FD (&con->rbuf));
       rbuf_uninitialize (&con->rbuf);
     }
   return TRYLIMEXC;
@@ -1629,7 +1620,10 @@ Already have correct symlink %s -> %s\n\n"),
        logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), con->target);
 
       if (f->perms && f->type == FT_PLAINFILE && dlthis)
-       chmod (con->target, f->perms);
+        {
+         if (opt.preserve_perm)
+           chmod (con->target, f->perms);
+        }
       else
        DEBUGP (("Unrecognized permissions for %s.\n", con->target));
 
@@ -1923,10 +1917,10 @@ ftp_loop (struct url *u, int *dt, struct url *proxy)
     *dt |= RETROKF;
   /* If a connection was left, quench it.  */
   if (rbuf_initialized_p (&con.rbuf))
-    CLOSE (RBUF_FD (&con.rbuf));
-  FREE_MAYBE (con.id);
+    fd_close (RBUF_FD (&con.rbuf));
+  xfree_null (con.id);
   con.id = NULL;
-  FREE_MAYBE (con.target);
+  xfree_null (con.target);
   con.target = NULL;
   return res;
 }
@@ -1941,7 +1935,7 @@ delelement (struct fileinfo *f, struct fileinfo **start)
   struct fileinfo *next = f->next;
 
   xfree (f->name);
-  FREE_MAYBE (f->linkto);
+  xfree_null (f->linkto);
   xfree (f);
 
   if (next)