]> sjero.net Git - wget/blobdiff - src/retr.c
[svn] Extract timers to a separate file.
[wget] / src / retr.c
index 5d9795ad67ac7177163f96d1dff28f2eaa6bb9c7..a5198b7e591171792bf8b11360003d01c8dc4fed 100644 (file)
@@ -54,6 +54,7 @@ so, delete this exception statement from your version.  */
 #include "connect.h"
 #include "hash.h"
 #include "convert.h"
 #include "connect.h"
 #include "hash.h"
 #include "convert.h"
+#include "ptimer.h"
 
 #ifdef HAVE_SSL
 # include "gen_sslfunc.h"      /* for ssl_iread */
 
 #ifdef HAVE_SSL
 # include "gen_sslfunc.h"      /* for ssl_iread */
@@ -63,15 +64,19 @@ so, delete this exception statement from your version.  */
 extern int errno;
 #endif
 
 extern int errno;
 #endif
 
-/* See the comment in gethttp() why this is needed. */
-int global_download_count;
-
 /* Total size of downloaded files.  Used to enforce quota.  */
 LARGE_INT total_downloaded_bytes;
 
 /* Total size of downloaded files.  Used to enforce quota.  */
 LARGE_INT total_downloaded_bytes;
 
+/* If non-NULL, the stream to which output should be written.  This
+   stream is initialized when `-O' is used.  */
+FILE *output_stream;
+
+/* Whether output_document is a regular file we can manipulate,
+   i.e. not `-' or a device file. */
+int output_stream_regular;
 \f
 static struct {
 \f
 static struct {
-  long chunk_bytes;
+  wgint chunk_bytes;
   double chunk_start;
   double sleep_adjust;
 } limit_data;
   double chunk_start;
   double sleep_adjust;
 } limit_data;
@@ -88,9 +93,9 @@ limit_bandwidth_reset (void)
    is the timer that started at the beginning of download.  */
 
 static void
    is the timer that started at the beginning of download.  */
 
 static void
-limit_bandwidth (long bytes, struct wget_timer *timer)
+limit_bandwidth (wgint bytes, struct ptimer *timer)
 {
 {
-  double delta_t = wtimer_read (timer) - limit_data.chunk_start;
+  double delta_t = ptimer_read (timer) - limit_data.chunk_start;
   double expected;
 
   limit_data.chunk_bytes += bytes;
   double expected;
 
   limit_data.chunk_bytes += bytes;
@@ -106,17 +111,18 @@ limit_bandwidth (long bytes, struct wget_timer *timer)
       double t0, t1;
       if (slp < 200)
        {
       double t0, t1;
       if (slp < 200)
        {
-         DEBUGP (("deferring a %.2f ms sleep (%ld/%.2f).\n",
-                  slp, limit_data.chunk_bytes, delta_t));
+         DEBUGP (("deferring a %.2f ms sleep (%s/%.2f).\n",
+                  slp, number_to_static_string (limit_data.chunk_bytes),
+                  delta_t));
          return;
        }
          return;
        }
-      DEBUGP (("\nsleeping %.2f ms for %ld bytes, adjust %.2f ms\n",
-              slp, limit_data.chunk_bytes, limit_data.sleep_adjust));
+      DEBUGP (("\nsleeping %.2f ms for %s bytes, adjust %.2f ms\n",
+              slp, number_to_static_string (limit_data.chunk_bytes),
+              limit_data.sleep_adjust));
 
 
-      t0 = wtimer_read (timer);
+      t0 = ptimer_read (timer);
       xsleep (slp / 1000);
       xsleep (slp / 1000);
-      wtimer_update (timer);
-      t1 = wtimer_read (timer);
+      t1 = ptimer_measure (timer);
 
       /* Due to scheduling, we probably slept slightly longer (or
         shorter) than desired.  Calculate the difference between the
 
       /* Due to scheduling, we probably slept slightly longer (or
         shorter) than desired.  Calculate the difference between the
@@ -126,38 +132,78 @@ limit_bandwidth (long bytes, struct wget_timer *timer)
     }
 
   limit_data.chunk_bytes = 0;
     }
 
   limit_data.chunk_bytes = 0;
-  limit_data.chunk_start = wtimer_read (timer);
+  limit_data.chunk_start = ptimer_read (timer);
 }
 
 }
 
-#define MIN(i, j) ((i) <= (j) ? (i) : (j))
+#ifndef MIN
+# define MIN(i, j) ((i) <= (j) ? (i) : (j))
+#endif
 
 
-/* Reads the contents of file descriptor FD, until it is closed, or a
-   read error occurs.  The data is read in 8K chunks, and stored to
-   stream fp, which should have been open for writing.
+/* Write data in BUF to OUT.  However, if *SKIP is non-zero, skip that
+   amount of data and decrease SKIP.  Increment *TOTAL by the amount
+   of data written.  */
 
 
-   The EXPECTED argument is passed to show_progress() unchanged, but
-   otherwise ignored.
+static int
+write_data (FILE *out, const char *buf, int bufsize, wgint *skip,
+           wgint *written)
+{
+  if (!out)
+    return 1;
+  if (*skip > bufsize)
+    {
+      *skip -= bufsize;
+      return 1;
+    }
+  if (*skip)
+    {
+      buf += *skip;
+      bufsize -= *skip;
+      *skip = 0;
+      if (bufsize == 0)
+       return 1;
+    }
 
 
-   If opt.verbose is set, the progress is also shown.  RESTVAL
-   represents a value from which to start downloading (which will be
-   shown accordingly).  If RESTVAL is non-zero, the stream should have
-   been open for appending.
+  fwrite (buf, 1, bufsize, out);
+  *written += bufsize;
 
 
-   The function exits and returns codes of 0, -1 and -2 if the
-   connection was closed, there was a read error, or if it could not
-   write to the output stream, respectively.  */
+  /* Immediately flush the downloaded data.  This should not hinder
+     performance: fast downloads will arrive in large 16K chunks
+     (which stdio would write out immediately anyway), and slow
+     downloads wouldn't be limited by disk speed.  */
+  fflush (out);
+  return !ferror (out);
+}
+
+/* Read the contents of file descriptor FD until it the connection
+   terminates or a read error occurs.  The data is read in portions of
+   up to 16K and written to OUT as it arrives.  If opt.verbose is set,
+   the progress is shown.
+
+   TOREAD is the amount of data expected to arrive, normally only used
+   by the progress gauge.
+
+   STARTPOS is the position from which the download starts, used by
+   the progress gauge.  If QTYREAD is non-NULL, the value it points to
+   is incremented by the amount of data read from the network.  If
+   QTYWRITTEN is non-NULL, the value it points to is incremented by
+   the amount of data written to disk.  The time it took to download
+   the data (in milliseconds) is stored to ELAPSED.
+
+   The function exits and returns the amount of data read.  In case of
+   error while reading data, -1 is returned.  In case of error while
+   writing data, -2 is returned.  */
 
 int
 
 int
-fd_read_body (int fd, FILE *out, long *len, long restval, long expected,
-             int use_expected, double *elapsed)
+fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
+             wgint *qtyread, wgint *qtywritten, double *elapsed, int flags)
 {
 {
-  int res = 0;
+  int ret = 0;
 
   static char dlbuf[16384];
   int dlbufsize = sizeof (dlbuf);
 
 
   static char dlbuf[16384];
   int dlbufsize = sizeof (dlbuf);
 
-  struct wget_timer *timer = wtimer_allocate ();
-  double last_successful_read_tm;
+  struct ptimer *timer = NULL;
+  double last_successful_read_tm = 0;
 
   /* The progress gauge, set according to the user preferences. */
   void *progress = NULL;
 
   /* The progress gauge, set according to the user preferences. */
   void *progress = NULL;
@@ -168,18 +214,36 @@ fd_read_body (int fd, FILE *out, long *len, long restval, long expected,
      data arrives slowly. */
   int progress_interactive = 0;
 
      data arrives slowly. */
   int progress_interactive = 0;
 
-  *len = restval;
+  int exact = flags & rb_read_exactly;
+  wgint skip = 0;
+
+  /* How much data we've read/written.  */
+  wgint sum_read = 0;
+  wgint sum_written = 0;
+
+  if (flags & rb_skip_startpos)
+    skip = startpos;
 
   if (opt.verbose)
     {
 
   if (opt.verbose)
     {
-      progress = progress_create (restval, expected);
+      /* If we're skipping STARTPOS bytes, pass 0 as the INITIAL
+        argument to progress_create because the indicator doesn't
+        (yet) know about "skipping" data.  */
+      progress = progress_create (skip ? 0 : startpos, startpos + toread);
       progress_interactive = progress_interactive_p (progress);
     }
 
   if (opt.limit_rate)
     limit_bandwidth_reset ();
       progress_interactive = progress_interactive_p (progress);
     }
 
   if (opt.limit_rate)
     limit_bandwidth_reset ();
-  wtimer_reset (timer);
-  last_successful_read_tm = 0;
+
+  /* A timer is needed for tracking progress, for throttling, and for
+     tracking elapsed time.  If either of these are requested, start
+     the timer.  */
+  if (progress || opt.limit_rate || elapsed)
+    {
+      timer = ptimer_new ();
+      last_successful_read_tm = 0;
+    }
 
   /* Use a smaller buffer for low requested bandwidths.  For example,
      with --limit-rate=2k, it doesn't make sense to slurp in 16K of
 
   /* Use a smaller buffer for low requested bandwidths.  For example,
      with --limit-rate=2k, it doesn't make sense to slurp in 16K of
@@ -188,97 +252,138 @@ fd_read_body (int fd, FILE *out, long *len, long restval, long expected,
   if (opt.limit_rate && opt.limit_rate < dlbufsize)
     dlbufsize = opt.limit_rate;
 
   if (opt.limit_rate && opt.limit_rate < dlbufsize)
     dlbufsize = opt.limit_rate;
 
-  /* Read from fd while there is available data.
-
-     Normally, if expected is 0, it means that it is not known how
-     much data is expected.  However, if use_expected is specified,
-     then expected being zero means exactly that.  */
-  while (!use_expected || (*len < expected))
+  /* Read from FD while there is data to read.  Normally toread==0
+     means that it is unknown how much data is to arrive.  However, if
+     EXACT is set, then toread==0 means what it says: that no data
+     should be read.  */
+  while (!exact || (sum_read < toread))
     {
     {
-      int amount_to_read = (use_expected
-                           ? MIN (expected - *len, dlbufsize) : dlbufsize);
+      int rdsize = exact ? MIN (toread - sum_read, dlbufsize) : dlbufsize;
       double tmout = opt.read_timeout;
       if (progress_interactive)
        {
       double tmout = opt.read_timeout;
       if (progress_interactive)
        {
-         double waittm;
          /* For interactive progress gauges, always specify a ~1s
             timeout, so that the gauge can be updated regularly even
             when the data arrives very slowly or stalls.  */
          tmout = 0.95;
          /* For interactive progress gauges, always specify a ~1s
             timeout, so that the gauge can be updated regularly even
             when the data arrives very slowly or stalls.  */
          tmout = 0.95;
-         waittm = (wtimer_read (timer) - last_successful_read_tm) / 1000;
-         if (waittm + tmout > opt.read_timeout)
+         if (opt.read_timeout)
            {
            {
-             /* Don't allow waiting time to exceed read timeout. */
-             tmout = opt.read_timeout - waittm;
-             if (tmout < 0)
+             double waittm;
+             waittm = (ptimer_read (timer) - last_successful_read_tm) / 1000;
+             if (waittm + tmout > opt.read_timeout)
                {
                {
-                 /* We've already exceeded the timeout. */
-                 res = -1, errno = ETIMEDOUT;
-                 break;
+                 /* Don't let total idle time exceed read timeout. */
+                 tmout = opt.read_timeout - waittm;
+                 if (tmout < 0)
+                   {
+                     /* We've already exceeded the timeout. */
+                     ret = -1, errno = ETIMEDOUT;
+                     break;
+                   }
                }
            }
        }
                }
            }
        }
-      res = fd_read (fd, dlbuf, amount_to_read, tmout);
+      ret = fd_read (fd, dlbuf, rdsize, tmout);
+
+      if (ret == 0 || (ret < 0 && errno != ETIMEDOUT))
+       break;                  /* read error */
+      else if (ret < 0)
+       ret = 0;                /* read timeout */
 
 
-      if (res == 0 || (res < 0 && errno != ETIMEDOUT))
-       break;
-      else if (res < 0)
-       res = 0;                /* timeout */
+      if (progress || opt.limit_rate)
+       {
+         ptimer_measure (timer);
+         if (ret > 0)
+           last_successful_read_tm = ptimer_read (timer);
+       }
 
 
-      wtimer_update (timer);
-      if (res > 0)
+      if (ret > 0)
        {
        {
-         fwrite (dlbuf, 1, res, out);
-         /* Always flush the contents of the network packet.  This
-            should not hinder performance: fast downloads will be
-            received in 16K chunks (which stdio would write out
-            anyway), and slow downloads won't be limited by disk
-            performance.  */
-         fflush (out);
-         if (ferror (out))
+         sum_read += ret;
+         if (!write_data (out, dlbuf, ret, &skip, &sum_written))
            {
            {
-             res = -2;
+             ret = -2;
              goto out;
            }
              goto out;
            }
-         last_successful_read_tm = wtimer_read (timer);
        }
 
       if (opt.limit_rate)
        }
 
       if (opt.limit_rate)
-       limit_bandwidth (res, timer);
+       limit_bandwidth (ret, timer);
 
 
-      *len += res;
       if (progress)
       if (progress)
-       progress_update (progress, res, wtimer_read (timer));
+       progress_update (progress, ret, ptimer_read (timer));
 #ifdef WINDOWS
 #ifdef WINDOWS
-      if (use_expected && expected > 0)
-       ws_percenttitle (100.0 * (double)(*len) / (double)expected);
+      if (toread > 0 && !opt.quiet)
+       ws_percenttitle (100.0 *
+                        (startpos + sum_read) / (startpos + toread));
 #endif
     }
 #endif
     }
-  if (res < -1)
-    res = -1;
+  if (ret < -1)
+    ret = -1;
 
  out:
   if (progress)
 
  out:
   if (progress)
-    progress_finish (progress, wtimer_read (timer));
+    progress_finish (progress, ptimer_read (timer));
+
   if (elapsed)
   if (elapsed)
-    *elapsed = wtimer_read (timer);
-  wtimer_delete (timer);
+    *elapsed = ptimer_read (timer);
+  if (timer)
+    ptimer_destroy (timer);
 
 
-  return res;
+  if (qtyread)
+    *qtyread += sum_read;
+  if (qtywritten)
+    *qtywritten += sum_written;
+
+  return ret;
 }
 \f
 }
 \f
-typedef const char *(*finder_t) PARAMS ((const char *, int, int));
+/* Read a hunk of data from FD, up until a terminator.  The terminator
+   is whatever the TERMINATOR function determines it to be; for
+   example, it can be a line of data, or the head of an HTTP response.
+   The function returns the data read allocated with malloc.
 
 
-/* Driver for fd_read_line and fd_read_head: keeps reading data until
-   a terminator (as decided by FINDER) occurs in the data.  The trick
-   is that the data is first peeked at, and only then actually read.
-   That way the data after the terminator is never read.  */
+   In case of error, NULL is returned.  In case of EOF and no data
+   read, NULL is returned and errno set to 0.  In case of EOF with
+   data having been read, the data is returned, but it will
+   (obviously) not contain the terminator.
 
 
-static char *
-fd_read_until (int fd, finder_t finder, int bufsize)
+   The idea is to be able to read a line of input, or otherwise a hunk
+   of text, such as the head of an HTTP request, without crossing the
+   boundary, so that the next call to fd_read etc. reads the data
+   after the hunk.  To achieve that, this function does the following:
+
+   1. Peek at available data.
+
+   2. Determine whether the peeked data, along with the previously
+      read data, includes the terminator.
+
+      2a. If yes, read the data until the end of the terminator, and
+          exit.
+
+      2b. If no, read the peeked data and goto 1.
+
+   The function is careful to assume as little as possible about the
+   implementation of peeking.  For example, every peek is followed by
+   a read.  If the read returns a different amount of data, the
+   process is retried until all data arrives safely.
+
+   SIZEHINT is the buffer size sufficient to hold all the data in the
+   typical case (it is used as the initial buffer size).  MAXSIZE is
+   the maximum amount of memory this function is allowed to allocate,
+   or 0 if no upper limit is to be enforced.
+
+   This function should be used as a building block for other
+   functions -- see fd_read_line as a simple example.  */
+
+char *
+fd_read_hunk (int fd, hunk_terminator_t terminator, long sizehint, long maxsize)
 {
 {
-  int size = bufsize, tail = 0;
-  char *buf = xmalloc (size);
+  long bufsize = sizehint;
+  char *hunk = xmalloc (bufsize);
+  int tail = 0;                        /* tail position in HUNK */
+
+  assert (maxsize >= bufsize);
 
   while (1)
     {
 
   while (1)
     {
@@ -287,23 +392,28 @@ fd_read_until (int fd, finder_t finder, int bufsize)
 
       /* First, peek at the available data. */
 
 
       /* First, peek at the available data. */
 
-      pklen = fd_peek (fd, buf + tail, size - tail, -1);
+      pklen = fd_peek (fd, hunk + tail, bufsize - 1 - tail, -1);
       if (pklen < 0)
        {
       if (pklen < 0)
        {
-         xfree (buf);
+         xfree (hunk);
          return NULL;
        }
          return NULL;
        }
-      end = finder (buf, tail, pklen);
+      end = terminator (hunk, tail, pklen);
       if (end)
        {
       if (end)
        {
-         /* The data contains the terminator: we'll read the data up
+         /* The data contains the terminator: we'll drain the data up
             to the end of the terminator.  */
             to the end of the terminator.  */
-         remain = end - (buf + tail);
-         /* Note +1 for trailing \0. */
-         if (size < tail + remain + 1)
+         remain = end - (hunk + tail);
+         if (remain == 0)
            {
            {
-             size = tail + remain + 1;
-             buf = xrealloc (buf, size);
+             /* No more data needs to be read. */
+             hunk[tail] = '\0';
+             return hunk;
+           }
+         if (bufsize - 1 < tail + remain)
+           {
+             bufsize = tail + remain + 1;
+             hunk = xrealloc (hunk, bufsize);
            }
        }
       else
            }
        }
       else
@@ -315,62 +425,71 @@ fd_read_until (int fd, finder_t finder, int bufsize)
         how much data we'll get.  (Some TCP stacks are notorious for
         read returning less data than the previous MSG_PEEK.)  */
 
         how much data we'll get.  (Some TCP stacks are notorious for
         read returning less data than the previous MSG_PEEK.)  */
 
-      rdlen = fd_read (fd, buf + tail, remain, 0);
+      rdlen = fd_read (fd, hunk + tail, remain, 0);
       if (rdlen < 0)
        {
       if (rdlen < 0)
        {
-         xfree_null (buf);
+         xfree_null (hunk);
          return NULL;
        }
          return NULL;
        }
+      tail += rdlen;
+      hunk[tail] = '\0';
+
       if (rdlen == 0)
        {
          if (tail == 0)
            {
              /* EOF without anything having been read */
       if (rdlen == 0)
        {
          if (tail == 0)
            {
              /* EOF without anything having been read */
-             xfree (buf);
+             xfree (hunk);
              errno = 0;
              return NULL;
            }
              errno = 0;
              return NULL;
            }
-         /* Return what we received so far. */
-         if (size < tail + 1)
-           {
-             size = tail + 1;  /* expand the buffer to receive the
-                                  terminating \0 */
-             buf = xrealloc (buf, size);
-           }
-         buf[tail] = '\0';
-         return buf;
+         else
+           /* EOF seen: return the data we've read. */
+           return hunk;
        }
        }
-      tail += rdlen;
       if (end && rdlen == remain)
       if (end && rdlen == remain)
-       {
-         /* The end was seen and the data read -- we got what we came
-            for.  */
-         buf[tail] = '\0';
-         return buf;
-       }
+       /* The terminator was seen and the remaining data drained --
+          we got what we came for.  */
+       return hunk;
 
       /* Keep looping until all the data arrives. */
 
 
       /* Keep looping until all the data arrives. */
 
-      if (tail == size)
+      if (tail == bufsize - 1)
        {
        {
-         size <<= 1;
-         buf = xrealloc (buf, size);
+         /* Double the buffer size, but refuse to allocate more than
+            MAXSIZE bytes.  */
+         if (maxsize && bufsize >= maxsize)
+           {
+             xfree (hunk);
+             errno = ENOMEM;
+             return NULL;
+           }
+         bufsize <<= 1;
+         if (maxsize && bufsize > maxsize)
+           bufsize = maxsize;
+         hunk = xrealloc (hunk, bufsize);
        }
     }
 }
 
 static const char *
        }
     }
 }
 
 static const char *
-line_terminator (const char *buf, int tail, int peeklen)
+line_terminator (const char *hunk, int oldlen, int peeklen)
 {
 {
-  const char *p = memchr (buf + tail, '\n', peeklen);
+  const char *p = memchr (hunk + oldlen, '\n', peeklen);
   if (p)
     /* p+1 because we want the line to include '\n' */
     return p + 1;
   return NULL;
 }
 
   if (p)
     /* p+1 because we want the line to include '\n' */
     return p + 1;
   return NULL;
 }
 
+/* The maximum size of the single line we agree to accept.  This is
+   not meant to impose an arbitrary limit, but to protect the user
+   from Wget slurping up available memory upon encountering malicious
+   or buggy server output.  Define it to 0 to remove the limit.  */
+#define FD_READ_LINE_MAX 4096
+
 /* Read one line from FD and return it.  The line is allocated using
 /* Read one line from FD and return it.  The line is allocated using
-   malloc.
+   malloc, but is never larger than FD_READ_LINE_MAX.
 
    If an error occurs, or if no data can be read, NULL is returned.
    In the former case errno indicates the error condition, and in the
 
    If an error occurs, or if no data can be read, NULL is returned.
    In the former case errno indicates the error condition, and in the
@@ -379,53 +498,17 @@ line_terminator (const char *buf, int tail, int peeklen)
 char *
 fd_read_line (int fd)
 {
 char *
 fd_read_line (int fd)
 {
-  return fd_read_until (fd, line_terminator, 128);
-}
-
-static const char *
-head_terminator (const char *buf, int tail, int peeklen)
-{
-  const char *start, *end;
-  if (tail < 4)
-    start = buf;
-  else
-    start = buf + tail - 4;
-  end = buf + tail + peeklen;
-
-  for (; start < end - 1; start++)
-    if (*start == '\n')
-      {
-       if (start < end - 2
-           && start[1] == '\r'
-           && start[2] == '\n')
-         return start + 3;
-       if (start[1] == '\n')
-         return start + 2;
-      }
-  return NULL;
-}
-
-/* Read the request head from FD and return it.  The chunk of data is
-   allocated using malloc.
-
-   If an error occurs, or if no data can be read, NULL is returned.
-   In the former case errno indicates the error condition, and in the
-   latter case, errno is NULL.  */
-
-char *
-fd_read_head (int fd)
-{
-  return fd_read_until (fd, head_terminator, 512);
+  return fd_read_hunk (fd, line_terminator, 128, FD_READ_LINE_MAX);
 }
 \f
 /* Return a printed representation of the download rate, as
    appropriate for the speed.  If PAD is non-zero, strings will be
    padded to the width of 7 characters (xxxx.xx).  */
 char *
 }
 \f
 /* Return a printed representation of the download rate, as
    appropriate for the speed.  If PAD is non-zero, strings will be
    padded to the width of 7 characters (xxxx.xx).  */
 char *
-retr_rate (long bytes, double msecs, int pad)
+retr_rate (wgint bytes, double msecs, int pad)
 {
   static char res[20];
 {
   static char res[20];
-  static char *rate_names[] = {"B/s", "KB/s", "MB/s", "GB/s" };
+  static const char *rate_names[] = {"B/s", "KB/s", "MB/s", "GB/s" };
   int units = 0;
 
   double dlrate = calc_rate (bytes, msecs, &units);
   int units = 0;
 
   double dlrate = calc_rate (bytes, msecs, &units);
@@ -442,7 +525,7 @@ retr_rate (long bytes, double msecs, int pad)
    UNITS is zero for B/s, one for KB/s, two for MB/s, and three for
    GB/s.  */
 double
    UNITS is zero for B/s, one for KB/s, two for MB/s, and three for
    GB/s.  */
 double
-calc_rate (long bytes, double msecs, int *units)
+calc_rate (wgint bytes, double msecs, int *units)
 {
   double dlrate;
 
 {
   double dlrate;
 
@@ -451,11 +534,12 @@ calc_rate (long bytes, double msecs, int *units)
 
   if (msecs == 0)
     /* If elapsed time is exactly zero, it means we're under the
 
   if (msecs == 0)
     /* If elapsed time is exactly zero, it means we're under the
-       granularity of the timer.  This often happens on systems that
-       use time() for the timer.  */
-    msecs = wtimer_granularity ();
+       granularity of the timer.  This can easily happen on systems
+       that use time() for the timer.  Since the interval lies between
+       0 and the timer's granularity, assume half the granularity.  */
+    msecs = ptimer_granularity () / 2.0;
 
 
-  dlrate = (double)1000 * bytes / msecs;
+  dlrate = 1000.0 * bytes / msecs;
   if (dlrate < 1024.0)
     *units = 0;
   else if (dlrate < 1024.0 * 1024.0)
   if (dlrate < 1024.0)
     *units = 0;
   else if (dlrate < 1024.0 * 1024.0)
@@ -630,7 +714,7 @@ retrieve_url (const char *origurl, char **file, char **newloc,
       newloc_parsed = url_parse (mynewloc, &up_error_code);
       if (!newloc_parsed)
        {
       newloc_parsed = url_parse (mynewloc, &up_error_code);
       if (!newloc_parsed)
        {
-         logprintf (LOG_NOTQUIET, "%s: %s.\n", mynewloc,
+         logprintf (LOG_NOTQUIET, "%s: %s.\n", escnonprint_uri (mynewloc),
                     url_error (up_error_code));
          url_free (u);
          xfree (url);
                     url_error (up_error_code));
          url_free (u);
          xfree (url);
@@ -707,7 +791,6 @@ retrieve_url (const char *origurl, char **file, char **newloc,
       xfree (url);
     }
 
       xfree (url);
     }
 
-  ++global_download_count;
   RESTORE_POST_DATA;
 
   return result;
   RESTORE_POST_DATA;
 
   return result;
@@ -846,7 +929,7 @@ rotate_backups(const char *fname)
   int maxlen = strlen (fname) + 1 + numdigit (opt.backups) + 1;
   char *from = (char *)alloca (maxlen);
   char *to = (char *)alloca (maxlen);
   int maxlen = strlen (fname) + 1 + numdigit (opt.backups) + 1;
   char *from = (char *)alloca (maxlen);
   char *to = (char *)alloca (maxlen);
-  struct stat sb;
+  struct_stat sb;
   int i;
 
   if (stat (fname, &sb) == 0)
   int i;
 
   if (stat (fname, &sb) == 0)
@@ -904,7 +987,7 @@ getproxy (struct url *u)
   rewritten_url = rewrite_shorthand_url (proxy);
   if (rewritten_url)
     {
   rewritten_url = rewrite_shorthand_url (proxy);
   if (rewritten_url)
     {
-      strncpy (rewritten_storage, rewritten_url, sizeof(rewritten_storage));
+      strncpy (rewritten_storage, rewritten_url, sizeof (rewritten_storage));
       rewritten_storage[sizeof (rewritten_storage) - 1] = '\0';
       proxy = rewritten_storage;
     }
       rewritten_storage[sizeof (rewritten_storage) - 1] = '\0';
       proxy = rewritten_storage;
     }