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: 513 913 56.2 %
Date: 2016-09-18 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-2016 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             : #ifdef HAVE_FTP_SSL
      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             : #ifdef HAVE_FTP_SSL
     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             : #ifdef HAVE_FTP_SSL
     249          32 :         SSL_CTX *ctx = NULL;
     250          32 :         long ssl_ctx_options = SSL_OP_ALL;
     251             :         int err, res;
     252             :         zend_bool retry;
     253             : #endif
     254          32 :         if (ftp == NULL) {
     255           0 :                 return 0;
     256             :         }
     257             : 
     258             : #ifdef HAVE_FTP_SSL
     259          32 :         if (ftp->use_ssl && !ftp->ssl_active) {
     260           2 :                 if (!ftp_putcmd(ftp, "AUTH", "TLS")) {
     261           0 :                         return 0;
     262             :                 }
     263           2 :                 if (!ftp_getresp(ftp)) {
     264           0 :                         return 0;
     265             :                 }
     266             : 
     267           2 :                 if (ftp->resp != 234) {
     268           1 :                         if (!ftp_putcmd(ftp, "AUTH", "SSL")) {
     269           0 :                                 return 0;
     270             :                         }
     271           1 :                         if (!ftp_getresp(ftp)) {
     272           0 :                                 return 0;
     273             :                         }
     274             : 
     275           1 :                         if (ftp->resp != 334) {
     276           1 :                                 return 0;
     277             :                         } else {
     278           0 :                                 ftp->old_ssl = 1;
     279           0 :                                 ftp->use_ssl_for_data = 1;
     280             :                         }
     281             :                 }
     282             : 
     283           1 :                 ctx = SSL_CTX_new(SSLv23_client_method());
     284           1 :                 if (ctx == NULL) {
     285           0 :                         php_error_docref(NULL, E_WARNING, "failed to create the SSL context");
     286           0 :                         return 0;
     287             :                 }
     288             : 
     289             : #if OPENSSL_VERSION_NUMBER >= 0x0090605fL
     290           1 :                 ssl_ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
     291             : #endif
     292           1 :                 SSL_CTX_set_options(ctx, ssl_ctx_options);
     293             : 
     294             :                 /* allow SSL to re-use sessions */
     295           1 :                 SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
     296             : 
     297           1 :                 ftp->ssl_handle = SSL_new(ctx);
     298           1 :                 if (ftp->ssl_handle == NULL) {
     299           0 :                         php_error_docref(NULL, E_WARNING, "failed to create the SSL handle");
     300           0 :                         SSL_CTX_free(ctx);
     301           0 :                         return 0;
     302             :                 }
     303             : 
     304           1 :                 SSL_set_fd(ftp->ssl_handle, ftp->fd);
     305             : 
     306             :                 do {
     307           1 :                         res = SSL_connect(ftp->ssl_handle);
     308           1 :                         err = SSL_get_error(ftp->ssl_handle, res);
     309             : 
     310             :                         /* TODO check if handling other error codes would make sense */
     311           1 :                         switch (err) {
     312             :                                 case SSL_ERROR_NONE:
     313           1 :                                         retry = 0;
     314           1 :                                         break;
     315             : 
     316             :                                 case SSL_ERROR_ZERO_RETURN:
     317           0 :                                         retry = 0;
     318           0 :                                         SSL_shutdown(ftp->ssl_handle);
     319           0 :                                         break;
     320             : 
     321             :                                 case SSL_ERROR_WANT_READ:
     322             :                                 case SSL_ERROR_WANT_WRITE: {
     323             :                                                 php_pollfd p;
     324             :                                                 int i;
     325             : 
     326           0 :                                                 p.fd = ftp->fd;
     327           0 :                                                 p.events = (err == SSL_ERROR_WANT_READ) ? (POLLIN|POLLPRI) : POLLOUT;
     328           0 :                                                 p.revents = 0;
     329             : 
     330           0 :                                                 i = php_poll2(&p, 1, 300);
     331             : 
     332           0 :                                                 retry = i > 0;
     333             :                                         }
     334           0 :                                         break;
     335             : 
     336             :                                 default:
     337           0 :                                         php_error_docref(NULL, E_WARNING, "SSL/TLS handshake failed");
     338           0 :                                         SSL_shutdown(ftp->ssl_handle);
     339           0 :                                         SSL_free(ftp->ssl_handle);
     340           0 :                                         return 0;
     341             :                         }
     342           1 :                 } while (retry);
     343             : 
     344           1 :                 ftp->ssl_active = 1;
     345             : 
     346           1 :                 if (!ftp->old_ssl) {
     347             : 
     348             :                         /* set protection buffersize to zero */
     349           1 :                         if (!ftp_putcmd(ftp, "PBSZ", "0")) {
     350           0 :                                 return 0;
     351             :                         }
     352           1 :                         if (!ftp_getresp(ftp)) {
     353           0 :                                 return 0;
     354             :                         }
     355             : 
     356             :                         /* enable data conn encryption */
     357           1 :                         if (!ftp_putcmd(ftp, "PROT", "P")) {
     358           0 :                                 return 0;
     359             :                         }
     360           1 :                         if (!ftp_getresp(ftp)) {
     361           0 :                                 return 0;
     362             :                         }
     363             : 
     364           1 :                         ftp->use_ssl_for_data = (ftp->resp >= 200 && ftp->resp <=299);
     365             :                 }
     366             :         }
     367             : #endif
     368             : 
     369          31 :         if (!ftp_putcmd(ftp, "USER", user)) {
     370           0 :                 return 0;
     371             :         }
     372          31 :         if (!ftp_getresp(ftp)) {
     373           0 :                 return 0;
     374             :         }
     375          31 :         if (ftp->resp == 230) {
     376           4 :                 return 1;
     377             :         }
     378          27 :         if (ftp->resp != 331) {
     379           0 :                 return 0;
     380             :         }
     381          27 :         if (!ftp_putcmd(ftp, "PASS", pass)) {
     382           0 :                 return 0;
     383             :         }
     384          27 :         if (!ftp_getresp(ftp)) {
     385           0 :                 return 0;
     386             :         }
     387          27 :         return (ftp->resp == 230);
     388             : }
     389             : /* }}} */
     390             : 
     391             : /* {{{ ftp_reinit
     392             :  */
     393             : int
     394           0 : ftp_reinit(ftpbuf_t *ftp)
     395             : {
     396           0 :         if (ftp == NULL) {
     397           0 :                 return 0;
     398             :         }
     399             : 
     400           0 :         ftp_gc(ftp);
     401             : 
     402           0 :         ftp->nb = 0;
     403             : 
     404           0 :         if (!ftp_putcmd(ftp, "REIN", NULL)) {
     405           0 :                 return 0;
     406             :         }
     407           0 :         if (!ftp_getresp(ftp) || ftp->resp != 220) {
     408           0 :                 return 0;
     409             :         }
     410             : 
     411           0 :         return 1;
     412             : }
     413             : /* }}} */
     414             : 
     415             : /* {{{ ftp_syst
     416             :  */
     417             : const char*
     418           3 : ftp_syst(ftpbuf_t *ftp)
     419             : {
     420             :         char *syst, *end;
     421             : 
     422           3 :         if (ftp == NULL) {
     423           0 :                 return NULL;
     424             :         }
     425             : 
     426             :         /* default to cached value */
     427           3 :         if (ftp->syst) {
     428           0 :                 return ftp->syst;
     429             :         }
     430           3 :         if (!ftp_putcmd(ftp, "SYST", NULL)) {
     431           0 :                 return NULL;
     432             :         }
     433           3 :         if (!ftp_getresp(ftp) || ftp->resp != 215) {
     434           1 :                 return NULL;
     435             :         }
     436           2 :         syst = ftp->inbuf;
     437           6 :         while (*syst == ' ') {
     438           2 :                 syst++;
     439             :         }
     440           2 :         if ((end = strchr(syst, ' '))) {
     441           2 :                 *end = 0;
     442             :         }
     443           2 :         ftp->syst = estrdup(syst);
     444           2 :         if (end) {
     445           2 :                 *end = ' ';
     446             :         }
     447           2 :         return ftp->syst;
     448             : }
     449             : /* }}} */
     450             : 
     451             : /* {{{ ftp_pwd
     452             :  */
     453             : const char*
     454           6 : ftp_pwd(ftpbuf_t *ftp)
     455             : {
     456             :         char *pwd, *end;
     457             : 
     458           6 :         if (ftp == NULL) {
     459           0 :                 return NULL;
     460             :         }
     461             : 
     462             :         /* default to cached value */
     463           6 :         if (ftp->pwd) {
     464           0 :                 return ftp->pwd;
     465             :         }
     466           6 :         if (!ftp_putcmd(ftp, "PWD", NULL)) {
     467           0 :                 return NULL;
     468             :         }
     469           6 :         if (!ftp_getresp(ftp) || ftp->resp != 257) {
     470           1 :                 return NULL;
     471             :         }
     472             :         /* copy out the pwd from response */
     473           5 :         if ((pwd = strchr(ftp->inbuf, '"')) == NULL) {
     474           0 :                 return NULL;
     475             :         }
     476           5 :         if ((end = strrchr(++pwd, '"')) == NULL) {
     477           0 :                 return NULL;
     478             :         }
     479           5 :         ftp->pwd = estrndup(pwd, end - pwd);
     480             : 
     481           5 :         return ftp->pwd;
     482             : }
     483             : /* }}} */
     484             : 
     485             : /* {{{ ftp_exec
     486             :  */
     487             : int
     488           2 : ftp_exec(ftpbuf_t *ftp, const char *cmd)
     489             : {
     490           2 :         if (ftp == NULL) {
     491           0 :                 return 0;
     492             :         }
     493           2 :         if (!ftp_putcmd(ftp, "SITE EXEC", cmd)) {
     494           0 :                 return 0;
     495             :         }
     496           2 :         if (!ftp_getresp(ftp) || ftp->resp != 200) {
     497           1 :                 return 0;
     498             :         }
     499             : 
     500           1 :         return 1;
     501             : }
     502             : /* }}} */
     503             : 
     504             : /* {{{ ftp_raw
     505             :  */
     506             : void
     507           4 : ftp_raw(ftpbuf_t *ftp, const char *cmd, zval *return_value)
     508             : {
     509           4 :         if (ftp == NULL || cmd == NULL) {
     510           0 :                 RETURN_NULL();
     511             :         }
     512           4 :         if (!ftp_putcmd(ftp, cmd, NULL)) {
     513           0 :                 RETURN_NULL();
     514             :         }
     515           4 :         array_init(return_value);
     516           4 :         while (ftp_readline(ftp)) {
     517          10 :                 add_next_index_string(return_value, ftp->inbuf);
     518          10 :                 if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
     519           4 :                         return;
     520             :                 }
     521             :         }
     522             : }
     523             : /* }}} */
     524             : 
     525             : /* {{{ ftp_chdir
     526             :  */
     527             : int
     528           4 : ftp_chdir(ftpbuf_t *ftp, const char *dir)
     529             : {
     530           4 :         if (ftp == NULL) {
     531           0 :                 return 0;
     532             :         }
     533             : 
     534           4 :         if (ftp->pwd) {
     535           3 :                 efree(ftp->pwd);
     536           3 :                 ftp->pwd = NULL;
     537             :         }
     538             : 
     539           4 :         if (!ftp_putcmd(ftp, "CWD", dir)) {
     540           0 :                 return 0;
     541             :         }
     542           4 :         if (!ftp_getresp(ftp) || ftp->resp != 250) {
     543           1 :                 return 0;
     544             :         }
     545           3 :         return 1;
     546             : }
     547             : /* }}} */
     548             : 
     549             : /* {{{ ftp_cdup
     550             :  */
     551             : int
     552           2 : ftp_cdup(ftpbuf_t *ftp)
     553             : {
     554           2 :         if (ftp == NULL) {
     555           0 :                 return 0;
     556             :         }
     557             : 
     558           2 :         if (ftp->pwd) {
     559           1 :                 efree(ftp->pwd);
     560           1 :                 ftp->pwd = NULL;
     561             :         }
     562             : 
     563           2 :         if (!ftp_putcmd(ftp, "CDUP", NULL)) {
     564           0 :                 return 0;
     565             :         }
     566           2 :         if (!ftp_getresp(ftp) || ftp->resp != 250) {
     567           1 :                 return 0;
     568             :         }
     569           1 :         return 1;
     570             : }
     571             : /* }}} */
     572             : 
     573             : /* {{{ ftp_mkdir
     574             :  */
     575             : zend_string*
     576           3 : ftp_mkdir(ftpbuf_t *ftp, const char *dir)
     577             : {
     578             :         char *mkd, *end;
     579             :         zend_string *ret;
     580             : 
     581           3 :         if (ftp == NULL) {
     582           0 :                 return NULL;
     583             :         }
     584           3 :         if (!ftp_putcmd(ftp, "MKD", dir)) {
     585           0 :                 return NULL;
     586             :         }
     587           3 :         if (!ftp_getresp(ftp) || ftp->resp != 257) {
     588           1 :                 return NULL;
     589             :         }
     590             :         /* copy out the dir from response */
     591           2 :         if ((mkd = strchr(ftp->inbuf, '"')) == NULL) {
     592           2 :                 return zend_string_init(dir, strlen(dir), 0);
     593             :         }
     594           1 :         if ((end = strrchr(++mkd, '"')) == NULL) {
     595           0 :                 return NULL;
     596             :         }
     597           1 :         *end = 0;
     598           2 :         ret = zend_string_init(mkd, end - mkd, 0);
     599           1 :         *end = '"';
     600             : 
     601           1 :         return ret;
     602             : }
     603             : /* }}} */
     604             : 
     605             : /* {{{ ftp_rmdir
     606             :  */
     607             : int
     608           2 : ftp_rmdir(ftpbuf_t *ftp, const char *dir)
     609             : {
     610           2 :         if (ftp == NULL) {
     611           0 :                 return 0;
     612             :         }
     613           2 :         if (!ftp_putcmd(ftp, "RMD", dir)) {
     614           0 :                 return 0;
     615             :         }
     616           2 :         if (!ftp_getresp(ftp) || ftp->resp != 250) {
     617           1 :                 return 0;
     618             :         }
     619           1 :         return 1;
     620             : }
     621             : /* }}} */
     622             : 
     623             : /* {{{ ftp_chmod
     624             :  */
     625             : int
     626           2 : ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int filename_len)
     627             : {
     628             :         char *buffer;
     629             : 
     630           2 :         if (ftp == NULL || filename_len <= 0) {
     631           0 :                 return 0;
     632             :         }
     633             : 
     634           2 :         spprintf(&buffer, 0, "CHMOD %o %s", mode, filename);
     635             : 
     636           2 :         if (!ftp_putcmd(ftp, "SITE", buffer)) {
     637           0 :                 efree(buffer);
     638           0 :                 return 0;
     639             :         }
     640             : 
     641           2 :         efree(buffer);
     642             : 
     643           2 :         if (!ftp_getresp(ftp) || ftp->resp != 200) {
     644           1 :                 return 0;
     645             :         }
     646             : 
     647           1 :         return 1;
     648             : }
     649             : /* }}} */
     650             : 
     651             : /* {{{ ftp_alloc
     652             :  */
     653             : int
     654           3 : ftp_alloc(ftpbuf_t *ftp, const zend_long size, zend_string **response)
     655             : {
     656             :         char buffer[64];
     657             : 
     658           3 :         if (ftp == NULL || size <= 0) {
     659           0 :                 return 0;
     660             :         }
     661             : 
     662           3 :         snprintf(buffer, sizeof(buffer) - 1, ZEND_LONG_FMT, size);
     663             : 
     664           3 :         if (!ftp_putcmd(ftp, "ALLO", buffer)) {
     665           0 :                 return 0;
     666             :         }
     667             : 
     668           3 :         if (!ftp_getresp(ftp)) {
     669           0 :                 return 0;
     670             :         }
     671             : 
     672           3 :         if (response) {
     673           2 :                 *response = zend_string_init(ftp->inbuf, strlen(ftp->inbuf), 0);
     674             :         }
     675             : 
     676           3 :         if (ftp->resp < 200 || ftp->resp >= 300) {
     677           1 :                 return 0;
     678             :         }
     679             : 
     680           2 :         return 1;
     681             : }
     682             : /* }}} */
     683             : 
     684             : /* {{{ ftp_nlist
     685             :  */
     686             : char**
     687           6 : ftp_nlist(ftpbuf_t *ftp, const char *path)
     688             : {
     689           6 :         return ftp_genlist(ftp, "NLST", path);
     690             : }
     691             : /* }}} */
     692             : 
     693             : /* {{{ ftp_list
     694             :  */
     695             : char**
     696           1 : ftp_list(ftpbuf_t *ftp, const char *path, int recursive)
     697             : {
     698           1 :         return ftp_genlist(ftp, ((recursive) ? "LIST -R" : "LIST"), path);
     699             : }
     700             : /* }}} */
     701             : 
     702             : /* {{{ ftp_type
     703             :  */
     704             : int
     705          25 : ftp_type(ftpbuf_t *ftp, ftptype_t type)
     706             : {
     707          25 :         char typechar[2] = "?";
     708             : 
     709          25 :         if (ftp == NULL) {
     710           0 :                 return 0;
     711             :         }
     712          25 :         if (type == ftp->type) {
     713           4 :                 return 1;
     714             :         }
     715          21 :         if (type == FTPTYPE_ASCII) {
     716          14 :                 typechar[0] = 'A';
     717           7 :         } else if (type == FTPTYPE_IMAGE) {
     718           7 :                 typechar[0] = 'I';
     719             :         } else {
     720           0 :                 return 0;
     721             :         }
     722          21 :         if (!ftp_putcmd(ftp, "TYPE", typechar)) {
     723           0 :                 return 0;
     724             :         }
     725          21 :         if (!ftp_getresp(ftp) || ftp->resp != 200) {
     726           1 :                 return 0;
     727             :         }
     728          20 :         ftp->type = type;
     729             : 
     730          20 :         return 1;
     731             : }
     732             : /* }}} */
     733             : 
     734             : /* {{{ ftp_pasv
     735             :  */
     736             : int
     737           0 : ftp_pasv(ftpbuf_t *ftp, int pasv)
     738             : {
     739             :         char                    *ptr;
     740             :         union ipbox             ipbox;
     741             :         unsigned long           b[6];
     742             :         socklen_t                       n;
     743             :         struct sockaddr *sa;
     744             :         struct sockaddr_in *sin;
     745             : 
     746           0 :         if (ftp == NULL) {
     747           0 :                 return 0;
     748             :         }
     749           0 :         if (pasv && ftp->pasv == 2) {
     750           0 :                 return 1;
     751             :         }
     752           0 :         ftp->pasv = 0;
     753           0 :         if (!pasv) {
     754           0 :                 return 1;
     755             :         }
     756           0 :         n = sizeof(ftp->pasvaddr);
     757           0 :         memset(&ftp->pasvaddr, 0, n);
     758           0 :         sa = (struct sockaddr *) &ftp->pasvaddr;
     759             : 
     760           0 :         if (getpeername(ftp->fd, sa, &n) < 0) {
     761           0 :                 return 0;
     762             :         }
     763             : 
     764             : #if HAVE_IPV6
     765           0 :         if (sa->sa_family == AF_INET6) {
     766           0 :                 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
     767             :                 char *endptr, delimiter;
     768             : 
     769             :                 /* try EPSV first */
     770           0 :                 if (!ftp_putcmd(ftp, "EPSV", NULL)) {
     771           0 :                         return 0;
     772             :                 }
     773           0 :                 if (!ftp_getresp(ftp)) {
     774           0 :                         return 0;
     775             :                 }
     776           0 :                 if (ftp->resp == 229) {
     777             :                         /* parse out the port */
     778           0 :                         for (ptr = ftp->inbuf; *ptr && *ptr != '('; ptr++);
     779           0 :                         if (!*ptr) {
     780           0 :                                 return 0;
     781             :                         }
     782           0 :                         delimiter = *++ptr;
     783           0 :                         for (n = 0; *ptr && n < 3; ptr++) {
     784           0 :                                 if (*ptr == delimiter) {
     785           0 :                                         n++;
     786             :                                 }
     787             :                         }
     788             : 
     789           0 :                         sin6->sin6_port = htons((unsigned short) strtoul(ptr, &endptr, 10));
     790           0 :                         if (ptr == endptr || *endptr != delimiter) {
     791           0 :                                 return 0;
     792             :                         }
     793           0 :                         ftp->pasv = 2;
     794           0 :                         return 1;
     795             :                 }
     796             :         }
     797             : 
     798             :         /* fall back to PASV */
     799             : #endif
     800             : 
     801           0 :         if (!ftp_putcmd(ftp, "PASV", NULL)) {
     802           0 :                 return 0;
     803             :         }
     804           0 :         if (!ftp_getresp(ftp) || ftp->resp != 227) {
     805           0 :                 return 0;
     806             :         }
     807             :         /* parse out the IP and port */
     808           0 :         for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
     809           0 :         n = sscanf(ptr, "%lu,%lu,%lu,%lu,%lu,%lu", &b[0], &b[1], &b[2], &b[3], &b[4], &b[5]);
     810           0 :         if (n != 6) {
     811           0 :                 return 0;
     812             :         }
     813           0 :         for (n = 0; n < 6; n++) {
     814           0 :                 ipbox.c[n] = (unsigned char) b[n];
     815             :         }
     816           0 :         sin = (struct sockaddr_in *) sa;
     817           0 :         if (ftp->usepasvaddress) {
     818           0 :                 sin->sin_addr = ipbox.ia[0];
     819             :         }
     820           0 :         sin->sin_port = ipbox.s[2];
     821             : 
     822           0 :         ftp->pasv = 2;
     823             : 
     824           0 :         return 1;
     825             : }
     826             : /* }}} */
     827             : 
     828             : /* {{{ ftp_get
     829             :  */
     830             : int
     831           9 : ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, zend_long resumepos)
     832             : {
     833           9 :         databuf_t               *data = NULL;
     834             :         size_t                  rcvd;
     835             :         char                    arg[11];
     836             : 
     837           9 :         if (ftp == NULL) {
     838           0 :                 return 0;
     839             :         }
     840           9 :         if (!ftp_type(ftp, type)) {
     841           0 :                 goto bail;
     842             :         }
     843             : 
     844           9 :         if ((data = ftp_getdata(ftp)) == NULL) {
     845           0 :                 goto bail;
     846             :         }
     847             : 
     848           9 :         ftp->data = data;
     849             : 
     850           9 :         if (resumepos > 0) {
     851           2 :                 snprintf(arg, sizeof(arg), ZEND_LONG_FMT, resumepos);
     852           2 :                 if (!ftp_putcmd(ftp, "REST", arg)) {
     853           0 :                         goto bail;
     854             :                 }
     855           2 :                 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
     856             :                         goto bail;
     857             :                 }
     858             :         }
     859             : 
     860           9 :         if (!ftp_putcmd(ftp, "RETR", path)) {
     861           0 :                 goto bail;
     862             :         }
     863           9 :         if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
     864             :                 goto bail;
     865             :         }
     866             : 
     867           7 :         if ((data = data_accept(data, ftp)) == NULL) {
     868           0 :                 goto bail;
     869             :         }
     870             : 
     871          21 :         while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
     872           7 :                 if (rcvd == (size_t)-1) {
     873           0 :                         goto bail;
     874             :                 }
     875             : 
     876           7 :                 if (type == FTPTYPE_ASCII) {
     877             : #ifndef PHP_WIN32
     878             :                         char *s;
     879             : #endif
     880           5 :                         char *ptr = data->buf;
     881           5 :                         char *e = ptr + rcvd;
     882             :                         /* logic depends on the OS EOL
     883             :                          * Win32 -> \r\n
     884             :                          * Everything Else \n
     885             :                          */
     886             : #ifdef PHP_WIN32
     887             :                         php_stream_write(outstream, ptr, (e - ptr));
     888             :                         ptr = e;
     889             : #else
     890          15 :                         while (e > ptr && (s = memchr(ptr, '\r', (e - ptr)))) {
     891           5 :                                 php_stream_write(outstream, ptr, (s - ptr));
     892           5 :                                 if (*(s + 1) == '\n') {
     893           5 :                                         s++;
     894           5 :                                         php_stream_putc(outstream, '\n');
     895             :                                 }
     896           5 :                                 ptr = s + 1;
     897             :                         }
     898             : #endif
     899           5 :                         if (ptr < e) {
     900           0 :                                 php_stream_write(outstream, ptr, (e - ptr));
     901             :                         }
     902           2 :                 } else if (rcvd != php_stream_write(outstream, data->buf, rcvd)) {
     903           0 :                         goto bail;
     904             :                 }
     905             :         }
     906             : 
     907           7 :         ftp->data = data = data_close(ftp, data);
     908             : 
     909           7 :         if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
     910             :                 goto bail;
     911             :         }
     912             : 
     913           7 :         return 1;
     914             : bail:
     915           2 :         ftp->data = data_close(ftp, data);
     916           2 :         return 0;
     917             : }
     918             : /* }}} */
     919             : 
     920             : /* {{{ ftp_put
     921             :  */
     922             : int
     923           2 : ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, zend_long startpos)
     924             : {
     925           2 :         databuf_t               *data = NULL;
     926             :         zend_long                       size;
     927             :         char                    *ptr;
     928             :         int                     ch;
     929             :         char                    arg[11];
     930             : 
     931           2 :         if (ftp == NULL) {
     932           0 :                 return 0;
     933             :         }
     934           2 :         if (!ftp_type(ftp, type)) {
     935           0 :                 goto bail;
     936             :         }
     937           2 :         if ((data = ftp_getdata(ftp)) == NULL) {
     938           0 :                 goto bail;
     939             :         }
     940           2 :         ftp->data = data;
     941             : 
     942           2 :         if (startpos > 0) {
     943           0 :                 snprintf(arg, sizeof(arg), ZEND_LONG_FMT, startpos);
     944           0 :                 if (!ftp_putcmd(ftp, "REST", arg)) {
     945           0 :                         goto bail;
     946             :                 }
     947           0 :                 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
     948             :                         goto bail;
     949             :                 }
     950             :         }
     951             : 
     952           2 :         if (!ftp_putcmd(ftp, "STOR", path)) {
     953           0 :                 goto bail;
     954             :         }
     955           2 :         if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
     956             :                 goto bail;
     957             :         }
     958           2 :         if ((data = data_accept(data, ftp)) == NULL) {
     959           0 :                 goto bail;
     960             :         }
     961             : 
     962           2 :         size = 0;
     963           2 :         ptr = data->buf;
     964        1050 :         while (!php_stream_eof(instream) && (ch = php_stream_getc(instream))!=EOF) {
     965             :                 /* flush if necessary */
     966        1046 :                 if (FTP_BUFSIZE - size < 2) {
     967           0 :                         if (my_send(ftp, data->fd, data->buf, size) != size) {
     968           0 :                                 goto bail;
     969             :                         }
     970           0 :                         ptr = data->buf;
     971           0 :                         size = 0;
     972             :                 }
     973             : 
     974        1046 :                 if (ch == '\n' && type == FTPTYPE_ASCII) {
     975          25 :                         *ptr++ = '\r';
     976          25 :                         size++;
     977             :                 }
     978             : 
     979        1046 :                 *ptr++ = ch;
     980        1046 :                 size++;
     981             :         }
     982             : 
     983           2 :         if (size && my_send(ftp, data->fd, data->buf, size) != size) {
     984           0 :                 goto bail;
     985             :         }
     986           2 :         ftp->data = data = data_close(ftp, data);
     987             : 
     988           2 :         if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) {
     989             :                 goto bail;
     990             :         }
     991           2 :         return 1;
     992             : bail:
     993           0 :         ftp->data = data_close(ftp, data);
     994           0 :         return 0;
     995             : }
     996             : /* }}} */
     997             : 
     998             : /* {{{ ftp_size
     999             :  */
    1000             : zend_long
    1001           2 : ftp_size(ftpbuf_t *ftp, const char *path)
    1002             : {
    1003           2 :         if (ftp == NULL) {
    1004           0 :                 return -1;
    1005             :         }
    1006           2 :         if (!ftp_type(ftp, FTPTYPE_IMAGE)) {
    1007           1 :                 return -1;
    1008             :         }
    1009           1 :         if (!ftp_putcmd(ftp, "SIZE", path)) {
    1010           0 :                 return -1;
    1011             :         }
    1012           1 :         if (!ftp_getresp(ftp) || ftp->resp != 213) {
    1013           0 :                 return -1;
    1014             :         }
    1015           1 :         return atol(ftp->inbuf);
    1016             : }
    1017             : /* }}} */
    1018             : 
    1019             : /* {{{ ftp_mdtm
    1020             :  */
    1021             : time_t
    1022           7 : ftp_mdtm(ftpbuf_t *ftp, const char *path)
    1023             : {
    1024             :         time_t          stamp;
    1025             :         struct tm       *gmt, tmbuf;
    1026             :         struct tm       tm;
    1027             :         char            *ptr;
    1028             :         int             n;
    1029             : 
    1030           7 :         if (ftp == NULL) {
    1031           0 :                 return -1;
    1032             :         }
    1033           7 :         if (!ftp_putcmd(ftp, "MDTM", path)) {
    1034           0 :                 return -1;
    1035             :         }
    1036           7 :         if (!ftp_getresp(ftp) || ftp->resp != 213) {
    1037           3 :                 return -1;
    1038             :         }
    1039             :         /* parse out the timestamp */
    1040           4 :         for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
    1041           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);
    1042           4 :         if (n != 6) {
    1043           0 :                 return -1;
    1044             :         }
    1045           4 :         tm.tm_year -= 1900;
    1046           4 :         tm.tm_mon--;
    1047           4 :         tm.tm_isdst = -1;
    1048             : 
    1049             :         /* figure out the GMT offset */
    1050           4 :         stamp = time(NULL);
    1051           4 :         gmt = php_gmtime_r(&stamp, &tmbuf);
    1052           4 :         if (!gmt) {
    1053           0 :                 return -1;
    1054             :         }
    1055           4 :         gmt->tm_isdst = -1;
    1056             : 
    1057             :         /* apply the GMT offset */
    1058           4 :         tm.tm_sec += stamp - mktime(gmt);
    1059           4 :         tm.tm_isdst = gmt->tm_isdst;
    1060             : 
    1061           4 :         stamp = mktime(&tm);
    1062             : 
    1063           4 :         return stamp;
    1064             : }
    1065             : /* }}} */
    1066             : 
    1067             : /* {{{ ftp_delete
    1068             :  */
    1069             : int
    1070           1 : ftp_delete(ftpbuf_t *ftp, const char *path)
    1071             : {
    1072           1 :         if (ftp == NULL) {
    1073           0 :                 return 0;
    1074             :         }
    1075           1 :         if (!ftp_putcmd(ftp, "DELE", path)) {
    1076           0 :                 return 0;
    1077             :         }
    1078           1 :         if (!ftp_getresp(ftp) || ftp->resp != 250) {
    1079           1 :                 return 0;
    1080             :         }
    1081             : 
    1082           0 :         return 1;
    1083             : }
    1084             : /* }}} */
    1085             : 
    1086             : /* {{{ ftp_rename
    1087             :  */
    1088             : int
    1089           0 : ftp_rename(ftpbuf_t *ftp, const char *src, const char *dest)
    1090             : {
    1091           0 :         if (ftp == NULL) {
    1092           0 :                 return 0;
    1093             :         }
    1094           0 :         if (!ftp_putcmd(ftp, "RNFR", src)) {
    1095           0 :                 return 0;
    1096             :         }
    1097           0 :         if (!ftp_getresp(ftp) || ftp->resp != 350) {
    1098           0 :                 return 0;
    1099             :         }
    1100           0 :         if (!ftp_putcmd(ftp, "RNTO", dest)) {
    1101           0 :                 return 0;
    1102             :         }
    1103           0 :         if (!ftp_getresp(ftp) || ftp->resp != 250) {
    1104           0 :                 return 0;
    1105             :         }
    1106           0 :         return 1;
    1107             : }
    1108             : /* }}} */
    1109             : 
    1110             : /* {{{ ftp_site
    1111             :  */
    1112             : int
    1113           0 : ftp_site(ftpbuf_t *ftp, const char *cmd)
    1114             : {
    1115           0 :         if (ftp == NULL) {
    1116           0 :                 return 0;
    1117             :         }
    1118           0 :         if (!ftp_putcmd(ftp, "SITE", cmd)) {
    1119           0 :                 return 0;
    1120             :         }
    1121           0 :         if (!ftp_getresp(ftp) || ftp->resp < 200 || ftp->resp >= 300) {
    1122           0 :                 return 0;
    1123             :         }
    1124             : 
    1125           0 :         return 1;
    1126             : }
    1127             : /* }}} */
    1128             : 
    1129             : /* static functions */
    1130             : 
    1131             : /* {{{ ftp_putcmd
    1132             :  */
    1133             : int
    1134         186 : ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const char *args)
    1135             : {
    1136             :         int             size;
    1137             :         char            *data;
    1138             : 
    1139         186 :         if (strpbrk(cmd, "\r\n")) {
    1140           0 :                 return 0;
    1141             :         }
    1142             :         /* build the output buffer */
    1143         343 :         if (args && args[0]) {
    1144             :                 /* "cmd args\r\n\0" */
    1145         157 :                 if (strlen(cmd) + strlen(args) + 4 > FTP_BUFSIZE) {
    1146           0 :                         return 0;
    1147             :                 }
    1148         157 :                 if (strpbrk(args, "\r\n")) {
    1149           0 :                         return 0;
    1150             :                 }
    1151         157 :                 size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s %s\r\n", cmd, args);
    1152             :         } else {
    1153             :                 /* "cmd\r\n\0" */
    1154          29 :                 if (strlen(cmd) + 3 > FTP_BUFSIZE) {
    1155           0 :                         return 0;
    1156             :                 }
    1157          29 :                 size = slprintf(ftp->outbuf, sizeof(ftp->outbuf), "%s\r\n", cmd);
    1158             :         }
    1159             : 
    1160         186 :         data = ftp->outbuf;
    1161             : 
    1162             :         /* Clear the extra-lines buffer */
    1163         186 :         ftp->extra = NULL;
    1164             : 
    1165         186 :         if (my_send(ftp, ftp->fd, data, size) != size) {
    1166           0 :                 return 0;
    1167             :         }
    1168         186 :         return 1;
    1169             : }
    1170             : /* }}} */
    1171             : 
    1172             : /* {{{ ftp_readline
    1173             :  */
    1174             : int
    1175         267 : ftp_readline(ftpbuf_t *ftp)
    1176             : {
    1177             :         long            size, rcvd;
    1178             :         char            *data, *eol;
    1179             : 
    1180             :         /* shift the extra to the front */
    1181         267 :         size = FTP_BUFSIZE;
    1182         267 :         rcvd = 0;
    1183         267 :         if (ftp->extra) {
    1184          33 :                 memmove(ftp->inbuf, ftp->extra, ftp->extralen);
    1185          33 :                 rcvd = ftp->extralen;
    1186             :         }
    1187             : 
    1188         267 :         data = ftp->inbuf;
    1189             : 
    1190             :         do {
    1191         490 :                 size -= rcvd;
    1192        6558 :                 for (eol = data; rcvd; rcvd--, eol++) {
    1193        6324 :                         if (*eol == '\r') {
    1194         256 :                                 *eol = 0;
    1195         256 :                                 ftp->extra = eol + 1;
    1196         256 :                                 if (rcvd > 1 && *(eol + 1) == '\n') {
    1197         256 :                                         ftp->extra++;
    1198         256 :                                         rcvd--;
    1199             :                                 }
    1200         256 :                                 if ((ftp->extralen = --rcvd) == 0) {
    1201         222 :                                         ftp->extra = NULL;
    1202             :                                 }
    1203         256 :                                 return 1;
    1204        6068 :                         } else if (*eol == '\n') {
    1205           0 :                                 *eol = 0;
    1206           0 :                                 ftp->extra = eol + 1;
    1207           0 :                                 if ((ftp->extralen = --rcvd) == 0) {
    1208           0 :                                         ftp->extra = NULL;
    1209             :                                 }
    1210           0 :                                 return 1;
    1211             :                         }
    1212             :                 }
    1213             : 
    1214         234 :                 data = eol;
    1215         234 :                 if ((rcvd = my_recv(ftp, ftp->fd, data, size)) < 1) {
    1216          11 :                         return 0;
    1217             :                 }
    1218         223 :         } while (size);
    1219             : 
    1220           0 :         return 0;
    1221             : }
    1222             : /* }}} */
    1223             : 
    1224             : /* {{{ ftp_getresp
    1225             :  */
    1226             : int
    1227         226 : ftp_getresp(ftpbuf_t *ftp)
    1228             : {
    1229         226 :         if (ftp == NULL) {
    1230           0 :                 return 0;
    1231             :         }
    1232         226 :         ftp->resp = 0;
    1233             : 
    1234             :         while (1) {
    1235             : 
    1236         257 :                 if (!ftp_readline(ftp)) {
    1237          11 :                         return 0;
    1238             :                 }
    1239             : 
    1240             :                 /* Break out when the end-tag is found */
    1241         246 :                 if (isdigit(ftp->inbuf[0]) && isdigit(ftp->inbuf[1]) && isdigit(ftp->inbuf[2]) && ftp->inbuf[3] == ' ') {
    1242         215 :                         break;
    1243             :                 }
    1244          31 :         }
    1245             : 
    1246             :         /* translate the tag */
    1247         215 :         if (!isdigit(ftp->inbuf[0]) || !isdigit(ftp->inbuf[1]) || !isdigit(ftp->inbuf[2])) {
    1248           0 :                 return 0;
    1249             :         }
    1250             : 
    1251         215 :         ftp->resp = 100 * (ftp->inbuf[0] - '0') + 10 * (ftp->inbuf[1] - '0') + (ftp->inbuf[2] - '0');
    1252             : 
    1253         215 :         memmove(ftp->inbuf, ftp->inbuf + 4, FTP_BUFSIZE - 4);
    1254             : 
    1255         215 :         if (ftp->extra) {
    1256           1 :                 ftp->extra -= 4;
    1257             :         }
    1258         215 :         return 1;
    1259             : }
    1260             : /* }}} */
    1261             : 
    1262             : /* {{{ my_send
    1263             :  */
    1264             : int
    1265         188 : my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
    1266             : {
    1267             :         zend_long               size, sent;
    1268             :     int         n;
    1269             : #ifdef HAVE_FTP_SSL
    1270             :         int err;
    1271         188 :         zend_bool retry = 0;
    1272         188 :         SSL *handle = NULL;
    1273             :         php_socket_t fd;
    1274             : #endif
    1275             : 
    1276             : 
    1277         188 :         size = len;
    1278         564 :         while (size) {
    1279         188 :                 n = php_pollfd_for_ms(s, POLLOUT, ftp->timeout_sec * 1000);
    1280             : 
    1281         188 :                 if (n < 1) {
    1282             : #ifdef PHP_WIN32
    1283             :                         if (n == 0) {
    1284             :                                 _set_errno(ETIMEDOUT);
    1285             :                         }
    1286             : #elif !(defined(NETWARE) && defined(USE_WINSOCK))
    1287           0 :                         if (n == 0) {
    1288           0 :                                 errno = ETIMEDOUT;
    1289             :                         }
    1290             : #endif
    1291           0 :                         return -1;
    1292             :                 }
    1293             : 
    1294             : #ifdef HAVE_FTP_SSL
    1295         195 :                 if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
    1296           7 :                         handle = ftp->ssl_handle;
    1297           7 :                         fd = ftp->fd;
    1298         181 :                 } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
    1299           0 :                         handle = ftp->data->ssl_handle;
    1300           0 :                         fd = ftp->data->fd;
    1301             :                 }
    1302             : 
    1303         188 :                 if (handle) {
    1304             :                         do {
    1305           7 :                                 sent = SSL_write(handle, buf, size);
    1306           7 :                                 err = SSL_get_error(handle, sent);
    1307             : 
    1308           7 :                                 switch (err) {
    1309             :                                         case SSL_ERROR_NONE:
    1310           7 :                                                 retry = 0;
    1311           7 :                                                 break;
    1312             : 
    1313             :                                         case SSL_ERROR_ZERO_RETURN:
    1314           0 :                                                 retry = 0;
    1315           0 :                                                 SSL_shutdown(handle);
    1316           0 :                                                 break;
    1317             : 
    1318             :                                         case SSL_ERROR_WANT_READ:
    1319             :                                         case SSL_ERROR_WANT_CONNECT: {
    1320             :                                                         php_pollfd p;
    1321             :                                                         int i;
    1322             : 
    1323           0 :                                                         p.fd = fd;
    1324           0 :                                                         p.events = POLLOUT;
    1325           0 :                                                         p.revents = 0;
    1326             : 
    1327           0 :                                                         i = php_poll2(&p, 1, 300);
    1328             : 
    1329           0 :                                                         retry = i > 0;
    1330             :                                                 }
    1331           0 :                                                 break;
    1332             : 
    1333             :                                         default:
    1334           0 :                                                 php_error_docref(NULL, E_WARNING, "SSL write failed");
    1335           0 :                                                 return -1;
    1336             :                                 }
    1337           7 :                         } while (retry);
    1338             :                 } else {
    1339             : #endif
    1340         181 :                         sent = send(s, buf, size, 0);
    1341             : #ifdef HAVE_FTP_SSL
    1342             :                 }
    1343             : #endif
    1344         188 :                 if (sent == -1) {
    1345           0 :                         return -1;
    1346             :                 }
    1347             : 
    1348         188 :                 buf = (char*) buf + sent;
    1349         188 :                 size -= sent;
    1350             :         }
    1351             : 
    1352         188 :         return len;
    1353             : }
    1354             : /* }}} */
    1355             : 
    1356             : /* {{{ my_recv
    1357             :  */
    1358             : int
    1359         263 : my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
    1360             : {
    1361             :         int             n, nr_bytes;
    1362             : #ifdef HAVE_FTP_SSL
    1363             :         int err;
    1364         263 :         zend_bool retry = 0;
    1365         263 :         SSL *handle = NULL;
    1366             :         php_socket_t fd;
    1367             : #endif
    1368             : 
    1369         263 :         n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
    1370         263 :         if (n < 1) {
    1371             : #ifdef PHP_WIN32
    1372             :                 if (n == 0) {
    1373             :                         _set_errno(ETIMEDOUT);
    1374             :                 }
    1375             : #elif !(defined(NETWARE) && defined(USE_WINSOCK))
    1376           0 :                 if (n == 0) {
    1377           0 :                         errno = ETIMEDOUT;
    1378             :                 }
    1379             : #endif
    1380           0 :                 return -1;
    1381             :         }
    1382             : 
    1383             : #ifdef HAVE_FTP_SSL
    1384         273 :         if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
    1385          10 :                 handle = ftp->ssl_handle;
    1386          10 :                 fd = ftp->fd;
    1387         253 :         } else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
    1388           0 :                 handle = ftp->data->ssl_handle;
    1389           0 :                 fd = ftp->data->fd;
    1390             :         }
    1391             : 
    1392         263 :         if (handle) {
    1393             :                 do {
    1394          10 :                         nr_bytes = SSL_read(handle, buf, len);
    1395          10 :                         err = SSL_get_error(handle, nr_bytes);
    1396             : 
    1397          10 :                         switch (err) {
    1398             :                                 case SSL_ERROR_NONE:
    1399           9 :                                         retry = 0;
    1400           9 :                                         break;
    1401             : 
    1402             :                                 case SSL_ERROR_ZERO_RETURN:
    1403           1 :                                         retry = 0;
    1404           1 :                                         SSL_shutdown(handle);
    1405           1 :                                         break;
    1406             : 
    1407             :                                 case SSL_ERROR_WANT_READ:
    1408             :                                 case SSL_ERROR_WANT_CONNECT: {
    1409             :                                                 php_pollfd p;
    1410             :                                                 int i;
    1411             : 
    1412           0 :                                                 p.fd = fd;
    1413           0 :                                                 p.events = POLLIN|POLLPRI;
    1414           0 :                                                 p.revents = 0;
    1415             : 
    1416           0 :                                                 i = php_poll2(&p, 1, 300);
    1417             : 
    1418           0 :                                                 retry = i > 0;
    1419             :                                         }
    1420           0 :                                         break;
    1421             : 
    1422             :                                 default:
    1423           0 :                                         php_error_docref(NULL, E_WARNING, "SSL read failed");
    1424           0 :                                         return -1;
    1425             :                         }
    1426          10 :                 } while (retry);
    1427             :         } else {
    1428             : #endif
    1429         253 :                 nr_bytes = recv(s, buf, len, 0);
    1430             : #ifdef HAVE_FTP_SSL
    1431             :         }
    1432             : #endif
    1433         263 :         return (nr_bytes);
    1434             : }
    1435             : /* }}} */
    1436             : 
    1437             : /* {{{ data_available
    1438             :  */
    1439             : int
    1440          10 : data_available(ftpbuf_t *ftp, php_socket_t s)
    1441             : {
    1442             :         int             n;
    1443             : 
    1444          10 :         n = php_pollfd_for_ms(s, PHP_POLLREADABLE, 1000);
    1445          10 :         if (n < 1) {
    1446             : #ifdef PHP_WIN32
    1447             :                 if (n == 0) {
    1448             :                         _set_errno(ETIMEDOUT);
    1449             :                 }
    1450             : #elif !(defined(NETWARE) && defined(USE_WINSOCK))
    1451           0 :                 if (n == 0) {
    1452           0 :                         errno = ETIMEDOUT;
    1453             :                 }
    1454             : #endif
    1455           0 :                 return 0;
    1456             :         }
    1457             : 
    1458          10 :         return 1;
    1459             : }
    1460             : /* }}} */
    1461             : /* {{{ data_writeable
    1462             :  */
    1463             : int
    1464           0 : data_writeable(ftpbuf_t *ftp, php_socket_t s)
    1465             : {
    1466             :         int             n;
    1467             : 
    1468           0 :         n = php_pollfd_for_ms(s, POLLOUT, 1000);
    1469           0 :         if (n < 1) {
    1470             : #ifdef PHP_WIN32
    1471             :                 if (n == 0) {
    1472             :                         _set_errno(ETIMEDOUT);
    1473             :                 }
    1474             : #elif !(defined(NETWARE) && defined(USE_WINSOCK))
    1475           0 :                 if (n == 0) {
    1476           0 :                         errno = ETIMEDOUT;
    1477             :                 }
    1478             : #endif
    1479           0 :                 return 0;
    1480             :         }
    1481             : 
    1482           0 :         return 1;
    1483             : }
    1484             : /* }}} */
    1485             : 
    1486             : /* {{{ my_accept
    1487             :  */
    1488             : int
    1489          17 : my_accept(ftpbuf_t *ftp, php_socket_t s, struct sockaddr *addr, socklen_t *addrlen)
    1490             : {
    1491             :         int             n;
    1492             : 
    1493          17 :         n = php_pollfd_for_ms(s, PHP_POLLREADABLE, ftp->timeout_sec * 1000);
    1494          17 :         if (n < 1) {
    1495             : #ifdef PHP_WIN32
    1496             :                 if (n == 0) {
    1497             :                         _set_errno(ETIMEDOUT);
    1498             :                 }
    1499             : #elif !(defined(NETWARE) && defined(USE_WINSOCK))
    1500           0 :                 if (n == 0) {
    1501           0 :                         errno = ETIMEDOUT;
    1502             :                 }
    1503             : #endif
    1504           0 :                 return -1;
    1505             :         }
    1506             : 
    1507          17 :         return accept(s, addr, addrlen);
    1508             : }
    1509             : /* }}} */
    1510             : 
    1511             : /* {{{ ftp_getdata
    1512             :  */
    1513             : databuf_t*
    1514          23 : ftp_getdata(ftpbuf_t *ftp)
    1515             : {
    1516          23 :         int                     fd = -1;
    1517             :         databuf_t               *data;
    1518             :         php_sockaddr_storage addr;
    1519             :         struct sockaddr *sa;
    1520             :         socklen_t               size;
    1521             :         union ipbox             ipbox;
    1522             :         char                    arg[sizeof("255, 255, 255, 255, 255, 255")];
    1523             :         struct timeval  tv;
    1524             : 
    1525             : 
    1526             :         /* ask for a passive connection if we need one */
    1527          23 :         if (ftp->pasv && !ftp_pasv(ftp, 1)) {
    1528           0 :                 return NULL;
    1529             :         }
    1530             :         /* alloc the data structure */
    1531          23 :         data = ecalloc(1, sizeof(*data));
    1532          23 :         data->listener = -1;
    1533          23 :         data->fd = -1;
    1534          23 :         data->type = ftp->type;
    1535             : 
    1536          23 :         sa = (struct sockaddr *) &ftp->localaddr;
    1537             :         /* bind/listen */
    1538          23 :         if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == SOCK_ERR) {
    1539           0 :                 php_error_docref(NULL, E_WARNING, "socket() failed: %s (%d)", strerror(errno), errno);
    1540           0 :                 goto bail;
    1541             :         }
    1542             : 
    1543             :         /* passive connection handler */
    1544          23 :         if (ftp->pasv) {
    1545             :                 /* clear the ready status */
    1546           0 :                 ftp->pasv = 1;
    1547             : 
    1548             :                 /* connect */
    1549             :                 /* Win 95/98 seems not to like size > sizeof(sockaddr_in) */
    1550           0 :                 size = php_sockaddr_size(&ftp->pasvaddr);
    1551           0 :                 tv.tv_sec = ftp->timeout_sec;
    1552           0 :                 tv.tv_usec = 0;
    1553           0 :                 if (php_connect_nonb(fd, (struct sockaddr*) &ftp->pasvaddr, size, &tv) == -1) {
    1554           0 :                         php_error_docref(NULL, E_WARNING, "php_connect_nonb() failed: %s (%d)", strerror(errno), errno);
    1555           0 :                         goto bail;
    1556             :                 }
    1557             : 
    1558           0 :                 data->fd = fd;
    1559             : 
    1560           0 :                 ftp->data = data;
    1561           0 :                 return data;
    1562             :         }
    1563             : 
    1564             : 
    1565             :         /* active (normal) connection */
    1566             : 
    1567             :         /* bind to a local address */
    1568          23 :         php_any_addr(sa->sa_family, &addr, 0);
    1569          23 :         size = php_sockaddr_size(&addr);
    1570             : 
    1571          23 :         if (bind(fd, (struct sockaddr*) &addr, size) != 0) {
    1572           0 :                 php_error_docref(NULL, E_WARNING, "bind() failed: %s (%d)", strerror(errno), errno);
    1573           0 :                 goto bail;
    1574             :         }
    1575             : 
    1576          23 :         if (getsockname(fd, (struct sockaddr*) &addr, &size) != 0) {
    1577           0 :                 php_error_docref(NULL, E_WARNING, "getsockname() failed: %s (%d)", strerror(errno), errno);
    1578           0 :                 goto bail;
    1579             :         }
    1580             : 
    1581          23 :         if (listen(fd, 5) != 0) {
    1582           0 :                 php_error_docref(NULL, E_WARNING, "listen() failed: %s (%d)", strerror(errno), errno);
    1583           0 :                 goto bail;
    1584             :         }
    1585             : 
    1586          23 :         data->listener = fd;
    1587             : 
    1588             : #if HAVE_IPV6 && HAVE_INET_NTOP
    1589          23 :         if (sa->sa_family == AF_INET6) {
    1590             :                 /* need to use EPRT */
    1591             :                 char eprtarg[INET6_ADDRSTRLEN + sizeof("|x||xxxxx|")];
    1592             :                 char out[INET6_ADDRSTRLEN];
    1593           0 :                 inet_ntop(AF_INET6, &((struct sockaddr_in6*) sa)->sin6_addr, out, sizeof(out));
    1594           0 :                 snprintf(eprtarg, sizeof(eprtarg), "|2|%s|%hu|", out, ntohs(((struct sockaddr_in6 *) &addr)->sin6_port));
    1595             : 
    1596           0 :                 if (!ftp_putcmd(ftp, "EPRT", eprtarg)) {
    1597           0 :                         goto bail;
    1598             :                 }
    1599             : 
    1600           0 :                 if (!ftp_getresp(ftp) || ftp->resp != 200) {
    1601             :                         goto bail;
    1602             :                 }
    1603             : 
    1604           0 :                 ftp->data = data;
    1605           0 :                 return data;
    1606             :         }
    1607             : #endif
    1608             : 
    1609             :         /* send the PORT */
    1610          23 :         ipbox.ia[0] = ((struct sockaddr_in*) sa)->sin_addr;
    1611          23 :         ipbox.s[2] = ((struct sockaddr_in*) &addr)->sin_port;
    1612          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]);
    1613             : 
    1614          23 :         if (!ftp_putcmd(ftp, "PORT", arg)) {
    1615           0 :                 goto bail;
    1616             :         }
    1617          23 :         if (!ftp_getresp(ftp) || ftp->resp != 200) {
    1618             :                 goto bail;
    1619             :         }
    1620             : 
    1621          23 :         ftp->data = data;
    1622          23 :         return data;
    1623             : 
    1624             : bail:
    1625           0 :         if (fd != -1) {
    1626           0 :                 closesocket(fd);
    1627             :         }
    1628           0 :         efree(data);
    1629           0 :         return NULL;
    1630             : }
    1631             : /* }}} */
    1632             : 
    1633             : /* {{{ data_accept
    1634             :  */
    1635             : databuf_t*
    1636          17 : data_accept(databuf_t *data, ftpbuf_t *ftp)
    1637             : {
    1638             :         php_sockaddr_storage addr;
    1639             :         socklen_t                       size;
    1640             : 
    1641             : #ifdef HAVE_FTP_SSL
    1642             :         SSL_CTX         *ctx;
    1643             :         SSL_SESSION *session;
    1644             :         int err, res;
    1645             :         zend_bool retry;
    1646             : #endif
    1647             : 
    1648          17 :         if (data->fd != -1) {
    1649           0 :                 goto data_accepted;
    1650             :         }
    1651          17 :         size = sizeof(addr);
    1652          17 :         data->fd = my_accept(ftp, data->listener, (struct sockaddr*) &addr, &size);
    1653          17 :         closesocket(data->listener);
    1654          17 :         data->listener = -1;
    1655             : 
    1656          17 :         if (data->fd == -1) {
    1657           0 :                 efree(data);
    1658           0 :                 return NULL;
    1659             :         }
    1660             : 
    1661             : data_accepted:
    1662             : #ifdef HAVE_FTP_SSL
    1663             : 
    1664             :         /* now enable ssl if we need to */
    1665          17 :         if (ftp->use_ssl && ftp->use_ssl_for_data) {
    1666           0 :                 ctx = SSL_get_SSL_CTX(ftp->ssl_handle);
    1667           0 :                 if (ctx == NULL) {
    1668           0 :                         php_error_docref(NULL, E_WARNING, "data_accept: failed to retreive the existing SSL context");
    1669           0 :                         return 0;
    1670             :                 }
    1671             : 
    1672           0 :                 data->ssl_handle = SSL_new(ctx);
    1673           0 :                 if (data->ssl_handle == NULL) {
    1674           0 :                         php_error_docref(NULL, E_WARNING, "data_accept: failed to create the SSL handle");
    1675           0 :                         return 0;
    1676             :                 }
    1677             : 
    1678           0 :                 SSL_set_fd(data->ssl_handle, data->fd);
    1679             : 
    1680           0 :                 if (ftp->old_ssl) {
    1681           0 :                         SSL_copy_session_id(data->ssl_handle, ftp->ssl_handle);
    1682             :                 }
    1683             : 
    1684             :                 /* get the session from the control connection so we can re-use it */
    1685           0 :                 session = SSL_get_session(ftp->ssl_handle);
    1686           0 :                 if (session == NULL) {
    1687           0 :                         php_error_docref(NULL, E_WARNING, "data_accept: failed to retreive the existing SSL session");
    1688           0 :                         SSL_free(data->ssl_handle);
    1689           0 :                         return 0;
    1690             :                 }
    1691             : 
    1692             :                 /* and set it on the data connection */
    1693           0 :                 res = SSL_set_session(data->ssl_handle, session);
    1694           0 :                 if (res == 0) {
    1695           0 :                         php_error_docref(NULL, E_WARNING, "data_accept: failed to set the existing SSL session");
    1696           0 :                         SSL_free(data->ssl_handle);
    1697           0 :                         return 0;
    1698             :                 }
    1699             : 
    1700             :                 do {
    1701           0 :                         res = SSL_connect(data->ssl_handle);
    1702           0 :                         err = SSL_get_error(data->ssl_handle, res);
    1703             : 
    1704           0 :                         switch (err) {
    1705             :                                 case SSL_ERROR_NONE:
    1706           0 :                                         retry = 0;
    1707           0 :                                         break;
    1708             : 
    1709             :                                 case SSL_ERROR_ZERO_RETURN:
    1710           0 :                                         retry = 0;
    1711           0 :                                         SSL_shutdown(data->ssl_handle);
    1712           0 :                                         break;
    1713             : 
    1714             :                                 case SSL_ERROR_WANT_READ:
    1715             :                                 case SSL_ERROR_WANT_WRITE: {
    1716             :                                                 php_pollfd p;
    1717             :                                                 int i;
    1718             : 
    1719           0 :                                                 p.fd = ftp->fd;
    1720           0 :                                                 p.events = (err == SSL_ERROR_WANT_READ) ? (POLLIN|POLLPRI) : POLLOUT;
    1721           0 :                                                 p.revents = 0;
    1722             : 
    1723           0 :                                                 i = php_poll2(&p, 1, 300);
    1724             : 
    1725           0 :                                                 retry = i > 0;
    1726             :                                         }
    1727           0 :                                         break;
    1728             : 
    1729             :                                 default:
    1730           0 :                                         php_error_docref(NULL, E_WARNING, "data_accept: SSL/TLS handshake failed");
    1731           0 :                                         SSL_shutdown(data->ssl_handle);
    1732           0 :                                         SSL_free(data->ssl_handle);
    1733           0 :                                         return 0;
    1734             :                         }
    1735           0 :                 } while (retry);
    1736             : 
    1737           0 :                 data->ssl_active = 1;
    1738             :         }
    1739             : 
    1740             : #endif
    1741             : 
    1742          17 :         return data;
    1743             : }
    1744             : /* }}} */
    1745             : 
    1746             : /* {{{ data_close
    1747             :  */
    1748             : databuf_t*
    1749          23 : data_close(ftpbuf_t *ftp, databuf_t *data)
    1750             : {
    1751             : #ifdef HAVE_FTP_SSL
    1752             :         SSL_CTX         *ctx;
    1753             : #endif
    1754          23 :         if (data == NULL) {
    1755           0 :                 return NULL;
    1756             :         }
    1757          23 :         if (data->listener != -1) {
    1758             : #ifdef HAVE_FTP_SSL
    1759           6 :                 if (data->ssl_active) {
    1760             :                         /* don't free the data context, it's the same as the control */
    1761           0 :                         SSL_shutdown(data->ssl_handle);
    1762           0 :                         SSL_free(data->ssl_handle);
    1763           0 :                         data->ssl_active = 0;
    1764             :                 }
    1765             : #endif
    1766           6 :                 closesocket(data->listener);
    1767             :         }
    1768          23 :         if (data->fd != -1) {
    1769             : #ifdef HAVE_FTP_SSL
    1770          17 :                 if (data->ssl_active) {
    1771             :                         /* don't free the data context, it's the same as the control */
    1772           0 :                         SSL_shutdown(data->ssl_handle);
    1773           0 :                         SSL_free(data->ssl_handle);
    1774           0 :                         data->ssl_active = 0;
    1775             :                 }
    1776             : #endif
    1777          17 :                 closesocket(data->fd);
    1778             :         }
    1779          23 :         if (ftp) {
    1780          23 :                 ftp->data = NULL;
    1781             :         }
    1782          23 :         efree(data);
    1783          23 :         return NULL;
    1784             : }
    1785             : /* }}} */
    1786             : 
    1787             : /* {{{ ftp_genlist
    1788             :  */
    1789             : char**
    1790           7 : ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path)
    1791             : {
    1792           7 :         php_stream      *tmpstream = NULL;
    1793           7 :         databuf_t       *data = NULL;
    1794             :         char            *ptr;
    1795             :         int             ch, lastch;
    1796             :         size_t          size, rcvd;
    1797             :         size_t          lines;
    1798           7 :         char            **ret = NULL;
    1799             :         char            **entry;
    1800             :         char            *text;
    1801             : 
    1802             : 
    1803           7 :         if ((tmpstream = php_stream_fopen_tmpfile()) == NULL) {
    1804           0 :                 php_error_docref(NULL, E_WARNING, "Unable to create temporary file.  Check permissions in temporary files directory.");
    1805           0 :                 return NULL;
    1806             :         }
    1807             : 
    1808           7 :         if (!ftp_type(ftp, FTPTYPE_ASCII)) {
    1809           0 :                 goto bail;
    1810             :         }
    1811             : 
    1812           7 :         if ((data = ftp_getdata(ftp)) == NULL) {
    1813           0 :                 goto bail;
    1814             :         }
    1815           7 :         ftp->data = data;
    1816             : 
    1817           7 :         if (!ftp_putcmd(ftp, cmd, path)) {
    1818           0 :                 goto bail;
    1819             :         }
    1820           7 :         if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125 && ftp->resp != 226)) {
    1821             :                 goto bail;
    1822             :         }
    1823             : 
    1824             :         /* some servers don't open a ftp-data connection if the directory is empty */
    1825           4 :         if (ftp->resp == 226) {
    1826           1 :                 ftp->data = data_close(ftp, data);
    1827           1 :                 php_stream_close(tmpstream);
    1828           1 :                 return ecalloc(1, sizeof(char*));
    1829             :         }
    1830             : 
    1831             :         /* pull data buffer into tmpfile */
    1832           3 :         if ((data = data_accept(data, ftp)) == NULL) {
    1833           0 :                 goto bail;
    1834             :         }
    1835           3 :         size = 0;
    1836           3 :         lines = 0;
    1837           3 :         lastch = 0;
    1838           8 :         while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
    1839           2 :                 if (rcvd == (size_t)-1 || rcvd > ((size_t)(-1))-size) {
    1840             :                         goto bail;
    1841             :                 }
    1842             : 
    1843           2 :                 php_stream_write(tmpstream, data->buf, rcvd);
    1844             : 
    1845           2 :                 size += rcvd;
    1846          52 :                 for (ptr = data->buf; rcvd; rcvd--, ptr++) {
    1847          50 :                         if (*ptr == '\n' && lastch == '\r') {
    1848           6 :                                 lines++;
    1849             :                         }
    1850          50 :                         lastch = *ptr;
    1851             :                 }
    1852             :         }
    1853             : 
    1854           3 :         ftp->data = data_close(ftp, data);
    1855             : 
    1856           3 :         php_stream_rewind(tmpstream);
    1857             : 
    1858           3 :         ret = safe_emalloc((lines + 1), sizeof(char*), size);
    1859             : 
    1860           3 :         entry = ret;
    1861           3 :         text = (char*) (ret + lines + 1);
    1862           3 :         *entry = text;
    1863           3 :         lastch = 0;
    1864          56 :         while ((ch = php_stream_getc(tmpstream)) != EOF) {
    1865          56 :                 if (ch == '\n' && lastch == '\r') {
    1866           6 :                         *(text - 1) = 0;
    1867           6 :                         *++entry = text;
    1868             :                 } else {
    1869          44 :                         *text++ = ch;
    1870             :                 }
    1871          50 :                 lastch = ch;
    1872             :         }
    1873           3 :         *entry = NULL;
    1874             : 
    1875           3 :         php_stream_close(tmpstream);
    1876             : 
    1877           3 :         if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
    1878           0 :                 efree(ret);
    1879           0 :                 return NULL;
    1880             :         }
    1881             : 
    1882           3 :         return ret;
    1883             : bail:
    1884           3 :         ftp->data = data_close(ftp, data);
    1885           3 :         php_stream_close(tmpstream);
    1886           3 :         if (ret)
    1887           0 :                 efree(ret);
    1888           3 :         return NULL;
    1889             : }
    1890             : /* }}} */
    1891             : 
    1892             : /* {{{ ftp_nb_get
    1893             :  */
    1894             : int
    1895           5 : ftp_nb_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type, zend_long resumepos)
    1896             : {
    1897           5 :         databuf_t               *data = NULL;
    1898             :         char                    arg[11];
    1899             : 
    1900           5 :         if (ftp == NULL) {
    1901           0 :                 return PHP_FTP_FAILED;
    1902             :         }
    1903             : 
    1904           5 :         if (!ftp_type(ftp, type)) {
    1905           0 :                 goto bail;
    1906             :         }
    1907             : 
    1908           5 :         if ((data = ftp_getdata(ftp)) == NULL) {
    1909           0 :                 goto bail;
    1910             :         }
    1911             : 
    1912           5 :         if (resumepos>0) {
    1913           3 :                 snprintf(arg, sizeof(arg), ZEND_LONG_FMT, resumepos);
    1914           3 :                 if (!ftp_putcmd(ftp, "REST", arg)) {
    1915           0 :                         goto bail;
    1916             :                 }
    1917           3 :                 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
    1918             :                         goto bail;
    1919             :                 }
    1920             :         }
    1921             : 
    1922           5 :         if (!ftp_putcmd(ftp, "RETR", path)) {
    1923           0 :                 goto bail;
    1924             :         }
    1925           5 :         if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
    1926             :                 goto bail;
    1927             :         }
    1928             : 
    1929           5 :         if ((data = data_accept(data, ftp)) == NULL) {
    1930           0 :                 goto bail;
    1931             :         }
    1932             : 
    1933           5 :         ftp->data = data;
    1934           5 :         ftp->stream = outstream;
    1935           5 :         ftp->lastch = 0;
    1936           5 :         ftp->nb = 1;
    1937             : 
    1938           5 :         return (ftp_nb_continue_read(ftp));
    1939             : 
    1940             : bail:
    1941           0 :         ftp->data = data_close(ftp, data);
    1942           0 :         return PHP_FTP_FAILED;
    1943             : }
    1944             : /* }}} */
    1945             : 
    1946             : /* {{{ ftp_nb_continue_read
    1947             :  */
    1948             : int
    1949          10 : ftp_nb_continue_read(ftpbuf_t *ftp)
    1950             : {
    1951          10 :         databuf_t       *data = NULL;
    1952             :         char            *ptr;
    1953             :         int             lastch;
    1954             :         size_t          rcvd;
    1955             :         ftptype_t       type;
    1956             : 
    1957          10 :         data = ftp->data;
    1958             : 
    1959             :         /* check if there is already more data */
    1960          10 :         if (!data_available(ftp, data->fd)) {
    1961           0 :                 return PHP_FTP_MOREDATA;
    1962             :         }
    1963             : 
    1964          10 :         type = ftp->type;
    1965             : 
    1966          10 :         lastch = ftp->lastch;
    1967          10 :         if ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
    1968           9 :                 if (rcvd == (size_t)-1) {
    1969           0 :                         goto bail;
    1970             :                 }
    1971             : 
    1972           9 :                 if (type == FTPTYPE_ASCII) {
    1973          26 :                         for (ptr = data->buf; rcvd; rcvd--, ptr++) {
    1974          23 :                                 if (lastch == '\r' && *ptr != '\n') {
    1975           0 :                                         php_stream_putc(ftp->stream, '\r');
    1976             :                                 }
    1977          23 :                                 if (*ptr != '\r') {
    1978          20 :                                         php_stream_putc(ftp->stream, *ptr);
    1979             :                                 }
    1980          23 :                                 lastch = *ptr;
    1981             :                         }
    1982           6 :                 } else if (rcvd != php_stream_write(ftp->stream, data->buf, rcvd)) {
    1983           0 :                         goto bail;
    1984             :                 }
    1985             : 
    1986           9 :                 ftp->lastch = lastch;
    1987           9 :                 return PHP_FTP_MOREDATA;
    1988             :         }
    1989             : 
    1990           1 :         if (type == FTPTYPE_ASCII && lastch == '\r') {
    1991           0 :                 php_stream_putc(ftp->stream, '\r');
    1992             :         }
    1993             : 
    1994           1 :         ftp->data = data = data_close(ftp, data);
    1995             : 
    1996           1 :         if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
    1997             :                 goto bail;
    1998             :         }
    1999             : 
    2000           1 :         ftp->nb = 0;
    2001           1 :         return PHP_FTP_FINISHED;
    2002             : bail:
    2003           0 :         ftp->nb = 0;
    2004           0 :         ftp->data = data_close(ftp, data);
    2005           0 :         return PHP_FTP_FAILED;
    2006             : }
    2007             : /* }}} */
    2008             : 
    2009             : /* {{{ ftp_nb_put
    2010             :  */
    2011             : int
    2012           0 : ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, zend_long startpos)
    2013             : {
    2014           0 :         databuf_t               *data = NULL;
    2015             :         char                    arg[11];
    2016             : 
    2017           0 :         if (ftp == NULL) {
    2018           0 :                 return 0;
    2019             :         }
    2020           0 :         if (!ftp_type(ftp, type)) {
    2021           0 :                 goto bail;
    2022             :         }
    2023           0 :         if ((data = ftp_getdata(ftp)) == NULL) {
    2024           0 :                 goto bail;
    2025             :         }
    2026           0 :         if (startpos > 0) {
    2027           0 :                 snprintf(arg, sizeof(arg), ZEND_LONG_FMT, startpos);
    2028           0 :                 if (!ftp_putcmd(ftp, "REST", arg)) {
    2029           0 :                         goto bail;
    2030             :                 }
    2031           0 :                 if (!ftp_getresp(ftp) || (ftp->resp != 350)) {
    2032             :                         goto bail;
    2033             :                 }
    2034             :         }
    2035             : 
    2036           0 :         if (!ftp_putcmd(ftp, "STOR", path)) {
    2037           0 :                 goto bail;
    2038             :         }
    2039           0 :         if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
    2040             :                 goto bail;
    2041             :         }
    2042           0 :         if ((data = data_accept(data, ftp)) == NULL) {
    2043           0 :                 goto bail;
    2044             :         }
    2045           0 :         ftp->data = data;
    2046           0 :         ftp->stream = instream;
    2047           0 :         ftp->lastch = 0;
    2048           0 :         ftp->nb = 1;
    2049             : 
    2050           0 :         return (ftp_nb_continue_write(ftp));
    2051             : 
    2052             : bail:
    2053           0 :         ftp->data = data_close(ftp, data);
    2054           0 :         return PHP_FTP_FAILED;
    2055             : }
    2056             : /* }}} */
    2057             : 
    2058             : 
    2059             : /* {{{ ftp_nb_continue_write
    2060             :  */
    2061             : int
    2062           0 : ftp_nb_continue_write(ftpbuf_t *ftp)
    2063             : {
    2064             :         long                    size;
    2065             :         char                    *ptr;
    2066             :         int                     ch;
    2067             : 
    2068             :         /* check if we can write more data */
    2069           0 :         if (!data_writeable(ftp, ftp->data->fd)) {
    2070           0 :                 return PHP_FTP_MOREDATA;
    2071             :         }
    2072             : 
    2073           0 :         size = 0;
    2074           0 :         ptr = ftp->data->buf;
    2075           0 :         while (!php_stream_eof(ftp->stream) && (ch = php_stream_getc(ftp->stream)) != EOF) {
    2076             : 
    2077           0 :                 if (ch == '\n' && ftp->type == FTPTYPE_ASCII) {
    2078           0 :                         *ptr++ = '\r';
    2079           0 :                         size++;
    2080             :                 }
    2081             : 
    2082           0 :                 *ptr++ = ch;
    2083           0 :                 size++;
    2084             : 
    2085             :                 /* flush if necessary */
    2086           0 :                 if (FTP_BUFSIZE - size < 2) {
    2087           0 :                         if (my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
    2088           0 :                                 goto bail;
    2089             :                         }
    2090           0 :                         return PHP_FTP_MOREDATA;
    2091             :                 }
    2092             :         }
    2093             : 
    2094           0 :         if (size && my_send(ftp, ftp->data->fd, ftp->data->buf, size) != size) {
    2095           0 :                 goto bail;
    2096             :         }
    2097           0 :         ftp->data = data_close(ftp, ftp->data);
    2098             : 
    2099           0 :         if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
    2100             :                 goto bail;
    2101             :         }
    2102           0 :         ftp->nb = 0;
    2103           0 :         return PHP_FTP_FINISHED;
    2104             : bail:
    2105           0 :         ftp->data = data_close(ftp, ftp->data);
    2106           0 :         ftp->nb = 0;
    2107           0 :         return PHP_FTP_FAILED;
    2108             : }
    2109             : /* }}} */
    2110             : 
    2111             : #endif /* HAVE_FTP */
    2112             : 
    2113             : /*
    2114             :  * Local variables:
    2115             :  * tab-width: 4
    2116             :  * c-basic-offset: 4
    2117             :  * End:
    2118             :  * vim600: sw=4 ts=4 fdm=marker
    2119             :  * vim<600: sw=4 ts=4
    2120             :  */

Generated by: LCOV version 1.10

Generated at Sun, 18 Sep 2016 08:20:05 +0000 (6 days ago)

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