📄 nanoftp.c.svn-base
字号:
xmlFree(proxy); proxy = NULL; } if (proxyPort != 0) { 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; buf[indx] = 0; while ((*cur != 0) && (indx < XML_NANO_MAX_URLBUF-1)) { if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) { buf[indx] = 0; indx = 0; cur += 3; break; } buf[indx++] = *cur++; } if (*cur == 0) return; buf[indx] = 0; while (indx < XML_NANO_MAX_URLBUF-1) { if ((strchr (cur, '[') && !strchr (cur, ']')) || (!strchr (cur, '[') && strchr (cur, ']'))) { xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPScanProxy: %s", "Syntax error\n"); return; } if (cur[0] == '[') { cur++; while (cur[0] != ']') buf[indx++] = *cur++; if (!strchr (buf, ':')) { xmlGenericError (xmlGenericErrorContext, "\nxmlNanoFTPScanProxy: %s", "Use [IPv6]/IPv4 format\n"); return; } buf[indx] = 0; proxy = xmlMemStrdup (buf); indx = 0; cur += 1; if (cur[0] == ':') { cur++; while (*cur >= '0' && *cur <= '9') { port *= 10; port += *cur - '0'; cur++; } if (port != 0) proxyPort = port; while ((cur[0] != '/') && (*cur != 0)) cur++; } break; } else { if (cur[0] == ':') { buf[indx] = 0; proxy = xmlMemStrdup (buf); indx = 0; cur += 1; while ((*cur >= '0') && (*cur <= '9')) { port *= 10; port += *cur - '0'; cur++; } if (port != 0) proxyPort = port; while ((cur[0] != '/') && (*cur != 0)) cur++; break; } if ((*cur == '/') || (*cur == 0)) { buf[indx] = 0; proxy = xmlMemStrdup (buf); indx = 0; break; } } buf[indx++] = *cur++; }}/** * 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); else if (URL != NULL) xmlNanoFTPScanURL(ret, URL); xmlFree(unescaped); 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 */static intxmlNanoFTPParseResponse(char *buf, int len) { int val = 0; if (len < 3) return(-1); if ((*buf >= '0') && (*buf <= '9')) val = val * 10 + (*buf - '0'); else return(0); buf++; if ((*buf >= '0') && (*buf <= '9')) val = val * 10 + (*buf - '0'); else return(0); buf++; if ((*buf >= '0') && (*buf <= '9')) val = val * 10 + (*buf - '0'); else return(0); buf++; if (*buf == '-') return(-val); return(val);}/** * xmlNanoFTPGetMore: * @ctx: an FTP context * * Read more information from the FTP control connection * Returns the number of bytes read, < 0 indicates an error */static intxmlNanoFTPGetMore(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; int len; int size; if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) {#ifdef DEBUG_FTP xmlGenericError(xmlGenericErrorContext, "xmlNanoFTPGetMore : controlBufIndex = %d\n", ctxt->controlBufIndex);#endif return(-1); } if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) {#ifdef DEBUG_FTP xmlGenericError(xmlGenericErrorContext, "xmlNanoFTPGetMore : controlBufUsed = %d\n", ctxt->controlBufUsed);#endif return(-1); } if (ctxt->controlBufIndex > ctxt->controlBufUsed) {#ifdef DEBUG_FTP xmlGenericError(xmlGenericErrorContext, "xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n", ctxt->controlBufIndex, ctxt->controlBufUsed);#endif return(-1); } /* * First pack the control buffer */ if (ctxt->controlBufIndex > 0) { memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex], ctxt->controlBufUsed - ctxt->controlBufIndex); ctxt->controlBufUsed -= ctxt->controlBufIndex; ctxt->controlBufIndex = 0; } size = FTP_BUF_SIZE - ctxt->controlBufUsed; if (size == 0) {#ifdef DEBUG_FTP xmlGenericError(xmlGenericErrorContext, "xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed);#endif return(0); } /* * Read the amount left on the control connection */ if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex], size, 0)) < 0) { __xmlIOErr(XML_FROM_FTP, 0, "recv failed"); closesocket(ctxt->controlFd); ctxt->controlFd = -1; ctxt->controlFd = -1; return(-1); }#ifdef DEBUG_FTP xmlGenericError(xmlGenericErrorContext, "xmlNanoFTPGetMore : read %d [%d - %d]\n", len, ctxt->controlBufUsed, ctxt->controlBufUsed + len);#endif ctxt->controlBufUsed += len; ctxt->controlBuf[ctxt->controlBufUsed] = 0; return(len);}/** * xmlNanoFTPReadResponse: * @ctx: an FTP context * * Read the response from the FTP server after a command. * Returns the code number */static intxmlNanoFTPReadResponse(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char *ptr, *end; int len; int res = -1, cur = -1;get_more: /* * Assumes everything up to controlBuf[controlBufIndex] has been read * and analyzed. */ len = xmlNanoFTPGetMore(ctx); if (len < 0) { return(-1); } if ((ctxt->controlBufUsed == 0) && (len == 0)) { return(-1); } ptr = &ctxt->controlBuf[ctxt->controlBufIndex]; end = &ctxt->controlBuf[ctxt->controlBufUsed];#ifdef DEBUG_FTP xmlGenericError(xmlGenericErrorContext, "\n<<<\n%s\n--\n", ptr);#endif while (ptr < end) { cur = xmlNanoFTPParseResponse(ptr, end - ptr); if (cur > 0) { /* * Successfully scanned the control code, scratch * till the end of the line, but keep the index to be * able to analyze the result if needed. */ res = cur; ptr += 3; ctxt->controlBufAnswer = ptr - ctxt->controlBuf; while ((ptr < end) && (*ptr != '\n')) ptr++; if (*ptr == '\n') ptr++; if (*ptr == '\r') ptr++; break; } while ((ptr < end) && (*ptr != '\n')) ptr++; if (ptr >= end) { ctxt->controlBufIndex = ctxt->controlBufUsed; goto get_more; } if (*ptr != '\r') ptr++; } if (res < 0) goto get_more; ctxt->controlBufIndex = ptr - ctxt->controlBuf;#ifdef DEBUG_FTP ptr = &ctxt->controlBuf[ctxt->controlBufIndex]; xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr);#endif#ifdef DEBUG_FTP xmlGenericError(xmlGenericErrorContext, "Got %d\n", res);#endif return(res / 100);}/** * xmlNanoFTPGetResponse: * @ctx: an FTP context * * Get the response from the FTP server after a command. * Returns the code number */intxmlNanoFTPGetResponse(void *ctx) { int res; res = xmlNanoFTPReadResponse(ctx); return(res);}/** * xmlNanoFTPCheckResponse: * @ctx: an FTP context * * Check if there is a response from the FTP server after a command. * Returns the code number, or 0 */intxmlNanoFTPCheckResponse(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; fd_set rfd; struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&rfd); FD_SET(ctxt->controlFd, &rfd); switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) { case 0: return(0); case -1: __xmlIOErr(XML_FROM_FTP, 0, "select"); return(-1); } return(xmlNanoFTPReadResponse(ctx));}/** * Send the user authentication */static intxmlNanoFTPSendUser(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char buf[200]; int len; int res; if (ctxt->user == NULL) snprintf(buf, sizeof(buf), "USER anonymous\r\n"); else snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user); buf[sizeof(buf) - 1] = 0; len = strlen(buf);#ifdef DEBUG_FTP xmlGenericError(xmlGenericErrorContext, "%s", buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); return(res); } return(0);}/** * Send the password authentication */static intxmlNanoFTPSendPasswd(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char buf[200]; int len; int res; if (ctxt->passwd == NULL) snprintf(buf, sizeof(buf), "PASS anonymous@\r\n"); else snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd); buf[sizeof(buf) - 1] = 0; len = strlen(buf);#ifdef DEBUG_FTP xmlGenericError(xmlGenericErrorContext, "%s", buf);#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); return(res); } return(0);}/** * xmlNanoFTPQuit: * @ctx: an FTP context * * Send a QUIT command to the server * * Returns -1 in case of error, 0 otherwise */intxmlNanoFTPQuit(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char buf[200]; int len, res; snprintf(buf, sizeof(buf), "QUIT\r\n"); len = strlen(buf);#ifdef DEBUG_FTP xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */#endif res = send(ctxt->controlFd, buf, len, 0); if (res < 0) { __xmlIOErr(XML_FROM_FTP, 0, "send failed"); return(res); } return(0);}/** * xmlNanoFTPConnect: * @ctx: an FTP context * * Tries to open a control connection * * Returns -1 in case of error, 0 otherwise */intxmlNanoFTPConnect(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; struct hostent *hp; int port; int res; int addrlen = sizeof (struct sockaddr_in); if (ctxt == NULL) return(-1); if (ctxt->hostname == NULL) return(-1); /* * do the blocking DNS query. */ if (proxy) { port = proxyPort; } else { port = ctxt->port; } if (port == 0) port = 21; memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));#ifdef SUPPORT_IP6 if (have_ipv6 ()) { struct addrinfo hints, *tmp, *result; result = NULL; memset (&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; if (proxy) { if (getaddrinfo (proxy, NULL, &hints, &result) != 0) { __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed"); return (-1); } } else if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0) { __xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed"); return (-1); } for (tmp = result; tmp; tmp = tmp->ai_next) if (tmp->ai_family == AF_INET || tmp->ai_family == AF_INET6) break; if (!tmp) { if (result) freeaddrinfo (result); return (-1); } else { if (tmp->ai_family == AF_INET6) { memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen); ((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port); ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0); } else { memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen); ((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port); ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0); } addrlen = tmp->ai_addrlen; freeaddrinfo (result); } } else#endif { if (proxy) hp = gethostbyname (proxy); else hp = gethostbyname (ctxt->hostname); if (hp == NULL) { __xmlIOErr(XML_FROM_FTP, 0, "gethostbyname failed"); return (-1); } /* * Prepare the socket */ ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_family = AF_INET; memcpy (&((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr, hp->h_addr_list[0], hp->h_length); ((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port = htons (port); ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0); addrlen = sizeof (struct sockaddr_in); } if (ctxt->controlFd < 0) { __xmlIOErr(XML_FROM_FTP, 0, "socket failed"); return(-1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -