]> sjero.net Git - wget/blobdiff - src/ftp-basic.c
[svn] Merge of fix for bugs 20341 and 20410.
[wget] / src / ftp-basic.c
index 131652333243902866c2408faabb3ff1a3c95df9..24026e194d89f0bff978e504ded1ab58189dea07 100644 (file)
@@ -1,11 +1,11 @@
 /* Basic FTP routines.
-   Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1996-2007 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
 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
+the Free Software Foundation; either version 3 of the License, or
  (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@ 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 Wget; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+along with Wget.  If not, see <http://www.gnu.org/licenses/>.
 
 In addition, as a special exception, the Free Software Foundation
 gives permission to link the code of its release of Wget with the
@@ -250,13 +249,11 @@ ip_address_to_port_repr (const ip_address *addr, int port, char *buf,
 {
   unsigned char *ptr;
 
-  assert (addr != NULL);
-  assert (addr->type == IPV4_ADDRESS);
-  assert (buf != NULL);
+  assert (addr->family == AF_INET);
   /* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
   assert (buflen >= 6 * 4);
 
-  ptr = ADDRESS_IPV4_DATA (addr);
+  ptr = IP_INADDR_DATA (addr);
   snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
             ptr[2], ptr[3], (port & 0xff00) >> 8, port & 0xff);
   buf[buflen - 1] = '\0';
@@ -280,7 +277,7 @@ ftp_port (int csock, int *local_sock)
   if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
     return FTPSYSERR;
 
-  assert (addr.type == IPV4_ADDRESS);
+  assert (addr.family == AF_INET);
 
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
@@ -326,32 +323,29 @@ static void
 ip_address_to_lprt_repr (const ip_address *addr, int port, char *buf, 
                          size_t buflen)
 {
-  unsigned char *ptr;
+  unsigned char *ptr = IP_INADDR_DATA (addr);
 
-  assert (addr != NULL);
-  assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
-  assert (buf != NULL);
   /* buf must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
   assert (buflen >= 21 * 4);
 
   /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
-  switch (addr->type
-    {
-      case IPV4_ADDRESS
-       ptr = ADDRESS_IPV4_DATA (addr);
-        snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4, 
-                  ptr[0], ptr[1], ptr[2], ptr[3], 2,
-                  (port & 0xff00) >> 8, port & 0xff);
-        buf[buflen - 1] = '\0';
-        break;
-      case IPV6_ADDRESS: 
-       ptr = ADDRESS_IPV6_DATA (addr);
-       snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
-                 6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], 
-                 ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2,
-                 (port & 0xff00) >> 8, port & 0xff);
-       buf[buflen - 1] = '\0';
-       break;
+  switch (addr->family
+    {
+    case AF_INET
+      snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4, 
+               ptr[0], ptr[1], ptr[2], ptr[3], 2,
+               (port & 0xff00) >> 8, port & 0xff);
+      break;
+    case AF_INET6: 
+      snprintf (buf, buflen,
+               "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+               6, 16,
+               ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], 
+               ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15],
+               2, (port & 0xff00) >> 8, port & 0xff);
+      break;
+    default:
+      abort ();
     }
 }
 
@@ -373,7 +367,7 @@ ftp_lprt (int csock, int *local_sock)
   if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
     return FTPSYSERR;
 
-  assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
+  assert (addr.family == AF_INET || addr.family == AF_INET6);
 
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
@@ -419,17 +413,14 @@ ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
 {
   int afnum;
 
-  assert (addr != NULL);
-  assert (addr->type == IPV4_ADDRESS || addr->type == IPV6_ADDRESS);
-  assert (buf != NULL);
   /* buf must contain the argument of EPRT (of the form |af|addr|port|). 
    * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr  
    * 1 char for af (1-2) and 5 chars for port (0-65535) */
   assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5); 
 
   /* Construct the argument of EPRT (of the form |af|addr|port|). */
-  afnum = (addr->type == IPV4_ADDRESS ? 1 : 2);
-  snprintf (buf, buflen, "|%d|%s|%d|", afnum, pretty_print_address (addr), port);
+  afnum = (addr->family == AF_INET ? 1 : 2);
+  snprintf (buf, buflen, "|%d|%s|%d|", afnum, print_address (addr), port);
   buf[buflen - 1] = '\0';
 }
 
@@ -453,8 +444,6 @@ ftp_eprt (int csock, int *local_sock)
   if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
     return FTPSYSERR;
 
-  assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
-
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
 
@@ -531,7 +520,8 @@ ftp_pasv (int csock, ip_address *addr, int *port)
     }
   /* Parse the request.  */
   s = respline;
-  for (s += 4; *s && !ISDIGIT (*s); s++);
+  for (s += 4; *s && !ISDIGIT (*s); s++)
+    ;
   if (!*s)
     return FTPINVPASV;
   for (i = 0; i < 6; i++)
@@ -550,8 +540,8 @@ ftp_pasv (int csock, ip_address *addr, int *port)
     }
   xfree (respline);
 
-  addr->type = IPV4_ADDRESS;
-  memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
+  addr->family = AF_INET;
+  memcpy (IP_INADDR_DATA (addr), tmp, 4);
   *port = ((tmp[4] << 8) & 0xff00) + tmp[5];
 
   return FTPOK;
@@ -599,7 +589,8 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
 
   /* Parse the response.  */
   s = respline;
-  for (s += 4; *s && !ISDIGIT (*s); s++);
+  for (s += 4; *s && !ISDIGIT (*s); s++)
+    ;
   if (!*s)
     return FTPINVPASV;
 
@@ -695,10 +686,10 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
 
   if (af == 4)
     {
-      addr->type = IPV4_ADDRESS;
-      memcpy (ADDRESS_IPV4_DATA (addr), tmp, 4);
+      addr->family = AF_INET;
+      memcpy (IP_INADDR_DATA (addr), tmp, 4);
       *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
-      DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
+      DEBUGP (("lpsv addr is: %s\n", print_address(addr)));
       DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
       DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
       DEBUGP (("*port is: %d\n", *port));
@@ -706,10 +697,10 @@ ftp_lpsv (int csock, ip_address *addr, int *port)
   else
     {
       assert (af == 6);
-      addr->type = IPV6_ADDRESS;
-      memcpy (ADDRESS_IPV6_DATA (addr), tmp, 16);
+      addr->family = AF_INET6;
+      memcpy (IP_INADDR_DATA (addr), tmp, 16);
       *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
-      DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
+      DEBUGP (("lpsv addr is: %s\n", print_address(addr)));
       DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
       DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
       DEBUGP (("*port is: %d\n", *port));
@@ -738,7 +729,7 @@ ftp_epsv (int csock, ip_address *ip, int *port)
 
   /* Form the request.  */
   /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
-  request = ftp_request ("EPSV", (ip->type == IPV4_ADDRESS ? "1" : "2"));
+  request = ftp_request ("EPSV", (ip->family == AF_INET ? "1" : "2"));
 
   /* And send it.  */
   nwritten = fd_write (csock, request, strlen (request), -1);
@@ -970,33 +961,45 @@ ftp_list (int csock, const char *file)
   char *request, *respline;
   int nwritten;
   uerr_t err;
-
-  /* Send LIST request.  */
-  request = ftp_request ("LIST", file);
-  nwritten = fd_write (csock, request, strlen (request), -1);
-  if (nwritten < 0)
-    {
-      xfree (request);
-      return WRITEFAILED;
-    }
-  xfree (request);
-  /* Get appropriate respone.  */
-  err = ftp_response (csock, &respline);
-  if (err != FTPOK)
-    return err;
-  if (*respline == '5')
-    {
-      xfree (respline);
-      return FTPNSFOD;
-    }
-  if (*respline != '1')
-    {
-      xfree (respline);
-      return FTPRERR;
-    }
-  xfree (respline);
-  /* All OK.  */
-  return FTPOK;
+  bool ok = false;
+  int i = 0;
+  /* Try `LIST -a' first and revert to `LIST' in case of failure.  */
+  const char *list_commands[] = { "LIST -a", 
+                                  "LIST" };
+
+  do {
+    /* Send request.  */
+    request = ftp_request (list_commands[i], file);
+    nwritten = fd_write (csock, request, strlen (request), -1);
+    if (nwritten < 0)
+      {
+        xfree (request);
+        return WRITEFAILED;
+      }
+    xfree (request);
+    /* Get appropriate response.  */
+    err = ftp_response (csock, &respline);
+    if (err == FTPOK)
+      {
+        if (*respline == '5')
+          {
+            err = FTPNSFOD;
+          }
+       else if (*respline == '1')
+          {
+            err = FTPOK;
+            ok = true;
+          }
+        else 
+          {
+           err = FTPRERR;
+          }
+        xfree (respline);
+      }
+    ++i;
+  } while (i < countof (list_commands) && !ok);
+  
+  return err;
 }
 
 /* Sends the SYST command to the server. */
@@ -1034,7 +1037,9 @@ ftp_syst (int csock, enum stype *server_type)
      first word of the server response)?  */
   request = strtok (NULL, " ");
 
-  if (!strcasecmp (request, "VMS"))
+  if (request == NULL)
+    *server_type = ST_OTHER;
+  else if (!strcasecmp (request, "VMS"))
     *server_type = ST_VMS;
   else if (!strcasecmp (request, "UNIX"))
     *server_type = ST_UNIX;