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

Generated by: LCOV version 1.10

Generated at Tue, 25 Nov 2014 09:10:54 +0000 (3 days ago)

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