ftplib源码剖析

ftplib是一组例程实现FTP协议。他们允许应用程序创建和访问远程文件通过函数调用,而不是需要叉和执行一个交互式的ftp客户端程序。
ftplib已经在Linux上构建和测试(X86)、Mac os x和OpenVMS(AXP)。
很快:我正在使用autotools版本。这应该是释放不久。

以上是ftplib官网上的说明文字。。(FTP官网链接,可以下载代码:http://www.nbpfaus.net/~pfau/ftplib/)


        ftplib是一个小巧的实现FTP协议的一组例程,里面包含了关于FTP各种操作的函数。阅读代码,不仅可以了解一下FTP的具体工作原理,还可以看一下FTP网络编程相关的知识,可谓一举两得。OK,闲话少说,还是直接上代码比较实在大笑

关于FTP的原理说明及FTP的应代码的介绍请参考:计算机网络中关于FTP的介绍和  FTP应答码 

我用的是ftplib-4.0的版本,下载链接:http://download.csdn.net/detail/u012796139/8877857


代码结构说明

        ftplib代码量比较小(总共也就1500行左右代码),主要有2个函数构成,ftplib.c和ftplib.h文件,还有一个测试程序qftp.c文件。

其中,ftplib最主要的一个结构就是NetBuf结构体了,它是ftplib的整个操作核心,包括了一下FTP相关的操作成员等,如下:

struct NetBuf {
    char *cput,*cget; 			/* cput和cget指向该buf的接收缓冲区 */
    int handle;					/* 待处理的文件描述符(比如在handle上设置的select I/O复用) */
    int cavail,cleft;			/* cavail 可用的字节数,*/
    char *buf;					/* 读写缓冲区 */
    int dir;					/* 表明执行的操作,比如write操作时,dir为FTPLIB_WRITE,read操作时,dir为FTPLIB_READ*/
    netbuf *ctrl;				/* 指向控制连接的netbuf */
    netbuf *data;    			/* 指向数据连接的netbuf */   
    int cmode;					/* connection mode 连接模式 可选值:FTPLIB_PASSIVE(被动传输模式) FTPLIB_PORT(主动传输模式) */
    struct timeval idletime;	/* IO复用函数的超时时间,暂时看到select用到了 */
    FtpCallback idlecb;			/* 回调函数,用于IO复用函数的等待 */
    void *idlearg;				/* 传递给idlecb回调函数的参数 */
    unsigned long int xfered;
    unsigned long int cbbytes;	/* 回调函数传输的字节数 */
    unsigned long int xfered1;
    char response[RESPONSE_BUFSIZ]; /* 存放服务器的应答数据*/
};
关于NetBuf中成员的含义直接看注释就行,就不在贴出来了。

FTP的控制操作有两个连接,一个是控制连接,负责命令的传输;另一个是数据连接,负责数据的收发等,比如上传下载等就是走的数据连接。


源代码分析

下面是ftplib.h头文件

/***************************************************************************/
/*									   */
/* ftplib.h - header file for callable ftp access routines                 */
/* Copyright (C) 1996-2001, 2013 Thomas Pfau, tfpfau@gmail.com		   */
/*	1407 Thomas Ave, North Brunswick, NJ, 08902			   */
/*									   */
/* This library is free software.  You can redistribute it and/or	   */
/* modify it under the terms of the Artistic License 2.0.		   */
/* 									   */
/* This library 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	   */
/* Artistic License 2.0 for more details.				   */
/* 									   */
/* See the file LICENSE or 						   */
/* http://www.perlfoundation.org/artistic_license_2_0			   */
/*									   */
/***************************************************************************/

#if !defined(__FTPLIB_H)
#define __FTPLIB_H

#if defined(__unix__) || defined(VMS)
#define GLOBALDEF
#define GLOBALREF extern
#elif defined(_WIN32)
#if defined BUILDING_LIBRARY
#define GLOBALDEF __declspec(dllexport)
#define GLOBALREF __declspec(dllexport)
#else
#define GLOBALREF __declspec(dllimport)
#endif
#endif

#include <limits.h>
#include <inttypes.h>

/* FtpAccess() type codes */
#define FTPLIB_DIR 1
#define FTPLIB_DIR_VERBOSE 2
#define FTPLIB_FILE_READ 3
#define FTPLIB_FILE_WRITE 4

/* FtpAccess() mode codes */
#define FTPLIB_ASCII 'A'
#define FTPLIB_IMAGE 'I'
#define FTPLIB_TEXT FTPLIB_ASCII
#define FTPLIB_BINARY FTPLIB_IMAGE

/* connection modes */
#define FTPLIB_PASSIVE 1
#define FTPLIB_PORT 2

/* connection option names */
#define FTPLIB_CONNMODE 1
#define FTPLIB_CALLBACK 2
#define FTPLIB_IDLETIME 3
#define FTPLIB_CALLBACKARG 4
#define FTPLIB_CALLBACKBYTES 5

#ifdef __cplusplus
extern "C" {
#endif

#if defined(__UINT64_MAX)
typedef uint64_t fsz_t;
#else
typedef uint32_t fsz_t;
#endif

typedef struct NetBuf netbuf;
typedef int (*FtpCallback)(netbuf *nControl, fsz_t xfered, void *arg);

typedef struct FtpCallbackOptions {
    FtpCallback cbFunc;		/* function to call */
    void *cbArg;		/* argument to pass to function */
    unsigned int bytesXferred;	/* callback if this number of bytes transferred */
    unsigned int idleTime;	/* callback if this many milliseconds have elapsed */
} FtpCallbackOptions;

GLOBALREF int ftplib_debug;
GLOBALREF void FtpInit(void);
GLOBALREF char *FtpLastResponse(netbuf *nControl);
GLOBALREF int FtpConnect(const char *host, netbuf **nControl);
GLOBALREF int FtpOptions(int opt, long val, netbuf *nControl);
GLOBALREF int FtpSetCallback(const FtpCallbackOptions *opt, netbuf *nControl);
GLOBALREF int FtpClearCallback(netbuf *nControl);
GLOBALREF int FtpLogin(const char *user, const char *pass, netbuf *nControl);
GLOBALREF int FtpAccess(const char *path, int typ, int mode, netbuf *nControl,
    netbuf **nData);
GLOBALREF int FtpRead(void *buf, int max, netbuf *nData);
GLOBALREF int FtpWrite(const void *buf, int len, netbuf *nData);
GLOBALREF int FtpClose(netbuf *nData);
GLOBALREF int FtpSite(const char *cmd, netbuf *nControl);
GLOBALREF int FtpSysType(char *buf, int max, netbuf *nControl);
GLOBALREF int FtpMkdir(const char *path, netbuf *nControl);
GLOBALREF int FtpChdir(const char *path, netbuf *nControl);
GLOBALREF int FtpCDUp(netbuf *nControl);
GLOBALREF int FtpRmdir(const char *path, netbuf *nControl);
GLOBALREF int FtpPwd(char *path, int max, netbuf *nControl);
GLOBALREF int FtpNlst(const char *output, const char *path, netbuf *nControl);
GLOBALREF int FtpDir(const char *output, const char *path, netbuf *nControl);
GLOBALREF int FtpSize(const char *path, unsigned int *size, char mode, netbuf *nControl);
#if defined(__UINT64_MAX)
GLOBALREF int FtpSizeLong(const char *path, fsz_t *size, char mode, netbuf *nControl);
#endif
GLOBALREF int FtpModDate(const char *path, char *dt, int max, netbuf *nControl);
GLOBALREF int FtpGet(const char *output, const char *path, char mode,
	netbuf *nControl);
GLOBALREF int FtpPut(const char *input, const char *path, char mode,
	netbuf *nControl);
GLOBALREF int FtpRename(const char *src, const char *dst, netbuf *nControl);
GLOBALREF int FtpDelete(const char *fnm, netbuf *nControl);
GLOBALREF void FtpQuit(netbuf *nControl);

#ifdef __cplusplus
};
#endif

#endif /* __FTPLIB_H */

下面是ftplib.c文件

/***************************************************************************/
/*									   */
/* ftplib.c - callable ftp access routines				   */
/* Copyright (C) 1996-2001, 2013 Thomas Pfau, tfpfau@gmail.com		   */
/*	1407 Thomas Ave, North Brunswick, NJ, 08902			   */
/*									   */
/* This library is free software.  You can redistribute it and/or	   */
/* modify it under the terms of the Artistic License 2.0.		   */
/* 									   */
/* This library 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	   */
/* Artistic License 2.0 for more details.				   */
/* 									   */
/* See the file LICENSE or 						   */
/* http://www.perlfoundation.org/artistic_license_2_0			   */
/* 									   */
/***************************************************************************/

#if defined(__unix__) || defined(__VMS)
#include <unistd.h>
#endif
#if defined(_WIN32)
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#if defined(__unix__)
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#elif defined(VMS)
#include <types.h>
#include <socket.h>
#include <in.h>
#include <netdb.h>
#include <inet.h>
#elif defined(_WIN32)
#include <winsock.h>
#endif
#if defined(__APPLE__)
#undef _REENTRANT
#endif

#define BUILDING_LIBRARY
#include "ftplib.h"

#if defined(__UINT64_MAX) && !defined(PRIu64)
#if ULONG_MAX == __UINT32_MAX
#define PRIu64 "llu"
#else
#define PRIu64 "lu"
#endif
#endif

#if defined(_WIN32)
#define SETSOCKOPT_OPTVAL_TYPE (const char *)
#else
#define SETSOCKOPT_OPTVAL_TYPE (void *)
#endif

#define FTPLIB_BUFSIZ 8192
#define RESPONSE_BUFSIZ 1024
#define TMP_BUFSIZ 1024
#define ACCEPT_TIMEOUT 30

#define FTPLIB_CONTROL 0
#define FTPLIB_READ 1
#define FTPLIB_WRITE 2

#if !defined FTPLIB_DEFMODE
#define FTPLIB_DEFMODE FTPLIB_PASSIVE
#endif

struct NetBuf {
    char *cput,*cget; 			/* cput和cget指向该buf的接收缓冲区 */
    int handle;					/* 待处理的文件描述符(比如在handle上设置的select I/O复用) */
    int cavail,cleft;			/* cavail 可用的字节数,*/
    char *buf;					/* 读写缓冲区 */
    int dir;					/* 表明执行的操作,比如write操作时,dir为FTPLIB_WRITE,read操作时,dir为FTPLIB_READ*/
    netbuf *ctrl;				/* 指向控制连接的netbuf */
    netbuf *data;    			/* 指向数据连接的netbuf */   
    int cmode;					/* connection mode 连接模式 可选值:FTPLIB_PASSIVE(被动传输模式) FTPLIB_PORT(主动传输模式) */
    struct timeval idletime;	/* IO复用函数的超时时间,暂时看到select用到了 */
    FtpCallback idlecb;			/* 回调函数,用于IO复用函数的等待 */
    void *idlearg;				/* 传递给idlecb回调函数的参数 */
    unsigned long int xfered;
    unsigned long int cbbytes;	/* 回调函数传输的字节数 */
    unsigned long int xfered1;
    char response[RESPONSE_BUFSIZ]; /* 存放服务器的应答数据*/
};

static char *version =
    "ftplib Release 4.0 07-Jun-2013, copyright 1996-2003, 2013 Thomas Pfau";

GLOBALDEF int ftplib_debug = 0;

#if defined(__unix__) || defined(VMS)
int net_read(int fd, char *buf, size_t len)
{
    while ( 1 )
    {
		int c = read(fd, buf, len);
		if ( c == -1 )
		{
		    if ( errno != EINTR && errno != EAGAIN )
			return -1;
		}
		else
		{
		    return c;
		}
    }
}

int net_write(int fd, const char *buf, size_t len)
{
    int done = 0;
    while ( len > 0 )
    {
	int c = write( fd, buf, len );
	if ( c == -1 )
	{
	    if ( errno != EINTR && errno != EAGAIN )
		return -1;
	}
	else if ( c == 0 )
	{
	    return done;
	}
	else
	{
	    buf += c;
	    done += c;
	    len -= c;
	}
    }
    return done;
}
#define net_close close
#elif defined(_WIN32)
#define net_read(x,y,z) recv(x,y,z,0)
#define net_write(x,y,z) send(x,y,z,0)
#define net_close closesocket
#endif

#if defined(NEED_MEMCCPY)
/*
 * VAX C does not supply a memccpy routine so I provide my own
 * 从src中赋值以c结尾的字符串,赋值的最大字节数为n
 */
void *memccpy(void *dest, const void *src, int c, size_t n)
{
    int i=0;
    const unsigned char *ip=src;
    unsigned char *op=dest;

    while (i < n)
    {
		if ((*op++ = *ip++) == c)
		    break;
		i++;
    }
    if (i == n)
		return NULL; /* 此时src的前n个字符中没有字符c */
    return op;
}
#endif
#if defined(NEED_STRDUP)
/*
 * strdup - return a malloc'ed copy of a string
 */
char *strdup(const char *src)
{
    int l = strlen(src) + 1;
    char *dst = malloc(l);
    if (dst)
        strcpy(dst,src);
    return dst;
}
#endif

/*
 * socket_wait - wait for socket to receive or flush data
 *
 * return 1 if no user callback, otherwise, return value returned by
 * user callback
 * 等待socket就绪,就绪时返回1,否则返回0
 */
static int socket_wait(netbuf *ctl)
{
    fd_set fd,*rfd = NULL,*wfd = NULL;
    struct timeval tv;
    int rv = 0;
    if ((ctl->dir == FTPLIB_CONTROL) || (ctl->idlecb == NULL))
		return 1;
    if (ctl->dir == FTPLIB_WRITE)
		wfd = &fd;
    else
		rfd = &fd;
    FD_ZERO(&fd);
    do
    {
		FD_SET(ctl->handle,&fd);
		tv = ctl->idletime; /* 设定select的超时时间 */
		rv = select(ctl->handle+1, rfd, wfd, NULL, &tv);
		if (rv == -1)
		{
		    rv = 0;
		    strncpy(ctl->ctrl->response, strerror(errno),
	                    sizeof(ctl->ctrl->response)); /* 这个地方问什么把错误信息复制到了ctl->ctrl->response中?*/
		    break;
		}
		else if (rv > 0)
		{
		    rv = 1; /* 为什么再把rv赋值为1呢,因为fd中只有一个文件描述符被监听,所以select最大也就返回1 */
		    break;
		}
    }while ((rv = ctl->idlecb(ctl, ctl->xfered, ctl->idlearg))); /* 设置的idlecb回调函数 */
	
    return rv;
}

/*
 * read a line of text
 * return -1 on error or bytecount
 * ctl->handle存放的是文件描述符
 * 当ctrl->buf中的数据够读时,直接复制到buf中,否则调用net_read进行读取操作
 */
static int readline(char *buf,int max,netbuf *ctl)
{
    int x,retval = 0;
    char *end,*bp=buf;
    int eof = 0;

    if ((ctl->dir != FTPLIB_CONTROL) && (ctl->dir != FTPLIB_READ))
		return -1;
    if (max == 0)
		return 0;
    do
    {
    	if (ctl->cavail > 0)
    	{
		    x = (max >= ctl->cavail) ? ctl->cavail : max-1;
		    end = memccpy(bp,ctl->cget,'\n',x);
		    if (end != NULL)
				x = end - bp;
		    retval += x;
		    bp += x;
		    *bp = '\0';
		    max -= x;
		    ctl->cget += x;  /* 已经读取了x字节数据 */
		    ctl->cavail -= x;
		    if (end != NULL)
		    {
				bp -= 2;
				if (strcmp(bp,"\r\n") == 0) /* 把buf中最后两个字节为\r\n,改为 \n\0 */
				{
				    *bp++ = '\n';
				    *bp++ = '\0';
				    --retval;
				}
			    break;
		    }
    	}

    	if (max == 1) /* max=1说明buf中已容不下输入缓冲区中的一行数据,直接返回,buf数组中最后一位必须存'\0' */
    	{
		    *buf = '\0';
		    break;
    	}
    	if (ctl->cput == ctl->cget) /* 该条件什么时候成立,参考FtpConnect函数中的ctrl = calloc(1,sizeof(netbuf));*/
    	{
		    ctl->cput = ctl->cget = ctl->buf;
		    ctl->cavail = 0;
		    ctl->cleft = FTPLIB_BUFSIZ;
    	}
		if (eof)
		{
		    if (retval == 0)
				retval = -1;
		    break;
		}
		if (!socket_wait(ctl))
		    return retval;
    	if ((x = net_read(ctl->handle,ctl->cput,ctl->cleft)) == -1)
    	{
		    if (ftplib_debug)
				perror("read");
		    retval = -1;
		    break;
    	}
		if (x == 0) /* net_read返回为0 */
		    eof = 1;
    	ctl->cleft -= x;
    	ctl->cavail += x;
    	ctl->cput += x;
    }
    while (1);
    return retval;
}

/*
 * write lines of text
 * return -1 on error or bytecount
 * 写一行数据到dData->handler(文件描述符)
 */
static int writeline(const char *buf, int len, netbuf *nData)
{
    int x, nb=0, w;
    const char *ubp = buf;
    char *nbp;
    char lc=0;

    if (nData->dir != FTPLIB_WRITE)
		return -1;
    nbp = nData->buf;
    for (x=0; x < len; x++)
    {
		if ((*ubp == '\n') && (lc != '\r'))
		{
		    if (nb == FTPLIB_BUFSIZ)
		    {
				if (!socket_wait(nData))
				    return x;
				w = net_write(nData->handle, nbp, FTPLIB_BUFSIZ);
				if (w != FTPLIB_BUFSIZ)
				{
				    if (ftplib_debug)
					printf("net_write(1) returned %d, errno = %d\n", w, errno);
				    return(-1);
				}
				nb = 0;
		    }
		    nbp[nb++] = '\r';
		}
		if (nb == FTPLIB_BUFSIZ) /* 如果nData->buf已满,则发送出去 */
		{
		    if (!socket_wait(nData))
				return x;
		    w = net_write(nData->handle, nbp, FTPLIB_BUFSIZ);
		    if (w != FTPLIB_BUFSIZ)
		    {
				if (ftplib_debug)
				    printf("net_write(2) returned %d, errno = %d\n", w, errno);
				return(-1);
		    }
		    nb = 0;
		}
		nbp[nb++] = lc = *ubp++;
    }
    if (nb)
    {
		if (!socket_wait(nData))
		    return x;
		w = net_write(nData->handle, nbp, nb);
		if (w != nb)
		{
		    if (ftplib_debug)
				printf("net_write(3) returned %d, errno = %d\n", w, errno);
		    return(-1);
		}
    }
    return len;
}

/*
 * read a response from the server
 * return 0 if first char doesn't match
 * return 1 if first char matches
 * 如果应答数据的第一个字符是c的话,返回1,否则返回0
 */
static int readresp(char c, netbuf *nControl)
{
    char match[5];
    if (readline(nControl->response,RESPONSE_BUFSIZ,nControl) == -1)
    {
		if (ftplib_debug)
		    perror("Control socket read failed");
		return 0;
    }
    if (ftplib_debug > 1)
		fprintf(stderr,"%s",nControl->response);
    if (nControl->response[3] == '-') /* 这个条件很少达到 */
    {
		strncpy(match,nControl->response,3);
		match[3] = ' ';
		match[4] = '\0';
		do
		{
		    if (readline(nControl->response,RESPONSE_BUFSIZ,nControl) == -1)
		    {
				if (ftplib_debug)
				    perror("Control socket read failed");
				return 0;
		    }
		    if (ftplib_debug > 1)
				fprintf(stderr,"%s",nControl->response);
		}
		while (strncmp(nControl->response,match,4));
    }
    if (nControl->response[0] == c)
		return 1;
    return 0;
}

/*
 * FtpInit for stupid operating systems that require it (Windows NT)
 * 该函数只有在windows NT中需要首先调用
 */
GLOBALDEF void FtpInit(void)
{
#if defined(_WIN32)
    WORD wVersionRequested;
    WSADATA wsadata;
    int err;
    wVersionRequested = MAKEWORD(1,1);
    if ((err = WSAStartup(wVersionRequested,&wsadata)) != 0)
	fprintf(stderr,"Network failed to start: %d\n",err);
#endif
}

/*
 * FtpLastResponse - return a pointer to the last response received
 * 返回最后一次接收到的服务器应答数据,数据存放在nControl->response中
 */
GLOBALDEF char *FtpLastResponse(netbuf *nControl)
{
    if ((nControl) && (nControl->dir == FTPLIB_CONTROL))
    	return nControl->response;
    return NULL;
}

/*
 * FtpConnect - connect to remote server
 * return 1 if connected, 0 if not
 * 与ftp server进行连接,host存放主机名
 */
GLOBALDEF int FtpConnect(const char *host, netbuf **nControl)
{
    int sControl;
    struct sockaddr_in sin;
    int on=1;
    netbuf *ctrl;
    char *lhost;
    char *pnum;

    memset(&sin,0,sizeof(sin));
    sin.sin_family = AF_INET;
    lhost = strdup(host);
    pnum = strchr(lhost,':');
    if (pnum == NULL)	/* lhost中不包含':' */
		pnum = "ftp";
    else
		*pnum++ = '\0';
    if (isdigit(*pnum))
		sin.sin_port = htons(atoi(pnum));
    else
    {
    	/* 未输入端口号时,获取主机信息,然后 */
		struct servent *pse;
#if _REENTRANT /* 如果是可重入函数 */
		struct servent se;
		char tmpbuf[TMP_BUFSIZ];
		int i;
		if ( ( i = getservbyname_r(pnum,"tcp",&se,tmpbuf,TMP_BUFSIZ,&pse) ) != 0 )
		{
		    errno = i;
		    if ( ftplib_debug )
				perror("getservbyname_r");
		    free(lhost);
		    return 0;
		}
#else
		if ((pse = getservbyname(pnum,"tcp") ) == NULL )
		{
		    if ( ftplib_debug )
				perror("getservbyname");
		    free(lhost); /* 释放strdup申请的内存空间 */
		    return 0;
		}
#endif
		sin.sin_port = pse->s_port; /* 该端口号默认为21,里面存放的为21的网络序 */
    }
    if ((sin.sin_addr.s_addr = inet_addr(lhost)) == INADDR_NONE)
    {
		struct hostent *phe;
#ifdef _REENTRANT
		struct hostent he;
		char tmpbuf[TMP_BUFSIZ];
		int i, herr;
		if ( ( i = gethostbyname_r( lhost, &he, tmpbuf, TMP_BUFSIZ, &phe, &herr ) ) != 0 )
		{
		    if ( ftplib_debug )
			fprintf(stderr, "gethostbyname: %s\n", hstrerror(herr));
		    free(lhost);
		    return 0;
		}
#else
	    	if ((phe = gethostbyname(lhost)) == NULL) /* 获取server主机信息 */
	    	{
		    if (ftplib_debug)
			fprintf(stderr, "gethostbyname: %s\n", hstrerror(h_errno));
		    free(lhost);
		    return 0;
	    	}
#endif
	    	memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
    }
    free(lhost);
    sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sControl == -1)
    {
		if (ftplib_debug)
		    perror("socket");
		return 0;
    }
	/* 端口可重用 */
    if (setsockopt(sControl,SOL_SOCKET,SO_REUSEADDR,
		   SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
    {
		if (ftplib_debug)
		    perror("setsockopt");
		net_close(sControl);
		return 0;
    }
    if (connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1)
    {
		if (ftplib_debug)
		    perror("connect");
		net_close(sControl);
		return 0;
    }
    ctrl = calloc(1,sizeof(netbuf)); /* 分配内存并初始化为0,*/
    if (ctrl == NULL)
    {
		if (ftplib_debug)
		    perror("calloc");
		net_close(sControl);
		return 0;
    }
    ctrl->buf = malloc(FTPLIB_BUFSIZ);
    if (ctrl->buf == NULL)
    {
		if (ftplib_debug)
		    perror("calloc");
		net_close(sControl);
		free(ctrl);
		return 0;
    }
    ctrl->handle = sControl;
    ctrl->dir = FTPLIB_CONTROL;
    ctrl->ctrl = NULL;
    ctrl->cmode = FTPLIB_DEFMODE;
    ctrl->idlecb = NULL;
    ctrl->idletime.tv_sec = ctrl->idletime.tv_usec = 0;
    ctrl->idlearg = NULL;
    ctrl->xfered = 0;
    ctrl->xfered1 = 0;
    ctrl->cbbytes = 0; /* ctrl中的其余变量都已经初始化为0了,ctrl执行的内存使用calloc分配的 */

	/* 如果应答开头是'2',表示命令成功
	 * FTP应答码: http://t175010415.blog.163.com/blog/static/1317066342012111914836972/
	 */
    if (readresp('2', ctrl) == 0)
    {
		net_close(sControl);
		free(ctrl->buf);
		free(ctrl);
		return 0;
    }
    *nControl = ctrl;
    return 1;
}

/*
 * 创建和清除回调函数
 */
GLOBALDEF int FtpSetCallback(const FtpCallbackOptions *opt, netbuf *nControl)
{
    nControl->idlecb = opt->cbFunc;
    nControl->idlearg = opt->cbArg;
    nControl->idletime.tv_sec = opt->idleTime / 1000;
    nControl->idletime.tv_usec = (opt->idleTime % 1000) * 1000;
    nControl->cbbytes = opt->bytesXferred;
    return 1;
}
GLOBALDEF int FtpClearCallback(netbuf *nControl)
{
    nControl->idlecb = NULL;
    nControl->idlearg = NULL;
    nControl->idletime.tv_sec = 0;
    nControl->idletime.tv_usec = 0;
    nControl->cbbytes = 0;
    return 1;
}
/*
 * FtpOptions - change connection options
 * returns 1 if successful, 0 on error
 */
GLOBALDEF int FtpOptions(int opt, long val, netbuf *nControl)
{
    int v,rv=0;

	/* 根据opt的不同更改netbuf中不同的成员变量 */
    switch (opt)
    {
    case FTPLIB_CONNMODE:
		v = (int) val;
		if ((v == FTPLIB_PASSIVE) || (v == FTPLIB_PORT))
		{
		    nControl->cmode = v;
		    rv = 1;
		}
		break;
    case FTPLIB_CALLBACK: /* 以下几个选项不建议修改 */
		nControl->idlecb = (FtpCallback) val;
		rv = 1;
		break;
	case FTPLIB_IDLETIME:
		v = (int) val;
		rv = 1;
		nControl->idletime.tv_sec = v / 1000;
		nControl->idletime.tv_usec = (v % 1000) * 1000;
		break;
    case FTPLIB_CALLBACKARG: /* 更改回调函数参数 */
		rv = 1;
		nControl->idlearg = (void *) val;
		break;
    case FTPLIB_CALLBACKBYTES:
        rv = 1;
        nControl->cbbytes = (int) val;
        break;
    }
    return rv;
}

/*
 * FtpSendCmd - send a command and wait for expected response
 * return 1 if proper response received, 0 otherwise
 * 发送命令 FTP应答码: http://t175010415.blog.163.com/blog/static/1317066342012111914836972/
 */
static int FtpSendCmd(const char *cmd, char expresp, netbuf *nControl)
{
    char buf[TMP_BUFSIZ];
    if (nControl->dir != FTPLIB_CONTROL)
		return 0;
    if (ftplib_debug > 2)
	fprintf(stderr,"%s\n",cmd);
    if ((strlen(cmd) + 3) > sizeof(buf))
        return 0;
    sprintf(buf,"%s\r\n",cmd);
    if (net_write(nControl->handle,buf,strlen(buf)) <= 0)
    {
		if (ftplib_debug)
		    perror("write");
		return 0;
    }
    return readresp(expresp, nControl);
}

/*
 * FtpLogin - log in to remote server
 * return 1 if logged in, 0 otherwise
 * ftp登陆函数,需要输入用户名和密码
 */
GLOBALDEF int FtpLogin(const char *user, const char *pass, netbuf *nControl)
{
    char tempbuf[64];

    if (((strlen(user) + 7) > sizeof(tempbuf)) ||
        ((strlen(pass) + 7) > sizeof(tempbuf)))
        return 0;
    sprintf(tempbuf,"USER %s",user);
    if (!FtpSendCmd(tempbuf,'3',nControl)) /* 应答码第一位不是3的话,表示不需要密码 */
    {
		if (nControl->response[0] == '2')
		    return 1;
		return 0;
    }
    sprintf(tempbuf,"PASS %s",pass);
    return FtpSendCmd(tempbuf,'2',nControl);
}

/*
 * FtpOpenPort - set up data connection
 * return 1 if successful, 0 otherwise
 * 打开一个端口,在passive模式下与ftp server进行connect
 * 在主动模式下等待ftp server的connect
 */
static int FtpOpenPort(netbuf *nControl, netbuf **nData, int mode, int dir)
{
    int sData;
    union {
	struct sockaddr sa;
	struct sockaddr_in in;
    } sin;
    struct linger lng = { 0, 0 };
    unsigned int l;
    int on=1;
    netbuf *ctrl;
    char *cp;
    unsigned int v[6];
    char buf[TMP_BUFSIZ];

    if (nControl->dir != FTPLIB_CONTROL)
		return -1;
    if ((dir != FTPLIB_READ) && (dir != FTPLIB_WRITE))
    {
		sprintf(nControl->response, "Invalid direction %d\n", dir);
		return -1;
    }
    if ((mode != FTPLIB_ASCII) && (mode != FTPLIB_IMAGE))
    {
		sprintf(nControl->response, "Invalid mode %c\n", mode);
		return -1;
    }
    l = sizeof(sin);
    if (nControl->cmode == FTPLIB_PASSIVE) /* 使用被动模式进行数据传输 */
    {
		memset(&sin, 0, l);
		sin.in.sin_family = AF_INET;
		if (!FtpSendCmd("PASV",'2',nControl)) /* 进入被动模式,FTP服务器在指定的端口进行监听 */
		    return -1;
		cp = strchr(nControl->response,'(');
		if (cp == NULL)
		    return -1;
		cp++;
		sscanf(cp,"%u,%u,%u,%u,%u,%u",&v[2],&v[3],&v[4],&v[5],&v[0],&v[1]);
		sin.sa.sa_data[2] = v[2];
		sin.sa.sa_data[3] = v[3];
		sin.sa.sa_data[4] = v[4];
		sin.sa.sa_data[5] = v[5]; /* 以上4个存放的是IP地址 */
		sin.sa.sa_data[0] = v[0];
		sin.sa.sa_data[1] = v[1]; /* 以上2个存放的是端口号 */
    }
    else
    {
		if (getsockname(nControl->handle, &sin.sa, &l) < 0) /* 获取sockfd对应的本端socket地址 */
		{
		    if (ftplib_debug)
				perror("getsockname");
		    return -1;
		}
    }
    sData = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
    if (sData == -1)
    {
		if (ftplib_debug)
		    perror("socket");
		return -1;
    }
	/* 设置socket可重用 */
    if (setsockopt(sData,SOL_SOCKET,SO_REUSEADDR,
		   SETSOCKOPT_OPTVAL_TYPE &on,sizeof(on)) == -1)
    {
		if (ftplib_debug)
		    perror("setsockopt");
		net_close(sData);
		return -1;
    }
	/* SO_LINGER若有数据发送,则延迟关闭 */
    if (setsockopt(sData,SOL_SOCKET,SO_LINGER,
		   SETSOCKOPT_OPTVAL_TYPE &lng,sizeof(lng)) == -1)
    {
		if (ftplib_debug)
		    perror("setsockopt");
		net_close(sData);
		return -1;
    }
    if (nControl->cmode == FTPLIB_PASSIVE) /* 被动模式,client主动连接FTP server */
    {
		if (connect(sData, &sin.sa, sizeof(sin.sa)) == -1)
		{
		    if (ftplib_debug)
			perror("connect");
		    net_close(sData);
		    return -1;
		}
    }
    else /* 主动模式 */
    {
		sin.in.sin_port = 0;
		if (bind(sData, &sin.sa, sizeof(sin)) == -1)
		{
		    if (ftplib_debug)
			perror("bind");
		    net_close(sData);
		    return -1;
		}
		if (listen(sData, 1) < 0)
		{
		    if (ftplib_debug)
			perror("listen");
		    net_close(sData);
		    return -1;
		}
		if (getsockname(sData, &sin.sa, &l) < 0)
		    return -1;
		sprintf(buf, "PORT %d,%d,%d,%d,%d,%d",
			(unsigned char) sin.sa.sa_data[2],
			(unsigned char) sin.sa.sa_data[3],
			(unsigned char) sin.sa.sa_data[4],
			(unsigned char) sin.sa.sa_data[5],
			(unsigned char) sin.sa.sa_data[0],
			(unsigned char) sin.sa.sa_data[1]);
		if (!FtpSendCmd(buf,'2',nControl))
		{
		    net_close(sData);
		    return -1;
		}
    }
    ctrl = calloc(1,sizeof(netbuf));
    if (ctrl == NULL)
    {
		if (ftplib_debug)
		    perror("calloc");
		net_close(sData);
		return -1;
    }
    if ((mode == 'A') && ((ctrl->buf = malloc(FTPLIB_BUFSIZ)) == NULL))
    {
		if (ftplib_debug)
		    perror("calloc");
		net_close(sData);
		free(ctrl);
		return -1;
    }
    ctrl->handle = sData; /* sData 是监听描述符 */
    ctrl->dir = dir;
    ctrl->idletime = nControl->idletime;
    ctrl->idlearg = nControl->idlearg;
    ctrl->xfered = 0;
    ctrl->xfered1 = 0;
    ctrl->cbbytes = nControl->cbbytes;
    if (ctrl->idletime.tv_sec || ctrl->idletime.tv_usec || ctrl->cbbytes)
		ctrl->idlecb = nControl->idlecb;
    else
		ctrl->idlecb = NULL;
    *nData = ctrl;
    return 1;
}

/*
 * FtpAcceptConnection - accept connection from server
 * return 1 if successful, 0 otherwise
 * 此函数是在被动模式下调用的
 */
static int FtpAcceptConnection(netbuf *nData, netbuf *nControl)
{
    int sData;
    struct sockaddr addr;
    unsigned int l;
    int i;
    struct timeval tv;
    fd_set mask;
    int rv;

    FD_ZERO(&mask);
    FD_SET(nControl->handle, &mask);
    FD_SET(nData->handle, &mask);
    tv.tv_usec = 0;
    tv.tv_sec = ACCEPT_TIMEOUT;
    i = nControl->handle;
    if (i < nData->handle)
	i = nData->handle;
    i = select(i+1, &mask, NULL, NULL, &tv);
    if (i == -1)
    {
        strncpy(nControl->response, strerror(errno),
                sizeof(nControl->response));
        net_close(nData->handle);
        nData->handle = 0;
        rv = 0;
    }
    else if (i == 0)
    {
		strcpy(nControl->response, "timed out waiting for connection");
		net_close(nData->handle);
		nData->handle = 0;
		rv = 0;
    }
    else
    {
		if (FD_ISSET(nData->handle, &mask))
		{
		    l = sizeof(addr);
		    sData = accept(nData->handle, &addr, &l);
		    i = errno;
		    net_close(nData->handle);
		    if (sData > 0)
		    {
				rv = 1;
				nData->handle = sData;
		    }
		    else
		    {
				strncpy(nControl->response, strerror(i),
		                        sizeof(nControl->response));
				nData->handle = 0;
				rv = 0;
		    }
		}
		else if (FD_ISSET(nControl->handle, &mask))
		{
		    net_close(nData->handle);
		    nData->handle = 0;
		    readresp('2', nControl);
		    rv = 0;
		}
    }
    return rv;	
}

/*
 * FtpAccess - return a handle for a data stream
 * return 1 if successful, 0 otherwise
 * mode: 设置传输的文件类型 'A'/'I'
 */
GLOBALDEF int FtpAccess(const char *path, int typ, int mode, netbuf *nControl,
    netbuf **nData)
{
    char buf[TMP_BUFSIZ];
    int dir;
    if ((path == NULL) &&
        ((typ == FTPLIB_FILE_WRITE) || (typ == FTPLIB_FILE_READ)))
    {
		sprintf(nControl->response,
	                "Missing path argument for file transfer\n");
		return 0;
    }
    sprintf(buf, "TYPE %c", mode);
    if (!FtpSendCmd(buf, '2', nControl))
		return 0;
    switch (typ)
    {
    case FTPLIB_DIR:
		strcpy(buf,"NLST");
		dir = FTPLIB_READ;
		break;
    case FTPLIB_DIR_VERBOSE:
		strcpy(buf,"LIST");
		dir = FTPLIB_READ;
		break;
    case FTPLIB_FILE_READ:
		strcpy(buf,"RETR");
		dir = FTPLIB_READ;
		break;
    case FTPLIB_FILE_WRITE:
		strcpy(buf,"STOR");
		dir = FTPLIB_WRITE;
		break;
    default:
		sprintf(nControl->response, "Invalid open type %d\n", typ);
		return 0;
    }
    if (path != NULL)
    {
        int i = strlen(buf);
        buf[i++] = ' ';
        if ((strlen(path) + i + 1) >= sizeof(buf))
            return 0;
        strcpy(&buf[i],path);
    }
    if (FtpOpenPort(nControl, nData, mode, dir) == -1)
		return 0;
    if (!FtpSendCmd(buf, '1', nControl))
    {
		FtpClose(*nData);
		*nData = NULL;
		return 0;
    }
    (*nData)->ctrl = nControl;
    nControl->data = *nData;
    if (nControl->cmode == FTPLIB_PORT)
    {
		if (!FtpAcceptConnection(*nData,nControl))
		{
		    FtpClose(*nData);
		    *nData = NULL;
		    nControl->data = NULL;
		    return 0;
		}
    }
    return 1;
}

/*
 * FtpRead - read from a data connection
 * 读取数据
 */
GLOBALDEF int FtpRead(void *buf, int max, netbuf *nData)
{
    int i;
    if (nData->dir != FTPLIB_READ)
		return 0;
    if (nData->buf) /* 如果nData有缓冲区,则读取到dData的缓冲区中 */
        i = readline(buf, max, nData);
    else
    {
        i = socket_wait(nData);
		if (i != 1)
		    return 0;
	    i = net_read(nData->handle, buf, max);
    }
    if (i == -1)
		return 0;
    nData->xfered += i;
    if (nData->idlecb && nData->cbbytes)
    {
        nData->xfered1 += i;
        if (nData->xfered1 > nData->cbbytes)
        {
		    if (nData->idlecb(nData, nData->xfered, nData->idlearg) == 0)
			return 0;
	            nData->xfered1 = 0;
        }
    }
    return i;
}

/*
 * FtpWrite - write to a data connection
 * 写数据
 */
GLOBALDEF int FtpWrite(const void *buf, int len, netbuf *nData)
{
    int i;
    if (nData->dir != FTPLIB_WRITE)
		return 0;
    if (nData->buf)
    	i = writeline(buf, len, nData);
    else
    {
        socket_wait(nData);
        i = net_write(nData->handle, buf, len);
    }
    if (i == -1)
		return 0;
    nData->xfered += i;
    if (nData->idlecb && nData->cbbytes)
    {
        nData->xfered1 += i;
        if (nData->xfered1 > nData->cbbytes)
        {
            nData->idlecb(nData, nData->xfered, nData->idlearg);
            nData->xfered1 = 0;
        }
    }
    return i;
}

/*
 * FtpClose - close a data connection
 * 关闭数据连接
 */
GLOBALDEF int FtpClose(netbuf *nData)
{
    netbuf *ctrl;
    switch (nData->dir)
    {
    case FTPLIB_WRITE:
		/* potential problem - if buffer flush fails, how to notify user? */
		if (nData->buf != NULL)
		    writeline(NULL, 0, nData);
    case FTPLIB_READ:
		if (nData->buf)
		    free(nData->buf);
		shutdown(nData->handle,2);
		net_close(nData->handle);
		ctrl = nData->ctrl;
		free(nData);
		ctrl->data = NULL;
		if (ctrl && ctrl->response[0] != '4' && ctrl->response[0] != 5)
		{
		    return(readresp('2', ctrl));
		}
		return 1;
    case FTPLIB_CONTROL:
		if (nData->data)
		{
		    nData->ctrl = NULL;
		    FtpClose(nData->data);
		}
		net_close(nData->handle);
		free(nData);
		return 0;
    }
    return 1;
}

/*
 * FtpSite - send a SITE command
 * return 1 if command successful, 0 otherwise
 * site不知道什么意思
 */
GLOBALDEF int FtpSite(const char *cmd, netbuf *nControl)
{
    char buf[TMP_BUFSIZ];
    
    if ((strlen(cmd) + 7) > sizeof(buf))
        return 0;
    sprintf(buf,"SITE %s",cmd);
    if (!FtpSendCmd(buf,'2',nControl))
		return 0;
    return 1;
}

/*
 * FtpSysType - send a SYST command
 * Fills in the user buffer with the remote system type.  If more
 * information from the response is required, the user can parse
 * it out of the response buffer returned by FtpLastResponse().
 * return 1 if command successful, 0 otherwise
 * 获取FTP服务器的操作系统,复制到buf中,比如WINDOWS
 */
GLOBALDEF int FtpSysType(char *buf, int max, netbuf *nControl)
{
    int l = max;
    char *b = buf;
    char *s;
    if (!FtpSendCmd("SYST",'2',nControl))
		return 0;
    s = &nControl->response[4];
    while ((--l) && (*s != ' '))
		*b++ = *s++;
    *b++ = '\0';
    return 1;
}

/*
 * FtpMkdir - create a directory at server
 * return 1 if successful, 0 otherwise
 * 创建文件夹
 */
GLOBALDEF int FtpMkdir(const char *path, netbuf *nControl)
{
    char buf[TMP_BUFSIZ];

    if ((strlen(path) + 6) > sizeof(buf))
        return 0;
    sprintf(buf,"MKD %s",path);
    if (!FtpSendCmd(buf,'2', nControl))
		return 0;
    return 1;
}

/*
 * FtpChdir - change path at remote
 * return 1 if successful, 0 otherwise
 * 切换文件夹
 */
GLOBALDEF int FtpChdir(const char *path, netbuf *nControl)
{
    char buf[TMP_BUFSIZ];

    if ((strlen(path) + 6) > sizeof(buf))
        return 0;
    sprintf(buf,"CWD %s",path);
    if (!FtpSendCmd(buf,'2',nControl))
		return 0;
    return 1;
}

/*
 * FtpCDUp - move to parent directory at remote
 * return 1 if successful, 0 otherwise
 * 跳到..文件夹,当在最顶层的文件夹时,就不要在跳了,否则可能错粗呦
 */
GLOBALDEF int FtpCDUp(netbuf *nControl)
{
    if (!FtpSendCmd("CDUP",'2',nControl))
		return 0;
    return 1;
}

/*
 * FtpRmdir - remove directory at remote
 * return 1 if successful, 0 otherwise
 * 删除文件夹
 */
GLOBALDEF int FtpRmdir(const char *path, netbuf *nControl)
{
    char buf[TMP_BUFSIZ];

    if ((strlen(path) + 6) > sizeof(buf))
        return 0;
    sprintf(buf,"RMD %s",path);
    if (!FtpSendCmd(buf,'2',nControl))
		return 0;
    return 1;
}

/*
 * FtpPwd - get working directory at remote
 * return 1 if successful, 0 otherwise
 * 获取当前文件夹
 */
GLOBALDEF int FtpPwd(char *path, int max, netbuf *nControl)
{
    int l = max;
    char *b = path;
    char *s;
    if (!FtpSendCmd("PWD",'2',nControl))
		return 0;
    s = strchr(nControl->response, '"');
    if (s == NULL)
		return 0;
    s++;
    while ((--l) && (*s) && (*s != '"'))
		*b++ = *s++;
    *b++ = '\0';
    return 1;
}

/*
 * FtpXfer - issue a command and transfer data
 * return 1 if successful, 0 otherwise
 * typ: read/write, mode: IMAGE/ASCII
 */
static int FtpXfer(const char *localfile, const char *path,
	netbuf *nControl, int typ, int mode)
{
    int l,c;
    char *dbuf;
    FILE *local = NULL;
    netbuf *nData;
    int rv=1;

    if (localfile != NULL)
    {
		char ac[4];
		memset( ac, 0, sizeof(ac) );
		if (typ == FTPLIB_FILE_WRITE)
		    ac[0] = 'r';
		else
		    ac[0] = 'w';
		if (mode == FTPLIB_IMAGE)
		    ac[1] = 'b';
		local = fopen(localfile, ac);
		if (local == NULL)
		{
		    strncpy(nControl->response, strerror(errno),
	                    sizeof(nControl->response));
		    return 0;
		}
    }
	/* when localfile is NULL, local point to stdin/stdout */
    if (local == NULL)
		local = (typ == FTPLIB_FILE_WRITE) ? stdin : stdout;
    if (!FtpAccess(path, typ, mode, nControl, &nData)) /* open the remote file error */
    {
		if (localfile)
		{
		    fclose(local);
		    if ( typ == FTPLIB_FILE_WRITE )
				unlink(localfile);
		}
		return 0;
    }
    dbuf = malloc(FTPLIB_BUFSIZ);
    if (typ == FTPLIB_FILE_WRITE)
    {
		while ((l = fread(dbuf, 1, FTPLIB_BUFSIZ, local)) > 0)
		{
		    if ((c = FtpWrite(dbuf, l, nData)) < l)
		    {
				printf("short write: passed %d, wrote %d\n", l, c);
				rv = 0;
				break;
		    }
		}
    }
    else
    {
    	while ((l = FtpRead(dbuf, FTPLIB_BUFSIZ, nData)) > 0)
		{
		    if (fwrite(dbuf, 1, l, local) == 0)
		    {
				if (ftplib_debug)
				    perror("localfile write");
				rv = 0;
				break;
		    }
		}
    }
    free(dbuf);
    fflush(local);
    if (localfile != NULL)
	fclose(local);
    FtpClose(nData);
    return rv;
}

/*
 * FtpNlst - issue an NLST command and write response to output
 * return 1 if successful, 0 otherwise
 * 返回指定路径下的目录列表
 */
GLOBALDEF int FtpNlst(const char *outputfile, const char *path,
	netbuf *nControl)
{
    return FtpXfer(outputfile, path, nControl, FTPLIB_DIR, FTPLIB_ASCII);
}

/*
 * FtpDir - issue a LIST command and write response to output
 * return 1 if successful, 0 otherwise
 * 返回指定路径下的目录列表
 */
GLOBALDEF int FtpDir(const char *outputfile, const char *path, netbuf *nControl)
{
    return FtpXfer(outputfile, path, nControl, FTPLIB_DIR_VERBOSE, FTPLIB_ASCII);
}

/*
 * FtpSize - determine the size of a remote file
 * return 1 if successful, 0 otherwise
 */
GLOBALDEF int FtpSize(const char *path, unsigned int *size, char mode, netbuf *nControl)
{
    char cmd[TMP_BUFSIZ];
    int resp,rv=1;
    unsigned int sz;

    if ((strlen(path) + 7) > sizeof(cmd))
        return 0;
    sprintf(cmd, "TYPE %c", mode);
    if (!FtpSendCmd(cmd, '2', nControl))
		return 0;
    sprintf(cmd,"SIZE %s",path);
    if (!FtpSendCmd(cmd,'2',nControl))
		rv = 0;
    else
    {
		if (sscanf(nControl->response, "%d %u", &resp, &sz) == 2)
		    *size = sz;
		else
		    rv = 0;
    }   
    return rv;
}

#if defined(__UINT64_MAX)
/*
 * FtpSizeLong - determine the size of a remote file
 * return 1 if successful, 0 otherwise
 */
GLOBALDEF int FtpSizeLong(const char *path, fsz_t *size, char mode, netbuf *nControl)
{
    char cmd[TMP_BUFSIZ];
    int resp,rv=1;
    fsz_t sz;

    if ((strlen(path) + 7) > sizeof(cmd))
        return 0;
    sprintf(cmd, "TYPE %c", mode);
    if (!FtpSendCmd(cmd, '2', nControl))
	return 0;
    sprintf(cmd,"SIZE %s",path);
    if (!FtpSendCmd(cmd,'2',nControl))
	rv = 0;
    else
    {
	if (sscanf(nControl->response, "%d %" PRIu64 "", &resp, &sz) == 2)
	    *size = sz;
	else
	    rv = 0;
    }   
    return rv;
}
#endif

/*
 * FtpModDate - determine the modification date of a remote file
 * return 1 if successful, 0 otherwise
 */
GLOBALDEF int FtpModDate(const char *path, char *dt, int max, netbuf *nControl)
{
    char buf[TMP_BUFSIZ];
    int rv = 1;

    if ((strlen(path) + 7) > sizeof(buf))
        return 0;
    sprintf(buf,"MDTM %s",path);
    if (!FtpSendCmd(buf,'2',nControl))
	rv = 0;
    else
	strncpy(dt, &nControl->response[4], max);
    return rv;
}

/*
 * FtpGet - issue a GET command and write received data to output
 * return 1 if successful, 0 otherwise
 * 下载文件
 */
GLOBALDEF int FtpGet(const char *outputfile, const char *path,
	char mode, netbuf *nControl)
{
    return FtpXfer(outputfile, path, nControl, FTPLIB_FILE_READ, mode);
}

/*
 * FtpPut - issue a PUT command and send data from input
 * return 1 if successful, 0 otherwise
 * 上传文件
 */
GLOBALDEF int FtpPut(const char *inputfile, const char *path, char mode,
	netbuf *nControl)
{
    return FtpXfer(inputfile, path, nControl, FTPLIB_FILE_WRITE, mode);
}

/*
 * FtpRename - rename a file at remote
 * return 1 if successful, 0 otherwise
 * 更改文件名称
 */
GLOBALDEF int FtpRename(const char *src, const char *dst, netbuf *nControl)
{
    char cmd[TMP_BUFSIZ];

    if (((strlen(src) + 7) > sizeof(cmd)) ||
        ((strlen(dst) + 7) > sizeof(cmd)))
        return 0;
    sprintf(cmd,"RNFR %s",src);
    if (!FtpSendCmd(cmd,'3',nControl))
		return 0;
    sprintf(cmd,"RNTO %s",dst);
    if (!FtpSendCmd(cmd,'2',nControl))
		return 0;
    return 1;
}

/*
 * FtpDelete - delete a file at remote
 * return 1 if successful, 0 otherwise
 * 删除文件
 */
GLOBALDEF int FtpDelete(const char *fnm, netbuf *nControl)
{
    char cmd[TMP_BUFSIZ];

    if ((strlen(fnm) + 7) > sizeof(cmd))
        return 0;
    sprintf(cmd,"DELE %s",fnm);
    if (!FtpSendCmd(cmd,'2', nControl))
		return 0;
    return 1;
}

/*
 * FtpQuit - disconnect from remote
 * return 1 if successful, 0 otherwise
 * 退出ftp登录
 */
GLOBALDEF void FtpQuit(netbuf *nControl)
{
    if (nControl->dir != FTPLIB_CONTROL)
		return;
    FtpSendCmd("QUIT",'2',nControl);
    net_close(nControl->handle);
    free(nControl->buf);
    free(nControl);
}

参考

        1、《计算机网络》 第6版 FTP相关章节

        2、《UNIX网络编程》 第3版 相关章节


  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FTP Library Routines Release 4.0 Thomas Pfau ([email protected]) June 7, 2013 This package implements a callable interface to FTP. The FTP protocol is specified in RFC 959. The library has been tested on linux, OpenVMS and Windows NT. It should also work without major modification on other POSIX systems. All programs using the library should include ftplib.h. FTP开源库。 Miscellaneous Functions FtpInit() - Initialize the library FtpSite() - Send a 'SITE' command FtpLastResponse() - Retrieve last server response FtpSysType() - Determine remote system type FtpSize() - Determine size of remote file FtpSizeLong() - Determine size of remote file FtpModDate() - Determine modification time of file FtpSetCallback() - Establish a callback function FtpClearCallback() - Remove a callback function Server Connection FtpConnect() - Connect to a remote server FtpLogin() - Login to remote machine FtpQuit() - Disconnect from remote server FtpOptions() - Set Connection Options Directory Functions FtpChdir() - Change working directory FtpMkdir() - Create a directory FtpRmdir() - Remove a directory FtpDir() - List a remote directory FtpNlst() - List a remote directory FtpCDUp() - Change to parent directory FtpPwd() - Determine current working directory File to File Transfer FtpGet() - Retreive a remote file FtpPut() - Send a local file to remote FtpDelete() - Delete a remote file FtpRename() - Rename a remote file File to Program Transfer These routines allow programs access to the data streams connected to remote files and directories. FtpAccess() - Open a remote file or directory FtpRead() - Read from remote file or directory FtpWrite() - Write to remote file FtpClose() - Close data connection Utilities qftp - Command line ftp utility

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值