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

📄 ftp.c

📁 站点映像程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    sitecopy, for managing remote web sites. Generic(ish) FTP routines.   Copyright (C) 1998-99, Joe Orton <joe@orton.demon.co.uk> (except   where otherwise indicated).                                                                        This program 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   (at your option) any later version.     This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   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   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     $Id: ftp.c,v 1.12.2.6 1999/08/19 10:26:07 joe Exp $*//* This contains an FTP client implementation. * It performs transparent connection management - it it dies, * it will be reconnected automagically. */#include <config.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <netinet/in.h>#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <time.h>#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_STRINGS_H#include <strings.h>#endif #ifdef HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#ifdef HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#ifndef HAVE_SNPRINTF#include "snprintf.h"#endif#include "common.h"#include "frontend.h"#include "ftp.h"#include "protocol.h"#include "socket.h"char ftp_error[BUFSIZ];bool ftp_use_passive = true; /* whether we use PASV mode or not *//* The address of the server for the DTP connection -  * this goes here because it's got from ftp_read() rather than in a decent * manner */unsigned short ftp_dtp_port;struct in_addr ftp_dtp_addr;int ftp_dtp_socket;struct in_addr ftp_pi_addr;unsigned short ftp_pi_port;int ftp_pi_socket;bool ftp_connection; /* true when open *//* Reply codes - these are returned by internal functions, * ftp_exec and ftp_open mainly. */#define FTP_OK 0#define FTP_NEEDPASSWORD 1#define FTP_PASSIVE 2#define FTP_READY 3#define FTP_FILEMORE 4#define FTP_MODTIME 5#define FTP_SENT 6#define FTP_CLOSED 101#define FTP_FILEBAD 102#define FTP_CONNECT 992#define FTP_HELLO 993#define FTP_LOGIN 994#define FTP_BROKEN 995#define FTP_DENIED 996#define FTP_UNSUPPORTED 997#define FTP_NOPASSIVE 998#define FTP_ERROR 999/* time from MDTM response */time_t ftp_modtime;/* remember these... we may have to log in more than once. */char *ftp_username, *ftp_password;/* Stores the current transfer type is: *  -1: Unknown *   0: Binary *   1: ASCII */int ftp_using_ascii;/* Opens the control connection if necessary. * Returns: *   FTP_OK on success *   FTP_CONNECT on failed socket connect *   FTP_HELLO if the greeting message couldn't be read *   FTP_LOGIN on failed login */int ftp_open( void );int ftp_close( void );int ftp_fetch_gettree( const char *startdir, struct proto_file_t **files );int ftp_fetch_walktree( const char *rotodir, struct proto_file_t *files );int ftp_login( void ); /* Performs the login procedure */int ftp_settype( bool ascii );int ftp_active_open(const char * );int ftp_data_open( const char * ); /* Opens the data connection */int ftp_data_close( void ); /* Closes the data connection */int ftp_connect_pasv( void );int ftp_read_pasv( const char * ); /* Used by ftp_response to get the remote IP */int ftp_read_mdtm( const char *response );int ftp_response( const char *, const int ); /* Gets the return code */int get_reply_code( const char * ); /* Used by ftp_response to get the actual code */int ftp_exec( const char * ); /* Executes given command, reads response */int ftp_read( void );/* Initializes the driver + connection. * Returns PROTO_OK on success, or PROTO_LOOKUP if the hostname * could not be resolved. */int ftp_init( const char *remote_root, 	      struct proto_host_t *server, struct proto_host_t *proxy ) {    ftp_pi_port = server->port;    fe_connection( fe_namelookup );    if( host_lookup( server->hostname, &ftp_pi_addr ) )	return PROTO_LOOKUP;    ftp_username = server->username;    ftp_password = server->password;    ftp_connection = false;    ftp_using_ascii = -1; /* unknown */    switch( ftp_open() ) {    case FTP_CONNECT:    case FTP_HELLO:	return PROTO_CONNECT;    case FTP_LOGIN:	return PROTO_AUTH;    default:	return PROTO_OK;    }}/* Cleans up and closes the control connection. * Returns PROTO_OK if the connection is closed, else PROTO_ERROR; */int ftp_finish( void ) {    if( ftp_connection )	if( ftp_close( ) != FTP_CLOSED )	    return PROTO_ERROR;    return PROTO_OK;}/* Closes the PI connection. */int ftp_close( ) {    int ret;    ret = ftp_exec( "QUIT" );    close( ftp_pi_socket );    ftp_connection = false; /* although it should have been done already */    return ret;}/* Creates the given directory * FTP state response */int ftp_mkdir( const char *dir ) {    char command[BUFSIZ];    snprintf( command, BUFSIZ, "MKD %s", dir );    if( ftp_exec( command ) == FTP_OK ) {	return PROTO_OK;    } else {	return PROTO_ERROR;    }} /* Renames or moves a file */int ftp_move( const char *from, const char *to ) {    char command[BUFSIZ];    snprintf( command, BUFSIZ, "RNFR %s", from );    if( ftp_exec( command ) == FTP_FILEMORE ) {	snprintf( command, BUFSIZ, "RNTO %s", to );	if( ftp_exec( command ) == PROTO_OK ) {	    return PROTO_OK;	}    }    return PROTO_ERROR;}int ftp_delete( const char *filename ) {    char command[BUFSIZ];    snprintf( command, BUFSIZ, "DELE %s", filename );    if( ftp_exec( command ) == FTP_OK ) {	return PROTO_OK;    } else {	return PROTO_ERROR;    }}int ftp_rmdir( const char *filename ) {    char command[BUFSIZ];    snprintf( command, BUFSIZ, "RMD %s", filename );    if( ftp_exec( command ) == FTP_OK ) {	return PROTO_OK;    } else {	return PROTO_ERROR;    }}/* FTP non-PASV mode open */int ftp_active_open(const char *command) {    char *a, *p;    int ret;    ksize_t slen;    int listener;    char cmd[BUFSIZ];    struct sockaddr_in gotaddr;    struct sockaddr_in localaddr;    if( ftp_open( ) != FTP_OK ) return FTP_ERROR;        slen = sizeof( localaddr );    if( getsockname( ftp_pi_socket, (struct sockaddr *)&localaddr, &slen ) < 0 ) {	ftp_seterror_err( "Could not get socket name" );	return FTP_ERROR;    }    /* But let bind pick a random port for us to use */    localaddr.sin_port = 0;    /* Create a local socket to accept the connection on */    listener = socket( AF_INET, SOCK_STREAM, 0 );    if ( listener < 0 ) {	ftp_seterror_err( "Could not create socket" );	return FTP_ERROR;    }    /* Bind it to a port. */    if ( bind(listener, (struct sockaddr *)&localaddr, sizeof(struct sockaddr_in)) < 0 ) {	ftp_seterror_err( "Could not bind socket." );	close( listener );	return FTP_ERROR;    }    slen = sizeof( struct sockaddr_in );    if (getsockname(listener, (struct sockaddr *)&gotaddr, &slen) < 0) {	ftp_seterror_err( "Could get get name of socket" );	close( listener );	return FTP_ERROR;    }    if (listen(listener, 1) < 0) {	ftp_seterror_err( "Could not listen for connection" );	close( listener );	return FTP_ERROR;    }    /* Let the remote end know the address of our port.     * Q(joe): Will this actually work on differently-endian machines?      */#define	UC(b)	(((int)b)&0xff)    a = (char *)&gotaddr.sin_addr.s_addr;    p = (char *)&gotaddr.sin_port;        snprintf(cmd, BUFSIZ, "PORT %d,%d,%d,%d,%d,%d",	     UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),	     UC(p[0]), UC(p[1]) );    /* Execute the PORT command */    ret = ftp_exec(cmd);    if( ret != FTP_OK ) {	/* Failed to execute the PORT command - close the socket */	DEBUG( DEBUG_FTP, "PORT command failed.\n" );	close( listener );	return ret;    }    /* Send the command.  This will make the remote end     * initiate the connection.     */    ret = ftp_exec(command);        if( ret != FTP_READY ) {	/* Do they want it? */	DEBUG( DEBUG_FTP, "Command failed.\n" );	close( listener );	return ret;    }    /* Now wait for a connection from the remote end.     */    ftp_dtp_socket = accept( listener, NULL, NULL );    if (ftp_dtp_socket < 0) {	close( listener );	ftp_seterror_err( "Could not accept connection" );	return FTP_ERROR;    }    close( listener );        return ret;}int ftp_chmod( const char *filename, const mode_t mode ) {    char command[BUFSIZ];    snprintf( command, BUFSIZ, "SITE CHMOD %3o %s", mode & 0777, filename );    if( ftp_exec( command ) == FTP_OK ) {	return PROTO_OK;    } else {	return PROTO_ERROR;    }}int ftp_data_open( const char *command ) {    int ret;    if( ftp_use_passive ) {	ret = ftp_exec( "PASV" );	if( ret == FTP_PASSIVE ) {	    if( ftp_connect_pasv( ) ) {		return ftp_exec( command );	    } else {		return FTP_ERROR;	    }	} else {	    return FTP_NOPASSIVE;	}    } else {	/* we are not using passive mode. */	return ftp_active_open(command);    }}/* Closes the data connection */int ftp_data_close( ) {    /* Read the response line */    if( close( ftp_dtp_socket ) < 0 ) {	ftp_seterror_err( "Error closing data socket" );	return FTP_ERROR;    } else {	return ftp_read();    }}/* Set the transfer type appropriately. * Only set it if it *needs* setting, though. * Returns FTP_OK on success, or something else otherwise. */int ftp_settype( bool ascii ) {    int newascii, ret;    newascii = ascii?1:0;    if( (ftp_using_ascii == -1) || (newascii != ftp_using_ascii ) ) {	ret = ftp_exec( ascii?"TYPE A":"TYPE I" );	if( ret == FTP_OK ) {	    ftp_using_ascii = newascii;	} else {	    ftp_using_ascii = -1; /* unknown */	}    } else {	ret = FTP_OK;    }    return ret;}/* upload the given file */int ftp_put( const char *localfile, const char *remotefile, const bool ascii ) {    char command[BUFSIZ];    /* Set the transfer type correctly */    if( ftp_settype( ascii ) != FTP_OK )	return PROTO_ERROR;    snprintf( command, BUFSIZ, "STOR %s", remotefile );    if( ftp_data_open( command ) == FTP_READY ) {	int ret;	/* Send the file. FIXME: We rely on the server's return	 * code to determine whether the transfer was successful. */	if( ascii ) {	    ret = send_file_ascii( ftp_dtp_socket, localfile );	} else {	    ret = send_file_binary( ftp_dtp_socket, localfile );	}	if( ret > 0 ) { 	    DEBUG( DEBUG_FTP, "Error sending file... ignoring.\n" );	}	if( ftp_data_close( ) == FTP_SENT ) {	    return PROTO_OK;	}    }    return PROTO_ERROR;}/* Slightly dodgy ftp_get in that you need to know the remote file * size. Works, but not very generic. */int ftp_get( const char *localfile, const char *remotefile, 	     const int remotesize, const bool ascii ) {    char command[BUFSIZ];    int ret;    if(ascii) strcpy( command, "TYPE A" );    else strcpy( command, "TYPE I");    ret = ftp_exec( command );    snprintf( command, BUFSIZ, "RETR %s", remotefile );    if( ftp_data_open( command ) == FTP_READY ) {	/* send the file */	recv_file( ftp_dtp_socket, localfile, remotesize );	if( ftp_data_close( ) == FTP_SENT ) {	    return PROTO_OK;	}    }    return PROTO_ERROR;

⌨️ 快捷键说明

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