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

📄 ftp.c

📁 -
💻 C
📖 第 1 页 / 共 5 页
字号:
	    mode = mimeGetTransferMode(filename);	}	break;    }    if (mode == 'I')	ftpState->flags.binary = 1;    else	ftpState->flags.binary = 0;    snprintf(cbuf, 1024, "TYPE %c\r\n", mode);    ftpWriteCommand(cbuf, ftpState);    ftpState->state = SENT_TYPE;}static voidftpReadType(FtpStateData * ftpState){    int code = ftpState->ctrl.replycode;    char *path;    char *d, *p;    debug(9, 3) ("This is ftpReadType\n");    if (code == 200) {	p = path = xstrdup(strBuf(ftpState->request->urlpath));	if (*p == '/')	    p++;	while (*p) {	    d = p;	    p += strcspn(p, "/");	    if (*p)		*p++ = '\0';	    rfc1738_unescape(d);	    wordlistAdd(&ftpState->pathcomps, d);	}	xfree(path);	if (ftpState->pathcomps)	    ftpTraverseDirectory(ftpState);	else	    ftpListDir(ftpState);    } else {	ftpFail(ftpState);    }}static voidftpTraverseDirectory(FtpStateData * ftpState){    wordlist *w;    debug(9, 4) ("ftpTraverseDirectory %s\n",	ftpState->filepath ? ftpState->filepath : "<NULL>");    safe_free(ftpState->filepath);    /* Done? */    if (ftpState->pathcomps == NULL) {	debug(9, 3) ("the final component was a directory\n");	ftpListDir(ftpState);	return;    }    /* Go to next path component */    w = ftpState->pathcomps;    ftpState->filepath = w->key;    ftpState->pathcomps = w->next;    xfree(w);    /* Check if we are to CWD or RETR */    if (ftpState->pathcomps != NULL || ftpState->flags.isdir) {	ftpSendCwd(ftpState);    } else {	debug(9, 3) ("final component is probably a file\n");	ftpGetFile(ftpState);	return;    }}static voidftpSendCwd(FtpStateData * ftpState){    char *path = ftpState->filepath;    debug(9, 3) ("ftpSendCwd\n");    if (!strcmp(path, "..") || !strcmp(path, "/")) {	ftpState->flags.no_dotdot = 1;    } else {	ftpState->flags.no_dotdot = 0;    }    if (*path)	snprintf(cbuf, 1024, "CWD %s\r\n", path);    else	snprintf(cbuf, 1024, "CWD\r\n");    ftpWriteCommand(cbuf, ftpState);    ftpState->state = SENT_CWD;}static voidftpReadCwd(FtpStateData * ftpState){    int code = ftpState->ctrl.replycode;    debug(9, 3) ("This is ftpReadCwd\n");    if (code >= 200 && code < 300) {	/* CWD OK */	ftpUnhack(ftpState);	if (ftpState->cwd_message)	    wordlistDestroy(&ftpState->cwd_message);	ftpState->cwd_message = ftpState->ctrl.message;	ftpState->ctrl.message = NULL;	/* Continue to traverse the path */	ftpTraverseDirectory(ftpState);    } else {	/* CWD FAILED */	if (!ftpState->flags.put)	    ftpFail(ftpState);	else	    ftpTryMkdir(ftpState);    }}static voidftpTryMkdir(FtpStateData * ftpState){    char *path = ftpState->filepath;    debug(9, 3) ("ftpTryMkdir: with path=%s\n", path);    snprintf(cbuf, 1024, "MKD %s\r\n", path);    ftpWriteCommand(cbuf, ftpState);    ftpState->state = SENT_MKDIR;}static voidftpReadMkdir(FtpStateData * ftpState){    char *path = ftpState->filepath;    int code = ftpState->ctrl.replycode;    debug(9, 3) ("ftpReadMkdir: path %s, code %d\n", path, code);    if (code == 257) {		/* success */	ftpSendCwd(ftpState);    } else if (code == 550) {	/* dir exists */	if (ftpState->flags.put_mkdir) {	    ftpState->flags.put_mkdir = 1;	    ftpSendCwd(ftpState);	} else	    ftpSendReply(ftpState);    } else	ftpSendReply(ftpState);}static voidftpGetFile(FtpStateData * ftpState){    assert(*ftpState->filepath != '\0');    ftpState->flags.isdir = 0;    ftpSendMdtm(ftpState);}static voidftpListDir(FtpStateData * ftpState){    if (!ftpState->flags.isdir) {	debug(9, 3) ("Directory path did not end in /\n");	strcat(ftpState->title_url, "/");	ftpState->flags.isdir = 1;	ftpState->flags.use_base = 1;    }    ftpSendPasv(ftpState);}static voidftpSendMdtm(FtpStateData * ftpState){    assert(*ftpState->filepath != '\0');    snprintf(cbuf, 1024, "MDTM %s\r\n", ftpState->filepath);    ftpWriteCommand(cbuf, ftpState);    ftpState->state = SENT_MDTM;}static voidftpReadMdtm(FtpStateData * ftpState){    int code = ftpState->ctrl.replycode;    debug(9, 3) ("This is ftpReadMdtm\n");    if (code == 213) {	ftpState->mdtm = parse_iso3307_time(ftpState->ctrl.last_reply);	ftpUnhack(ftpState);    } else if (code < 0) {	ftpFail(ftpState);    }    ftpSendSize(ftpState);}static voidftpSendSize(FtpStateData * ftpState){    /* Only send SIZE for binary transfers. The returned size     * is useless on ASCII transfers */    if (ftpState->flags.binary) {	assert(ftpState->filepath != NULL);	assert(*ftpState->filepath != '\0');	snprintf(cbuf, 1024, "SIZE %s\r\n", ftpState->filepath);	ftpWriteCommand(cbuf, ftpState);	ftpState->state = SENT_SIZE;    } else	/* Skip to next state no non-binary transfers */	ftpSendPasv(ftpState);}static voidftpReadSize(FtpStateData * ftpState){    int code = ftpState->ctrl.replycode;    debug(9, 3) ("This is ftpReadSize\n");    if (code == 213) {	ftpUnhack(ftpState);	ftpState->size = atoi(ftpState->ctrl.last_reply);	if (ftpState->size == 0) {	    debug(9, 2) ("ftpReadSize: SIZE reported %s on %s\n",		ftpState->ctrl.last_reply,		ftpState->title_url);	    ftpState->size = -1;	}    } else if (code < 0) {	ftpFail(ftpState);    }    ftpSendPasv(ftpState);}static voidftpSendPasv(FtpStateData * ftpState){    int fd;    struct sockaddr_in addr;    socklen_t addr_len;    if (ftpState->data.fd >= 0) {	if (!ftpState->flags.datachannel_hack) {	    /* We are already connected, reuse this connection. */	    ftpRestOrList(ftpState);	    return;	} else {	    /* Close old connection */	    comm_close(ftpState->data.fd);	    ftpState->data.fd = -1;	}    }    if (!ftpState->flags.pasv_supported) {	ftpSendPort(ftpState);	return;    }    addr_len = sizeof(addr);    if (getsockname(ftpState->ctrl.fd, (struct sockaddr *) &addr, &addr_len)) {	debug(9, 0) ("ftpSendPasv: getsockname(%d,..): %s\n",	    ftpState->ctrl.fd, xstrerror());	addr.sin_addr = Config.Addrs.tcp_outgoing;    }    /* Open data channel with the same local address as control channel */    fd = comm_open(SOCK_STREAM,	0,	addr.sin_addr,	0,	COMM_NONBLOCKING,	storeUrl(ftpState->entry));    debug(9, 3) ("ftpSendPasv: Unconnected data socket created on FD %d\n", fd);    if (fd < 0) {	ftpFail(ftpState);	return;    }    /*     * No comm_add_close_handler() here.  If we have both ctrl and     * data FD's call ftpStateFree() upon close, then we have     * to delete the close handler which did NOT get called     * to prevent ftpStateFree() getting called twice.     * Instead we'll always call comm_close() on the ctrl FD.     */    ftpState->data.fd = fd;    snprintf(cbuf, 1024, "PASV\r\n");    ftpWriteCommand(cbuf, ftpState);    ftpState->state = SENT_PASV;}static voidftpReadPasv(FtpStateData * ftpState){    int code = ftpState->ctrl.replycode;    int h1, h2, h3, h4;    int p1, p2;    int n;    u_short port;    int fd = ftpState->data.fd;    char *buf = ftpState->ctrl.last_reply;    LOCAL_ARRAY(char, junk, 1024);    debug(9, 3) ("This is ftpReadPasv\n");    if (code != 227) {	debug(9, 3) ("PASV not supported by remote end\n");	comm_close(ftpState->data.fd);	ftpState->data.fd = -1;	ftpSendPort(ftpState);	return;    }    if ((int) strlen(buf) > 1024) {	debug(9, 1) ("ftpReadPasv: Avoiding potential buffer overflow\n");	ftpSendPort(ftpState);	return;    }    /*  227 Entering Passive Mode (h1,h2,h3,h4,p1,p2).  */    /*  ANSI sez [^0-9] is undefined, it breaks on Watcom cc */    debug(9, 5) ("scanning: %s\n", buf);    n = sscanf(buf, "%[^0123456789]%d,%d,%d,%d,%d,%d",	junk, &h1, &h2, &h3, &h4, &p1, &p2);    if (n != 7 || p1 < 0 || p2 < 0 || p1 > 255 || p2 > 255) {	debug(9, 3) ("Bad 227 reply\n");	debug(9, 3) ("n=%d, p1=%d, p2=%d\n", n, p1, p2);	ftpSendPort(ftpState);	return;    }    snprintf(junk, 1024, "%d.%d.%d.%d", h1, h2, h3, h4);    if (!safe_inet_addr(junk, NULL)) {	debug(9, 1) ("unsafe address (%s)\n", junk);	ftpSendPort(ftpState);	return;    }    port = ((p1 << 8) + p2);    if (0 == port) {	debug(9, 1) ("ftpReadPasv: Invalid PASV reply: %s\n", buf);	ftpSendPort(ftpState);	return;    }    debug(9, 5) ("ftpReadPasv: connecting to %s, port %d\n", junk, port);    ftpState->data.port = port;    ftpState->data.host = xstrdup(junk);    commConnectStart(fd, junk, port, ftpPasvCallback, ftpState);}static voidftpPasvCallback(int fd, int status, void *data){    FtpStateData *ftpState = data;    request_t *request = ftpState->request;    ErrorState *err;    debug(9, 3) ("ftpPasvCallback\n");    if (status != COMM_OK) {	err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE);	err->xerrno = errno;	err->host = xstrdup(ftpState->data.host);	err->port = ftpState->data.port;	err->request = requestLink(request);	errorAppendEntry(ftpState->entry, err);	comm_close(ftpState->ctrl.fd);	return;    }    ftpRestOrList(ftpState);}static intftpOpenListenSocket(FtpStateData * ftpState, int fallback){    int fd;    struct sockaddr_in addr;    socklen_t addr_len;    int on = 1;    u_short port = 0;    /*     * Set up a listen socket on the same local address as the     * control connection.     */    addr_len = sizeof(addr);    if (getsockname(ftpState->ctrl.fd, (struct sockaddr *) &addr, &addr_len)) {	debug(9, 0) ("ftpOpenListenSocket: getsockname(%d,..): %s\n",	    ftpState->ctrl.fd, xstrerror());	return -1;    }    /*     * REUSEADDR is needed in fallback mode, since the same port is     * used for both control and data.     */    if (fallback) {	setsockopt(ftpState->ctrl.fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));	port = ntohs(addr.sin_port);    }    fd = comm_open(SOCK_STREAM,	0,	addr.sin_addr,	port,	COMM_NONBLOCKING | (fallback ? COMM_REUSEADDR : 0),	storeUrl(ftpState->entry));    debug(9, 3) ("ftpOpenListenSocket: Unconnected data socket created on FD %d\n", fd);    if (fd < 0) {	debug(9, 0) ("ftpOpenListenSocket: comm_open failed\n");	return -1;    }    if (comm_listen(fd) < 0) {	comm_close(fd);	return -1;    }    ftpState->data.fd = fd;    ftpState->data.port = comm_local_port(fd);;    ftpState->data.host = NULL;    return fd;}static voidftpSendPort(FtpStateData * ftpState){    int fd;    struct sockaddr_in addr;    socklen_t addr_len;    unsigned char *addrptr;    unsigned char *portptr;    debug(9, 3) ("This is ftpSendPort\n");    ftpState->flags.pasv_supported = 0;    fd = ftpOpenListenSocket(ftpState, 0);    addr_len = sizeof(addr);    if (getsockname(fd, (struct sockaddr *) &addr, &addr_len)) {	debug(9, 0) ("ftpSendPort: getsockname(%d,..): %s\n", fd, xstrerror());	/* XXX Need to set error message */	ftpFail(ftpState);	return;    }    addrptr = (unsigned char *) &addr.sin_addr.s_addr;    portptr = (unsigned char *) &addr.sin_port;    snprintf(cbuf, 1024, "PORT %d,%d,%d,%d,%d,%d\r\n",	addrptr[0], addrptr[1], addrptr[2], addrptr[3],	portptr[0], portptr[1]);    ftpWriteCommand(cbuf, ftpState);    ftpState->state = SENT_PORT;}static voidftpReadPort(FtpStateData * ftpState){    int code = ftpState->ctrl.replycode;    debug(9, 3) ("This is ftpReadPort\n");    if (code != 200) {	/* Fall back on using the same port as the control connection */	debug(9, 3) ("PORT not supported by remote end\n");	comm_close(ftpState->data.fd);	ftpState->data.fd = -1;	ftpOpenListenSocket(ftpState, 1);    }    ftpRestOrList(ftpState);}/* "read" handler to accept data connection */static voidftpAcceptDataConnection(int fd, void *data){    FtpStateData *ftpState = data;    struct sockaddr_in peer, me;    debug(9, 3) ("ftpAcceptDataConnection\n");    fd = comm_accept(fd, &peer, &me);    if (fd < 0) {	debug(9, 1) ("ftpHandleDataAccept: comm_accept(%d): %s", fd, xstrerror());	/* XXX Need to set error message */	ftpFail(ftpState);	return;    }    /* Replace the Listen socket with the accepted data socket */    comm_close(ftpState->data.fd);    debug(9, 3) ("ftpAcceptDataConnection: Connected data socket on FD %d\n", fd);    ftpState->data.fd = fd;    ftpState->data.port = ntohs(peer.sin_port);    ftpState->data.host = xstrdup(inet_ntoa(peer.sin_addr));    commSetTimeout(ftpState->ctrl.fd, -1, NULL, NULL);    commSetTimeout(ftpState->data.fd, Config.Timeout.read, ftpTimeout,	ftpState);    /* XXX We should have a flag to track connect state...     *    host NULL -> not connected, port == local port     *    host set  -> connected, port == remote port     */    /* Restart state (SENT_NLST/LIST/RETR) */    FTP_SM_FUNCS[ftpState->state] (ftpState);}static void

⌨️ 快捷键说明

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