⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 retr.c

📁 一个从网络上自动下载文件的自由工具
💻 C
📖 第 1 页 / 共 3 页
字号:
/* File retrieval.   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.This file is part of GNU Wget.GNU Wget is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 3 of the License, or (atyour option) any later version.GNU Wget is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with Wget.  If not, see <http://www.gnu.org/licenses/>.Additional permission under GNU GPL version 3 section 7If you modify this program, or any covered work, by linking orcombining it with the OpenSSL project's OpenSSL library (or amodified version of that library), containing parts covered by theterms of the OpenSSL or SSLeay licenses, the Free Software Foundationgrants you additional permission to convey the resulting work.Corresponding Source for a non-source form of such a combinationshall include the source code for the parts of OpenSSL used as wellas that of the covered work.  */#include <config.h>#include <stdio.h>#include <stdlib.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif /* HAVE_UNISTD_H */#include <errno.h>#include <string.h>#include <assert.h>#include "wget.h"#include "utils.h"#include "retr.h"#include "progress.h"#include "url.h"#include "recur.h"#include "ftp.h"#include "http.h"#include "host.h"#include "connect.h"#include "hash.h"#include "convert.h"#include "ptimer.h"/* Total size of downloaded files.  Used to enforce quota.  */SUM_SIZE_INT total_downloaded_bytes;/* Total download time in seconds. */double total_download_time;/* 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. */bool output_stream_regular;static struct {  wgint chunk_bytes;  double chunk_start;  double sleep_adjust;} limit_data;static voidlimit_bandwidth_reset (void){  xzero (limit_data);}/* Limit the bandwidth by pausing the download for an amount of time.   BYTES is the number of bytes received from the network, and TIMER   is the timer that started at the beginning of download.  */static voidlimit_bandwidth (wgint bytes, struct ptimer *timer){  double delta_t = ptimer_read (timer) - limit_data.chunk_start;  double expected;  limit_data.chunk_bytes += bytes;  /* Calculate the amount of time we expect downloading the chunk     should take.  If in reality it took less time, sleep to     compensate for the difference.  */  expected = (double) limit_data.chunk_bytes / opt.limit_rate;  if (expected > delta_t)    {      double slp = expected - delta_t + limit_data.sleep_adjust;      double t0, t1;      if (slp < 0.2)        {          DEBUGP (("deferring a %.2f ms sleep (%s/%.2f).\n",                   slp * 1000, number_to_static_string (limit_data.chunk_bytes),                   delta_t));          return;        }      DEBUGP (("\nsleeping %.2f ms for %s bytes, adjust %.2f ms\n",               slp * 1000, number_to_static_string (limit_data.chunk_bytes),               limit_data.sleep_adjust));      t0 = ptimer_read (timer);      xsleep (slp);      t1 = ptimer_measure (timer);      /* Due to scheduling, we probably slept slightly longer (or         shorter) than desired.  Calculate the difference between the         desired and the actual sleep, and adjust the next sleep by         that amount.  */      limit_data.sleep_adjust = slp - (t1 - t0);      /* If sleep_adjust is very large, it's likely due to suspension         and not clock inaccuracy.  Don't enforce those.  */      if (limit_data.sleep_adjust > 0.5)        limit_data.sleep_adjust = 0.5;      else if (limit_data.sleep_adjust < -0.5)        limit_data.sleep_adjust = -0.5;    }  limit_data.chunk_bytes = 0;  limit_data.chunk_start = ptimer_read (timer);}#ifndef MIN# define MIN(i, j) ((i) <= (j) ? (i) : (j))#endif/* 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.  */static intwrite_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;    }  fwrite (buf, 1, bufsize, out);  *written += bufsize;  /* 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 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.  */intfd_read_body (int fd, FILE *out, wgint toread, wgint startpos,              wgint *qtyread, wgint *qtywritten, double *elapsed, int flags){  int ret = 0;  static char dlbuf[16384];  int dlbufsize = sizeof (dlbuf);  struct ptimer *timer = NULL;  double last_successful_read_tm = 0;  /* The progress gauge, set according to the user preferences. */  void *progress = NULL;  /* Non-zero if the progress gauge is interactive, i.e. if it can     continually update the display.  When true, smaller timeout     values are used so that the gauge can update the display when     data arrives slowly. */  bool progress_interactive = false;  bool 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 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 ();  /* 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     data and then sleep for 8s.  With buffer size equal to the limit,     we never have to sleep for more than one second.  */  if (opt.limit_rate && opt.limit_rate < dlbufsize)    dlbufsize = opt.limit_rate;  /* 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 rdsize = exact ? MIN (toread - sum_read, dlbufsize) : dlbufsize;      double tmout = opt.read_timeout;      if (progress_interactive)        {          /* 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;          if (opt.read_timeout)            {              double waittm;              waittm = ptimer_read (timer) - last_successful_read_tm;              if (waittm + tmout > opt.read_timeout)                {                  /* 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;                    }                }            }        }      ret = fd_read (fd, dlbuf, rdsize, tmout);      if (progress_interactive && ret < 0 && errno == ETIMEDOUT)        ret = 0;                /* interactive timeout, handled above */      else if (ret <= 0)        break;                  /* EOF or read error */      if (progress || opt.limit_rate)        {          ptimer_measure (timer);          if (ret > 0)            last_successful_read_tm = ptimer_read (timer);        }      if (ret > 0)        {          sum_read += ret;          if (!write_data (out, dlbuf, ret, &skip, &sum_written))            {              ret = -2;              goto out;            }        }      if (opt.limit_rate)        limit_bandwidth (ret, timer);      if (progress)        progress_update (progress, ret, ptimer_read (timer));#ifdef WINDOWS      if (toread > 0 && !opt.quiet)        ws_percenttitle (100.0 *                         (startpos + sum_read) / (startpos + toread));#endif    }  if (ret < -1)    ret = -1; out:  if (progress)    progress_finish (progress, ptimer_read (timer));  if (elapsed)    *elapsed = ptimer_read (timer);  if (timer)    ptimer_destroy (timer);  if (qtyread)    *qtyread += sum_read;  if (qtywritten)    *qtywritten += sum_written;  return ret;}/* Read a hunk of data from FD, up until a terminator.  The hunk is   limited by whatever the TERMINATOR callback chooses as its   terminator.  For example, if terminator stops at newline, the hunk   will consist of a line of data; if terminator stops at two   newlines, it can be used to read the head of an HTTP response.   Upon determining the boundary, the function returns the data (up to   the terminator) in malloc-allocated storage.   In case of read error, NULL is returned.  In case of EOF and no   data read, NULL is returned and errno set to 0.  In case of having   read some data, but encountering EOF before seeing the terminator,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -