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/standard - ftp_fopen_wrapper.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 32 547 5.9 %
Date: 2014-07-21 Functions: 2 14 14.3 %
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: Rasmus Lerdorf <rasmus@php.net>                             |
      16             :    |          Jim Winstead <jimw@php.net>                                 |
      17             :    |          Hartmut Holzgraefe <hholzgra@php.net>                       |
      18             :    |          Sara Golemon <pollita@php.net>                              |
      19             :    +----------------------------------------------------------------------+
      20             :  */
      21             : /* $Id$ */
      22             : 
      23             : #include "php.h"
      24             : #include "php_globals.h"
      25             : #include "php_network.h"
      26             : #include "php_ini.h"
      27             : 
      28             : #include <stdio.h>
      29             : #include <stdlib.h>
      30             : #include <errno.h>
      31             : #include <sys/types.h>
      32             : #include <sys/stat.h>
      33             : #include <fcntl.h>
      34             : 
      35             : #ifdef PHP_WIN32
      36             : #include <winsock2.h>
      37             : #define O_RDONLY _O_RDONLY
      38             : #include "win32/param.h"
      39             : #else
      40             : #include <sys/param.h>
      41             : #endif
      42             : 
      43             : #include "php_standard.h"
      44             : 
      45             : #include <sys/types.h>
      46             : #if HAVE_SYS_SOCKET_H
      47             : #include <sys/socket.h>
      48             : #endif
      49             : 
      50             : #ifdef PHP_WIN32
      51             : #include <winsock2.h>
      52             : #elif defined(NETWARE) && defined(USE_WINSOCK)
      53             : #include <novsock2.h>
      54             : #else
      55             : #include <netinet/in.h>
      56             : #include <netdb.h>
      57             : #if HAVE_ARPA_INET_H
      58             : #include <arpa/inet.h>
      59             : #endif
      60             : #endif
      61             : 
      62             : #if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)
      63             : #undef AF_UNIX
      64             : #endif
      65             : 
      66             : #if defined(AF_UNIX)
      67             : #include <sys/un.h>
      68             : #endif
      69             : 
      70             : #include "php_fopen_wrappers.h"
      71             : 
      72             : #define FTPS_ENCRYPT_DATA 1
      73             : #define GET_FTP_RESULT(stream)  get_ftp_result((stream), tmp_line, sizeof(tmp_line) TSRMLS_CC)
      74             : 
      75             : typedef struct _php_ftp_dirstream_data {
      76             :         php_stream *datastream;
      77             :         php_stream *controlstream;
      78             :         php_stream *dirstream;
      79             : } php_ftp_dirstream_data;
      80             : 
      81             : /* {{{ get_ftp_result
      82             :  */
      83           0 : static inline int get_ftp_result(php_stream *stream, char *buffer, size_t buffer_size TSRMLS_DC)
      84             : {
      85           0 :         while (php_stream_gets(stream, buffer, buffer_size-1) &&
      86           0 :                    !(isdigit((int) buffer[0]) && isdigit((int) buffer[1]) &&
      87           0 :                          isdigit((int) buffer[2]) && buffer[3] == ' '));
      88           0 :         return strtol(buffer, NULL, 10);
      89             : }
      90             : /* }}} */
      91             : 
      92             : /* {{{ php_stream_ftp_stream_stat
      93             :  */
      94           0 : static int php_stream_ftp_stream_stat(php_stream_wrapper *wrapper, php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
      95             : {
      96             :         /* For now, we return with a failure code to prevent the underlying
      97             :          * file's details from being used instead. */
      98           0 :         return -1;
      99             : }
     100             : /* }}} */
     101             : 
     102             : /* {{{ php_stream_ftp_stream_close
     103             :  */
     104           0 : static int php_stream_ftp_stream_close(php_stream_wrapper *wrapper, php_stream *stream TSRMLS_DC)
     105             : {
     106           0 :         php_stream *controlstream = stream->wrapperthis;
     107           0 :         int ret = 0;
     108             :         
     109           0 :         if (controlstream) {
     110           0 :                 if (strpbrk(stream->mode, "wa+")) {
     111             :                         char tmp_line[512];
     112             :                         int result;
     113             : 
     114             :                         /* For write modes close data stream first to signal EOF to server */
     115           0 :                         result = GET_FTP_RESULT(controlstream);
     116           0 :                         if (result != 226 && result != 250) {
     117           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "FTP server error %d:%s", result, tmp_line);
     118           0 :                                 ret = EOF;
     119             :                         }
     120             :                 }
     121             : 
     122           0 :                 php_stream_write_string(controlstream, "QUIT\r\n");
     123           0 :                 php_stream_close(controlstream);
     124           0 :                 stream->wrapperthis = NULL;
     125             :         }
     126             : 
     127           0 :         return ret;
     128             : }
     129             : /* }}} */
     130             : 
     131             : /* {{{ php_ftp_fopen_connect
     132             :  */
     133           2 : static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char *path, const char *mode, int options,
     134             :                                                                                  char **opened_path, php_stream_context *context, php_stream **preuseid,
     135             :                                                                                  php_url **presource, int *puse_ssl, int *puse_ssl_on_data TSRMLS_DC)
     136             : {
     137           2 :         php_stream *stream = NULL, *reuseid = NULL;
     138           2 :         php_url *resource = NULL;
     139           2 :         int result, use_ssl, use_ssl_on_data = 0, tmp_len;
     140             :         char tmp_line[512];
     141             :         char *transport;
     142             :         int transport_len;
     143             : 
     144           2 :         resource = php_url_parse(path);
     145           2 :         if (resource == NULL || resource->path == NULL) {
     146           0 :                 if (resource && presource) {
     147           0 :                         *presource = resource;
     148             :                 }
     149           0 :                 return NULL;
     150             :         }
     151             : 
     152           2 :         use_ssl = resource->scheme && (strlen(resource->scheme) > 3) && resource->scheme[3] == 's';
     153             : 
     154             :         /* use port 21 if one wasn't specified */
     155           2 :         if (resource->port == 0)
     156           2 :                 resource->port = 21;
     157             :         
     158           2 :         transport_len = spprintf(&transport, 0, "tcp://%s:%d", resource->host, resource->port);
     159           2 :         stream = php_stream_xport_create(transport, transport_len, REPORT_ERRORS, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, NULL, NULL, context, NULL, NULL);
     160           2 :         efree(transport);
     161           2 :         if (stream == NULL) {
     162           2 :                 result = 0; /* silence */
     163           2 :                 goto connect_errexit;
     164             :         }
     165             : 
     166           0 :         php_stream_context_set(stream, context TSRMLS_CC);
     167           0 :         php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0);
     168             : 
     169             :         /* Start talking to ftp server */
     170           0 :         result = GET_FTP_RESULT(stream);
     171           0 :         if (result > 299 || result < 200) {
     172           0 :                 php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
     173           0 :                 goto connect_errexit;
     174             :         }
     175             : 
     176           0 :         if (use_ssl)    {
     177             :         
     178             :                 /* send the AUTH TLS request name */
     179           0 :                 php_stream_write_string(stream, "AUTH TLS\r\n");
     180             : 
     181             :                 /* get the response */
     182           0 :                 result = GET_FTP_RESULT(stream);
     183           0 :                 if (result != 234) {
     184             :                         /* AUTH TLS not supported try AUTH SSL */
     185           0 :                         php_stream_write_string(stream, "AUTH SSL\r\n");
     186             :                         
     187             :                         /* get the response */
     188           0 :                         result = GET_FTP_RESULT(stream);
     189           0 :                         if (result != 334) {
     190           0 :                                 use_ssl = 0;
     191             :                         } else {
     192             :                                 /* we must reuse the old SSL session id */
     193             :                                 /* if we talk to an old ftpd-ssl */
     194           0 :                                 reuseid = stream;
     195             :                         }
     196             :                 } else {
     197             :                         /* encrypt data etc */
     198             : 
     199             : 
     200             :                 }
     201             : 
     202             :         }
     203             :         
     204           0 :         if (use_ssl) {
     205           0 :                 if (php_stream_xport_crypto_setup(stream,
     206             :                                 STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0
     207           0 :                                 || php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) {
     208           0 :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unable to activate SSL mode");
     209           0 :                         php_stream_close(stream);
     210           0 :                         stream = NULL;
     211           0 :                         goto connect_errexit;
     212             :                 }
     213             :         
     214             :                 /* set PBSZ to 0 */
     215           0 :                 php_stream_write_string(stream, "PBSZ 0\r\n");
     216             : 
     217             :                 /* ignore the response */
     218           0 :                 result = GET_FTP_RESULT(stream);
     219             :                 
     220             :                 /* set data connection protection level */
     221             : #if FTPS_ENCRYPT_DATA
     222           0 :                 php_stream_write_string(stream, "PROT P\r\n");
     223             : 
     224             :                 /* get the response */
     225           0 :                 result = GET_FTP_RESULT(stream);
     226           0 :                 use_ssl_on_data = (result >= 200 && result<=299) || reuseid;
     227             : #else
     228             :                 php_stream_write_string(stream, "PROT C\r\n");
     229             : 
     230             :                 /* get the response */
     231             :                 result = GET_FTP_RESULT(stream);
     232             : #endif
     233             :         }
     234             : 
     235             : #define PHP_FTP_CNTRL_CHK(val, val_len, err_msg) {      \
     236             :         unsigned char *s = val, *e = s + val_len;       \
     237             :         while (s < e) {      \
     238             :                 if (iscntrl(*s)) {      \
     239             :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, err_msg, val); \
     240             :                         goto connect_errexit;   \
     241             :                 }       \
     242             :                 s++;    \
     243             :         }       \
     244             : } 
     245             : 
     246             :         /* send the user name */
     247           0 :         if (resource->user != NULL) {
     248           0 :                 tmp_len = php_raw_url_decode(resource->user, strlen(resource->user));
     249             : 
     250           0 :                 PHP_FTP_CNTRL_CHK(resource->user, tmp_len, "Invalid login %s")
     251             : 
     252           0 :                 php_stream_printf(stream TSRMLS_CC, "USER %s\r\n", resource->user);
     253             :         } else {
     254           0 :                 php_stream_write_string(stream, "USER anonymous\r\n");
     255             :         }
     256             :         
     257             :         /* get the response */
     258           0 :         result = GET_FTP_RESULT(stream);
     259             :         
     260             :         /* if a password is required, send it */
     261           0 :         if (result >= 300 && result <= 399) {
     262           0 :                 php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, tmp_line, 0);
     263             : 
     264           0 :                 if (resource->pass != NULL) {
     265           0 :                         tmp_len = php_raw_url_decode(resource->pass, strlen(resource->pass));
     266             : 
     267           0 :                         PHP_FTP_CNTRL_CHK(resource->pass, tmp_len, "Invalid password %s")
     268             : 
     269           0 :                         php_stream_printf(stream TSRMLS_CC, "PASS %s\r\n", resource->pass);
     270             :                 } else {
     271             :                         /* if the user has configured who they are,
     272             :                            send that as the password */
     273           0 :                         if (FG(from_address)) {
     274           0 :                                 php_stream_printf(stream TSRMLS_CC, "PASS %s\r\n", FG(from_address));
     275             :                         } else {
     276           0 :                                 php_stream_write_string(stream, "PASS anonymous\r\n");
     277             :                         }
     278             :                 }
     279             : 
     280             :                 /* read the response */
     281           0 :                 result = GET_FTP_RESULT(stream);
     282             : 
     283           0 :                 if (result > 299 || result < 200) {
     284           0 :                         php_stream_notify_error(context, PHP_STREAM_NOTIFY_AUTH_RESULT, tmp_line, result);
     285             :                 } else {
     286           0 :                         php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_RESULT, tmp_line, result);
     287             :                 }
     288             :         }
     289           0 :         if (result > 299 || result < 200) {
     290             :                 goto connect_errexit;
     291             :         }
     292             : 
     293           0 :         if (puse_ssl) {
     294           0 :                 *puse_ssl = use_ssl;
     295             :         }
     296           0 :         if (puse_ssl_on_data) {
     297           0 :                 *puse_ssl_on_data = use_ssl_on_data;
     298             :         }
     299           0 :         if (preuseid) {
     300           0 :                 *preuseid = reuseid;
     301             :         }
     302           0 :         if (presource) {
     303           0 :                 *presource = resource;
     304             :         }
     305             : 
     306           0 :         return stream;
     307             : 
     308             : connect_errexit:
     309           2 :         if (resource) {
     310           2 :                 php_url_free(resource); 
     311             :         }
     312             : 
     313           2 :         if (stream) {
     314           0 :                 php_stream_close(stream);
     315             :         }
     316             : 
     317           2 :         return NULL;
     318             : }
     319             : /* }}} */
     320             : 
     321             : /* {{{ php_fopen_do_pasv
     322             :  */
     323           0 : static unsigned short php_fopen_do_pasv(php_stream *stream, char *ip, size_t ip_size, char **phoststart TSRMLS_DC)
     324             : {
     325             :         char tmp_line[512];
     326             :         int result, i;
     327             :         unsigned short portno;
     328           0 :         char *tpath, *ttpath, *hoststart=NULL;
     329             : 
     330             : #ifdef HAVE_IPV6
     331             :         /* We try EPSV first, needed for IPv6 and works on some IPv4 servers */
     332           0 :         php_stream_write_string(stream, "EPSV\r\n");
     333           0 :         result = GET_FTP_RESULT(stream);
     334             : 
     335             :         /* check if we got a 229 response */
     336           0 :         if (result != 229) {
     337             : #endif
     338             :                 /* EPSV failed, let's try PASV */
     339           0 :                 php_stream_write_string(stream, "PASV\r\n");
     340           0 :                 result = GET_FTP_RESULT(stream);
     341             :                 
     342             :                 /* make sure we got a 227 response */
     343           0 :                 if (result != 227) {
     344           0 :                         return 0;
     345             :                 }
     346             : 
     347             :                 /* parse pasv command (129, 80, 95, 25, 13, 221) */
     348           0 :                 tpath = tmp_line;
     349             :                 /* skip over the "227 Some message " part */
     350           0 :                 for (tpath += 4; *tpath && !isdigit((int) *tpath); tpath++);
     351           0 :                 if (!*tpath) {
     352           0 :                         return 0;
     353             :                 }
     354             :                 /* skip over the host ip, to get the port */
     355           0 :                 hoststart = tpath;
     356           0 :                 for (i = 0; i < 4; i++) {
     357           0 :                         for (; isdigit((int) *tpath); tpath++);
     358           0 :                         if (*tpath != ',') {
     359           0 :                                 return 0;
     360             :                         }
     361           0 :                         *tpath='.';     
     362           0 :                         tpath++;
     363             :                 }
     364           0 :                 tpath[-1] = '\0';
     365           0 :                 memcpy(ip, hoststart, ip_size);
     366           0 :                 ip[ip_size-1] = '\0';
     367           0 :                 hoststart = ip;
     368             :                 
     369             :                 /* pull out the MSB of the port */
     370           0 :                 portno = (unsigned short) strtoul(tpath, &ttpath, 10) * 256;
     371           0 :                 if (ttpath == NULL) {
     372             :                         /* didn't get correct response from PASV */
     373           0 :                         return 0;
     374             :                 }
     375           0 :                 tpath = ttpath;
     376           0 :                 if (*tpath != ',') {
     377           0 :                         return 0;
     378             :                 }
     379           0 :                 tpath++;
     380             :                 /* pull out the LSB of the port */
     381           0 :                 portno += (unsigned short) strtoul(tpath, &ttpath, 10);
     382             : #ifdef HAVE_IPV6
     383             :         } else {
     384             :                 /* parse epsv command (|||6446|) */
     385           0 :                 for (i = 0, tpath = tmp_line + 4; *tpath; tpath++) {
     386           0 :                         if (*tpath == '|') {
     387           0 :                                 i++;
     388           0 :                                 if (i == 3)
     389           0 :                                         break;
     390             :                         }
     391             :                 }
     392           0 :                 if (i < 3) {
     393           0 :                         return 0;
     394             :                 }
     395             :                 /* pull out the port */
     396           0 :                 portno = (unsigned short) strtoul(tpath + 1, &ttpath, 10);
     397             :         }
     398             : #endif  
     399           0 :         if (ttpath == NULL) {
     400             :                 /* didn't get correct response from EPSV/PASV */
     401           0 :                 return 0;
     402             :         }
     403             : 
     404           0 :         if (phoststart) {
     405           0 :                 *phoststart = hoststart;
     406             :         }       
     407             : 
     408           0 :         return portno;
     409             : }
     410             : /* }}} */
     411             : 
     412             : /* {{{ php_fopen_url_wrap_ftp
     413             :  */
     414           0 : php_stream * php_stream_url_wrap_ftp(php_stream_wrapper *wrapper, const char *path, const char *mode,
     415             :                                                                          int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
     416             : {
     417           0 :         php_stream *stream = NULL, *datastream = NULL;
     418           0 :         php_url *resource = NULL;
     419             :         char tmp_line[512];
     420             :         char ip[sizeof("123.123.123.123")];
     421             :         unsigned short portno;
     422           0 :         char *hoststart = NULL;
     423           0 :         int result = 0, use_ssl, use_ssl_on_data=0;
     424           0 :         php_stream *reuseid=NULL;
     425           0 :         size_t file_size = 0;
     426             :         zval **tmpzval;
     427           0 :         int allow_overwrite = 0;
     428           0 :         int read_write = 0;
     429             :         char *transport;
     430             :         int transport_len;
     431             : 
     432           0 :         tmp_line[0] = '\0';
     433             : 
     434           0 :         if (strpbrk(mode, "r+")) {
     435           0 :                 read_write = 1; /* Open for reading */
     436             :         }
     437           0 :         if (strpbrk(mode, "wa+")) {
     438           0 :                 if (read_write) {
     439           0 :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "FTP does not support simultaneous read/write connections");
     440           0 :                         return NULL;
     441             :                 }
     442           0 :                 if (strchr(mode, 'a')) {
     443           0 :                         read_write = 3; /* Open for Appending */
     444             :                 } else {
     445           0 :                         read_write = 2; /* Open for writing */
     446             :                 }
     447             :         }
     448           0 :         if (!read_write) {
     449             :                 /* No mode specified? */
     450           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unknown file open mode");
     451           0 :                 return NULL;
     452             :         }
     453             : 
     454           0 :         if (context &&
     455           0 :                 php_stream_context_get_option(context, "ftp", "proxy", &tmpzval) == SUCCESS) {
     456           0 :                 if (read_write == 1) {
     457             :                         /* Use http wrapper to proxy ftp request */
     458           0 :                         return php_stream_url_wrap_http(wrapper, path, mode, options, opened_path, context STREAMS_CC TSRMLS_CC);
     459             :                 } else {
     460             :                         /* ftp proxy is read-only */
     461           0 :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "FTP proxy may only be used in read mode");
     462           0 :                         return NULL;
     463             :                 }
     464             :         }
     465             : 
     466           0 :         stream = php_ftp_fopen_connect(wrapper, path, mode, options, opened_path, context, &reuseid, &resource, &use_ssl, &use_ssl_on_data TSRMLS_CC);
     467           0 :         if (!stream) {
     468           0 :                 goto errexit;
     469             :         }
     470             : 
     471             :         /* set the connection to be binary */
     472           0 :         php_stream_write_string(stream, "TYPE I\r\n");
     473           0 :         result = GET_FTP_RESULT(stream);
     474           0 :         if (result > 299 || result < 200)
     475             :                 goto errexit;
     476             :         
     477             :         /* find out the size of the file (verifying it exists) */
     478           0 :         php_stream_printf(stream TSRMLS_CC, "SIZE %s\r\n", resource->path);
     479             :         
     480             :         /* read the response */
     481           0 :         result = GET_FTP_RESULT(stream);
     482           0 :         if (read_write == 1) {
     483             :                 /* Read Mode */
     484             :                 char *sizestr;
     485             :                 
     486             :                 /* when reading file, it must exist */
     487           0 :                 if (result > 299 || result < 200) {
     488           0 :                         errno = ENOENT;
     489           0 :                         goto errexit;
     490             :                 }
     491             :                 
     492           0 :                 sizestr = strchr(tmp_line, ' ');
     493           0 :                 if (sizestr) {
     494           0 :                         sizestr++;
     495           0 :                         file_size = atoi(sizestr);
     496           0 :                         php_stream_notify_file_size(context, file_size, tmp_line, result);
     497             :                 }       
     498           0 :         } else if (read_write == 2) {
     499             :                 /* when writing file (but not appending), it must NOT exist, unless a context option exists which allows it */
     500           0 :                 if (context && php_stream_context_get_option(context, "ftp", "overwrite", &tmpzval) == SUCCESS) {
     501           0 :                         allow_overwrite = Z_LVAL_PP(tmpzval);
     502             :                 }
     503           0 :                 if (result <= 299 && result >= 200) {
     504           0 :                         if (allow_overwrite) {
     505             :                                 /* Context permits overwriting file, 
     506             :                                    so we just delete whatever's there in preparation */
     507           0 :                                 php_stream_printf(stream TSRMLS_CC, "DELE %s\r\n", resource->path);
     508           0 :                                 result = GET_FTP_RESULT(stream);
     509           0 :                                 if (result >= 300 || result <= 199) {
     510             :                                         goto errexit;
     511             :                                 }
     512             :                         } else {
     513           0 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Remote file already exists and overwrite context option not specified");
     514           0 :                                 errno = EEXIST;
     515           0 :                                 goto errexit;
     516             :                         }
     517             :                 }
     518             :         }
     519             : 
     520             :         /* set up the passive connection */
     521           0 :         portno = php_fopen_do_pasv(stream, ip, sizeof(ip), &hoststart TSRMLS_CC);
     522             : 
     523           0 :         if (!portno) {
     524           0 :                 goto errexit;
     525             :         }
     526             : 
     527             :         /* Send RETR/STOR command */
     528           0 :         if (read_write == 1) {
     529             :                 /* set resume position if applicable */
     530           0 :                 if (context &&
     531           0 :                         php_stream_context_get_option(context, "ftp", "resume_pos", &tmpzval) == SUCCESS &&
     532           0 :                         Z_TYPE_PP(tmpzval) == IS_LONG &&
     533           0 :                         Z_LVAL_PP(tmpzval) > 0) {
     534           0 :                         php_stream_printf(stream TSRMLS_CC, "REST %ld\r\n", Z_LVAL_PP(tmpzval));
     535           0 :                         result = GET_FTP_RESULT(stream);
     536           0 :                         if (result < 300 || result > 399) {                       
     537           0 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unable to resume from offset %ld", Z_LVAL_PP(tmpzval));
     538           0 :                                 goto errexit;
     539             :                         }
     540             :                 }
     541             : 
     542             :                 /* retrieve file */
     543           0 :                 memcpy(tmp_line, "RETR", sizeof("RETR"));
     544           0 :         } else if (read_write == 2) {
     545             :                 /* Write new file */
     546           0 :                 memcpy(tmp_line, "STOR", sizeof("STOR"));
     547             :         } else {
     548             :                 /* Append */
     549           0 :                 memcpy(tmp_line, "APPE", sizeof("APPE"));
     550             :         } 
     551           0 :         php_stream_printf(stream TSRMLS_CC, "%s %s\r\n", tmp_line, (resource->path != NULL ? resource->path : "/"));
     552             :         
     553             :         /* open the data channel */
     554           0 :         if (hoststart == NULL) {
     555           0 :                 hoststart = resource->host;
     556             :         }
     557           0 :         transport_len = spprintf(&transport, 0, "tcp://%s:%d", hoststart, portno);
     558           0 :         datastream = php_stream_xport_create(transport, transport_len, REPORT_ERRORS, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, NULL, NULL, context, NULL, NULL);
     559           0 :         efree(transport);
     560           0 :         if (datastream == NULL) {
     561           0 :                 goto errexit;
     562             :         }
     563             : 
     564           0 :         result = GET_FTP_RESULT(stream);
     565           0 :         if (result != 150 && result != 125) {
     566             :                 /* Could not retrieve or send the file 
     567             :                  * this data will only be sent to us after connection on the data port was initiated.
     568             :                  */
     569           0 :                 php_stream_close(datastream);
     570           0 :                 datastream = NULL;
     571           0 :                 goto errexit;   
     572             :         }
     573             :         
     574           0 :         php_stream_context_set(datastream, context TSRMLS_CC);
     575           0 :         php_stream_notify_progress_init(context, 0, file_size);
     576             : 
     577           0 :         if (use_ssl_on_data && (php_stream_xport_crypto_setup(datastream,
     578           0 :                         STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0 ||
     579           0 :                         php_stream_xport_crypto_enable(datastream, 1 TSRMLS_CC) < 0)) {
     580             : 
     581           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unable to activate SSL mode");
     582           0 :                 php_stream_close(datastream);
     583           0 :                 datastream = NULL;
     584           0 :                 goto errexit;
     585             :         }
     586             : 
     587             :         /* remember control stream */   
     588           0 :         datastream->wrapperthis = stream;
     589             : 
     590           0 :         php_url_free(resource);
     591           0 :         return datastream;
     592             : 
     593             : errexit:
     594           0 :         if (resource) {
     595           0 :                 php_url_free(resource);
     596             :         }
     597           0 :         if (stream) {
     598           0 :                 php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
     599           0 :                 php_stream_close(stream);
     600             :         }
     601           0 :         if (tmp_line[0] != '\0')
     602           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "FTP server reports %s", tmp_line);
     603           0 :         return NULL;
     604             : }
     605             : /* }}} */
     606             : 
     607             : /* {{{ php_ftp_dirsteam_read
     608             :  */
     609           0 : static size_t php_ftp_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
     610             : {
     611           0 :         php_stream_dirent *ent = (php_stream_dirent *)buf;
     612             :         php_stream *innerstream;
     613             :         size_t tmp_len;
     614             :         char *basename;
     615             :         size_t basename_len;
     616             : 
     617           0 :         innerstream =  ((php_ftp_dirstream_data *)stream->abstract)->datastream;
     618             : 
     619           0 :         if (count != sizeof(php_stream_dirent)) {
     620           0 :                 return 0;
     621             :         }
     622             : 
     623           0 :         if (php_stream_eof(innerstream)) {
     624           0 :                 return 0;
     625             :         }
     626             : 
     627           0 :         if (!php_stream_get_line(innerstream, ent->d_name, sizeof(ent->d_name), &tmp_len)) {
     628           0 :                 return 0;
     629             :         }
     630             : 
     631           0 :         php_basename(ent->d_name, tmp_len, NULL, 0, &basename, &basename_len TSRMLS_CC);
     632           0 :         if (!basename) {
     633           0 :                 return 0;
     634             :         }
     635             : 
     636           0 :         if (!basename_len) {
     637           0 :                 efree(basename);
     638           0 :                 return 0;
     639             :         }
     640             : 
     641           0 :         tmp_len = MIN(sizeof(ent->d_name), basename_len - 1);
     642           0 :         memcpy(ent->d_name, basename, tmp_len);
     643           0 :         ent->d_name[tmp_len - 1] = '\0';
     644           0 :         efree(basename);
     645             : 
     646             :         /* Trim off trailing whitespace characters */
     647           0 :         tmp_len--;
     648           0 :         while (tmp_len >= 0 &&
     649           0 :                         (ent->d_name[tmp_len] == '\n' || ent->d_name[tmp_len] == '\r' ||
     650           0 :                          ent->d_name[tmp_len] == '\t' || ent->d_name[tmp_len] == ' ')) {
     651           0 :                 ent->d_name[tmp_len--] = '\0';
     652             :         }
     653             : 
     654           0 :         return sizeof(php_stream_dirent);
     655             : }
     656             : /* }}} */
     657             : 
     658             : /* {{{ php_ftp_dirstream_close
     659             :  */
     660           0 : static int php_ftp_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC)
     661             : {
     662           0 :         php_ftp_dirstream_data *data = stream->abstract;
     663             : 
     664             :         /* close control connection */
     665           0 :         if (data->controlstream) {
     666           0 :                 php_stream_close(data->controlstream);
     667           0 :                 data->controlstream = NULL;
     668             :         }
     669             :         /* close data connection */
     670           0 :         php_stream_close(data->datastream);
     671           0 :         data->datastream = NULL;
     672             :         
     673           0 :         efree(data);
     674           0 :         stream->abstract = NULL;
     675             : 
     676           0 :         return 0;
     677             : }
     678             : /* }}} */
     679             : 
     680             : /* ftp dirstreams only need to support read and close operations,
     681             :    They can't be rewound because the underlying ftp stream can't be rewound. */
     682             : static php_stream_ops php_ftp_dirstream_ops = {
     683             :         NULL, /* write */
     684             :         php_ftp_dirstream_read, /* read */
     685             :         php_ftp_dirstream_close, /* close */
     686             :         NULL, /* flush */
     687             :         "ftpdir",
     688             :         NULL, /* rewind */
     689             :         NULL, /* cast */
     690             :         NULL, /* stat */
     691             :         NULL  /* set option */
     692             : };
     693             : 
     694             : /* {{{ php_stream_ftp_opendir
     695             :  */
     696           2 : php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const char *path, const char *mode, int options,
     697             :                                                                         char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
     698             : {
     699           2 :         php_stream *stream, *reuseid, *datastream = NULL;
     700             :         php_ftp_dirstream_data *dirsdata;
     701           2 :         php_url *resource = NULL;
     702           2 :         int result = 0, use_ssl, use_ssl_on_data = 0;
     703           2 :         char *hoststart = NULL, tmp_line[512];
     704             :         char ip[sizeof("123.123.123.123")];
     705             :         unsigned short portno;
     706             : 
     707           2 :         tmp_line[0] = '\0';
     708             : 
     709           2 :         stream = php_ftp_fopen_connect(wrapper, path, mode, options, opened_path, context, &reuseid, &resource, &use_ssl, &use_ssl_on_data TSRMLS_CC);
     710           2 :         if (!stream) {
     711           2 :                 goto opendir_errexit;   
     712             :         }
     713             : 
     714             :         /* set the connection to be ascii */
     715           0 :         php_stream_write_string(stream, "TYPE A\r\n");
     716           0 :         result = GET_FTP_RESULT(stream);
     717           0 :         if (result > 299 || result < 200)
     718             :                 goto opendir_errexit;
     719             : 
     720             :         /* set up the passive connection */
     721           0 :         portno = php_fopen_do_pasv(stream, ip, sizeof(ip), &hoststart TSRMLS_CC);
     722             : 
     723           0 :         if (!portno) {
     724           0 :                 goto opendir_errexit;
     725             :         }
     726             : 
     727           0 :         php_stream_printf(stream TSRMLS_CC, "NLST %s\r\n", (resource->path != NULL ? resource->path : "/"));
     728             :         
     729             :         /* open the data channel */
     730           0 :         if (hoststart == NULL) {
     731           0 :                 hoststart = resource->host;
     732             :         }
     733           0 :         datastream = php_stream_sock_open_host(hoststart, portno, SOCK_STREAM, 0, 0);
     734           0 :         if (datastream == NULL) {
     735           0 :                 goto opendir_errexit;
     736             :         }
     737             : 
     738           0 :         result = GET_FTP_RESULT(stream);
     739           0 :         if (result != 150 && result != 125) {
     740             :                 /* Could not retrieve or send the file 
     741             :                  * this data will only be sent to us after connection on the data port was initiated.
     742             :                  */
     743           0 :                 php_stream_close(datastream);
     744           0 :                 datastream = NULL;
     745           0 :                 goto opendir_errexit;   
     746             :         }
     747             :         
     748           0 :         php_stream_context_set(datastream, context TSRMLS_CC);
     749             : 
     750           0 :         if (use_ssl_on_data && (php_stream_xport_crypto_setup(stream,
     751           0 :                         STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0 ||
     752           0 :                         php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0)) {
     753             : 
     754           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unable to activate SSL mode");
     755           0 :                 php_stream_close(datastream);
     756           0 :                 datastream = NULL;
     757           0 :                 goto opendir_errexit;
     758             :         }
     759             : 
     760           0 :         php_url_free(resource);
     761             : 
     762           0 :         dirsdata = emalloc(sizeof *dirsdata);
     763           0 :         dirsdata->datastream = datastream;
     764           0 :         dirsdata->controlstream = stream;
     765           0 :         dirsdata->dirstream = php_stream_alloc(&php_ftp_dirstream_ops, dirsdata, 0, mode);
     766             : 
     767           0 :         return dirsdata->dirstream;
     768             : 
     769             : opendir_errexit:
     770           2 :         if (resource) {
     771           0 :                 php_url_free(resource);
     772             :         }
     773           2 :         if (stream) {
     774           0 :                 php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
     775           0 :                 php_stream_close(stream);
     776             :         }
     777           2 :         if (tmp_line[0] != '\0') {
     778           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "FTP server reports %s", tmp_line);
     779             :         }
     780           2 :         return NULL;
     781             : }
     782             : /* }}} */
     783             : 
     784             : /* {{{ php_stream_ftp_url_stat
     785             :  */
     786           0 : static int php_stream_ftp_url_stat(php_stream_wrapper *wrapper, const char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
     787             : {
     788           0 :         php_stream *stream = NULL;
     789           0 :         php_url *resource = NULL;
     790             :         int result;
     791             :         char tmp_line[512];
     792             : 
     793             :         /* If ssb is NULL then someone is misbehaving */
     794           0 :         if (!ssb) return -1;
     795             : 
     796           0 :         stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, context, NULL, &resource, NULL, NULL TSRMLS_CC);
     797           0 :         if (!stream) {
     798           0 :                 goto stat_errexit;
     799             :         }
     800             : 
     801           0 :         ssb->sb.st_mode = 0644;                                                                      /* FTP won't give us a valid mode, so aproximate one based on being readable */
     802           0 :         php_stream_printf(stream TSRMLS_CC, "CWD %s\r\n", (resource->path != NULL ? resource->path : "/")); /* If we can CWD to it, it's a directory (maybe a link, but we can't tell) */
     803           0 :         result = GET_FTP_RESULT(stream);
     804           0 :         if (result < 200 || result > 299) {
     805           0 :                 ssb->sb.st_mode |= S_IFREG;
     806             :         } else {
     807           0 :                 ssb->sb.st_mode |= S_IFDIR;
     808             :         }
     809             : 
     810           0 :         php_stream_write_string(stream, "TYPE I\r\n"); /* we need this since some servers refuse to accept SIZE command in ASCII mode */
     811             :         
     812           0 :         result = GET_FTP_RESULT(stream);
     813             : 
     814           0 :         if(result < 200 || result > 299) {
     815             :                 goto stat_errexit;
     816             :         }
     817             :         
     818           0 :         php_stream_printf(stream TSRMLS_CC, "SIZE %s\r\n", (resource->path != NULL ? resource->path : "/"));
     819           0 :         result = GET_FTP_RESULT(stream);
     820           0 :         if (result < 200 || result > 299) {
     821             :                 /* Failure either means it doesn't exist 
     822             :                    or it's a directory and this server
     823             :                    fails on listing directory sizes */
     824           0 :                 if (ssb->sb.st_mode & S_IFDIR) {
     825           0 :                         ssb->sb.st_size = 0;
     826             :                 } else {
     827           0 :                         goto stat_errexit;
     828             :                 }
     829             :         } else {
     830           0 :                 ssb->sb.st_size = atoi(tmp_line + 4);
     831             :         }
     832             : 
     833           0 :         php_stream_printf(stream TSRMLS_CC, "MDTM %s\r\n", (resource->path != NULL ? resource->path : "/"));
     834           0 :         result = GET_FTP_RESULT(stream);
     835           0 :         if (result == 213) {
     836           0 :                 char *p = tmp_line + 4;
     837             :                 int n;
     838             :                 struct tm tm, tmbuf, *gmt;
     839             :                 time_t stamp;
     840             : 
     841           0 :                 while (p - tmp_line < sizeof(tmp_line) && !isdigit(*p)) {
     842           0 :                         p++;
     843             :                 }
     844             : 
     845           0 :                 if (p - tmp_line > sizeof(tmp_line)) {
     846           0 :                         goto mdtm_error;
     847             :                 }
     848             : 
     849           0 :                 n = sscanf(p, "%4u%2u%2u%2u%2u%2u", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
     850           0 :                 if (n != 6) {
     851           0 :                         goto mdtm_error;
     852             :                 }
     853             : 
     854           0 :                 tm.tm_year -= 1900;
     855           0 :                 tm.tm_mon--;
     856           0 :                 tm.tm_isdst = -1;
     857             : 
     858             :                 /* figure out the GMT offset */
     859           0 :                 stamp = time(NULL);
     860           0 :                 gmt = php_gmtime_r(&stamp, &tmbuf);
     861           0 :                 if (!gmt) {
     862           0 :                         goto mdtm_error;
     863             :                 }
     864           0 :                 gmt->tm_isdst = -1;
     865             : 
     866             :                 /* apply the GMT offset */
     867           0 :                 tm.tm_sec += stamp - mktime(gmt);
     868           0 :                 tm.tm_isdst = gmt->tm_isdst;
     869             : 
     870           0 :                 ssb->sb.st_mtime = mktime(&tm);
     871             :         } else {
     872             :                 /* error or unsupported command */
     873             : mdtm_error:
     874           0 :                 ssb->sb.st_mtime = -1;
     875             :         }
     876             : 
     877           0 :         ssb->sb.st_ino = 0;                                          /* Unknown values */
     878           0 :         ssb->sb.st_dev = 0;
     879           0 :         ssb->sb.st_uid = 0;
     880           0 :         ssb->sb.st_gid = 0;
     881           0 :         ssb->sb.st_atime = -1;
     882           0 :         ssb->sb.st_ctime = -1;
     883             : 
     884           0 :         ssb->sb.st_nlink = 1;
     885           0 :         ssb->sb.st_rdev = -1;
     886             : #ifdef HAVE_ST_BLKSIZE
     887           0 :         ssb->sb.st_blksize = 4096;                           /* Guess since FTP won't expose this information */
     888             : #ifdef HAVE_ST_BLOCKS
     889           0 :         ssb->sb.st_blocks = (int)((4095 + ssb->sb.st_size) / ssb->sb.st_blksize); /* emulate ceil */
     890             : #endif
     891             : #endif
     892           0 :         php_stream_close(stream);
     893           0 :         php_url_free(resource);
     894           0 :         return 0;
     895             : 
     896             : stat_errexit:
     897           0 :         if (resource) {
     898           0 :                 php_url_free(resource);
     899             :         }
     900           0 :         if (stream) {
     901           0 :                 php_stream_close(stream);
     902             :         }
     903           0 :         return -1;
     904             : }
     905             : /* }}} */
     906             : 
     907             : /* {{{ php_stream_ftp_unlink
     908             :  */
     909           0 : static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context TSRMLS_DC)
     910             : {
     911           0 :         php_stream *stream = NULL;
     912           0 :         php_url *resource = NULL;
     913             :         int result;
     914             :         char tmp_line[512];
     915             : 
     916           0 :         stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, NULL, NULL, &resource, NULL, NULL TSRMLS_CC);
     917           0 :         if (!stream) {
     918           0 :                 if (options & REPORT_ERRORS) {
     919           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", url);
     920             :                 }
     921           0 :                 goto unlink_errexit;
     922             :         }
     923             : 
     924           0 :         if (resource->path == NULL) {
     925           0 :                 if (options & REPORT_ERRORS) {
     926           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path provided in %s", url);
     927             :                 }
     928           0 :                 goto unlink_errexit;
     929             :         }
     930             : 
     931             :         /* Attempt to delete the file */
     932           0 :         php_stream_printf(stream TSRMLS_CC, "DELE %s\r\n", (resource->path != NULL ? resource->path : "/"));
     933             : 
     934           0 :         result = GET_FTP_RESULT(stream);
     935           0 :         if (result < 200 || result > 299) {
     936           0 :                 if (options & REPORT_ERRORS) {
     937           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error Deleting file: %s", tmp_line);
     938             :                 }
     939           0 :                 goto unlink_errexit;
     940             :         }
     941             : 
     942           0 :         php_url_free(resource);
     943           0 :         php_stream_close(stream);
     944           0 :         return 1;
     945             : 
     946             : unlink_errexit:
     947           0 :         if (resource) {
     948           0 :                 php_url_free(resource);
     949             :         }
     950           0 :         if (stream) {
     951           0 :                 php_stream_close(stream);
     952             :         }
     953           0 :         return 0;
     954             : }
     955             : /* }}} */
     956             : 
     957             : /* {{{ php_stream_ftp_rename
     958             :  */
     959           0 : static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to, int options, php_stream_context *context TSRMLS_DC)
     960             : {
     961           0 :         php_stream *stream = NULL;
     962           0 :         php_url *resource_from = NULL, *resource_to = NULL;
     963             :         int result;
     964             :         char tmp_line[512];
     965             : 
     966           0 :         resource_from = php_url_parse(url_from);
     967           0 :         resource_to = php_url_parse(url_to);
     968             :         /* Must be same scheme (ftp/ftp or ftps/ftps), same host, and same port 
     969             :                 (or a 21/0 0/21 combination which is also "same") 
     970             :            Also require paths to/from */
     971           0 :         if (!resource_from ||
     972             :                 !resource_to ||
     973           0 :                 !resource_from->scheme ||
     974           0 :                 !resource_to->scheme ||
     975           0 :                 strcmp(resource_from->scheme, resource_to->scheme) ||
     976           0 :                 !resource_from->host ||
     977           0 :                 !resource_to->host ||
     978           0 :                 strcmp(resource_from->host, resource_to->host) ||
     979           0 :                 (resource_from->port != resource_to->port && 
     980           0 :                  resource_from->port * resource_to->port != 0 && 
     981           0 :                  resource_from->port + resource_to->port != 21) ||
     982           0 :                 !resource_from->path ||
     983           0 :                 !resource_to->path) {
     984             :                 goto rename_errexit;
     985             :         }
     986             : 
     987           0 :         stream = php_ftp_fopen_connect(wrapper, url_from, "r", 0, NULL, NULL, NULL, NULL, NULL, NULL TSRMLS_CC);
     988           0 :         if (!stream) {
     989           0 :                 if (options & REPORT_ERRORS) {
     990           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", resource_from->host);
     991             :                 }
     992           0 :                 goto rename_errexit;
     993             :         }
     994             : 
     995             :         /* Rename FROM */
     996           0 :         php_stream_printf(stream TSRMLS_CC, "RNFR %s\r\n", (resource_from->path != NULL ? resource_from->path : "/"));
     997             : 
     998           0 :         result = GET_FTP_RESULT(stream);
     999           0 :         if (result < 300 || result > 399) {
    1000           0 :                 if (options & REPORT_ERRORS) {
    1001           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error Renaming file: %s", tmp_line);
    1002             :                 }
    1003           0 :                 goto rename_errexit;
    1004             :         }
    1005             : 
    1006             :         /* Rename TO */
    1007           0 :         php_stream_printf(stream TSRMLS_CC, "RNTO %s\r\n", (resource_to->path != NULL ? resource_to->path : "/"));
    1008             : 
    1009           0 :         result = GET_FTP_RESULT(stream);
    1010           0 :         if (result < 200 || result > 299) {
    1011           0 :                 if (options & REPORT_ERRORS) {
    1012           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error Renaming file: %s", tmp_line);
    1013             :                 }
    1014           0 :                 goto rename_errexit;
    1015             :         }
    1016             : 
    1017           0 :         php_url_free(resource_from);
    1018           0 :         php_url_free(resource_to);
    1019           0 :         php_stream_close(stream);
    1020           0 :         return 1;
    1021             : 
    1022             : rename_errexit:
    1023           0 :         if (resource_from) {
    1024           0 :                 php_url_free(resource_from);
    1025             :         }
    1026           0 :         if (resource_to) {
    1027           0 :                 php_url_free(resource_to);
    1028             :         }
    1029           0 :         if (stream) {
    1030           0 :                 php_stream_close(stream);
    1031             :         }
    1032           0 :         return 0;
    1033             : }
    1034             : /* }}} */
    1035             : 
    1036             : /* {{{ php_stream_ftp_mkdir
    1037             :  */
    1038           0 : static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, int mode, int options, php_stream_context *context TSRMLS_DC)
    1039             : {
    1040           0 :         php_stream *stream = NULL;
    1041           0 :         php_url *resource = NULL;
    1042           0 :         int result, recursive = options & PHP_STREAM_MKDIR_RECURSIVE;
    1043             :         char tmp_line[512];
    1044             : 
    1045           0 :         stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, NULL, NULL, &resource, NULL, NULL TSRMLS_CC);
    1046           0 :         if (!stream) {
    1047           0 :                 if (options & REPORT_ERRORS) {
    1048           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", url);
    1049             :                 }
    1050           0 :                 goto mkdir_errexit;
    1051             :         }
    1052             : 
    1053           0 :         if (resource->path == NULL) {
    1054           0 :                 if (options & REPORT_ERRORS) {
    1055           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path provided in %s", url);
    1056             :                 }
    1057           0 :                 goto mkdir_errexit;
    1058             :         }
    1059             : 
    1060           0 :         if (!recursive) {
    1061           0 :                 php_stream_printf(stream TSRMLS_CC, "MKD %s\r\n", resource->path);
    1062           0 :                 result = GET_FTP_RESULT(stream);
    1063             :     } else {
    1064             :         /* we look for directory separator from the end of string, thus hopefuly reducing our work load */
    1065             :         char *p, *e, *buf;
    1066             : 
    1067           0 :         buf = estrdup(resource->path);
    1068           0 :         e = buf + strlen(buf);
    1069             : 
    1070             :         /* find a top level directory we need to create */
    1071           0 :         while ((p = strrchr(buf, '/'))) {
    1072           0 :             *p = '\0';
    1073           0 :                         php_stream_printf(stream TSRMLS_CC, "CWD %s\r\n", buf);
    1074           0 :                         result = GET_FTP_RESULT(stream);
    1075           0 :                         if (result >= 200 && result <= 299) {
    1076           0 :                                 *p = '/';
    1077           0 :                                 break;
    1078             :                         }
    1079             :         }
    1080           0 :         if (p == buf) {
    1081           0 :                         php_stream_printf(stream TSRMLS_CC, "MKD %s\r\n", resource->path);
    1082           0 :                         result = GET_FTP_RESULT(stream);
    1083             :         } else {
    1084           0 :                         php_stream_printf(stream TSRMLS_CC, "MKD %s\r\n", buf);
    1085           0 :                         result = GET_FTP_RESULT(stream);
    1086           0 :                         if (result >= 200 && result <= 299) {
    1087           0 :                                 if (!p) {
    1088           0 :                                         p = buf;
    1089             :                                 }
    1090             :                                 /* create any needed directories if the creation of the 1st directory worked */
    1091           0 :                                 while (++p != e) {
    1092           0 :                                         if (*p == '\0' && *(p + 1) != '\0') {
    1093           0 :                                                 *p = '/';
    1094           0 :                                                 php_stream_printf(stream TSRMLS_CC, "MKD %s\r\n", buf);
    1095           0 :                                                 result = GET_FTP_RESULT(stream);
    1096           0 :                                                 if (result < 200 || result > 299) {
    1097           0 :                                                         if (options & REPORT_ERRORS) {
    1098           0 :                                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", tmp_line);
    1099             :                                                         }
    1100           0 :                                                         break;
    1101             :                                                 }
    1102             :                                         }
    1103             :                                 }
    1104             :                         }
    1105             :                 }
    1106           0 :         efree(buf);
    1107             :     }
    1108             : 
    1109           0 :         php_url_free(resource);
    1110           0 :         php_stream_close(stream);
    1111             : 
    1112           0 :         if (result < 200 || result > 299) {
    1113             :                 /* Failure */
    1114           0 :                 return 0;
    1115             :         }
    1116             : 
    1117           0 :         return 1;
    1118             : 
    1119             : mkdir_errexit:
    1120           0 :         if (resource) {
    1121           0 :                 php_url_free(resource);
    1122             :         }
    1123           0 :         if (stream) {
    1124           0 :                 php_stream_close(stream);
    1125             :         }
    1126           0 :         return 0;
    1127             : }
    1128             : /* }}} */
    1129             : 
    1130             : /* {{{ php_stream_ftp_rmdir
    1131             :  */
    1132           0 : static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context TSRMLS_DC)
    1133             : {
    1134           0 :         php_stream *stream = NULL;
    1135           0 :         php_url *resource = NULL;
    1136             :         int result;
    1137             :         char tmp_line[512];
    1138             : 
    1139           0 :         stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, NULL, NULL, &resource, NULL, NULL TSRMLS_CC);
    1140           0 :         if (!stream) {
    1141           0 :                 if (options & REPORT_ERRORS) {
    1142           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", url);
    1143             :                 }
    1144           0 :                 goto rmdir_errexit;
    1145             :         }
    1146             : 
    1147           0 :         if (resource->path == NULL) {
    1148           0 :                 if (options & REPORT_ERRORS) {
    1149           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path provided in %s", url);
    1150             :                 }
    1151           0 :                 goto rmdir_errexit;
    1152             :         }
    1153             : 
    1154           0 :         php_stream_printf(stream TSRMLS_CC, "RMD %s\r\n", resource->path);
    1155           0 :         result = GET_FTP_RESULT(stream);
    1156             : 
    1157           0 :         if (result < 200 || result > 299) {
    1158           0 :                 if (options & REPORT_ERRORS) {
    1159           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", tmp_line);
    1160             :                 }
    1161           0 :                 goto rmdir_errexit;
    1162             :         }
    1163             : 
    1164           0 :         php_url_free(resource);
    1165           0 :         php_stream_close(stream);
    1166             : 
    1167           0 :         return 1;
    1168             : 
    1169             : rmdir_errexit:
    1170           0 :         if (resource) {
    1171           0 :                 php_url_free(resource);
    1172             :         }
    1173           0 :         if (stream) {
    1174           0 :                 php_stream_close(stream);
    1175             :         }
    1176           0 :         return 0;
    1177             : }
    1178             : /* }}} */
    1179             : 
    1180             : static php_stream_wrapper_ops ftp_stream_wops = {
    1181             :         php_stream_url_wrap_ftp,
    1182             :         php_stream_ftp_stream_close, /* stream_close */
    1183             :         php_stream_ftp_stream_stat,
    1184             :         php_stream_ftp_url_stat, /* stat_url */
    1185             :         php_stream_ftp_opendir, /* opendir */
    1186             :         "ftp",
    1187             :         php_stream_ftp_unlink, /* unlink */
    1188             :         php_stream_ftp_rename, /* rename */
    1189             :         php_stream_ftp_mkdir,  /* mkdir */
    1190             :         php_stream_ftp_rmdir   /* rmdir */
    1191             : };
    1192             : 
    1193             : PHPAPI php_stream_wrapper php_stream_ftp_wrapper =      {
    1194             :         &ftp_stream_wops,
    1195             :         NULL,
    1196             :         1 /* is_url */
    1197             : };
    1198             : 
    1199             : 
    1200             : /*
    1201             :  * Local variables:
    1202             :  * tab-width: 4
    1203             :  * c-basic-offset: 4
    1204             :  * End:
    1205             :  * vim600: sw=4 ts=4 fdm=marker
    1206             :  * vim<600: sw=4 ts=4
    1207             :  */

Generated by: LCOV version 1.10

Generated at Tue, 22 Jul 2014 01:33:19 +0000 (10 days ago)

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