📄 nanoftp.c
字号:
/* * nanoftp.c: basic FTP client support * * Reference: RFC 959 */#ifdef TESTING#define STANDALONE#define HAVE_STDLIB_H#define HAVE_UNISTD_H#define HAVE_SYS_SOCKET_H#define HAVE_NETINET_IN_H#define HAVE_NETDB_H#define HAVE_SYS_TIME_H#else /* TESTING */#define NEED_SOCKETS#endif /* TESTING */#define IN_LIBXML#include "libxml.h"#ifdef LIBXML_FTP_ENABLED#include <string.h>#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#ifdef HAVE_ARPA_INET_H#include <arpa/inet.h>#endif#ifdef HAVE_NETDB_H#include <netdb.h>#endif#ifdef HAVE_FCNTL_H#include <fcntl.h> #endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_STRINGS_H#include <strings.h>#endif#include <libxml/xmlmemory.h>#include <libxml/parser.h>#include <libxml/xmlerror.h>#include <libxml/uri.h>#include <libxml/nanoftp.h>#include <libxml/globals.h>/* #define DEBUG_FTP 1 */#ifdef STANDALONE#ifndef DEBUG_FTP#define DEBUG_FTP 1#endif#endif#ifdef __MINGW32__#define _WINSOCKAPI_#include <wsockcompat.h>#include <winsock2.h>#undef XML_SOCKLEN_T#define XML_SOCKLEN_T unsigned int#endif/** * A couple portability macros */#ifndef _WINSOCKAPI_#ifndef __BEOS__#define closesocket(s) close(s)#endif#define SOCKET int#endif#if defined(VMS) || defined(__VMS)#define XML_SOCKLEN_T unsigned int#endif#ifdef __BEOS__#ifndef PF_INET#define PF_INET AF_INET#endif#endif#ifdef _AIX#define ss_family __ss_family#endif#define FTP_COMMAND_OK 200#define FTP_SYNTAX_ERROR 500#define FTP_GET_PASSWD 331#define FTP_BUF_SIZE 512#define XML_NANO_MAX_URLBUF 4096typedef struct xmlNanoFTPCtxt { char *protocol; /* the protocol name */ char *hostname; /* the host name */ int port; /* the port */ char *path; /* the path within the URL */ char *user; /* user string */ char *passwd; /* passwd string */#ifdef SUPPORT_IP6 struct sockaddr_storage ftpAddr; /* this is large enough to hold IPv6 address*/#else struct sockaddr_in ftpAddr; /* the socket address struct */#endif int passive; /* currently we support only passive !!! */ SOCKET controlFd; /* the file descriptor for the control socket */ SOCKET dataFd; /* the file descriptor for the data socket */ int state; /* WRITE / READ / CLOSED */ int returnValue; /* the protocol return value */ /* buffer for data received from the control connection */ char controlBuf[FTP_BUF_SIZE + 1]; int controlBufIndex; int controlBufUsed; int controlBufAnswer;} xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr;static int initialized = 0;static char *proxy = NULL; /* the proxy name if any */static int proxyPort = 0; /* the proxy port if any */static char *proxyUser = NULL; /* user for proxy authentication */static char *proxyPasswd = NULL;/* passwd for proxy authentication */static int proxyType = 0; /* uses TYPE or a@b ? */#ifdef SUPPORT_IP6staticint have_ipv6(void) { int s; s = socket (AF_INET6, SOCK_STREAM, 0); if (s != -1) { close (s); return (1); } return (0);}#endif/** * xmlFTPErrMemory: * @extra: extra informations * * Handle an out of memory condition */static voidxmlFTPErrMemory(const char *extra){ __xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);}/** * xmlNanoFTPInit: * * Initialize the FTP protocol layer. * Currently it just checks for proxy informations, * and get the hostname */voidxmlNanoFTPInit(void) { const char *env;#ifdef _WINSOCKAPI_ WSADATA wsaData; #endif if (initialized) return;#ifdef _WINSOCKAPI_ if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) return;#endif proxyPort = 21; env = getenv("no_proxy"); if (env && ((env[0] == '*' ) && (env[1] == 0))) return; env = getenv("ftp_proxy"); if (env != NULL) { xmlNanoFTPScanProxy(env); } else { env = getenv("FTP_PROXY"); if (env != NULL) { xmlNanoFTPScanProxy(env); } } env = getenv("ftp_proxy_user"); if (env != NULL) { proxyUser = xmlMemStrdup(env); } env = getenv("ftp_proxy_password"); if (env != NULL) { proxyPasswd = xmlMemStrdup(env); } initialized = 1;}/** * xmlNanoFTPCleanup: * * Cleanup the FTP protocol layer. This cleanup proxy informations. */voidxmlNanoFTPCleanup(void) { if (proxy != NULL) { xmlFree(proxy); proxy = NULL; } if (proxyUser != NULL) { xmlFree(proxyUser); proxyUser = NULL; } if (proxyPasswd != NULL) { xmlFree(proxyPasswd); proxyPasswd = NULL; }#ifdef _WINSOCKAPI_ if (initialized) WSACleanup();#endif initialized = 0;}/** * xmlNanoFTPProxy: * @host: the proxy host name * @port: the proxy port * @user: the proxy user name * @passwd: the proxy password * @type: the type of proxy 1 for using SITE, 2 for USER a@b * * Setup the FTP proxy informations. * This can also be done by using ftp_proxy ftp_proxy_user and * ftp_proxy_password environment variables. */voidxmlNanoFTPProxy(const char *host, int port, const char *user, const char *passwd, int type) { if (proxy != NULL) { xmlFree(proxy); proxy = NULL; } if (proxyUser != NULL) { xmlFree(proxyUser); proxyUser = NULL; } if (proxyPasswd != NULL) { xmlFree(proxyPasswd); proxyPasswd = NULL; } if (host) proxy = xmlMemStrdup(host); if (user) proxyUser = xmlMemStrdup(user); if (passwd) proxyPasswd = xmlMemStrdup(passwd); proxyPort = port; proxyType = type;}/** * xmlNanoFTPScanURL: * @ctx: an FTP context * @URL: The URL used to initialize the context * * (Re)Initialize an FTP context by parsing the URL and finding * the protocol host port and path it indicates. */static voidxmlNanoFTPScanURL(void *ctx, const char *URL) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; xmlURIPtr uri; /* * Clear any existing data from the context */ if (ctxt->protocol != NULL) { xmlFree(ctxt->protocol); ctxt->protocol = NULL; } if (ctxt->hostname != NULL) { xmlFree(ctxt->hostname); ctxt->hostname = NULL; } if (ctxt->path != NULL) { xmlFree(ctxt->path); ctxt->path = NULL; } if (URL == NULL) return; uri = xmlParseURI(URL); if (uri == NULL) return; if ((uri->scheme == NULL) || (uri->server == NULL)) { xmlFreeURI(uri); return; } ctxt->protocol = xmlMemStrdup(uri->scheme); ctxt->hostname = xmlMemStrdup(uri->server); if (uri->path != NULL) ctxt->path = xmlMemStrdup(uri->path); else ctxt->path = xmlMemStrdup("/"); if (uri->port != 0) ctxt->port = uri->port; if (uri->user != NULL) { char *cptr; if ((cptr=strchr(uri->user, ':')) == NULL) ctxt->user = xmlMemStrdup(uri->user); else { ctxt->user = (char *)xmlStrndup((xmlChar *)uri->user, (cptr - uri->user)); ctxt->passwd = xmlMemStrdup(cptr+1); } } xmlFreeURI(uri);}/** * xmlNanoFTPUpdateURL: * @ctx: an FTP context * @URL: The URL used to update the context * * Update an FTP context by parsing the URL and finding * new path it indicates. If there is an error in the * protocol, hostname, port or other information, the * error is raised. It indicates a new connection has to * be established. * * Returns 0 if Ok, -1 in case of error (other host). */intxmlNanoFTPUpdateURL(void *ctx, const char *URL) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; xmlURIPtr uri; if (URL == NULL) return(-1); if (ctxt == NULL) return(-1); if (ctxt->protocol == NULL) return(-1); if (ctxt->hostname == NULL) return(-1); uri = xmlParseURI(URL); if (uri == NULL) return(-1); if ((uri->scheme == NULL) || (uri->server == NULL)) { xmlFreeURI(uri); return(-1); } if ((strcmp(ctxt->protocol, uri->scheme)) || (strcmp(ctxt->hostname, uri->server)) || ((uri->port != 0) && (ctxt->port != uri->port))) { xmlFreeURI(uri); return(-1); } if (uri->port != 0) ctxt->port = uri->port; if (ctxt->path != NULL) { xmlFree(ctxt->path); ctxt->path = NULL; } if (uri->path == NULL) ctxt->path = xmlMemStrdup("/"); else ctxt->path = xmlMemStrdup(uri->path); xmlFreeURI(uri); return(0);}/** * xmlNanoFTPScanProxy: * @URL: The proxy URL used to initialize the proxy context * * (Re)Initialize the FTP Proxy context by parsing the URL and finding * the protocol host port it indicates. * Should be like ftp://myproxy/ or ftp://myproxy:3128/ * A NULL URL cleans up proxy informations. */voidxmlNanoFTPScanProxy(const char *URL) { xmlURIPtr uri; if (proxy != NULL) { xmlFree(proxy); proxy = NULL; } proxyPort = 0;#ifdef DEBUG_FTP if (URL == NULL) xmlGenericError(xmlGenericErrorContext, "Removing FTP proxy info\n"); else xmlGenericError(xmlGenericErrorContext, "Using FTP proxy %s\n", URL);#endif if (URL == NULL) return; uri = xmlParseURI(URL); if ((uri == NULL) || (uri->scheme == NULL) || (strcmp(uri->scheme, "ftp")) || (uri->server == NULL)) { __xmlIOErr(XML_FROM_FTP, XML_FTP_URL_SYNTAX, "Syntax Error\n"); if (uri != NULL) xmlFreeURI(uri); return; } proxy = xmlMemStrdup(uri->server); if (uri->port != 0) proxyPort = uri->port; xmlFreeURI(uri);}/** * xmlNanoFTPNewCtxt: * @URL: The URL used to initialize the context * * Allocate and initialize a new FTP context. * * Returns an FTP context or NULL in case of error. */void*xmlNanoFTPNewCtxt(const char *URL) { xmlNanoFTPCtxtPtr ret; char *unescaped; ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt)); if (ret == NULL) { xmlFTPErrMemory("allocating FTP context"); return(NULL); } memset(ret, 0, sizeof(xmlNanoFTPCtxt)); ret->port = 21; ret->passive = 1; ret->returnValue = 0; ret->controlBufIndex = 0; ret->controlBufUsed = 0; ret->controlFd = -1; unescaped = xmlURIUnescapeString(URL, 0, NULL); if (unescaped != NULL) { xmlNanoFTPScanURL(ret, unescaped); xmlFree(unescaped); } else if (URL != NULL) xmlNanoFTPScanURL(ret, URL); return(ret);}/** * xmlNanoFTPFreeCtxt: * @ctx: an FTP context * * Frees the context after closing the connection. */voidxmlNanoFTPFreeCtxt(void * ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; if (ctxt == NULL) return; if (ctxt->hostname != NULL) xmlFree(ctxt->hostname); if (ctxt->protocol != NULL) xmlFree(ctxt->protocol); if (ctxt->path != NULL) xmlFree(ctxt->path); ctxt->passive = 1; if (ctxt->controlFd >= 0) closesocket(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlBufIndex = -1; ctxt->controlBufUsed = -1; xmlFree(ctxt);}/** * xmlNanoFTPParseResponse: * @buf: the buffer containing the response * @len: the buffer length * * Parsing of the server answer, we just extract the code. * * returns 0 for errors * +XXX for last line of response * -XXX for response to be continued */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -