PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/ftp - ftp.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 486 840 57.9 %
Date: 2015-03-01 Functions: 36 43 83.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2015 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andrew Skalski <askalski@chek.com>                          |
      16             :    |          Stefan Esser <sesser@php.net> (resume functions)            |
      17             :    +----------------------------------------------------------------------+
      18             :  */
      19             : 
      20             : /* $Id$ */
      21             : 
      22             : #ifdef HAVE_CONFIG_H
      23             : #include "config.h"
      24             : #endif
      25             : 
      26             : #include "php.h"
      27             : 
      28             : #if HAVE_FTP
      29             : 
      30             : #include <stdio.h>
      31             : #include <ctype.h>
      32             : #include <stdlib.h>
      33             : #ifdef HAVE_UNISTD_H
      34             : #include <unistd.h>
      35             : #endif
      36             : #include <fcntl.h>
      37             : #include <string.h>
      38             : #include <time.h>
      39             : #ifdef PHP_WIN32
      40             : #include <winsock2.h>
      41             : #elif defined(NETWARE)
      42             : #ifdef USE_WINSOCK    /* Modified to use Winsock (NOVSOCK2.H), at least for now */
      43             : #include <novsock2.h>
      44             : #else
      45             : #include <sys/socket.h>
      46             : #include <netinet/in.h>
      47             : #include <netdb.h>
      48             : #endif
      49             : #else
      50             : #ifdef HAVE_SYS_TYPES_H
      51             : #include <sys/types.h>
      52             : #endif
      53             : #include <sys/socket.h>
      54             : #include <netinet/in.h>
      55             : #include <arpa/inet.h>
      56             : #include <netdb.h>
      57             : #endif
      58             : #include <errno.h>
      59             : 
      60             : #if HAVE_SYS_TIME_H
      61             : #include <sys/time.h>
      62             : #endif
      63             : 
      64             : #ifdef HAVE_SYS_SELECT_H
      65             : #include <sys/select.h>
      66             : #endif
      67             : 
      68             : #if HAVE_OPENSSL_EXT
      69             : #include <openssl/ssl.h>
      70             : #endif
      71             : 
      72             : #include "ftp.h"
      73             : #include "ext/standard/fsock.h"
      74             : 
      75             : /* Additional headers for NetWare */
      76             : #if defined(NETWARE) && !defined(USE_WINSOCK)
      77             : #include <sys/select.h>
      78             : #endif
      79             : 
      80             : /* sends an ftp command, returns true on success, false on error.
      81             :  * it sends the string "cmd args\r\n" if args is non-null, or
      82             :  * "cmd\r\n" if args is null
      83             :  */
      84             : static int              ftp_putcmd(     ftpbuf_t *ftp,
      85             :                                         const char *cmd,
      86             :                                         const char *args);
      87             : 
      88             : /* wrapper around send/recv to handle timeouts */
      89             : static int              my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len);
      90             : static int              my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len);
      91             : static int              my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen);
      92             : 
      93             : /* reads a line the socket , returns true on success, false on error */
      94             : static int              ftp_readline(ftpbuf_t *ftp);
      95             : 
      96             : /* reads an ftp response, returns true on success, false on error */
      97             : static int              ftp_getresp(ftpbuf_t *ftp);
      98             : 
      99             : /* sets the ftp transfer type */
     100             : static int              ftp_type(ftpbuf_t *ftp, ftptype_t type);
     101             : 
     102             : /* opens up a data stream */
     103             : static databuf_t*       ftp_getdata(ftpbuf_t *ftp);
     104             : 
     105             : /* accepts the data connection, returns updated data buffer */
     106             : static databuf_t*       data_accept(databuf_t *data, ftpbuf_t *ftp);
     107             : 
     108             : /* closes the data connection, returns NULL */
     109             : static databuf_t*       data_close(ftpbuf_t *ftp, databuf_t *data);
     110             : 
     111             : /* generic file lister */
     112             : static char**           ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path);
     113             : 
     114             : /* IP and port conversion box */
     115             : union ipbox {
     116             :         struct in_addr  ia[2];
     117             :         unsigned short  s[4];
     118             :         unsigned char   c[8];
     119             : };
     120             : 
     121             : /* {{{ ftp_open
     122             :  */
     123             : ftpbuf_t*
     124          32 : ftp_open(const char *host, short port, zend_long timeout_sec)
     125             : {
     126             :         ftpbuf_t                *ftp;
     127             :         socklen_t                size;
     128             :         struct timeval tv;
     129             : 
     130             : 
     131             :         /* alloc the ftp structure */
     132          32 :         ftp = ecalloc(1, sizeof(*ftp));
     133             : 
     134          32 :         tv.tv_sec = timeout_sec;
     135          32 :         tv.tv_usec = 0;
     136             : 
     137          32 :         ftp->fd = php_network_connect_socket_to_host(host,
     138             :                         (unsigned short) (port ? port : 21), SOCK_STREAM,
     139             :                         0, &tv, NULL, NULL, NULL, 0, STREAM_SOCKOP_NONE);
     140          32 :         if (ftp->fd == -1) {
     141           1 :                 goto bail;
     142             :         }
     143             : 
     144             :         /* Default Settings */
     145          31 :         ftp->timeout_sec = timeout_sec;
     146          31 :         ftp->nb = 0;
     147             : 
     148          31 :         size = sizeof(ftp->localaddr);
     149          31 :         memset(&ftp->localaddr, 0, size);
     150          31 :         if (getsockname(ftp->fd, (struct sockaddr*) &ftp->localaddr, &size) != 0) {
     151           0 :                 php_error_docref(NULL, E_WARNING, "getsockname failed: %s (%d)", strerror(errno), errno);
     152           0 :                 goto bail;
     153             :         }
     154             : 
     155          31 :         if (!ftp_getresp(ftp) || ftp->resp != 220) {
     156             :                 goto bail;
     157             :         }
     158             : 
     159          31 :         return ftp;
     160             : 
     161             : bail:
     162           1 :         if (ftp->fd != -1) {
     163           0 :                 closesocket(ftp->fd);
     164             :         }
     165           1 :         efree(ftp);
     166           1 :         return NULL;
     167             : }
     168             : /* }}} */
     169             : 
     170             : /* {{{ ftp_close
     171             :  */
     172             : ftpbuf_t*
     173          31 : ftp_close(ftpbuf_t *ftp)
     174             : {
     175          31 :         if (ftp == NULL) {
     176           0 :                 return NULL;
     177             :         }
     178          31 :         if (ftp->data) {
     179           4 :                 data_close(ftp, ftp->data);
     180             :         }
     181          31 :         if (ftp->stream && ftp->closestream) {
     182           1 :                         php_stream_close(ftp->stream);
     183             :         }
     184          31 :         if (ftp->fd != -1) {
     185             : #if HAVE_OPENSSL_EXT
     186          31 :                 if (ftp->ssl_active) {
     187           1 :                         SSL_shutdown(ftp->ssl_handle);
     188           1 :                         SSL_free(ftp->ssl_handle);
     189             :                 }
     190             : #endif
     191          31 :                 closesocket(ftp->fd);
     192             :         }
     193          31 :         ftp_gc(ftp);
     194          31 :         efree(ftp);
     195          31 :         return NULL;
     196             : }
     197             : /* }}} */
     198             : 
     199             : /* {{{ ftp_gc
     200             :  */
     201             : void
     202          31 : ftp_gc(ftpbuf_t *ftp)
     203             : {
     204          31 :         if (ftp == NULL) {
     205           0 :                 return;
     206             :         }
     207          31 :         if (ftp->pwd) {
     208           1 :                 efree(ftp->pwd);
     209           1 :                 ftp->pwd = NULL;
     210             :         }
     211          31 :         if (ftp->syst) {
     212           2 :                 efree(ftp->syst);
     213           2 :                 ftp->syst = NULL;
     214             :         }
     215             : }
     216             : /* }}} */
     217             : 
     218             : /* {{{ ftp_quit
     219             :  */
     220             : int
     221          11 : ftp_quit(ftpbuf_t *ftp)
     222             : {
     223          11 :         if (ftp == NULL) {
     224           0 :                 return 0;
     225             :         }
     226             : 
     227          11 :         if (!ftp_putcmd(ftp, "QUIT", NULL)) {
     228           0 :                 return 0;
     229             :         }
     230          11 :         if (!ftp_getresp(ftp) || ftp->resp != 221) {
     231          11 :                 return 0;
     232             :         }
     233             : 
     234           0 :         if (ftp->pwd) {
     235           0 :                 efree(ftp->pwd);
     236           0 :                 ftp->pwd = NULL;
     237             :         }
     238             : 
     239           0 :         return 1;
     240             : }
     241             : /* }}} */
     242             : 
     243             : /* {{{ ftp_login
     244             :  */
     245             : int
     246          32 : ftp_login(ftpbuf_t *ftp, const char *user, const char *pass)
     247             : {
     248             : #if HAVE_OPENSSL_EXT
     249          32 :         SSL_CTX *ctx = NULL;
     250          32 :         zend_long ssl_ctx_options = SSL_OP_ALL;
     251             : #endif
     252          32 :         if (ftp == NULL) {
     253           0 :                 return 0;
     254             :         }
     255             : 
     256             : #if HAVE_OPENSSL_EXT
     257          32 :         if (ftp->use_ssl && !ftp->ssl_active) {
     258           2 :                 if (!ftp_putcmd(ftp, "AUTH", "TLS")) {
     259           0 :                         return 0;
     260             :                 }
     261           2 :                 if (!ftp_getresp(ftp)) {
     262           0 :                         return 0;
     263             :                 }
     264             : 
     265           2 :                 if (ftp->resp != 234) {
     266           1 :                         if (!ftp_putcmd(ftp, "AUTH", "SSL")) {
     267           0 :                                 return 0;
     268             :                         }
     269           1 :                         if (!ftp_getresp(ftp)) {
     270           0 :                                 return 0;
     271             :                         }
     272             : 
     273           1 :                         if (ftp->resp != 334) {
     274           1 :                                 return 0;
     275             :                         } else {
     276           0 :                                 ftp->old_ssl = 1;
     277           0 :                                 ftp->use_ssl_for_data = 1;
     278             :                         }
     279             :                 }
     280             : 
     281           1 :                 ctx = SSL_CTX_new(SSLv23_client_method());
     282           1 :                 if (ctx == NULL) {
     283           0 :                         php_error_docref(NULL, E_WARNING, "failed to create the SSL context");
     284           0 :                         return 0;
     285             :                 }
     286             : 
     287             : #if OPENSSL_VERSION_NUMBER >= 0x0090605fL
     288           1 :                 ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
     289             : #endif
     290           1 :                 SSL_CTX_set_options(ctx, ssl_ctx_options);
     291             : 
     292           1 :                 ftp->ssl_handle = SSL_new(ctx);
     293           1 :                 if (ftp->ssl_handle == NULL) {
     294           0 :                         php_error_docref(NULL, E_WARNING, "failed to create the SSL handle");
     295           0 :                         SSL_CTX_free(ctx);
     296           0 :                         return 0;
     297             :                 }
     298             : 
     299           1 :                 SSL_set_fd(ftp->ssl_handle, ftp->fd);
     300             : 
     301           1 :                 if (SSL_connect(ftp->ssl_handle) <= 0) {
     302           0 :                         php_error_docref(NULL, E_WARNING, "SSL/TLS handshake failed");
     303           0 :                         SSL_shutdown(ftp->ssl_handle);
     304           0 :                         SSL_free(ftp->ssl_handle);
     305           0 :                         return 0;
     306             :                 }
     307             : 
     308           1 :                 ftp->ssl_active = 1;
     309             : 
     310           1 :                 if (!ftp->old_ssl) {
     311             : 
     312             :                         /* set protection buffersize to zero */
     313           1 :                         if (!ftp_putcmd(ftp, "PBSZ", "0")) {
     314           0 :                                 return 0;
     315             :                         }
     316           1 :                         if (!ftp_getresp(ftp)) {
     317           0 :                                 return 0;
     318             :                         }
     319             : 
     320             :                         /* enable data conn encryption */
     321           1 :                         if (!ftp_putcmd(ftp, "PROT", "P")) {
     322           0 :                                 return 0;
     323             :                         }
     324           1 :                         if (!ftp_getresp(ftp)) {
     325           0 :                                 return 0;
     326             :                         }
     327             : 
     328           1 :                         ftp->use_ssl_for_data = (ftp->resp >= 200 && ftp->resp <=299);
     329             :                 }
     330             :         }
     331             : #endif
     332             : 
     333          31 :         if (!ftp_putcmd(ftp, "USER", user)) {
     334           0 :                 return 0;
     335             :         }
     336          31 :         if (!ftp_getresp(ftp)) {
     337           0 :                 return 0;
     338             :         }
     339          31 :         if (ftp->resp == 230) {
     340           4 :                 return 1;
     341             :         }
     342          27 :         if (ftp->resp != 331) {
     343           0 :                 return 0;
     344             :         }
     345          27 :         if (!ftp_putcmd(ftp, "PASS", pass)) {
     346           0 :                 return 0;
     347             :         }
     348          27 :         if (!ftp_getresp(ftp)) {
     349           0 :                 return 0;
     350             :         }
     351          27 :         return (ftp->resp == 230);
     352             : }
     353             : /* }}} */
     354             : 
     355             : /* {{{ ftp_reinit
     356             :  */
     357             : int
     358           0 : ftp_reinit(ftpbuf_t *ftp)
     359             : {
     360           0 :         if (ftp == NULL) {
     361           0 :                 return 0;
     362             :         }
     363             : 
     364           0 :         ftp_gc(ftp);
     365             : 
     366           0 :         ftp->nb = 0;
     367             : 
     368           0 :         if (!ftp_putcmd(ftp, "REIN", NULL)) {
     369           0 :                 return 0;
     370             :         }
     371           0 :         if (!ftp_getresp(ftp) || ftp->resp != 220) {
     372           0 :                 return 0;
     373             :         }
     374             : 
     375           0 :         return 1;
     376             : }
     377             : /* }}} */
     378             : 
     379             : /* {{{ ftp_syst
     380             :  */
     381             : const char*
     382           3 : ftp_syst(ftpbuf_t *ftp)
     383             : {
     384             :         char *syst, *end;
     385             : 
     386           3 :         if (ftp == NULL) {
     387           0 :                 return NULL;
     388             :         }
     389             : 
     390             :         /* default to cached value */
     391           3 :         if (ftp->syst) {
     392           0 :                 return ftp->syst;
     393             :         }
     394           3 :         if (!ftp_putcmd(ftp, "SYST", NULL)) {
     395           0 :                 return NULL;
     396             :         }
     397           3 :         if (!ftp_getresp(ftp) || ftp->resp != 215) {
     398           1 :                 return NULL;
     399             :         }
     400           2 :         syst = ftp->inbuf;
     401           6 :         while (*syst == ' ') {
     402           2 :                 syst++;
     403             :         }
     404           2 :         if ((end = strchr(syst, ' '))) {
     405           2 :                 *end = 0;
     406             :         }
     407           2 :         ftp->syst = estrdup(syst);
     408           2 :         if (end) {
     409           2 :                 *end = ' ';
     410             :         }
     411           2 :         return ftp->syst;
     412             : }
     413             : /* }}} */
     414             : 
     415             : /* {{{ ftp_pwd
     416             :  */
     417             : const char*
     418           6 : ftp_pwd(ftpbuf_t *ftp)
     419             : {
     420             :         char *pwd, *end;
     421             : 
     422           6 :         if (ftp == NULL) {
     423           0 :                 return NULL;
     424             :         }
     425             : 
     426             :         /* default to cached value */
     427           6 :         if (ftp->pwd) {
     428           0 :                 return ftp->pwd;
     429             :         }
     430           6 :         if (!ftp_putcmd(ftp, "PWD", NULL)) {
     431           0 :                 return NULL;
     432             :         }
     433           6 :         if (!ftp_getresp(ftp) || ftp->resp != 257) {
     434           1 :                 return NULL;
     435             :         }
     436             :         /* copy out the pwd from response */
     437           5 :         if ((pwd = strchr(ftp->inbuf, '"')) == NULL) {
     438           0 :                 return NULL;
     439             :         }
     440           5 :         if ((end = strrchr(++pwd, '"')) == NULL) {
     441           0 :                 return NULL;
     442             :         }
     443           5 :         ftp->pwd = estrndup(pwd, end - pwd);
     444             : 
     445           5 :         return ftp->pwd;
     446             : }
     447             : /* }}} */
     448             : 
     449             : /* {{{ ftp_exec
     450             :  */
     451             : int
     452           2 : ftp_exec(ftpbuf_t *ftp, const char *cmd)
     453             : {
     454           2 :         if (ftp == NULL) {
     455           0 :                 return 0;
     456             :         }
     457           2 :         if (!ftp_putcmd(ftp, "SITE EXEC", cmd)) {
     458           0 :                 return 0;
     459             :         }
     460           2 :         if (!ftp_getresp(ftp) || ftp->resp != 200) {
     461           1 :                 return 0;
     462             :         }
     463             : 
     464           1 :         return 1;
     465             : }
     466             : /* }}} */
     467             : 
     468             : /* {{{ ftp_raw
     469             :  */
     470             : void
     471           4 : ftp_raw(ftpbuf_t *ftp, const char *cmd, zval *return_value)
     472             : {
     473           4 :         if (ftp == NULL || cmd == NULL) {
     474           0 :                 RETURN_NULL();
     475             :         }
     476           4 :         if (!ftp_putcmd(ftp, cmd, NULL)) {
     477           0 :                 RETURN_NULL();
     478             :         }
     479           4 :         array_init(return_value);
     480           4 :         while (ftp_readline(ftp)) {
     481          10 :                 add_next_index_string(return_value, ftp->inbuf);
     482          10 :                 if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
     483           4 :                         return;
     484             :                 }
     485             :         }
     486             : }
     487             : /* }}} */
     488             : 
     489             : /* {{{ ftp_chdir
     490             :  */
     491             : int
     492           4 : ftp_chdir(ftpbuf_t *ftp, const char *dir)
     493             : {
     494           4 :         if (ftp == NULL) {
     495           0 :                 return 0;
     496             :         }
     497             : 
     498           4 :         if (ftp->pwd) {
     499           3 :                 efree(ftp->pwd);
     500           3 :                 ftp->pwd = NULL;
     501             :         }
     502             : 
     503           4 :         if (!ftp_putcmd(ftp, "CWD", dir)) {
     504           0 :                 return 0;
     505             :         }
     506           4 :         if (!ftp_getresp(ftp) || ftp->resp != 250) {
     507           1 :                 return 0;
     508             :         }
     509           3 :         return 1;
     510             : }
     511             : /* }}} */
     512             : 
     513             : /* {{{ ftp_cdup
     514             :  */
     515             : int
     516           2 : ftp_cdup(ftpbuf_t *ftp)
     517             : {
     518           2 :         if (ftp == NULL) {
     519           0 :                 return 0;
     520             :         }
     521             : 
     522           2 :         if (ftp->pwd) {
     523           1 :                 efree(ftp->pwd);
     524           1 :                 ftp->pwd = NULL;
     525             :         }
     526             : 
     527           2 :         if (!ftp_putcmd(ftp, "CDUP", NULL)) {
     528           0 :                 return 0;
     529             :         }
     530           2 :         if (!ftp_getresp(ftp) || ftp->resp != 250) {
     531           1 :                 return 0;
     532             :         }
     533           1 :         return 1;
     534             : }
     535             : /* }}} */
     536             : 
     537             : /* {{{ ftp_mkdir
     538             :  */
     539             : zend_string*
     540           3 : ftp_mkdir(ftpbuf_t *ftp, const char *dir)
     541             : {
     542             :         char *mkd, *end;
     543             :         zend_string *ret;
     544             : 
     545           3 :         if (ftp == NULL) {
     546           0 :                 return NULL;
     547             :         }
     548           3 :         if (!ftp_putcmd(ftp, "MKD", dir)) {
     549           0 :                 return NULL;
     550             :         }
     551           3 :         if (!ftp_getresp(ftp) || ftp->resp != 257) {
     552           1 :                 return NULL;
     553             :         }
     554             :         /* copy out the dir from response */
     555           2 :         if ((mkd = strchr(ftp->inbuf, '"')) == NULL) {
     556           2 :                 return zend_string_init(dir, strlen(dir), 0);
     557             :         }
     558           1 :         if ((end = strrchr(++mkd, '"')) == NULL) {
     559           0 :                 return NULL;
     560             :         }
     561           1 :         *end = 0;
     562           2 :         ret = zend_string_init(mkd, end - mkd, 0);
     563           1 :         *end = '"';
     564             : 
     565           1 :         return ret;
     566             : }
     567             : /* }}} */
     568             : 
     569             : /* {{{ ftp_rmdir
     570             :  */
     571             : int
     572           2 : ftp_rmdir(ftpbuf_t *ftp, const char *dir)
     573             : {
     574           2 :         if (ftp == NULL) {
     575           0 :                 return 0;
     576             :         }
     577           2 :         if (!ftp_putcmd(ftp, "RMD", dir)) {
     578           0 :                 return 0;
     579             :         }
     580           2 :         if (!ftp_getresp(ftp) || ftp->resp != 250) {
     581           1 :                 return 0;
     582             :         }
     583           1 :         return 1;
     584             : }
     585             : /* }}} */
     586             : 
     587             : /* {{{ ftp_chmod
     588             :  */
     589             : int
     590           2 : ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int filename_len)
     591             : {
     592             :         char *buffer;
     593             : 
     594           2 :         if (ftp == NULL || filename_len <= 0) {
     595           0 :                 return 0;
     596             :         }
     597             : 
     598           2 :         spprintf(&buffer, 0, "CHMOD %o %s", mode, filename);
     599             : 
     600           2 :         if (!ftp_putcmd(ftp, "SITE", buffer)) {
     601           0 :                 efree(buffer);
     602           0 :                 return 0;
     603             :         }
     604             : 
     605           2 :         efree(buffer);
     606             : 
     607           2 :         if (!ftp_getresp(ftp) || ftp->resp != 200) {
     608           1 :                 return 0;
     609             :         }
     610             : 
     611           1 :         return 1;
     612             : }
     613             : /* }}} */
     614             : 
     615             : /* {{{ ftp_alloc
     616             :  */
     617             : int
     618           3 : ftp_alloc(ftpbuf_t *ftp, const zend_long size, zend_string **response)
     619             : {
     620             :         char buffer[64];
     621             : 
     622           3 :         if (ftp == NULL || size <= 0) {
     623           0 :                 return 0;
     624             :         }
     625             : 
     626           3 :         snprintf(buffer, sizeof(buffer) - 1, ZEND_LONG_FMT, size);
     627             : 
     628           3 :         if (!ftp_putcmd(ftp, "ALLO", buffer)) {
     629           0 :                 return 0;
     630             :         }
     631             : 
     632           3 :         if (!ftp_getresp(ftp)) {
     633           0 :                 return 0;
     634             :         }
     635             : 
     636           3 :         if (response) {
     637           2 :                 *response = zend_string_init(ftp->inbuf, strlen(ftp->inbuf), 0);
     638             :         }
     639             : 
     640           3 :         if (ftp->resp < 200 || ftp->resp >= 300) {
     641           1 :                 return 0;
     642             :         }
     643             : 
     644           2 :         return 1;
     645             : }
     646             : /* }}} */
     647             : 
     648             : /* {{{ ftp_nlist
     649             :  */
     650             : char**
     651           6 : ftp_nlist(ftpbuf_t *ftp, const char *path)
     652             : {
     653           6 :         return ftp_genlist(ftp, "NLST", path);
     654             : }
     655             : /* }}} */
     656             : 
     657             : /* {{{ ftp_list
     658             :  */
     659             : char**
     660           1 : ftp_list(ftpbuf_t *ftp, const char *path, int recursive)
     661             : {
     662           1 :         return ftp_genlist(ftp, ((recursive) ? "LIST -R" : "LIST"), path);
     663             : }
     664             : /* }}} */
     665             : 
     666             : /* {{{ ftp_type
     667             :  */
     668             : int
     669          25 : ftp_type(ftpbuf_t *ftp, ftptype_t type)
     670             : {
     671          25 :         char typechar[2] = "?";
     672             : 
     673          25 :         if (ftp == NULL) {
     674           0 :                 return 0;
     675             :         }
     676          25 :         if (type == ftp->type) {
     677           4 :                 return 1;
     678             :         }
     679          21 :         if (type == FTPTYPE_ASCII) {
     680          14 :                 typechar[0] = 'A';
     681           7 :         } else if (type == FTPTYPE_IMAGE) {
     682           7 :                 typechar[0] = 'I';
     683             :         } else {
     684           0 :                 return 0;
     685             :         }
     686          21 :         if (!ftp_putcmd(ftp, "TYPE", typechar)) {
     687           0 :                 return 0;
     688             :         }
     689          21 :         if (!ftp_getresp(ftp) || ftp->resp != 200) {
     690           1 :                 return 0;
     691             :         }
     692          20 :         ftp->type = type;
     693             : 
     694          20 :         return 1;
     695             : }
     696             : /* }}} */
     697             : 
     698             : /* {{{ ftp_pasv
     699             :  */
     700             : int
     701           0 : ftp_pasv(ftpbuf_t *ftp, int pasv)
     702             : {
     703             :         char                    *ptr;
     704             :         union ipbox             ipbox;
     705             :         unsigned long           b[6];
     706             :         socklen_t                       n;
     707             :         struct sockaddr *sa;
     708             :         struct sockaddr_in *sin;
     709             : 
     710           0 :         if (ftp == NULL) {
     711           0 :                 return 0;
     712             :         }
     713           0 :         if (pasv && ftp->pasv == 2) {
     714           0 :                 return 1;
     715             :         }
     716           0 :         ftp->pasv = 0;
     717           0 :         if (!pasv) {
     718           0 :                 return 1;
     719             :         }
     720           0 :         n = sizeof(ftp->pasvaddr);
     721           0 :         memset(&ftp->pasvaddr, 0, n);
     722           0 :         sa = (struct sockaddr *) &ftp->pasvaddr;
     723             : 
     724             : #if HAVE_IPV6
     725           0 :         if (getpeername(ftp->fd, sa, &n) < 0) {
     726           0 :                 return 0;
     727             :         }
     728           0 :         if (sa->sa_family == AF_INET6) {
     729           0 :                 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
     730             :                 char *endptr, delimiter;
     731             : 
     732             :                 /* try EPSV first */
     733           0 :                 if (!ftp_putcmd(ftp, "EPSV", NULL)) {
     734           0 :                         return 0;
     735             :                 }
     736           0 :                 if (!ftp_getresp(ftp)) {
     737           0 :                         return 0;
     738             :                 }
     739           0 :                 if (ftp->resp == 229) {
     740             :                         /* parse out the port */
     741           0 :                         for (ptr = ftp->inbuf; *ptr && *ptr != '('; ptr++);
     742           0 :                         if (!*ptr) {
     743           0 :                                 return 0;
     744             :                         }
     745           0 :                         delimiter = *++ptr;
     746           0 :                         for (n = 0; *ptr && n < 3; ptr++) {
     747           0 :                                 if (*ptr == delimiter) {
     748           0 :                                         n++;
     749             :                                 }
     750             :                         }
     751             : 
     752           0 :                         sin6->sin6_port = htons((unsigned short) strtoul(ptr, &endptr, 10));
     753           0 :                         if (ptr == endptr || *endptr != delimiter) {
     754           0 :                                 return 0;
     755             :                         }
     756           0 :                         ftp->pasv = 2;
     757           0 :                         return 1;
     758             :                 }
     759             :         }
     760             : 
     761             :         /* fall back to PASV */
     762             : #endif
     763             : 
     764           0 :         if (!ftp_putcmd(ftp, "PASV", NULL)) {
     765           0 :                 return 0;
     766             :         }
     767           0 :         if (!ftp_getresp(ftp) || ftp->resp != 227) {
     768           0 :                 return 0;
     769             :         }
     770             :         /* parse out the IP and port */
     771           0 :         for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
     772           0 :         n = sscanf(ptr, "%lu,%lu,%lu,%lu,%lu,%lu", &b[0], &b[1], &b[2], &b[3], &b[4], &b[5]);
     773           0 :         if (n != 6) {
     774           0 :                 return 0;
     775             :         }
     776           0 :         for (n = 0; n < 6; n++) {
     777           0 :                 ipbox.c[n] = (unsigned char) b[n];
     778             :         }
     779           0 :         sin = (struct sockaddr_in *) sa;
     780           0 :         sin->sin_family = AF_INET;
     781           0 :         sin->sin_addr = ipbox.ia[0];
     782           0 :         sin->sin_port = ipbox.s[2];
     783             : 
     784           0 :         ftp->pasv = 2;
     785             : 
     786           0 :         return 1;
     787             : }
     788             : /* }}} */
     789             : 
     790             : /* {{{ ftp_get
     791             :  */
     792             : int
     793           9 : ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, zend_long resumepos)
     794             : {
     795           9 :         databuf_t               *data = NULL;
     796             :         size_t                  rcvd;
     797             :         char                    arg[11];
     798             : 
     799           9 :         if (ftp == NULL) {
     800           0 :                 return 0;
     801             :         }
     802           9 :         if (!ftp_type(ftp, type)) {
     803           0 :                 goto bail;
     804             :         }
     805             : 
     806           9 :         if ((data = ftp_getdata(ftp)) == NULL) {
     807           0 :                 goto bail;
     808             :         }
     809             : 
     810           9 :         ftp->data = data;
     811             : 
     812           9 :         if (resumepos > 0) {
     813           2 :                 snprintf(arg, sizeof(arg), ZEND_LONG_FMT, resumepos);
     814           2 :                 if (!ftp_putcmd(ftp, "REST", arg)) {
     815           0 :                         goto bail;
     816             :                 }
     817           2 :                 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
     818             :                         goto bail;
     819             :                 }
     820             :         }
     821             : 
     822           9 :         if (!ftp_putcmd(ftp, "RETR", path)) {
     823           0 :                 goto bail;
     824             :         }
     825           9 :         if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
     826             :                 goto bail;
     827             :         }
     828             : 
     829           7 :         if ((data = data_accept(data, ftp)) == NULL) {
     830           0 :                 goto bail;
     831             :         }
     832             : 
     833          21 :         while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
     834           7 :                 if (rcvd == -1) {
     835           0 :                         goto bail;
     836             :                 }
     837             : 
     838           7 :                 if (type == FTPTYPE_ASCII) {
     839             : #ifndef PHP_WIN32
     840             :                         char *s;
     841             : #endif
     842           5 :                         char *ptr = data->buf;
     843           5 :                         char *e = ptr + rcvd;
     844             :                         /* logic depends on the OS EOL
     845             :                          * Win32 -> \r\n
     846             :                          * Everything Else \n
     847             :                          */
     848             : #ifdef PHP_WIN32
     849             :                         php_stream_write(outstream, ptr, (e - ptr));
     850             :                         ptr = e;
     851             : #else
     852          15 :                         while (e > ptr && (s = memchr(ptr, '\r', (e - ptr)))) {
     853           5 :                                 php_stream_write(outstream, ptr, (s - ptr));
     854           5 :                                 if (*(s + 1) == '\n') {
     855           5 :                                         s++;
     856           5 :                                         php_stream_putc(outstream, '\n');
     857             :                                 }
     858           5 :                                 ptr = s + 1;
     859             :                         }
     860             : #endif
     861           5 :                         if (ptr < e) {
     862           0 :                                 php_stream_write(outstream, ptr, (e - ptr));
     863             :                         }
     864           2 :                 } else if (rcvd != php_stream_write(outstream, data->buf, rcvd)) {
     865           0 :                         goto bail;
     866             :                 }
     867             :         }
     868             : 
     869           7 :         ftp->data = data = data_close(ftp, data);
     870             : 
     871           7 :         if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
     872             :                 goto bail;
     873             :         }
     874             : 
     875           7 :         return 1;
     876             : bail:
     877           2 :         ftp->data = data_close(ftp, data);
     878           2 :         return 0;
     879             : }
     880             : /* }}} */
     881             : 
     882             : /* {{{ ftp_put
     883             :  */
     884             : int
     885           2 : ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, zend_long startpos)
     886             : {
     887           2 :         databuf_t               *data = NULL;
     888             :         zend_long                       size;
     889             :         char                    *ptr;
     890             :         int                     ch;
     891             :         char                    arg[11];
     892             : 
     893           2 :         if (ftp == NULL) {
     894           0 :                 return 0;
     895             :         }
     896           2 :         if (!ftp_type(ftp, type)) {
     897           0 :                 goto bail;
     898             :         }
     899           2 :         if ((data = ftp_getdata(ftp)) == NULL) {
     900           0 :                 goto bail;
     901             :         }
     902           2 :         ftp->data = data;
     903             : 
     904           2 :         if (startpos > 0) {
     905           0 :                 snprintf(arg, sizeof(arg), ZEND_LONG_FMT, startpos);
     906           0 :                 if (!ftp_putcmd(ftp, "REST", arg)) {
     907           0 :                         goto bail;
     908             :                 }
     909           0 :                 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
     910             :                         goto bail;
     911             :                 }
     912             :         }
     913             : 
     914           2 :         if (!ftp_putcmd(ftp, "STOR", path)) {
     915           0 :                 goto bail;
     916             :         }
     917           2 :         if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
     918             :                 goto bail;
     919             :         }
     920           2 :         if ((data = data_accept(data, ftp)) == NULL) {
     921           0 :                 goto bail;
     922             :         }
     923             : 
     924           2 :         size = 0;
     925           2 :         ptr = data->buf;
     926        1050 :         while (!php_stream_eof(instream) && (ch = php_stream_getc(instream))!=EOF) {
     927             :                 /* flush if necessary */
     928        1046 :                 if (FTP_BUFSIZE - size < 2) {
     929           0 :                         if (my_send(ftp, data->fd, data->buf, size) != size) {
     930           0 :                                 goto bail;
     931             :                         }
     932           0 :                         ptr = data->buf;
     933           0 :                         size = 0;
     934             :                 }
     935             : 
     936        1046 :                 if (ch == '\n' && type == FTPTYPE_ASCII) {
     937          25 :                         *ptr++ = '\r';
     938          25 :                         size++;
     939             :                 }
     940             : 
     941        1046 :                 *ptr++ = ch;
     942        1046 :                 size++;
     943             :         }
     944             : 
     945           2 :         if (size && my_send(ftp, data->fd, data->buf, size) != size) {
     946           0 :                 goto bail;
     947             :         }
     948           2 :         ftp->data = data = data_close(ftp, data);
     949             : 
     950           2 :         if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) {
     951             :                 goto bail;
     952             :         }
     953           2 :         return 1;
     954             : bail:
     955           0 :         ftp->data = data_close(ftp, data);
     956           0 :         return 0;
     957             : }
     958             : /* }}} */
     959             : 
     960             : /* {{{ ftp_size
     961             :  */
     962             : zend_long
     963           2 : ftp_size(ftpbuf_t *ftp, const char *path)
     964             : {
     965           2 :         if (ftp == NULL) {
     966           0 :                 return -1;
     967             :         }
     968           2 :         if (!ftp_type(ftp, FTPTYPE_IMAGE)) {
     969           1 :                 return -1;
     970             :         }
     971           1 :         if (!ftp_putcmd(ftp, "SIZE", path)) {
     972           0 :                 return -1;
     973             :         }
     974           1 :         if (!ftp_getresp(ftp) || ftp->resp != 213) {
     975           0 :                 return -1;
     976             :         }
     977           1 :         return atol(ftp->inbuf);
     978             : }
     979             : /* }}} */
     980             : 
     981             : /* {{{ ftp_mdtm
     982             :  */
     983             : time_t
     984           7 : ftp_mdtm(ftpbuf_t *ftp, const char *path)
     985             : {
     986             :         time_t          stamp;
     987             :         struct tm       *gmt, tmbuf;
     988             :         struct tm       tm;
     989             :         char            *ptr;
     990             :         int             n;
     991             : 
     992           7 :         if (ftp == NULL) {
     993           0 :                 return -1;
     994             :         }
     995           7 :         if (!ftp_putcmd(ftp, "MDTM", path)) {
     996           0 :                 return -1;
     997             :         }
     998           7 :         if (!ftp_getresp(ftp) || ftp->resp != 213) {
     999           3 :                 return -1;
    1000             :         }
    1001             :         /* parse out the timestamp */
    1002           4 :         for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
    1003           4 :         n = sscanf(ptr, "%4u%2u%2u%2u%2u%2u", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
    1004           4 :         if (n != 6) {
    1005           0 :                 return -1;
    1006             :         }
    1007           4 :         tm.tm_year -= 1900;
    1008           4 :         tm.tm_mon--;
    1009           4 :         tm.tm_isdst = -1;
    1010             : 
    1011             :         /* figure out the GMT offset */
    1012           4 :         stamp = time(NULL);
    1013           4 :         gmt = php_gmtime_r(&stamp, &tmbuf);
    1014           4 :         if (!gmt) {
    1015           0 :                 return -1;
    1016             :         }
    1017           4 :         gmt->tm_isdst = -1;
    1018             : 
    1019             :         /* apply the GMT offset */
    1020           4 :         tm.tm_sec += stamp - mktime(gmt);
    1021           4 :         tm.tm_isdst = gmt->tm_isdst;
    1022             : 
    1023           4 :         stamp = mktime(&tm);
    1024             : 
    1025           4 :         return stamp;
    1026             : }
    1027             : /* }}} */
    1028             : 
    1029             : /* {{{ ftp_delete
    1030             :  */
    1031             : int
    1032           1 : ftp_delete(ftpbuf_t *ftp, const char *path)
    1033             : {
    1034           1 :         if (ftp == NULL) {
    1035           0 :                 return 0;
    1036             :         }
    1037           1 :         if (!ftp_putcmd(ftp, "DELE", path)) {
    1038           0 :                 return 0;
    1039             :         }
    1040           1 :         if (!ftp_getresp(ftp) || ftp->resp != 250) {
    1041           1 :                 return 0;
    1042             :         }
    1043             : 
    1044           0 :         return 1;
    1045             : }
    1046             : /* }}} */
    1047             : 
    1048             : /* {{{ ftp_rename
    1049             :  */
    1050             : int
    1051           0 : ftp_rename(ftpbuf_t *ftp, const char *src, const char *dest)
    1052             : {
    1053           0 :         if (ftp == NULL) {
    1054           0 :                 return 0;
    1055             :         }
    1056           0 :         if (!ftp_putcmd(ftp, "RNFR", src)) {
    1057           0 :                 return 0;
    1058             :         }
    1059           0 :         if (!ftp_getresp(ftp) || ftp->resp != 350) {
    1060           0 :                 return 0;
    1061             :         }
    1062           0 :         if (!ftp_putcmd(ftp, "RNTO", dest)) {
    1063           0 :                 return 0;
    1064             :         }
    1065           0 :         if (!ftp_getresp(ftp) || ftp->resp != 250) {
    1066           0 :                 return 0;
    1067             :         }
    1068           0 :         return 1;
    1069             : }
    1070             : /* }}} */
    1071             : 
    1072             : /* {{{ ftp_site
    1073             :  */
    1074             : int
    1075           0 : ftp_site(ftpbuf_t *ftp, const char *cmd)
    1076             : {
    1077           0 :         if (ftp == NULL) {
    1078           0 :                 return 0;
    1079             :         }
    1080           0 :         if (!ftp_putcmd(ftp, "SITE", cmd)) {
    1081           0 :                 return 0;
    1082             :         }
    1083           0 :         if (!ftp_getresp(ftp) || ftp->resp < 200 || ftp->resp >= 300) {
    1084           0 :                 return 0;
    1085             :         }
    1086             : 
    1087           0 :         return 1;
    1088             : }
    1089             : /* }}} */
    1090             : 
    1091             : /* static functions */
    1092             : 
    1093             : /* {{{ ftp_putcmd
    1094             :  */
    1095             : int
    1096         186 : ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const char *args)
    1097             : {
    1098             :         int             size;
    1099             :         char            *data;
    1100             : 
    1101         186 :         if (strpbrk(cmd, "\r\n")) {
    1102           0 :                 return 0;
    1103             :         }
    1104             :         /* build the output buffer */
    1105         343 :         if (args && args[0]) {
    1106             :                 /* "cmd args\r\n\0" */
    1107         157 :                 if (strlen(cmd) + strlen(args) + 4 > FTP_BUFSIZE) {
    1108           0 :                         return 0;
    1109             :                 }
    1110         157 :                 if (strpbrk(args, "\r\n")) {
    1111           0 :                         return 0;
    1112             :                 }
    1113         157 :                 size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s %s\r\n", cmd, args);
    1114             :         } else {
    1115             :                 /* "cmd\r\n\0" */
    1116          29 :                 if (strlen(cmd) + 3 > FTP_BUFSIZE) {
    1117           0 :                         return 0;
    1118             :                 }
    1119          29 :                 size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s\r\n", cmd);
    1120             :         }
    1121             : 
    1122         186 :         data = ftp->outbuf;
    1123             : 
    1124             :         /* Clear the extra-lines buffer */
    1125         186 :         ftp->extra = NULL;
    1126             : 
    1127         186 :         if (my_send(ftp, ftp->fd, data, size) != size) {
    1128           0 :                 return 0;
    1129             :         }
    1130         186 :         return 1;
    1131             : }
    1132             : /* }}} */
    1133             : 
    1134             : /* {{{ ftp_readline
    1135             :  */
    1136             : int
    1137         267 : ftp_readline(ftpbuf_t *ftp)
    1138             : {
    1139             :         long            size, rcvd;
    1140             :         char            *data, *eol;
    1141             : 
    1142             :         /* shift the extra to the front */
    1143         267 :         size = FTP_BUFSIZE;
    1144         267 :         rcvd = 0;
    1145         267 :         if (ftp->extra) {
    1146          33 :                 memmove(ftp->inbuf, ftp->extra, ftp->extralen);
    1147          33 :                 rcvd = ftp->extralen;
    1148             :         }
    1149             : 
    1150         267 :         data = ftp->inbuf;
    1151             : 
    1152             :         do {
    1153         490 :                 size -= rcvd;
    1154        6558 :                 for (eol = data; rcvd; rcvd--, eol++) {
    1155        6324 :                         if (*eol == '\r') {
    1156         256 :                                 *eol = 0;
    1157         256 :                                 ftp->extra = eol + 1;
    1158         256 :                                 if (rcvd > 1 && *(eol + 1) == '\n') {
    1159         256 :                                         ftp->extra++;
    1160         256 :                                         rcvd--;
    1161             :                                 }
    1162         256 :                                 if ((ftp->extralen = --rcvd) == 0) {
    1163         222 :                                         ftp->extra = NULL;
    1164             :                                 }
    1165         256 :                                 return 1;
    1166        6068 :                         } else if (*eol == '\n') {
    1167           0 :                                 *eol = 0;
    1168           0 :                                 ftp->extra = eol + 1;
    1169           0 :                                 if ((ftp->extralen = --rcvd) == 0) {
    1170           0 :                                         ftp->extra = NULL;
    1171             :                                 }
    1172           0 :                                 return 1;
    1173             :                         }
    1174             :                 }
    1175             : 
    1176         234 :                 data = eol;
    1177         234 :                 if ((rcvd = my_recv(ftp, ftp->fd, data, size)) < 1) {
    1178          11 :                         return 0;
    1179             :                 }
    1180         223 :         } while (size);
    1181             : 
    1182           0 :         return 0;
    1183             : }
    1184             : /* }}} */
    1185             : 
    1186             : /* {{{ ftp_getresp
    1187             :  */
    1188             : int
    1189         226 : ftp_getresp(ftpbuf_t *ftp)
    1190             : {
    1191         226 :         if (ftp == NULL) {
    1192           0 :                 return 0;
    1193             :         }
    1194         226 :         ftp->resp = 0;
    1195             : 
    1196             :         while (1) {
    1197             : 
    1198         257 :                 if (!ftp_readline(ftp)) {
    1199          11 :                         return 0;
    1200             :                 }
    1201             : 
    1202             :                 /* Break out when the end-tag is found */
    1203         246 :                 if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
    1204         215 :                         break;
    1205             :                 }
    1206          31 :         }
    1207             : 
    1208             :         /* translate the tag */
    1209         215 :         if (!isdigit(ftp->inbuf[0]) || !isdigit(ftp->inbuf[1]) || !isdigit(ftp->inbuf[2])) {
    1210           0 :                 return 0;
    1211             :         }
    1212             : 
    1213         215 :         ftp->resp = 100 * (ftp->inbuf[0] - '0') + 10 * (ftp->inbuf[1] - '0') + (ftp->inbuf[2] - '0');
    1214             : 
    1215         215 :         memmove(ftp->inbuf, ftp->inbuf + 4, FTP_BUFSIZE - 4);
    1216             : 
    1217         215 :         if (ftp->extra) {
    1218           1 :                 ftp->extra -= 4;
    1219             :         }
    1220         215 :         return 1;
    1221             : }
    1222             : /* }}} */
    1223             : 
    1224             : /* {{{ my_send
    1225             :  */
    1226             : int
    1227         188 : my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
    1228             : {
    1229             :         zend_long               size, sent;
    1230             :     int         n;
    1231             : 
    1232         188 :         size = len;
    1233         564 :         while (size) {
    1234         188 :                 n = php_pollfd_for_ms(s, POLLOUT, ftp->timeout_sec * 1000);
    1235             : 
    1236         188 :                 if (n < 1) {
    1237             : 
    1238             : #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
    1239           0 :                         if (n == 0) {
    1240           0 :                                 errno = ETIMEDOUT;
    1241             :                         }
    1242             : #endif
    1243           0 :                         return -1;
    1244             :                 }
    1245             : 
    1246             : #if HAVE_OPENSSL_EXT
    1247         195 :                 if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
    1248           7 :                         sent = SSL_write(ftp->ssl_handle, buf, size);
    1249         181 :                 } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
    1250           0 :                         sent = SSL_write(ftp->data->ssl_handle, buf, size);
    1251             :                 } else {
    1252             : #endif
    1253         181 :                         sent = send(s, buf, size, 0);
    1254             : #if HAVE_OPENSSL_EXT
    1255             :                 }
    1256             : #endif
    1257         188 :                 if (sent == -1) {
    1258           0 :                         return -1;
    1259             :                 }
    1260             : 
    1261         188 :                 buf = (char*) buf + sent;
    1262         188 :                 size -= sent;
    1263             :         }
    1264             : 
    1265         188 :         return len;
    1266             : }
    1267             : /* }}} */
    1268             : 
    1269             : /* {{{ my_recv
    1270             :  */
    1271             : int
    1272         263 : my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
    1273             : {
    1274             :         int             n, nr_bytes;
    1275             : 
    1276         263 :         n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
    1277         263 :         if (n < 1) {
    1278             : #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
    1279           0 :                 if (n == 0) {
    1280           0 :                         errno = ETIMEDOUT;
    1281             :                 }
    1282             : #endif
    1283           0 :                 return -1;
    1284             :         }
    1285             : 
    1286             : #if HAVE_OPENSSL_EXT
    1287         273 :         if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
    1288          10 :                 nr_bytes = SSL_read(ftp->ssl_handle, buf, len);
    1289         253 :         } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
    1290           0 :                 nr_bytes = SSL_read(ftp->data->ssl_handle, buf, len);
    1291             :         } else {
    1292             : #endif
    1293         253 :                 nr_bytes = recv(s, buf, len, 0);
    1294             : #if HAVE_OPENSSL_EXT
    1295             :         }
    1296             : #endif
    1297         263 :         return (nr_bytes);
    1298             : }
    1299             : /* }}} */
    1300             : 
    1301             : /* {{{ data_available
    1302             :  */
    1303             : int
    1304          10 : data_available(ftpbuf_t *ftp, php_socket_t s)
    1305             : {
    1306             :         int             n;
    1307             : 
    1308          10 :         n = php_pollfd_for_ms(s, PHP_POLLREADABLE, 1000);
    1309          10 :         if (n < 1) {
    1310             : #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
    1311           0 :                 if (n == 0) {
    1312           0 :                         errno = ETIMEDOUT;
    1313             :                 }
    1314             : #endif
    1315           0 :                 return 0;
    1316             :         }
    1317             : 
    1318          10 :         return 1;
    1319             : }
    1320             : /* }}} */
    1321             : /* {{{ data_writeable
    1322             :  */
    1323             : int
    1324           0 : data_writeable(ftpbuf_t *ftp, php_socket_t s)
    1325             : {
    1326             :         int             n;
    1327             : 
    1328           0 :         n = php_pollfd_for_ms(s, POLLOUT, 1000);
    1329           0 :         if (n < 1) {
    1330             : #ifndef PHP_WIN32
    1331           0 :                 if (n == 0) {
    1332           0 :                         errno = ETIMEDOUT;
    1333             :                 }
    1334             : #endif
    1335           0 :                 return 0;
    1336             :         }
    1337             : 
    1338           0 :         return 1;
    1339             : }
    1340             : /* }}} */
    1341             : 
    1342             : /* {{{ my_accept
    1343             :  */
    1344             : int
    1345          17 : my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen)
    1346             : {
    1347             :         int             n;
    1348             : 
    1349          17 :         n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
    1350          17 :         if (n < 1) {
    1351             : #if !defined(PHP_WIN32) && !(defined(NETWARE) && defined(USE_WINSOCK))
    1352           0 :                 if (n == 0) {
    1353           0 :                         errno = ETIMEDOUT;
    1354             :                 }
    1355             : #endif
    1356           0 :                 return -1;
    1357             :         }
    1358             : 
    1359          17 :         return accept(s, addr, addrlen);
    1360             : }
    1361             : /* }}} */
    1362             : 
    1363             : /* {{{ ftp_getdata
    1364             :  */
    1365             : databuf_t*
    1366          23 : ftp_getdata(ftpbuf_t *ftp)
    1367             : {
    1368          23 :         int                     fd = -1;
    1369             :         databuf_t               *data;
    1370             :         php_sockaddr_storage addr;
    1371             :         struct sockaddr *sa;
    1372             :         socklen_t               size;
    1373             :         union ipbox             ipbox;
    1374             :         char                    arg[sizeof("255, 255, 255, 255, 255, 255")];
    1375             :         struct timeval  tv;
    1376             : 
    1377             : 
    1378             :         /* ask for a passive connection if we need one */
    1379          23 :         if (ftp->pasv && !ftp_pasv(ftp, 1)) {
    1380           0 :                 return NULL;
    1381             :         }
    1382             :         /* alloc the data structure */
    1383          23 :         data = ecalloc(1, sizeof(*data));
    1384          23 :         data->listener = -1;
    1385          23 :         data->fd = -1;
    1386          23 :         data->type = ftp->type;
    1387             : 
    1388          23 :         sa = (struct sockaddr *) &ftp->localaddr;
    1389             :         /* bind/listen */
    1390          23 :         if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == SOCK_ERR) {
    1391           0 :                 php_error_docref(NULL, E_WARNING, "socket() failed: %s (%d)", strerror(errno), errno);
    1392           0 :                 goto bail;
    1393             :         }
    1394             : 
    1395             :         /* passive connection handler */
    1396          23 :         if (ftp->pasv) {
    1397             :                 /* clear the ready status */
    1398           0 :                 ftp->pasv = 1;
    1399             : 
    1400             :                 /* connect */
    1401             :                 /* Win 95/98 seems not to like size > sizeof(sockaddr_in) */
    1402           0 :                 size = php_sockaddr_size(&ftp->pasvaddr);
    1403           0 :                 tv.tv_sec = ftp->timeout_sec;
    1404           0 :                 tv.tv_usec = 0;
    1405           0 :                 if (php_connect_nonb(fd, (struct sockaddr*) &ftp->pasvaddr, size, &tv) == -1) {
    1406           0 :                         php_error_docref(NULL, E_WARNING, "php_connect_nonb() failed: %s (%d)", strerror(errno), errno);
    1407           0 :                         goto bail;
    1408             :                 }
    1409             : 
    1410           0 :                 data->fd = fd;
    1411             : 
    1412           0 :                 ftp->data = data;
    1413           0 :                 return data;
    1414             :         }
    1415             : 
    1416             : 
    1417             :         /* active (normal) connection */
    1418             : 
    1419             :         /* bind to a local address */
    1420          23 :         php_any_addr(sa->sa_family, &addr, 0);
    1421          23 :         size = php_sockaddr_size(&addr);
    1422             : 
    1423          23 :         if (bind(fd, (struct sockaddr*) &addr, size) != 0) {
    1424           0 :                 php_error_docref(NULL, E_WARNING, "bind() failed: %s (%d)", strerror(errno), errno);
    1425           0 :                 goto bail;
    1426             :         }
    1427             : 
    1428          23 :         if (getsockname(fd, (struct sockaddr*) &addr, &size) != 0) {
    1429           0 :                 php_error_docref(NULL, E_WARNING, "getsockname() failed: %s (%d)", strerror(errno), errno);
    1430           0 :                 goto bail;
    1431             :         }
    1432             : 
    1433          23 :         if (listen(fd, 5) != 0) {
    1434           0 :                 php_error_docref(NULL, E_WARNING, "listen() failed: %s (%d)", strerror(errno), errno);
    1435           0 :                 goto bail;
    1436             :         }
    1437             : 
    1438          23 :         data->listener = fd;
    1439             : 
    1440             : #if HAVE_IPV6 && HAVE_INET_NTOP
    1441          23 :         if (sa->sa_family == AF_INET6) {
    1442             :                 /* need to use EPRT */
    1443             :                 char eprtarg[INET6_ADDRSTRLEN + sizeof("|x||xxxxx|")];
    1444             :                 char out[INET6_ADDRSTRLEN];
    1445           0 :                 inet_ntop(AF_INET6, &((struct sockaddr_in6*) sa)->sin6_addr, out, sizeof(out));
    1446           0 :                 snprintf(eprtarg, sizeof(eprtarg), "|2|%s|%hu|", out, ntohs(((struct sockaddr_in6 *) &addr)->sin6_port));
    1447             : 
    1448           0 :                 if (!ftp_putcmd(ftp, "EPRT", eprtarg)) {
    1449           0 :                         goto bail;
    1450             :                 }
    1451             : 
    1452           0 :                 if (!ftp_getresp(ftp) || ftp->resp != 200) {
    1453             :                         goto bail;
    1454             :                 }
    1455             : 
    1456           0 :                 ftp->data = data;
    1457           0 :                 return data;
    1458             :         }
    1459             : #endif
    1460             : 
    1461             :         /* send the PORT */
    1462          23 :         ipbox.ia[0] = ((struct sockaddr_in*) sa)->sin_addr;
    1463          23 :         ipbox.s[2] = ((struct sockaddr_in*) &addr)->sin_port;
    1464          23 :         snprintf(arg, sizeof(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]);
    1465             : 
    1466          23 :         if (!ftp_putcmd(ftp, "PORT", arg)) {
    1467           0 :                 goto bail;
    1468             :         }
    1469          23 :         if (!ftp_getresp(ftp) || ftp->resp != 200) {
    1470             :                 goto bail;
    1471             :         }
    1472             : 
    1473          23 :         ftp->data = data;
    1474          23 :         return data;
    1475             : 
    1476             : bail:
    1477           0 :         if (fd != -1) {
    1478           0 :                 closesocket(fd);
    1479             :         }
    1480           0 :         efree(data);
    1481           0 :         return NULL;
    1482             : }
    1483             : /* }}} */
    1484             : 
    1485             : /* {{{ data_accept
    1486             :  */
    1487             : databuf_t*
    1488          17 : data_accept(databuf_t *data, ftpbuf_t *ftp)
    1489             : {
    1490             :         php_sockaddr_storage addr;
    1491             :         socklen_t                       size;
    1492             : 
    1493             : #if HAVE_OPENSSL_EXT
    1494             :         SSL_CTX         *ctx;
    1495          17 :         zend_long ssl_ctx_options = SSL_OP_ALL;
    1496             : #endif
    1497             : 
    1498          17 :         if (data->fd != -1) {
    1499           0 :                 goto data_accepted;
    1500             :         }
    1501          17 :         size = sizeof(addr);
    1502          17 :         data->fd = my_accept(ftp, data->listener, (struct sockaddr*) &addr, &size);
    1503          17 :         closesocket(data->listener);
    1504          17 :         data->listener = -1;
    1505             : 
    1506          17 :         if (data->fd == -1) {
    1507           0 :                 efree(data);
    1508           0 :                 return NULL;
    1509             :         }
    1510             : 
    1511             : data_accepted:
    1512             : #if HAVE_OPENSSL_EXT
    1513             : 
    1514             :         /* now enable ssl if we need to */
    1515          17 :         if (ftp->use_ssl && ftp->use_ssl_for_data) {
    1516           0 :                 ctx = SSL_CTX_new(SSLv23_client_method());
    1517           0 :                 if (ctx == NULL) {
    1518           0 :                         php_error_docref(NULL, E_WARNING, "data_accept: failed to create the SSL context");
    1519           0 :                         return 0;
    1520             :                 }
    1521             : 
    1522             : #if OPENSSL_VERSION_NUMBER >= 0x0090605fL
    1523           0 :                 ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
    1524             : #endif
    1525           0 :                 SSL_CTX_set_options(ctx, ssl_ctx_options);
    1526             : 
    1527           0 :                 data->ssl_handle = SSL_new(ctx);
    1528           0 :                 if (data->ssl_handle == NULL) {
    1529           0 :                         php_error_docref(NULL, E_WARNING, "data_accept: failed to create the SSL handle");
    1530           0 :                         SSL_CTX_free(ctx);
    1531           0 :                         return 0;
    1532             :                 }
    1533             : 
    1534             : 
    1535           0 :                 SSL_set_fd(data->ssl_handle, data->fd);
    1536             : 
    1537           0 :                 if (ftp->old_ssl) {
    1538           0 :                         SSL_copy_session_id(data->ssl_handle, ftp->ssl_handle);
    1539             :                 }
    1540             : 
    1541           0 :                 if (SSL_connect(data->ssl_handle) <= 0) {
    1542           0 :                         php_error_docref(NULL, E_WARNING, "data_accept: SSL/TLS handshake failed");
    1543           0 :                         SSL_shutdown(data->ssl_handle);
    1544           0 :                         SSL_free(data->ssl_handle);
    1545           0 :                         return 0;
    1546             :                 }
    1547             : 
    1548           0 :                 data->ssl_active = 1;
    1549             :         }
    1550             : 
    1551             : #endif
    1552             : 
    1553          17 :         return data;
    1554             : }
    1555             : /* }}} */
    1556             : 
    1557             : /* {{{ data_close
    1558             :  */
    1559             : databuf_t*
    1560          23 : data_close(ftpbuf_t *ftp, databuf_t *data)
    1561             : {
    1562             : #if HAVE_OPENSSL_EXT
    1563             :         SSL_CTX         *ctx;
    1564             : #endif
    1565          23 :         if (data == NULL) {
    1566           0 :                 return NULL;
    1567             :         }
    1568          23 :         if (data->listener != -1) {
    1569             : #if HAVE_OPENSSL_EXT
    1570           6 :                 if (data->ssl_active) {
    1571             : 
    1572           0 :                         ctx = SSL_get_SSL_CTX(data->ssl_handle);
    1573           0 :                         SSL_CTX_free(ctx);
    1574             : 
    1575           0 :                         SSL_shutdown(data->ssl_handle);
    1576           0 :                         SSL_free(data->ssl_handle);
    1577           0 :                         data->ssl_active = 0;
    1578             :                 }
    1579             : #endif
    1580           6 :                 closesocket(data->listener);
    1581             :         }
    1582          23 :         if (data->fd != -1) {
    1583             : #if HAVE_OPENSSL_EXT
    1584          17 :                 if (data->ssl_active) {
    1585           0 :                         ctx = SSL_get_SSL_CTX(data->ssl_handle);
    1586           0 :                         SSL_CTX_free(ctx);
    1587             : 
    1588           0 :                         SSL_shutdown(data->ssl_handle);
    1589           0 :                         SSL_free(data->ssl_handle);
    1590           0 :                         data->ssl_active = 0;
    1591             :                 }
    1592             : #endif
    1593          17 :                 closesocket(data->fd);
    1594             :         }
    1595          23 :         if (ftp) {
    1596          23 :                 ftp->data = NULL;
    1597             :         }
    1598          23 :         efree(data);
    1599          23 :         return NULL;
    1600             : }
    1601             : /* }}} */
    1602             : 
    1603             : /* {{{ ftp_genlist
    1604             :  */
    1605             : char**
    1606           7 : ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path)
    1607             : {
    1608           7 :         php_stream      *tmpstream = NULL;
    1609           7 :         databuf_t       *data = NULL;
    1610             :         char            *ptr;
    1611             :         int             ch, lastch;
    1612             :         int             size, rcvd;
    1613             :         int             lines;
    1614           7 :         char            **ret = NULL;
    1615             :         char            **entry;
    1616             :         char            *text;
    1617             : 
    1618             : 
    1619           7 :         if ((tmpstream = php_stream_fopen_tmpfile()) == NULL) {
    1620           0 :                 php_error_docref(NULL, E_WARNING, "Unable to create temporary file.  Check permissions in temporary files directory.");
    1621           0 :                 return NULL;
    1622             :         }
    1623             : 
    1624           7 :         if (!ftp_type(ftp, FTPTYPE_ASCII)) {
    1625           0 :                 goto bail;
    1626             :         }
    1627             : 
    1628           7 :         if ((data = ftp_getdata(ftp)) == NULL) {
    1629           0 :                 goto bail;
    1630             :         }
    1631           7 :         ftp->data = data;
    1632             : 
    1633           7 :         if (!ftp_putcmd(ftp, cmd, path)) {
    1634           0 :                 goto bail;
    1635             :         }
    1636           7 :         if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125 && ftp->resp != 226)) {
    1637             :                 goto bail;
    1638             :         }
    1639             : 
    1640             :         /* some servers don't open a ftp-data connection if the directory is empty */
    1641           4 :         if (ftp->resp == 226) {
    1642           1 :                 ftp->data = data_close(ftp, data);
    1643           1 :                 php_stream_close(tmpstream);
    1644           1 :                 return ecalloc(1, sizeof(char*));
    1645             :         }
    1646             : 
    1647             :         /* pull data buffer into tmpfile */
    1648           3 :         if ((data = data_accept(data, ftp)) == NULL) {
    1649           0 :                 goto bail;
    1650             :         }
    1651           3 :         size = 0;
    1652           3 :         lines = 0;
    1653           3 :         lastch = 0;
    1654           8 :         while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
    1655           2 :                 if (rcvd == -1) {
    1656           0 :                         goto bail;
    1657             :                 }
    1658             : 
    1659           2 :                 php_stream_write(tmpstream, data->buf, rcvd);
    1660             : 
    1661           2 :                 size += rcvd;
    1662          52 :                 for (ptr = data->buf; rcvd; rcvd--, ptr++) {
    1663          56 :                         if (*ptr == '\n' && lastch == '\r') {
    1664           6 :                                 lines++;
    1665             :                         } else {
    1666          44 :                                 size++;
    1667             :                         }
    1668          50 :                         lastch = *ptr;
    1669             :                 }
    1670             :         }
    1671             : 
    1672           3 :         ftp->data = data_close(ftp, data);
    1673             : 
    1674           3 :         php_stream_rewind(tmpstream);
    1675             : 
    1676           3 :         ret = safe_emalloc((lines + 1), sizeof(char*), size);
    1677             : 
    1678           3 :         entry = ret;
    1679           3 :         text = (char*) (ret + lines + 1);
    1680           3 :         *entry = text;
    1681           3 :         lastch = 0;
    1682          56 :         while ((ch = php_stream_getc(tmpstream)) != EOF) {
    1683          56 :                 if (ch == '\n' && lastch == '\r') {
    1684           6 :                         *(text - 1) = 0;
    1685           6 :                         *++entry = text;
    1686             :                 } else {
    1687          44 :                         *text++ = ch;
    1688             :                 }
    1689          50 :                 lastch = ch;
    1690             :         }
    1691           3 :         *entry = NULL;
    1692             : 
    1693           3 :         php_stream_close(tmpstream);
    1694             : 
    1695           3 :         if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
    1696           0 :                 efree(ret);
    1697           0 :                 return NULL;
    1698             :         }
    1699             : 
    1700           3 :         return ret;
    1701             : bail:
    1702           3 :         ftp->data = data_close(ftp, data);
    1703           3 :         php_stream_close(tmpstream);
    1704           3 :         if (ret)
    1705           0 :                 efree(ret);
    1706           3 :         return NULL;
    1707             : }
    1708             : /* }}} */
    1709             : 
    1710             : /* {{{ ftp_nb_get
    1711             :  */
    1712             : int
    1713           5 : ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, zend_long resumepos)
    1714             : {
    1715           5 :         databuf_t               *data = NULL;
    1716             :         char                    arg[11];
    1717             : 
    1718           5 :         if (ftp == NULL) {
    1719           0 :                 return PHP_FTP_FAILED;
    1720             :         }
    1721             : 
    1722           5 :         if (!ftp_type(ftp, type)) {
    1723           0 :                 goto bail;
    1724             :         }
    1725             : 
    1726           5 :         if ((data = ftp_getdata(ftp)) == NULL) {
    1727           0 :                 goto bail;
    1728             :         }
    1729             : 
    1730           5 :         if (resumepos>0) {
    1731           3 :                 snprintf(arg, sizeof(arg), ZEND_LONG_FMT, resumepos);
    1732           3 :                 if (!ftp_putcmd(ftp, "REST", arg)) {
    1733           0 :                         goto bail;
    1734             :                 }
    1735           3 :                 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
    1736             :                         goto bail;
    1737             :                 }
    1738             :         }
    1739             : 
    1740           5 :         if (!ftp_putcmd(ftp, "RETR", path)) {
    1741           0 :                 goto bail;
    1742             :         }
    1743           5 :         if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
    1744             :                 goto bail;
    1745             :         }
    1746             : 
    1747           5 :         if ((data = data_accept(data, ftp)) == NULL) {
    1748           0 :                 goto bail;
    1749             :         }
    1750             : 
    1751           5 :         ftp->data = data;
    1752           5 :         ftp->stream = outstream;
    1753           5 :         ftp->lastch = 0;
    1754           5 :         ftp->nb = 1;
    1755             : 
    1756           5 :         return (ftp_nb_continue_read(ftp));
    1757             : 
    1758             : bail:
    1759           0 :         ftp->data = data_close(ftp, data);
    1760           0 :         return PHP_FTP_FAILED;
    1761             : }
    1762             : /* }}} */
    1763             : 
    1764             : /* {{{ ftp_nb_continue_read
    1765             :  */
    1766             : int
    1767          10 : ftp_nb_continue_read(ftpbuf_t *ftp)
    1768             : {
    1769          10 :         databuf_t       *data = NULL;
    1770             :         char            *ptr;
    1771             :         int             lastch;
    1772             :         size_t          rcvd;
    1773             :         ftptype_t       type;
    1774             : 
    1775          10 :         data = ftp->data;
    1776             : 
    1777             :         /* check if there is already more data */
    1778          10 :         if (!data_available(ftp, data->fd)) {
    1779           0 :                 return PHP_FTP_MOREDATA;
    1780             :         }
    1781             : 
    1782          10 :         type = ftp->type;
    1783             : 
    1784          10 :         lastch = ftp->lastch;
    1785          10 :         if ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
    1786           9 :                 if (rcvd == -1) {
    1787           0 :                         goto bail;
    1788             :                 }
    1789             : 
    1790           9 :                 if (type == FTPTYPE_ASCII) {
    1791          26 :                         for (ptr = data->buf; rcvd; rcvd--, ptr++) {
    1792          23 :                                 if (lastch == '\r' && *ptr != '\n') {
    1793           0 :                                         php_stream_putc(ftp->stream, '\r');
    1794             :                                 }
    1795          23 :                                 if (*ptr != '\r') {
    1796          20 :                                         php_stream_putc(ftp->stream, *ptr);
    1797             :                                 }
    1798          23 :                                 lastch = *ptr;
    1799             :                         }
    1800           6 :                 } else if (rcvd != php_stream_write(ftp->stream, data->buf, rcvd)) {
    1801           0 :                         goto bail;
    1802             :                 }
    1803             : 
    1804           9 :                 ftp->lastch = lastch;
    1805           9 :                 return PHP_FTP_MOREDATA;
    1806             :         }
    1807             : 
    1808           1 :         if (type == FTPTYPE_ASCII && lastch == '\r') {
    1809           0 :                 php_stream_putc(ftp->stream, '\r');
    1810             :         }
    1811             : 
    1812           1 :         ftp->data = data = data_close(ftp, data);
    1813             : 
    1814           1 :         if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
    1815             :                 goto bail;
    1816             :         }
    1817             : 
    1818           1 :         ftp->nb = 0;
    1819           1 :         return PHP_FTP_FINISHED;
    1820             : bail:
    1821           0 :         ftp->nb = 0;
    1822           0 :         ftp->data = data_close(ftp, data);
    1823           0 :         return PHP_FTP_FAILED;
    1824             : }
    1825             : /* }}} */
    1826             : 
    1827             : /* {{{ ftp_nb_put
    1828             :  */
    1829             : int
    1830           0 : ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, zend_long startpos)
    1831             : {
    1832           0 :         databuf_t               *data = NULL;
    1833             :         char                    arg[11];
    1834             : 
    1835           0 :         if (ftp == NULL) {
    1836           0 :                 return 0;
    1837             :         }
    1838           0 :         if (!ftp_type(ftp, type)) {
    1839           0 :                 goto bail;
    1840             :         }
    1841           0 :         if ((data = ftp_getdata(ftp)) == NULL) {
    1842           0 :                 goto bail;
    1843             :         }
    1844           0 :         if (startpos > 0) {
    1845           0 :                 snprintf(arg, sizeof(arg), ZEND_LONG_FMT, startpos);
    1846           0 :                 if (!ftp_putcmd(ftp, "REST", arg)) {
    1847           0 :                         goto bail;
    1848             :                 }
    1849           0 :                 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
    1850             :                         goto bail;
    1851             :                 }
    1852             :         }
    1853             : 
    1854           0 :         if (!ftp_putcmd(ftp, "STOR", path)) {
    1855           0 :                 goto bail;
    1856             :         }
    1857           0 :         if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
    1858             :                 goto bail;
    1859             :         }
    1860           0 :         if ((data = data_accept(data, ftp)) == NULL) {
    1861           0 :                 goto bail;
    1862             :         }
    1863           0 :         ftp->data = data;
    1864           0 :         ftp->stream = instream;
    1865           0 :         ftp->lastch = 0;
    1866           0 :         ftp->nb = 1;
    1867             : 
    1868           0 :         return (ftp_nb_continue_write(ftp));
    1869             : 
    1870             : bail:
    1871           0 :         ftp->data = data_close(ftp, data);
    1872           0 :         return PHP_FTP_FAILED;
    1873             : }
    1874             : /* }}} */
    1875             : 
    1876             : 
    1877             : /* {{{ ftp_nb_continue_write
    1878             :  */
    1879             : int
    1880           0 : ftp_nb_continue_write(ftpbuf_t *ftp)
    1881             : {
    1882             :         long                    size;
    1883             :         char                    *ptr;
    1884             :         int                     ch;
    1885             : 
    1886             :         /* check if we can write more data */
    1887           0 :         if (!data_writeable(ftp, ftp->data->fd)) {
    1888           0 :                 return PHP_FTP_MOREDATA;
    1889             :         }
    1890             : 
    1891           0 :         size = 0;
    1892           0 :         ptr = ftp->data->buf;
    1893           0 :         while (!php_stream_eof(ftp->stream) && (ch = php_stream_getc(ftp->stream)) != EOF) {
    1894             : 
    1895           0 :                 if (ch == '\n' && ftp->type == FTPTYPE_ASCII) {
    1896           0 :                         *ptr++ = '\r';
    1897           0 :                         size++;
    1898             :                 }
    1899             : 
    1900           0 :                 *ptr++ = ch;
    1901           0 :                 size++;
    1902             : 
    1903             :                 /* flush if necessary */
    1904           0 :                 if (FTP_BUFSIZE - size < 2) {
    1905           0 :                         if (my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
    1906           0 :                                 goto bail;
    1907             :                         }
    1908           0 :                         return PHP_FTP_MOREDATA;
    1909             :                 }
    1910             :         }
    1911             : 
    1912           0 :         if (size && my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
    1913           0 :                 goto bail;
    1914             :         }
    1915           0 :         ftp->data = data_close(ftp, ftp->data);
    1916             : 
    1917           0 :         if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
    1918             :                 goto bail;
    1919             :         }
    1920           0 :         ftp->nb = 0;
    1921           0 :         return PHP_FTP_FINISHED;
    1922             : bail:
    1923           0 :         ftp->data = data_close(ftp, ftp->data);
    1924           0 :         ftp->nb = 0;
    1925           0 :         return PHP_FTP_FAILED;
    1926             : }
    1927             : /* }}} */
    1928             : 
    1929             : #endif /* HAVE_FTP */
    1930             : 
    1931             : /*
    1932             :  * Local variables:
    1933             :  * tab-width: 4
    1934             :  * c-basic-offset: 4
    1935             :  * End:
    1936             :  * vim600: sw=4 ts=4 fdm=marker
    1937             :  * vim<600: sw=4 ts=4
    1938             :  */

Generated by: LCOV version 1.10

Generated at Sun, 01 Mar 2015 23:22:25 +0000 (2 days ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.