📄 ftp.c
字号:
int n; tv.tv_sec = 0; tv.tv_usec = 1; FD_ZERO(&write_set); FD_SET(s, &write_set); n = select(s + 1, NULL, &write_set, NULL, &tv); if (n < 1) {#ifndef PHP_WIN32 if (n == 0) errno = ETIMEDOUT;#endif return 0; } return 1;}/* }}} *//* {{{ my_accept */intmy_accept(ftpbuf_t *ftp, int s, struct sockaddr *addr, socklen_t *addrlen){ fd_set accept_set; struct timeval tv; int n; tv.tv_sec = ftp->timeout_sec; tv.tv_usec = 0; FD_ZERO(&accept_set); FD_SET(s, &accept_set); n = select(s + 1, &accept_set, NULL, NULL, &tv); if (n < 1) {#if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK)) if (n == 0) errno = ETIMEDOUT;#endif return -1; } return accept(s, addr, addrlen);}/* }}} *//* {{{ ftp_getdata */databuf_t*ftp_getdata(ftpbuf_t *ftp TSRMLS_DC){ int fd = -1; databuf_t *data; php_sockaddr_storage addr; struct sockaddr *sa; socklen_t size; union ipbox ipbox; char arg[sizeof("255, 255, 255, 255, 255, 255")]; struct timeval tv; /* ask for a passive connection if we need one */ if (ftp->pasv && !ftp_pasv(ftp, 1)) return NULL; /* alloc the data structure */ data = ecalloc(1, sizeof(*data)); data->listener = -1; data->fd = -1; data->type = ftp->type; sa = (struct sockaddr *) &ftp->localaddr; /* bind/listen */ if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "socket() failed: %s (%d)\n", strerror(errno), errno); goto bail; } /* passive connection handler */ if (ftp->pasv) { /* clear the ready status */ ftp->pasv = 1; /* connect */ /* Win 95/98 seems not to like size > sizeof(sockaddr_in) */ size = php_sockaddr_size(&ftp->pasvaddr); tv.tv_sec = ftp->timeout_sec; tv.tv_usec = 0; if (php_connect_nonb(fd, (struct sockaddr*) &ftp->pasvaddr, size, &tv) == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "php_connect_nonb() failed: %s (%d)\n", strerror(errno), errno); goto bail; } data->fd = fd; ftp->data = data; return data; } /* active (normal) connection */ /* bind to a local address */ php_any_addr(sa->sa_family, &addr, 0); size = php_sockaddr_size(&addr); if (bind(fd, (struct sockaddr*) &addr, size) == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "bind() failed: %s (%d)\n", strerror(errno), errno); goto bail; } if (getsockname(fd, (struct sockaddr*) &addr, &size) == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "getsockname() failed: %s (%d)\n", strerror(errno), errno); goto bail; } if (listen(fd, 5) == -1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "listen() failed: %s (%d)\n", strerror(errno), errno); goto bail; } data->listener = fd;#ifdef HAVE_IPV6 if (sa->sa_family == AF_INET6) { /* need to use EPRT */ char eprtarg[INET6_ADDRSTRLEN + sizeof("|x||xxxxx|")]; char out[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &((struct sockaddr_in6*) sa)->sin6_addr, out, sizeof(out)); sprintf(eprtarg, "|2|%s|%hu|", out, ntohs(((struct sockaddr_in6 *) &addr)->sin6_port)); if (!ftp_putcmd(ftp, "EPRT", eprtarg)) goto bail; if (!ftp_getresp(ftp) || ftp->resp != 200) goto bail; ftp->data = data; return data; }#endif /* send the PORT */ ipbox.ia[0] = ((struct sockaddr_in*) sa)->sin_addr; ipbox.s[2] = ((struct sockaddr_in*) &addr)->sin_port; sprintf(arg, "%u,%u,%u,%u,%u,%u", ipbox.c[0], ipbox.c[1], ipbox.c[2], ipbox.c[3], ipbox.c[4], ipbox.c[5]); if (!ftp_putcmd(ftp, "PORT", arg)) goto bail; if (!ftp_getresp(ftp) || ftp->resp != 200) goto bail; ftp->data = data; return data;bail: if (fd != -1) closesocket(fd); efree(data); return NULL;}/* }}} *//* {{{ data_accept */databuf_t*data_accept(databuf_t *data, ftpbuf_t *ftp){ php_sockaddr_storage addr; socklen_t size;#ifdef HAVE_OPENSSL_EXT SSL_CTX *ctx; TSRMLS_FETCH(); #endif if (data->fd != -1) goto data_accepted; size = sizeof(addr); data->fd = my_accept(ftp, data->listener, (struct sockaddr*) &addr, &size); closesocket(data->listener); data->listener = -1; if (data->fd == -1) { efree(data); return NULL; }data_accepted:#ifdef HAVE_OPENSSL_EXT /* now enable ssl if we need to */ if (ftp->use_ssl && ftp->use_ssl_for_data) { ctx = SSL_CTX_new(SSLv23_client_method()); if (ctx == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to create the SSL context"); return 0; } SSL_CTX_set_options(ctx, SSL_OP_ALL); data->ssl_handle = SSL_new(ctx); if (data->ssl_handle == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: failed to create the SSL handle"); SSL_CTX_free(ctx); return 0; } SSL_set_fd(data->ssl_handle, data->fd); if (ftp->old_ssl) { SSL_copy_session_id(data->ssl_handle, ftp->ssl_handle); } if (SSL_connect(data->ssl_handle) <= 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: SSL/TLS handshake failed"); SSL_shutdown(data->ssl_handle); return 0; } data->ssl_active = 1; } #endif return data;}/* }}} *//* {{{ data_close */databuf_t*data_close(ftpbuf_t *ftp, databuf_t *data){ if (data == NULL) return NULL; if (data->listener != -1) {#ifdef HAVE_OPENSSL_EXT if (data->ssl_active) { SSL_shutdown(data->ssl_handle); data->ssl_active = 0; }#endif closesocket(data->listener); } if (data->fd != -1) {#ifdef HAVE_OPENSSL_EXT if (data->ssl_active) { SSL_shutdown(data->ssl_handle); data->ssl_active = 0; }#endif closesocket(data->fd); } if (ftp) { ftp->data = NULL; } efree(data); return NULL;}/* }}} *//* {{{ ftp_genlist */char**ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC){ php_stream *tmpstream = NULL; databuf_t *data = NULL; char *ptr; int ch, lastch; int size, rcvd; int lines; char **ret = NULL; char **entry; char *text; if ((tmpstream = php_stream_fopen_tmpfile()) == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create temporary file. Check permissions in temporary files directory."); return NULL; } if (!ftp_type(ftp, FTPTYPE_ASCII)) goto bail; if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) goto bail; ftp->data = data; if (!ftp_putcmd(ftp, cmd, path)) goto bail; if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125 && ftp->resp != 226)) goto bail; /* some servers don't open a ftp-data connection if the directory is empty */ if (ftp->resp == 226) { ftp->data = data_close(ftp, data); php_stream_close(tmpstream); return ecalloc(1, sizeof(char**)); } /* pull data buffer into tmpfile */ if ((data = data_accept(data, ftp)) == NULL) goto bail; size = 0; lines = 0; lastch = 0; while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) { if (rcvd == -1) goto bail; php_stream_write(tmpstream, data->buf, rcvd); size += rcvd; for (ptr = data->buf; rcvd; rcvd--, ptr++) { if (*ptr == '\n' && lastch == '\r') lines++; else size++; lastch = *ptr; } } ftp->data = data = data_close(ftp, data); php_stream_rewind(tmpstream); ret = emalloc((lines + 1) * sizeof(char**) + size * sizeof(char*)); entry = ret; text = (char*) (ret + lines + 1); *entry = text; lastch = 0; while ((ch = php_stream_getc(tmpstream)) != EOF) { if (ch == '\n' && lastch == '\r') { *(text - 1) = 0; *++entry = text; } else { *text++ = ch; } lastch = ch; } *entry = NULL; php_stream_close(tmpstream); if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) { efree(ret); return NULL; } return ret;bail: ftp->data = data_close(ftp, data); php_stream_close(tmpstream); if (ret) efree(ret); return NULL;}/* }}} *//* {{{ ftp_nb_get */intftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, int resumepos TSRMLS_DC){ databuf_t *data = NULL; char arg[11]; if (ftp == NULL) goto bail; if (!ftp_type(ftp, type)) { goto bail; } if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) { goto bail; } if (resumepos>0) { sprintf(arg, "%u", resumepos); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 350)) { goto bail; } } if (!ftp_putcmd(ftp, "RETR", path)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) { goto bail; } if ((data = data_accept(data, ftp)) == NULL) { goto bail; } ftp->data = data; ftp->stream = outstream; ftp->lastch = 0; ftp->nb = 1; return (ftp_nb_continue_read(ftp));bail: ftp->data = data_close(ftp, data); return PHP_FTP_FAILED;}/* }}} *//* {{{ ftp_nb_continue_read */intftp_nb_continue_read(ftpbuf_t *ftp){ databuf_t *data = NULL; char *ptr; int lastch; size_t rcvd; ftptype_t type; TSRMLS_FETCH(); data = ftp->data; /* check if there is already more data */ if (!data_available(ftp, data->fd)) { return PHP_FTP_MOREDATA; } type = ftp->type; lastch = ftp->lastch; if ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) { if (rcvd == -1) { goto bail; } if (type == FTPTYPE_ASCII) { for (ptr = data->buf; rcvd; rcvd--, ptr++) { if (lastch == '\r' && *ptr != '\n') php_stream_putc(ftp->stream, '\r'); if (*ptr != '\r') php_stream_putc(ftp->stream, *ptr); lastch = *ptr; } } else { if (rcvd != php_stream_write(ftp->stream, data->buf, rcvd)) goto bail; } ftp->lastch = lastch; return PHP_FTP_MOREDATA; } if (type == FTPTYPE_ASCII && lastch == '\r') php_stream_putc(ftp->stream, '\r'); ftp->data = data = data_close(ftp, data); if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) { goto bail; } ftp->nb = 0; return PHP_FTP_FINISHED;bail: ftp->nb = 0; ftp->data = data_close(ftp, data); return PHP_FTP_FAILED;}/* }}} *//* {{{ ftp_nb_put */intftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, int startpos TSRMLS_DC){ databuf_t *data = NULL; char arg[11]; if (ftp == NULL) return 0; if (!ftp_type(ftp, type)) goto bail; if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) goto bail; if (startpos>0) { if (startpos > 2147483647) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP cannot handle files with a size greater then 2147483647 bytes.\n"); goto bail; } sprintf(arg, "%u", startpos); if (!ftp_putcmd(ftp, "REST", arg)) { goto bail; } if (!ftp_getresp(ftp) || (ftp->resp != 350)) { goto bail; } } if (!ftp_putcmd(ftp, "STOR", path)) goto bail; if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) goto bail; if ((data = data_accept(data, ftp)) == NULL) goto bail; ftp->data = data; ftp->stream = instream; ftp->lastch = 0; ftp->nb = 1; return (ftp_nb_continue_write(ftp));bail: ftp->data = data_close(ftp, data); return PHP_FTP_FAILED;}/* }}} *//* {{{ ftp_nb_continue_write */intftp_nb_continue_write(ftpbuf_t *ftp){ int size; char *ptr; int ch; TSRMLS_FETCH(); /* check if we can write more data */ if (!data_writeable(ftp, ftp->data->fd)) { return PHP_FTP_MOREDATA; } size = 0; ptr = ftp->data->buf; while (!php_stream_eof(ftp->stream) && (ch = php_stream_getc(ftp->stream))!=EOF) { if (ch == '\n' && ftp->type == FTPTYPE_ASCII) { *ptr++ = '\r'; size++; } *ptr++ = ch; size++; /* flush if necessary */ if (FTP_BUFSIZE - size < 2) { if (my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) goto bail; return PHP_FTP_MOREDATA; } } if (size && my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) goto bail; ftp->data = data_close(ftp, ftp->data); if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) goto bail; ftp->nb = 0; return PHP_FTP_FINISHED;bail: ftp->data = data_close(ftp, ftp->data); ftp->nb = 0; return PHP_FTP_FAILED;}/* }}} */#endif /* HAVE_FTP *//* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -