📄 nanoftp.c
字号:
*/
static int
xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) {
const char *cur = list;
char filename[151];
char attrib[11];
char owner[11];
char group[11];
char month[4];
int year = 0;
int minute = 0;
int hour = 0;
int day = 0;
unsigned long size = 0;
int links = 0;
int i;
if (!strncmp(cur, "total", 5)) {
cur += 5;
while (*cur == ' ') cur++;
while ((*cur >= '0') && (*cur <= '9'))
links = (links * 10) + (*cur++ - '0');
while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
cur++;
return(cur - list);
} else if (*list == '+') {
return(0);
} else {
while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
cur++;
if (*cur == 0) return(0);
i = 0;
while (*cur != ' ') {
if (i < 10)
attrib[i++] = *cur;
cur++;
if (*cur == 0) return(0);
}
attrib[10] = 0;
while (*cur == ' ') cur++;
if (*cur == 0) return(0);
while ((*cur >= '0') && (*cur <= '9'))
links = (links * 10) + (*cur++ - '0');
while (*cur == ' ') cur++;
if (*cur == 0) return(0);
i = 0;
while (*cur != ' ') {
if (i < 10)
owner[i++] = *cur;
cur++;
if (*cur == 0) return(0);
}
owner[i] = 0;
while (*cur == ' ') cur++;
if (*cur == 0) return(0);
i = 0;
while (*cur != ' ') {
if (i < 10)
group[i++] = *cur;
cur++;
if (*cur == 0) return(0);
}
group[i] = 0;
while (*cur == ' ') cur++;
if (*cur == 0) return(0);
while ((*cur >= '0') && (*cur <= '9'))
size = (size * 10) + (*cur++ - '0');
while (*cur == ' ') cur++;
if (*cur == 0) return(0);
i = 0;
while (*cur != ' ') {
if (i < 3)
month[i++] = *cur;
cur++;
if (*cur == 0) return(0);
}
month[i] = 0;
while (*cur == ' ') cur++;
if (*cur == 0) return(0);
while ((*cur >= '0') && (*cur <= '9'))
day = (day * 10) + (*cur++ - '0');
while (*cur == ' ') cur++;
if (*cur == 0) return(0);
if ((cur[1] == 0) || (cur[2] == 0)) return(0);
if ((cur[1] == ':') || (cur[2] == ':')) {
while ((*cur >= '0') && (*cur <= '9'))
hour = (hour * 10) + (*cur++ - '0');
if (*cur == ':') cur++;
while ((*cur >= '0') && (*cur <= '9'))
minute = (minute * 10) + (*cur++ - '0');
} else {
while ((*cur >= '0') && (*cur <= '9'))
year = (year * 10) + (*cur++ - '0');
}
while (*cur == ' ') cur++;
if (*cur == 0) return(0);
i = 0;
while ((*cur != '\n') && (*cur != '\r')) {
if (i < 150)
filename[i++] = *cur;
cur++;
if (*cur == 0) return(0);
}
filename[i] = 0;
if ((*cur != '\n') && (*cur != '\r'))
return(0);
while ((*cur == '\n') || (*cur == '\r'))
cur++;
}
if (callback != NULL) {
callback(userData, filename, attrib, owner, group, size, links,
year, month, day, hour, minute);
}
return(cur - list);
}
/**
* xmlNanoFTPList:
* @ctx: an FTP context
* @callback: the user callback
* @userData: the user callback data
* @filename: optional files to list
*
* Do a listing on the server. All files info are passed back
* in the callbacks.
*
* Returns -1 incase of error, 0 otherwise
*/
int
xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData,
const char *filename) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
char buf[4096 + 1];
int len, res;
int indx = 0, base;
fd_set rfd, efd;
struct timeval tv;
if (ctxt == NULL) return (-1);
if (filename == NULL) {
if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
return(-1);
ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
if (ctxt->dataFd == -1)
return(-1);
snprintf(buf, sizeof(buf), "LIST -L\r\n");
} else {
if (filename[0] != '/') {
if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
return(-1);
}
ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
if (ctxt->dataFd == -1)
return(-1);
snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename);
}
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");
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(res);
}
res = xmlNanoFTPReadResponse(ctxt);
if (res != 1) {
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(-res);
}
do {
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&rfd);
FD_SET(ctxt->dataFd, &rfd);
FD_ZERO(&efd);
FD_SET(ctxt->dataFd, &efd);
res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv);
if (res < 0) {
#ifdef DEBUG_FTP
perror("select");
#endif
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(-1);
}
if (res == 0) {
res = xmlNanoFTPCheckResponse(ctxt);
if (res < 0) {
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
ctxt->dataFd = -1;
return(-1);
}
if (res == 2) {
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(0);
}
continue;
}
if ((len = recv(ctxt->dataFd, &buf[indx], sizeof(buf) - (indx + 1), 0)) < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "recv");
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
ctxt->dataFd = -1;
return(-1);
}
#ifdef DEBUG_FTP
write(1, &buf[indx], len);
#endif
indx += len;
buf[indx] = 0;
base = 0;
do {
res = xmlNanoFTPParseList(&buf[base], callback, userData);
base += res;
} while (res > 0);
memmove(&buf[0], &buf[base], indx - base);
indx -= base;
} while (len != 0);
xmlNanoFTPCloseConnection(ctxt);
return(0);
}
/**
* xmlNanoFTPGetSocket:
* @ctx: an FTP context
* @filename: the file to retrieve (or NULL if path is in context).
*
* Initiate fetch of the given file from the server.
*
* Returns the socket for the data connection, or <0 in case of error
*/
int
xmlNanoFTPGetSocket(void *ctx, const char *filename) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
char buf[300];
int res, len;
if (ctx == NULL)
return(-1);
if ((filename == NULL) && (ctxt->path == NULL))
return(-1);
ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
if (ctxt->dataFd == -1)
return(-1);
snprintf(buf, sizeof(buf), "TYPE I\r\n");
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");
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(res);
}
res = xmlNanoFTPReadResponse(ctxt);
if (res != 2) {
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(-res);
}
if (filename == NULL)
snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path);
else
snprintf(buf, sizeof(buf), "RETR %s\r\n", filename);
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");
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(res);
}
res = xmlNanoFTPReadResponse(ctxt);
if (res != 1) {
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(-res);
}
return(ctxt->dataFd);
}
/**
* xmlNanoFTPGet:
* @ctx: an FTP context
* @callback: the user callback
* @userData: the user callback data
* @filename: the file to retrieve
*
* Fetch the given file from the server. All data are passed back
* in the callbacks. The last callback has a size of 0 block.
*
* Returns -1 incase of error, 0 otherwise
*/
int
xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData,
const char *filename) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
char buf[4096];
int len = 0, res;
fd_set rfd;
struct timeval tv;
if (ctxt == NULL) return(-1);
if ((filename == NULL) && (ctxt->path == NULL))
return(-1);
if (callback == NULL)
return(-1);
if (xmlNanoFTPGetSocket(ctxt, filename) < 0)
return(-1);
do {
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&rfd);
FD_SET(ctxt->dataFd, &rfd);
res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv);
if (res < 0) {
#ifdef DEBUG_FTP
perror("select");
#endif
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(-1);
}
if (res == 0) {
res = xmlNanoFTPCheckResponse(ctxt);
if (res < 0) {
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
ctxt->dataFd = -1;
return(-1);
}
if (res == 2) {
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(0);
}
continue;
}
if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) {
__xmlIOErr(XML_FROM_FTP, 0, "recv failed");
callback(userData, buf, len);
closesocket(ctxt->dataFd); ctxt->dataFd = -1;
return(-1);
}
callback(userData, buf, len);
} while (len != 0);
return(xmlNanoFTPCloseConnection(ctxt));
}
/**
* xmlNanoFTPRead:
* @ctx: the FTP context
* @dest: a buffer
* @len: the buffer length
*
* This function tries to read @len bytes from the existing FTP connection
* and saves them in @dest. This is a blocking call.
*
* Returns the number of byte read. 0 is an indication of an end of connection.
* -1 indicates a parameter error.
*/
int
xmlNanoFTPRead(void *ctx, void *dest, int len) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
if (ctx == NULL) return(-1);
if (ctxt->dataFd < 0) return(0);
if (dest == NULL) return(-1);
if (len <= 0) return(0);
len = recv(ctxt->dataFd, dest, len, 0);
if (len <= 0) {
if (len < 0)
__xmlIOErr(XML_FROM_FTP, 0, "recv failed");
xmlNanoFTPCloseConnection(ctxt);
}
#ifdef DEBUG_FTP
xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len);
#endif
return(len);
}
/**
* xmlNanoFTPOpen:
* @URL: the URL to the resource
*
* Start to fetch the given ftp:// resource
*
* Returns an FTP context, or NULL
*/
void*
xmlNanoFTPOpen(const char *URL) {
xmlNanoFTPCtxtPtr ctxt;
int sock;
xmlNanoFTPInit();
if (URL == NULL) return(NULL);
if (strncmp("ftp://", URL, 6)) return(NULL);
ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL);
if (ctxt == NULL) return(NULL);
if (xmlNanoFTPConnect(ctxt) < 0) {
xmlNanoFTPFreeCtxt(ctxt);
return(NULL);
}
sock = xmlNanoFTPGetSocket(ctxt, ctxt->path);
if (sock < 0) {
xmlNanoFTPFreeCtxt(ctxt);
return(NULL);
}
return(ctxt);
}
/**
* xmlNanoFTPClose:
* @ctx: an FTP context
*
* Close the connection and both control and transport
*
* Returns -1 incase of error, 0 otherwise
*/
int
xmlNanoFTPClose(void *ctx) {
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
if (ctxt == NULL)
return(-1);
if (ctxt->dataFd >= 0) {
closesocket(ctxt->dataFd);
ctxt->dataFd = -1;
}
if (ctxt->controlFd >= 0) {
xmlNanoFTPQuit(ctxt);
closesocket(ctxt->controlFd);
ctxt->controlFd = -1;
}
xmlNanoFTPFreeCtxt(ctxt);
return(0);
}
#ifdef STANDALONE
/************************************************************************
* *
* Basic test in Standalone mode *
* *
************************************************************************/
static
void ftpList(void *userData, const char *filename, const char* attrib,
const char *owner, const char *group, unsigned long size, int links,
int year, const char *month, int day, int hour, int minute) {
xmlGenericError(xmlGenericErrorContext,
"%s %s %s %ld %s\n", attrib, owner, group, size, filename);
}
static
void ftpData(void *userData, const char *data, int len) {
if (userData == NULL) return;
if (len <= 0) {
fclose((FILE*)userData);
return;
}
fwrite(data, len, 1, (FILE*)userData);
}
int main(int argc, char **argv) {
void *ctxt;
FILE *output;
char *tstfile = NULL;
xmlNanoFTPInit();
if (argc > 1) {
ctxt = xmlNanoFTPNewCtxt(argv[1]);
if (xmlNanoFTPConnect(ctxt) < 0) {
xmlGenericError(xmlGenericErrorContext,
"Couldn't connect to %s\n", argv[1]);
exit(1);
}
if (argc > 2)
tstfile = argv[2];
} else
ctxt = xmlNanoFTPConnectTo("localhost", 0);
if (ctxt == NULL) {
xmlGenericError(xmlGenericErrorContext,
"Couldn't connect to localhost\n");
exit(1);
}
xmlNanoFTPList(ctxt, ftpList, NULL, tstfile);
output = fopen("/tmp/tstdata", "w");
if (output != NULL) {
if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
xmlGenericError(xmlGenericErrorContext,
"Failed to get file\n");
}
xmlNanoFTPClose(ctxt);
xmlMemoryDump();
exit(0);
}
#endif /* STANDALONE */
#else /* !LIBXML_FTP_ENABLED */
#ifdef STANDALONE
#include <stdio.h>
int main(int argc, char **argv) {
xmlGenericError(xmlGenericErrorContext,
"%s : FTP support not compiled in\n", argv[0]);
return(0);
}
#endif /* STANDALONE */
#endif /* LIBXML_FTP_ENABLED */
#define bottom_nanoftp
#include "elfgcchack.h"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -