]> sjero.net Git - wget/blobdiff - src/ftp-ls.c
[svn] Merge of fix for bugs 20341 and 20410.
[wget] / src / ftp-ls.c
index 91c572e7018a9d3e138e6ebf2ae9bf6d2638c3e3..748bd788a9df591e3388ef49d77bfca09aada6bf 100644 (file)
@@ -1,12 +1,11 @@
 /* Parsing FTP `ls' output.
 /* 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
 
 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,
 (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
@@ -15,28 +14,35 @@ 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
 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
+OpenSSL project's "OpenSSL" library (or with modified versions of it
+that use the same license as the "OpenSSL" library), and distribute
+the linked executables.  You must obey the GNU General Public License
+in all respects for all of the code used other than "OpenSSL".  If you
+modify this file, you may extend this exception to your version of the
+file, but you are not obligated to do so.  If you do not wish to do
+so, delete this exception statement from your version.  */
 
 #include <config.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <config.h>
 
 #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
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
-#include <sys/types.h>
 #include <errno.h>
 #include <errno.h>
+#include <time.h>
 
 #include "wget.h"
 #include "utils.h"
 #include "ftp.h"
 #include "url.h"
 
 #include "wget.h"
 #include "utils.h"
 #include "ftp.h"
 #include "url.h"
+#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
 
 /* Converts symbolic permissions to number-style ones, e.g. string
    rwxr-xr-x to 755.  For now, it knows nothing of
@@ -97,7 +103,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
   struct tm timestruct, *tnow;
   time_t timenow;
 
   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");
   struct fileinfo *dir, *l, cur; /* list creation */
 
   fp = fopen (file, "rb");
@@ -109,7 +115,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
   dir = l = NULL;
 
   /* Line loop to end of 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);
       /* Skip if total...  */
     {
       len = clean_line (line);
       /* Skip if total...  */
@@ -188,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.  */
         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 */
        {
          --next;
          if (next < 0)         /* a month name was not encountered */
@@ -200,17 +208,25 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
                 size, and the filename is three tokens away.  */
              if (i != 12)
                {
                 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;
                    }
                      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]));
                  month = i;
                  next = 5;
                  DEBUGP (("month: %s; ", months[month]));
@@ -310,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' */
                 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)
                {
              memcpy (cur.name, tok, fnlen + 1);
              if (fnlen)
                {
@@ -343,27 +359,27 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
       if (!cur.name || (cur.type == FT_SYMLINK && !cur.linkto))
        error = 1;
 
       if (!cur.name || (cur.type == FT_SYMLINK && !cur.linkto))
        error = 1;
 
-      DEBUGP (("\n"));
+      DEBUGP (("%s\n", cur.name ? cur.name : ""));
 
       if (error || ignore)
        {
          DEBUGP (("Skipping.\n"));
 
       if (error || ignore)
        {
          DEBUGP (("Skipping.\n"));
-         FREE_MAYBE (cur.name);
-         FREE_MAYBE (cur.linkto);
+         xfree_null (cur.name);
+         xfree_null (cur.linkto);
          xfree (line);
          continue;
        }
 
       if (!dir)
        {
          xfree (line);
          continue;
        }
 
       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;
          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;
          l = l->next;
          memcpy (l, &cur, sizeof (cur));
          l->next = NULL;
@@ -426,7 +442,7 @@ ftp_parse_winnt_ls (const char *file)
   dir = l = NULL;
 
   /* Line loop to end of 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);
 
     {
       len = clean_line (line);
 
@@ -444,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, "-");
       /* 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, "-");
       month = atoi(tok) - 1;
       if (month < 0) month = 0;
       tok = strtok(NULL, "-");
+      if (tok == NULL) continue;
       day = atoi(tok);
       tok = strtok(NULL, " ");
       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;
       year = atoi(tok);
       /* Assuming the epoch starting at 1.1.1970 */
       if (year <= 70) year += 100;
@@ -456,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,  ":");
       /* 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");
       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 . */
       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 . */
@@ -487,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, " ");
          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;
       if (*tok == '<')
        {
          cur.type  = FT_DIRECTORY;
@@ -497,10 +520,16 @@ ftp_parse_winnt_ls (const char *file)
        }
       else
        {
        }
       else
        {
+         wgint size;
          cur.type  = FT_PLAINFILE;
          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;
          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;
        }
 
       cur.linkto = NULL;
@@ -508,20 +537,20 @@ ftp_parse_winnt_ls (const char *file)
       /* And put everything into the linked list */
       if (!dir)
        {
       /* 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;
          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;
        }
 
          l = l->next;
          memcpy (l, &cur, sizeof (cur));
          l->next = NULL;
        }
 
-      xfree(line);
+      xfree (line);
     }
 
   fclose(fp);
     }
 
   fclose(fp);
@@ -577,19 +606,28 @@ ftp_parse_vms_ls (const char *file)
     }
   dir = l = NULL;
 
     }
   dir = l = NULL;
 
-  /* Empty line */
-  read_whole_line (fp);
-  /* "Directory PUB$DEVICE[PUB]" */
-  read_whole_line (fp);
-  /* Empty line */
-  read_whole_line (fp);
+  /* Skip empty line. */
+  line = read_whole_line (fp);
+  xfree_null (line);
+
+  /* Skip "Directory PUB$DEVICE[PUB]" */
+  line = read_whole_line (fp);
+  xfree_null (line);
+
+  /* Skip empty line. */
+  line = read_whole_line (fp);
+  xfree_null (line);
 
   /* Line loop to end of file: */
 
   /* 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);
     {
       char *p;
       i = clean_line (line);
-      if (!i) break;
+      if (!i)
+       {
+         xfree (line);
+         break;
+       }
 
       /* First column: Name. A bit of black magic again. The name my be
          either ABCD.EXT or ABCD.EXT;NUM and it might be on a separate
 
       /* First column: Name. A bit of black magic again. The name my be
          either ABCD.EXT or ABCD.EXT;NUM and it might be on a separate
@@ -602,7 +640,8 @@ ftp_parse_vms_ls (const char *file)
       tok = strtok(line, " ");
       if (tok == NULL) tok = line;
       DEBUGP(("file name: '%s'\n", tok));
       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';
       if (*p == ';') *p = '\0';
       p   = tok + strlen(tok) - 4;
       if (!strcmp(p, ".DIR")) *p = '\0';
@@ -646,6 +685,7 @@ ftp_parse_vms_ls (const char *file)
         if (!i) 
         {
           DEBUGP(("confusing VMS listing item, leaving listing parser\n"));
         if (!i) 
         {
           DEBUGP(("confusing VMS listing item, leaving listing parser\n"));
+         xfree (line);
           break;
         }
         tok = strtok(line, " ");
           break;
         }
         tok = strtok(line, " ");
@@ -655,6 +695,7 @@ ftp_parse_vms_ls (const char *file)
       /* Third/Second column: Date DD-MMM-YYYY. */
 
       tok = strtok(NULL, "-");
       /* 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, "-");
       DEBUGP(("day: '%s'\n",tok));
       day = atoi(tok);
       tok = strtok(NULL, "-");
@@ -665,24 +706,29 @@ ftp_parse_vms_ls (const char *file)
            the first strtok(NULL, "-") will return everything until the end
            of the line and only the next strtok() call will return NULL. */
         DEBUGP(("nonsense in VMS listing, skipping this line\n"));
            the first strtok(NULL, "-") will return everything until the end
            of the line and only the next strtok() call will return NULL. */
         DEBUGP(("nonsense in VMS listing, skipping this line\n"));
+       xfree (line);
         break;
       }
       for (i=0; i<12; i++) if (!strcmp(tok,months[i])) break;
       /* Uknown months are mapped to January */
       month = i % 12 ; 
       tok = strtok (NULL, " ");
         break;
       }
       for (i=0; i<12; i++) if (!strcmp(tok,months[i])) break;
       /* 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, " ");
       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);
       p = tok;
       hour = atoi (p);
-      for (; *p && *p != ':'; ++p);
+      for (; *p && *p != ':'; ++p)
+       ;
       if (*p)
        min = atoi (++p);
       if (*p)
        min = atoi (++p);
-      for (; *p && *p != ':'; ++p);
+      for (; *p && *p != ':'; ++p)
+       ;
       if (*p)
        sec = atoi (++p);
 
       if (*p)
        sec = atoi (++p);
 
@@ -706,14 +752,17 @@ ftp_parse_vms_ls (const char *file)
       /* Skip the fifth column */
 
       tok = strtok(NULL, " ");
       /* Skip the fifth column */
 
       tok = strtok(NULL, " ");
+      if (tok == NULL) continue;
 
       /* Sixth column: Permissions */
 
       tok = strtok(NULL, ","); /* Skip the VMS-specific SYSTEM permissons */
 
       /* Sixth column: Permissions */
 
       tok = strtok(NULL, ","); /* Skip the VMS-specific SYSTEM permissons */
+      if (tok == NULL) continue;
       tok = strtok(NULL, ")");
       if (tok == NULL)
         {
           DEBUGP(("confusing VMS permissions, skipping line\n"));
       tok = strtok(NULL, ")");
       if (tok == NULL)
         {
           DEBUGP(("confusing VMS permissions, skipping line\n"));
+         xfree (line);
           continue;
         }
       /* Permissons have the format "RWED,RWED,RE" */
           continue;
         }
       /* Permissons have the format "RWED,RWED,RE" */
@@ -725,14 +774,14 @@ ftp_parse_vms_ls (const char *file)
       /* And put everything into the linked list */
       if (!dir)
         {
       /* 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;
           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;
           l = l->next;
           memcpy (l, &cur, sizeof (cur));
           l->next = NULL;
@@ -758,7 +807,7 @@ ftp_parse_ls (const char *file, const enum stype system_type)
   switch (system_type)
     {
     case ST_UNIX:
   switch (system_type)
     {
     case ST_UNIX:
-      return ftp_parse_unix_ls (file, FALSE);
+      return ftp_parse_unix_ls (file, 0);
     case ST_WINNT:
       {
        /* Detect whether the listing is simulating the UNIX format */
     case ST_WINNT:
       {
        /* Detect whether the listing is simulating the UNIX format */
@@ -777,16 +826,16 @@ ftp_parse_ls (const char *file, const enum stype system_type)
        if (c >= '0' && c <='9')
          return ftp_parse_winnt_ls (file);
         else
        if (c >= '0' && c <='9')
          return ftp_parse_winnt_ls (file);
         else
-          return ftp_parse_unix_ls (file, TRUE);
+          return ftp_parse_unix_ls (file, 1);
       }
     case ST_VMS:
       return ftp_parse_vms_ls (file);
     case ST_MACOS:
       }
     case ST_VMS:
       return ftp_parse_vms_ls (file);
     case ST_MACOS:
-      return ftp_parse_unix_ls (file, TRUE);
+      return ftp_parse_unix_ls (file, 1);
     default:
       logprintf (LOG_NOTQUIET, _("\
 Unsupported listing type, trying Unix listing parser.\n"));
     default:
       logprintf (LOG_NOTQUIET, _("\
 Unsupported listing type, trying Unix listing parser.\n"));
-      return ftp_parse_unix_ls (file, FALSE);
+      return ftp_parse_unix_ls (file, 0);
     }
 }
 \f
     }
 }
 \f
@@ -802,7 +851,7 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
   char *upwd;
   char *htclfile;              /* HTML-clean file name */
 
   char *upwd;
   char *htclfile;              /* HTML-clean file name */
 
-  if (!opt.dfp)
+  if (!output_stream)
     {
       fp = fopen (file, "wb");
       if (!fp)
     {
       fp = fopen (file, "wb");
       if (!fp)
@@ -812,18 +861,19 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
        }
     }
   else
        }
     }
   else
-    fp = opt.dfp;
+    fp = output_stream;
   if (u->user)
     {
       char *tmpu, *tmpp;        /* temporary, clean user and passwd */
 
   if (u->user)
     {
       char *tmpu, *tmpp;        /* temporary, clean user and passwd */
 
-      tmpu = encode_string (u->user);
-      tmpp = u->passwd ? encode_string (u->passwd) : NULL;
-      upwd = (char *)xmalloc (strlen (tmpu)
-                            + (tmpp ? (1 + strlen (tmpp)) : 0) + 2);
-      sprintf (upwd, "%s%s%s@", tmpu, tmpp ? ":" : "", tmpp ? tmpp : "");
+      tmpu = url_escape (u->user);
+      tmpp = u->passwd ? url_escape (u->passwd) : NULL;
+      if (tmpp)
+       upwd = concat_strings (tmpu, ":", tmpp, "@", (char *) 0);
+      else
+       upwd = concat_strings (tmpu, "@", (char *) 0);
       xfree (tmpu);
       xfree (tmpu);
-      FREE_MAYBE (tmpp);
+      xfree_null (tmpp);
     }
   else
     upwd = xstrdup ("");
     }
   else
     upwd = xstrdup ("");
@@ -838,8 +888,9 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
       fprintf (fp, "  ");
       if (f->tstamp != -1)
        {
       fprintf (fp, "  ");
       if (f->tstamp != -1)
        {
-         /* #### Should we translate the months? */
-         static char *months[] = {
+         /* #### Should we translate the months?  Or, even better, use
+            ISO 8601 dates?  */
+         static const char *months[] = {
            "Jan", "Feb", "Mar", "Apr", "May", "Jun",
            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
          };
            "Jan", "Feb", "Mar", "Apr", "May", "Jun",
            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
          };
@@ -870,7 +921,7 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
          break;
        }
       htclfile = html_quote_string (f->name);
          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);
       if (*u->dir != '/')
        putc ('/', fp);
       fprintf (fp, "%s", u->dir);
@@ -884,7 +935,7 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
        putc ('/', fp);
       fprintf (fp, "</a> ");
       if (f->type == FT_PLAINFILE)
        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);
       else if (f->type == FT_SYMLINK)
        fprintf (fp, "-> %s", f->linkto ? f->linkto : "(nil)");
       putc ('\n', fp);
@@ -893,7 +944,7 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
     }
   fprintf (fp, "</pre>\n</body>\n</html>\n");
   xfree (upwd);
     }
   fprintf (fp, "</pre>\n</body>\n</html>\n");
   xfree (upwd);
-  if (!opt.dfp)
+  if (!output_stream)
     fclose (fp);
   else
     fflush (fp);
     fclose (fp);
   else
     fflush (fp);