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: 475 832 57.1 %
Date: 2014-07-27 Functions: 36 43 83.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sun, 27 Jul 2014 12:58:28 +0000 (35 hours ago)

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