]> sjero.net Git - wget/blobdiff - src/ftp-ls.c
[svn] Merge of fix for bugs 20341 and 20410.
[wget] / src / ftp-ls.c
index 189bad9325699fa21c6d0ecac951a020d82c505d..748bd788a9df591e3388ef49d77bfca09aada6bf 100644 (file)
@@ -1,12 +1,11 @@
 /* Parsing FTP `ls' output.
-   Copyright (C) 1995, 1996, 1997, 2000, 2001
-   Free Software Foundation, Inc. 
+   Copyright (C) 1996-2004 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,
@@ -15,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
@@ -32,23 +30,19 @@ so, delete this exception statement from your version.  */
 
 #include <stdio.h>
 #include <stdlib.h>
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-#endif
+#include <string.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
-#include <sys/types.h>
 #include <errno.h>
+#include <time.h>
 
 #include "wget.h"
 #include "utils.h"
 #include "ftp.h"
 #include "url.h"
-
-extern FILE *output_stream;
+#include "convert.h"           /* for html_quote_string prototype */
+#include "retr.h"              /* for output_stream */
 
 /* Converts symbolic permissions to number-style ones, e.g. string
    rwxr-xr-x to 755.  For now, it knows nothing of
@@ -109,7 +103,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
   struct tm timestruct, *tnow;
   time_t timenow;
 
-  char *line, *tok;            /* tokenizer */
+  char *line, *tok, *ptok;     /* tokenizer */
   struct fileinfo *dir, *l, cur; /* list creation */
 
   fp = fopen (file, "rb");
@@ -121,7 +115,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
   dir = l = NULL;
 
   /* Line loop to end of file: */
-  while ((line = read_whole_line (fp)))
+  while ((line = read_whole_line (fp)) != NULL)
     {
       len = clean_line (line);
       /* Skip if total...  */
@@ -200,7 +194,9 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
         This tactic is quite dubious when it comes to
         internationalization issues (non-English month names), but it
         works for now.  */
-      while ((tok = strtok (NULL, " ")))
+      tok = line;
+      while (ptok = tok,
+            (tok = strtok (NULL, " ")) != NULL)
        {
          --next;
          if (next < 0)         /* a month name was not encountered */
@@ -212,17 +208,25 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
                 size, and the filename is three tokens away.  */
              if (i != 12)
                {
-                 char *t = tok - 2;
-                 long mul = 1;
+                 wgint size;
 
-                 for (cur.size = 0; t > line && ISDIGIT (*t); mul *= 10, t--)
-                   cur.size += mul * (*t - '0');
-                 if (t == line)
+                 /* Parse the previous token with str_to_wgint.  */
+                 if (ptok == line)
                    {
-                     /* Something is seriously wrong.  */
+                     /* Something has gone wrong during parsing. */
                      error = 1;
                      break;
                    }
+                 errno = 0;
+                 size = str_to_wgint (ptok, NULL, 10);
+                 if (size == WGINT_MAX && errno == ERANGE)
+                   /* Out of range -- ignore the size.  #### Should
+                      we refuse to start the download.  */
+                   cur.size = 0;
+                 else
+                   cur.size = size;
+                 DEBUGP (("size: %s; ", number_to_static_string(cur.size)));
+
                  month = i;
                  next = 5;
                  DEBUGP (("month: %s; ", months[month]));
@@ -322,7 +326,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
                 default -F output.  I believe these cases are very
                 rare.  */
              fnlen = strlen (tok); /* re-calculate `fnlen' */
-             cur.name = (char *)xmalloc (fnlen + 1);
+             cur.name = xmalloc (fnlen + 1);
              memcpy (cur.name, tok, fnlen + 1);
              if (fnlen)
                {
@@ -355,7 +359,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
       if (!cur.name || (cur.type == FT_SYMLINK && !cur.linkto))
        error = 1;
 
-      DEBUGP (("\n"));
+      DEBUGP (("%s\n", cur.name ? cur.name : ""));
 
       if (error || ignore)
        {
@@ -368,14 +372,14 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
 
       if (!dir)
        {
-         l = dir = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
+         l = dir = xnew (struct fileinfo);
          memcpy (l, &cur, sizeof (cur));
          l->prev = l->next = NULL;
        }
       else
        {
          cur.prev = l;
-         l->next = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
+         l->next = xnew (struct fileinfo);
          l = l->next;
          memcpy (l, &cur, sizeof (cur));
          l->next = NULL;
@@ -438,7 +442,7 @@ ftp_parse_winnt_ls (const char *file)
   dir = l = NULL;
 
   /* Line loop to end of file: */
-  while ((line = read_whole_line (fp)))
+  while ((line = read_whole_line (fp)) != NULL)
     {
       len = clean_line (line);
 
@@ -456,11 +460,14 @@ ftp_parse_winnt_ls (const char *file)
       /* First column: mm-dd-yy. Should atoi() on the month fail, january
         will be assumed.  */
       tok = strtok(line, "-");
+      if (tok == NULL) continue;
       month = atoi(tok) - 1;
       if (month < 0) month = 0;
       tok = strtok(NULL, "-");
+      if (tok == NULL) continue;
       day = atoi(tok);
       tok = strtok(NULL, " ");
+      if (tok == NULL) continue;
       year = atoi(tok);
       /* Assuming the epoch starting at 1.1.1970 */
       if (year <= 70) year += 100;
@@ -468,8 +475,10 @@ ftp_parse_winnt_ls (const char *file)
       /* Second column: hh:mm[AP]M, listing does not contain value for
          seconds */
       tok = strtok(NULL,  ":");
+      if (tok == NULL) continue;
       hour = atoi(tok);
       tok = strtok(NULL,  "M");
+      if (tok == NULL) continue;
       min = atoi(tok);
       /* Adjust hour from AM/PM. Just for the record, the sequence goes
          11:00AM, 12:00PM, 01:00PM ... 11:00PM, 12:00AM, 01:00AM . */
@@ -499,7 +508,9 @@ ftp_parse_winnt_ls (const char *file)
          directories as the listing does not give us a clue) and filetype
          here. */
       tok = strtok(NULL, " ");
-      while (*tok == '\0')  tok = strtok(NULL, " ");
+      if (tok == NULL) continue;
+      while ((tok != NULL) && (*tok == '\0'))  tok = strtok(NULL, " ");
+      if (tok == NULL) continue;
       if (*tok == '<')
        {
          cur.type  = FT_DIRECTORY;
@@ -509,10 +520,16 @@ ftp_parse_winnt_ls (const char *file)
        }
       else
        {
+         wgint size;
          cur.type  = FT_PLAINFILE;
-         cur.size  = atoi(tok);
+         errno = 0;
+         size = str_to_wgint (tok, NULL, 10);
+         if (size == WGINT_MAX && errno == ERANGE)
+           cur.size = 0;       /* overflow */
+         else
+           cur.size = size;
          cur.perms = 0644;
-         DEBUGP(("File, size %ld bytes\n", cur.size));
+         DEBUGP(("File, size %s bytes\n", number_to_static_string (cur.size)));
        }
 
       cur.linkto = NULL;
@@ -520,20 +537,20 @@ ftp_parse_winnt_ls (const char *file)
       /* And put everything into the linked list */
       if (!dir)
        {
-         l = dir = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
+         l = dir = xnew (struct fileinfo);
          memcpy (l, &cur, sizeof (cur));
          l->prev = l->next = NULL;
        }
       else
        {
          cur.prev = l;
-         l->next = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
+         l->next = xnew (struct fileinfo);
          l = l->next;
          memcpy (l, &cur, sizeof (cur));
          l->next = NULL;
        }
 
-      xfree(line);
+      xfree (line);
     }
 
   fclose(fp);
@@ -591,21 +608,18 @@ ftp_parse_vms_ls (const char *file)
 
   /* Skip empty line. */
   line = read_whole_line (fp);
-  if (line)
-    xfree (line);
+  xfree_null (line);
 
   /* Skip "Directory PUB$DEVICE[PUB]" */
   line = read_whole_line (fp);
-  if (line)
-    xfree (line);
+  xfree_null (line);
 
   /* Skip empty line. */
   line = read_whole_line (fp);
-  if (line)
-    xfree (line);
+  xfree_null (line);
 
   /* Line loop to end of file: */
-  while ((line = read_whole_line (fp)))
+  while ((line = read_whole_line (fp)) != NULL)
     {
       char *p;
       i = clean_line (line);
@@ -626,7 +640,8 @@ ftp_parse_vms_ls (const char *file)
       tok = strtok(line, " ");
       if (tok == NULL) tok = line;
       DEBUGP(("file name: '%s'\n", tok));
-      for (p = tok ; *p && *p != ';' ; p++);
+      for (p = tok ; *p && *p != ';' ; p++)
+       ;
       if (*p == ';') *p = '\0';
       p   = tok + strlen(tok) - 4;
       if (!strcmp(p, ".DIR")) *p = '\0';
@@ -680,6 +695,7 @@ ftp_parse_vms_ls (const char *file)
       /* Third/Second column: Date DD-MMM-YYYY. */
 
       tok = strtok(NULL, "-");
+      if (tok == NULL) continue;
       DEBUGP(("day: '%s'\n",tok));
       day = atoi(tok);
       tok = strtok(NULL, "-");
@@ -697,18 +713,22 @@ ftp_parse_vms_ls (const char *file)
       /* Uknown months are mapped to January */
       month = i % 12 ; 
       tok = strtok (NULL, " ");
+      if (tok == NULL) continue;
       year = atoi (tok) - 1900;
       DEBUGP(("date parsed\n"));
 
       /* Fourth/Third column: Time hh:mm[:ss] */
       tok = strtok (NULL, " ");
-      hour = min = sec = 0;
+      if (tok == NULL) continue;
+      min = sec = 0;
       p = tok;
       hour = atoi (p);
-      for (; *p && *p != ':'; ++p);
+      for (; *p && *p != ':'; ++p)
+       ;
       if (*p)
        min = atoi (++p);
-      for (; *p && *p != ':'; ++p);
+      for (; *p && *p != ':'; ++p)
+       ;
       if (*p)
        sec = atoi (++p);
 
@@ -732,10 +752,12 @@ ftp_parse_vms_ls (const char *file)
       /* Skip the fifth column */
 
       tok = strtok(NULL, " ");
+      if (tok == NULL) continue;
 
       /* Sixth column: Permissions */
 
       tok = strtok(NULL, ","); /* Skip the VMS-specific SYSTEM permissons */
+      if (tok == NULL) continue;
       tok = strtok(NULL, ")");
       if (tok == NULL)
         {
@@ -752,14 +774,14 @@ ftp_parse_vms_ls (const char *file)
       /* And put everything into the linked list */
       if (!dir)
         {
-          l = dir = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
+          l = dir = xnew (struct fileinfo);
           memcpy (l, &cur, sizeof (cur));
           l->prev = l->next = NULL;
         }
       else
         {
           cur.prev = l;
-          l->next = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
+          l->next = xnew (struct fileinfo);
           l = l->next;
           memcpy (l, &cur, sizeof (cur));
           l->next = NULL;
@@ -846,9 +868,10 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
 
       tmpu = url_escape (u->user);
       tmpp = u->passwd ? url_escape (u->passwd) : NULL;
-      upwd = (char *)xmalloc (strlen (tmpu)
-                            + (tmpp ? (1 + strlen (tmpp)) : 0) + 2);
-      sprintf (upwd, "%s%s%s@", tmpu, tmpp ? ":" : "", tmpp ? tmpp : "");
+      if (tmpp)
+       upwd = concat_strings (tmpu, ":", tmpp, "@", (char *) 0);
+      else
+       upwd = concat_strings (tmpu, "@", (char *) 0);
       xfree (tmpu);
       xfree_null (tmpp);
     }
@@ -898,7 +921,7 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
          break;
        }
       htclfile = html_quote_string (f->name);
-      fprintf (fp, "<a href=\"ftp://%s%s:%hu", upwd, u->host, u->port);
+      fprintf (fp, "<a href=\"ftp://%s%s:%d", upwd, u->host, u->port);
       if (*u->dir != '/')
        putc ('/', fp);
       fprintf (fp, "%s", u->dir);
@@ -912,7 +935,7 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
        putc ('/', fp);
       fprintf (fp, "</a> ");
       if (f->type == FT_PLAINFILE)
-       fprintf (fp, _(" (%s bytes)"), legible (f->size));
+       fprintf (fp, _(" (%s bytes)"), number_to_static_string (f->size));
       else if (f->type == FT_SYMLINK)
        fprintf (fp, "-> %s", f->linkto ? f->linkto : "(nil)");
       putc ('\n', fp);