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

📄 ftp.c

📁 很好的命令行下载工具.开发环境为unix/linux
💻 C
📖 第 1 页 / 共 4 页
字号:
/* File Transfer Protocol support.   Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001   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 2 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, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.In addition, as a special exception, the Free Software Foundationgives permission to link the code of its release of Wget with theOpenSSL project's "OpenSSL" library (or with modified versions of itthat use the same license as the "OpenSSL" library), and distributethe linked executables.  You must obey the GNU General Public Licensein all respects for all of the code used other than "OpenSSL".  If youmodify this file, you may extend this exception to your version of thefile, but you are not obligated to do so.  If you do not wish to doso, delete this exception statement from your version.  */#include <config.h>#include <stdio.h>#include <stdlib.h>#ifdef HAVE_STRING_H# include <string.h>#else# include <strings.h>#endif#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <sys/types.h>#include <assert.h>#include <errno.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 */#ifndef errnoextern int errno;#endifextern SUM_SIZE_INT total_downloaded_bytes;/* File where the "ls -al" listing will be saved.  */#define LIST_FILENAME ".listing"extern char ftp_last_respline[];extern FILE *output_stream;extern int output_stream_regular;typedef 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->type)    {    case IPV4_ADDRESS:      if (!opt.server_response)        logputs (LOG_VERBOSE, "==> PASV ... ");      err = ftp_pasv (csock, addr, port);      break;    case IPV6_ADDRESS:      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.type)    {    case IPV4_ADDRESS:      if (!opt.server_response)        logputs (LOG_VERBOSE, "==> PORT ... ");      err = ftp_port (csock, local_sock);      break;    case IPV6_ADDRESS:      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, int authoritative){  logprintf (LOG_VERBOSE, _("Length: %s"), with_thousand_seps (size));  if (size >= 1024)    logprintf (LOG_VERBOSE, " (%s)", human_readable (size));  if (start > 0)    {      if (start >= 1024)	logprintf (LOG_VERBOSE, _(", %s (%s) remaining"),		   with_thousand_seps (size - start),		   human_readable (size - start));      else	logprintf (LOG_VERBOSE, _(", %s remaining"),		   with_thousand_seps (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, *tmrate;  int cmd = con->cmd;  int pasv_mode_open = 0;  wgint expected_bytes = 0;  int rest_failed = 0;  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 */

⌨️ 快捷键说明

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