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

📄 ftp.c

📁 一个从网络上自动下载文件的自由工具
💻 C
📖 第 1 页 / 共 4 页
字号:
/* File Transfer Protocol support.   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(at your 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>#include <string.h>#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <assert.h>#include <errno.h>#include <time.h>#include "wget.h"#include "utils.h"#include "url.h"#include "retr.h"#include "ftp.h"#include "connect.h"#include "host.h"#include "netrc.h"#include "convert.h"            /* for downloaded_file */#include "recur.h"              /* for INFINITE_RECURSION *//* File where the "ls -al" listing will be saved.  */#ifdef MSDOS#define LIST_FILENAME "_listing"#else#define LIST_FILENAME ".listing"#endiftypedef struct{  int st;                       /* connection status */  int cmd;                      /* command code */  int csock;                    /* control connection socket */  double dltime;                /* time of the download in msecs */  enum stype rs;                /* remote system reported by ftp server */   char *id;                     /* initial directory */  char *target;                 /* target file name */  struct url *proxy;            /* FTWK-style proxy */} ccon;/* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in   the string S, and return the number converted to wgint, if found, 0   otherwise.  */static wgintftp_expected_bytes (const char *s){  wgint res;  while (1)    {      while (*s && *s != '(')        ++s;      if (!*s)        return 0;      ++s;                      /* skip the '(' */      res = str_to_wgint (s, (char **) &s, 10);      if (!*s)        return 0;      while (*s && ISSPACE (*s))        ++s;      if (!*s)        return 0;      if (TOLOWER (*s) != 'b')        continue;      if (strncasecmp (s, "byte", 4))        continue;      else        break;    }  return res;}#ifdef ENABLE_IPV6/*  * This function sets up a passive data connection with the FTP server. * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv. */static uerr_tftp_do_pasv (int csock, ip_address *addr, int *port){  uerr_t err;  /* We need to determine the address family and need to call     getpeername, so while we're at it, store the address to ADDR.     ftp_pasv and ftp_lpsv can simply override it.  */  if (!socket_ip_address (csock, addr, ENDPOINT_PEER))    abort ();  /* If our control connection is over IPv6, then we first try EPSV and then    * LPSV if the former is not supported. If the control connection is over    * IPv4, we simply issue the good old PASV request. */  switch (addr->family)    {    case AF_INET:      if (!opt.server_response)        logputs (LOG_VERBOSE, "==> PASV ... ");      err = ftp_pasv (csock, addr, port);      break;    case AF_INET6:      if (!opt.server_response)        logputs (LOG_VERBOSE, "==> EPSV ... ");      err = ftp_epsv (csock, addr, port);      /* If EPSV is not supported try LPSV */      if (err == FTPNOPASV)        {          if (!opt.server_response)            logputs (LOG_VERBOSE, "==> LPSV ... ");          err = ftp_lpsv (csock, addr, port);        }      break;    default:      abort ();    }  return err;}/*  * This function sets up an active data connection with the FTP server. * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port. */static uerr_tftp_do_port (int csock, int *local_sock){  uerr_t err;  ip_address cip;  if (!socket_ip_address (csock, &cip, ENDPOINT_PEER))    abort ();  /* If our control connection is over IPv6, then we first try EPRT and then    * LPRT if the former is not supported. If the control connection is over    * IPv4, we simply issue the good old PORT request. */  switch (cip.family)    {    case AF_INET:      if (!opt.server_response)        logputs (LOG_VERBOSE, "==> PORT ... ");      err = ftp_port (csock, local_sock);      break;    case AF_INET6:      if (!opt.server_response)        logputs (LOG_VERBOSE, "==> EPRT ... ");      err = ftp_eprt (csock, local_sock);      /* If EPRT is not supported try LPRT */      if (err == FTPPORTERR)        {          if (!opt.server_response)            logputs (LOG_VERBOSE, "==> LPRT ... ");          err = ftp_lprt (csock, local_sock);        }      break;    default:      abort ();    }  return err;}#elsestatic uerr_tftp_do_pasv (int csock, ip_address *addr, int *port){  if (!opt.server_response)    logputs (LOG_VERBOSE, "==> PASV ... ");  return ftp_pasv (csock, addr, port);}static uerr_tftp_do_port (int csock, int *local_sock){  if (!opt.server_response)    logputs (LOG_VERBOSE, "==> PORT ... ");  return ftp_port (csock, local_sock);}#endifstatic voidprint_length (wgint size, wgint start, bool authoritative){  logprintf (LOG_VERBOSE, _("Length: %s"), number_to_static_string (size));  if (size >= 1024)    logprintf (LOG_VERBOSE, " (%s)", human_readable (size));  if (start > 0)    {      if (start >= 1024)        logprintf (LOG_VERBOSE, _(", %s (%s) remaining"),                   number_to_static_string (size - start),                   human_readable (size - start));      else        logprintf (LOG_VERBOSE, _(", %s remaining"),                   number_to_static_string (size - start));    }  logputs (LOG_VERBOSE, !authoritative ? _(" (unauthoritative)\n") : "\n");}/* Retrieves a file with denoted parameters through opening an FTP   connection to the server.  It always closes the data connection,   and closes the control connection in case of error.  */static uerr_tgetftp (struct url *u, wgint *len, wgint restval, ccon *con){  int csock, dtsock, local_sock, res;  uerr_t err = RETROK;          /* appease the compiler */  FILE *fp;  char *user, *passwd, *respline;  char *tms;  const char *tmrate;  int cmd = con->cmd;  bool pasv_mode_open = false;  wgint expected_bytes = 0;  bool rest_failed = false;  int flags;  wgint rd_size;  assert (con != NULL);  assert (con->target != NULL);  /* Debug-check of the sanity of the request by making sure that LIST     and RETR are never both requested (since we can handle only one     at a time.  */  assert (!((cmd & DO_LIST) && (cmd & DO_RETR)));  /* Make sure that at least *something* is requested.  */  assert ((cmd & (DO_LIST | DO_CWD | DO_RETR | DO_LOGIN)) != 0);  user = u->user;  passwd = u->passwd;  search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);  user = user ? user : (opt.ftp_user ? opt.ftp_user : opt.user);  if (!user) user = "anonymous";  passwd = passwd ? passwd : (opt.ftp_passwd ? opt.ftp_passwd : opt.passwd);  if (!passwd) passwd = "-wget@";  dtsock = -1;  local_sock = -1;  con->dltime = 0;  if (!(cmd & DO_LOGIN))    csock = con->csock;  else                          /* cmd & DO_LOGIN */    {      char type_char;      char    *host = con->proxy ? con->proxy->host : u->host;      int      port = con->proxy ? con->proxy->port : u->port;      char *logname = user;      if (con->proxy)        {          /* If proxy is in use, log in as username@target-site. */          logname = concat_strings (user, "@", u->host, (char *) 0);        }      /* Login to the server: */      /* First: Establish the control connection.  */      csock = connect_to_host (host, port);      if (csock == E_HOST)        return HOSTERR;      else if (csock < 0)        return (retryable_socket_connect_error (errno)                ? CONERROR : CONIMPOSSIBLE);      if (cmd & LEAVE_PENDING)        con->csock = csock;      else        con->csock = -1;      /* Second: Login with proper USER/PASS sequence.  */      logprintf (LOG_VERBOSE, _("Logging in as %s ... "), escnonprint (user));      if (opt.server_response)        logputs (LOG_ALWAYS, "\n");      err = ftp_login (csock, logname, passwd);      if (con->proxy)        xfree (logname);      /* FTPRERR, FTPSRVERR, WRITEFAILED, FTPLOGREFUSED, FTPLOGINC */      switch (err)        {        case FTPRERR:          logputs (LOG_VERBOSE, "\n");          logputs (LOG_NOTQUIET, _("\Error in server response, closing control connection.\n"));          fd_close (csock);          con->csock = -1;          return err;        case FTPSRVERR:          logputs (LOG_VERBOSE, "\n");          logputs (LOG_NOTQUIET, _("Error in server greeting.\n"));          fd_close (csock);          con->csock = -1;          return err;        case WRITEFAILED:          logputs (LOG_VERBOSE, "\n");          logputs (LOG_NOTQUIET,                   _("Write failed, closing control connection.\n"));          fd_close (csock);          con->csock = -1;          return err;        case FTPLOGREFUSED:          logputs (LOG_VERBOSE, "\n");          logputs (LOG_NOTQUIET, _("The server refuses login.\n"));          fd_close (csock);          con->csock = -1;          return FTPLOGREFUSED;        case FTPLOGINC:          logputs (LOG_VERBOSE, "\n");          logputs (LOG_NOTQUIET, _("Login incorrect.\n"));          fd_close (csock);          con->csock = -1;          return FTPLOGINC;        case FTPOK:          if (!opt.server_response)            logputs (LOG_VERBOSE, _("Logged in!\n"));          break;        default:          abort ();        }      /* Third: Get the system type */      if (!opt.server_response)        logprintf (LOG_VERBOSE, "==> SYST ... ");      err = ftp_syst (csock, &con->rs);      /* FTPRERR */      switch (err)        {        case FTPRERR:          logputs (LOG_VERBOSE, "\n");          logputs (LOG_NOTQUIET, _("\Error in server response, closing control connection.\n"));          fd_close (csock);          con->csock = -1;          return err;        case FTPSRVERR:          logputs (LOG_VERBOSE, "\n");          logputs (LOG_NOTQUIET,                   _("Server error, can't determine system type.\n"));          break;        case FTPOK:          /* Everything is OK.  */          break;        default:          abort ();        }      if (!opt.server_response && err != FTPSRVERR)        logputs (LOG_VERBOSE, _("done.    "));      /* Fourth: Find the initial ftp directory */      if (!opt.server_response)        logprintf (LOG_VERBOSE, "==> PWD ... ");      err = ftp_pwd (csock, &con->id);      /* FTPRERR */      switch (err)        {        case FTPRERR:          logputs (LOG_VERBOSE, "\n");          logputs (LOG_NOTQUIET, _("\Error in server response, closing control connection.\n"));          fd_close (csock);          con->csock = -1;          return err;        case FTPSRVERR :          /* PWD unsupported -- assume "/". */          xfree_null (con->id);          con->id = xstrdup ("/");          break;        case FTPOK:          /* Everything is OK.  */          break;        default:          abort ();        }      /* VMS will report something like "PUB$DEVICE:[INITIAL.FOLDER]".         Convert it to "/INITIAL/FOLDER" */       if (con->rs == ST_VMS)        {          char *path = strchr (con->id, '[');          char *pathend = path ? strchr (path + 1, ']') : NULL;          if (!path || !pathend)            DEBUGP (("Initial VMS directory not in the form [...]!\n"));          else            {              char *idir = con->id;              DEBUGP (("Preprocessing the initial VMS directory\n"));              DEBUGP (("  old = '%s'\n", con->id));              /* We do the conversion in-place by copying the stuff                 between [ and ] to the beginning, and changing dots                 to slashes at the same time.  */              *idir++ = '/';              for (++path; path < pathend; path++, idir++)                *idir = *path == '.' ? '/' : *path;              *idir = '\0';              DEBUGP (("  new = '%s'\n\n", con->id));            }        }      if (!opt.server_response)        logputs (LOG_VERBOSE, _("done.\n"));      /* Fifth: Set the FTP type.  */      type_char = ftp_process_type (u->params);      if (!opt.server_response)        logprintf (LOG_VERBOSE, "==> TYPE %c ... ", type_char);      err = ftp_type (csock, type_char);      /* FTPRERR, WRITEFAILED, FTPUNKNOWNTYPE */      switch (err)        {        case FTPRERR:          logputs (LOG_VERBOSE, "\n");          logputs (LOG_NOTQUIET, _("\Error in server response, closing control connection.\n"));          fd_close (csock);          con->csock = -1;          return err;        case WRITEFAILED:          logputs (LOG_VERBOSE, "\n");          logputs (LOG_NOTQUIET,                   _("Write failed, closing control connection.\n"));          fd_close (csock);          con->csock = -1;          return err;        case FTPUNKNOWNTYPE:          logputs (LOG_VERBOSE, "\n");          logprintf (LOG_NOTQUIET,                     _("Unknown type `%c', closing control connection.\n"),                     type_char);          fd_close (csock);          con->csock = -1;          return err;        case FTPOK:          /* Everything is OK.  */          break;        default:          abort ();        }      if (!opt.server_response)        logputs (LOG_VERBOSE, _("done.  "));    } /* do login */  if (cmd & DO_CWD)    {      if (!*u->dir)        logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));      else        {

⌨️ 快捷键说明

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