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 540 5.9 %
Date: 2014-10-22 Functions: 2 14 14.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       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 :                 (tmpzval = php_stream_context_get_option(context, "ftp", "proxy")) != NULL) {
     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 && (tmpzval = php_stream_context_get_option(context, "ftp", "overwrite")) != NULL) {
     501           0 :                         allow_overwrite = Z_LVAL_P(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 :                         (tmpzval = php_stream_context_get_option(context, "ftp", "resume_pos")) != NULL &&
     532             :                         Z_TYPE_P(tmpzval) == IS_LONG &&
     533           0 :                         Z_LVAL_P(tmpzval) > 0) {
     534           0 :                         php_stream_printf(stream TSRMLS_CC, "REST %pd\r\n", Z_LVAL_P(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 %pd", Z_LVAL_P(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             :         zend_string *basename;
     615             : 
     616           0 :         innerstream =  ((php_ftp_dirstream_data *)stream->abstract)->datastream;
     617             : 
     618           0 :         if (count != sizeof(php_stream_dirent)) {
     619           0 :                 return 0;
     620             :         }
     621             : 
     622           0 :         if (php_stream_eof(innerstream)) {
     623           0 :                 return 0;
     624             :         }
     625             : 
     626           0 :         if (!php_stream_get_line(innerstream, ent->d_name, sizeof(ent->d_name), &tmp_len)) {
     627           0 :                 return 0;
     628             :         }
     629             : 
     630           0 :         basename = php_basename(ent->d_name, tmp_len, NULL, 0 TSRMLS_CC);
     631             : 
     632           0 :         tmp_len = MIN(sizeof(ent->d_name), basename->len - 1);
     633           0 :         memcpy(ent->d_name, basename->val, tmp_len);
     634           0 :         ent->d_name[tmp_len - 1] = '\0';
     635             :         zend_string_release(basename);
     636             : 
     637             :         /* Trim off trailing whitespace characters */
     638           0 :         tmp_len--;
     639           0 :         while (tmp_len > 0 &&
     640           0 :                         (ent->d_name[tmp_len] == '\n' || ent->d_name[tmp_len] == '\r' ||
     641           0 :                          ent->d_name[tmp_len] == '\t' || ent->d_name[tmp_len] == ' ')) {
     642           0 :                 ent->d_name[tmp_len--] = '\0';
     643             :         }
     644             : 
     645           0 :         return sizeof(php_stream_dirent);
     646             : }
     647             : /* }}} */
     648             : 
     649             : /* {{{ php_ftp_dirstream_close
     650             :  */
     651           0 : static int php_ftp_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC)
     652             : {
     653           0 :         php_ftp_dirstream_data *data = stream->abstract;
     654             : 
     655             :         /* close control connection */
     656           0 :         if (data->controlstream) {
     657           0 :                 php_stream_close(data->controlstream);
     658           0 :                 data->controlstream = NULL;
     659             :         }
     660             :         /* close data connection */
     661           0 :         php_stream_close(data->datastream);
     662           0 :         data->datastream = NULL;
     663             :         
     664           0 :         efree(data);
     665           0 :         stream->abstract = NULL;
     666             : 
     667           0 :         return 0;
     668             : }
     669             : /* }}} */
     670             : 
     671             : /* ftp dirstreams only need to support read and close operations,
     672             :    They can't be rewound because the underlying ftp stream can't be rewound. */
     673             : static php_stream_ops php_ftp_dirstream_ops = {
     674             :         NULL, /* write */
     675             :         php_ftp_dirstream_read, /* read */
     676             :         php_ftp_dirstream_close, /* close */
     677             :         NULL, /* flush */
     678             :         "ftpdir",
     679             :         NULL, /* rewind */
     680             :         NULL, /* cast */
     681             :         NULL, /* stat */
     682             :         NULL  /* set option */
     683             : };
     684             : 
     685             : /* {{{ php_stream_ftp_opendir
     686             :  */
     687           2 : php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, const char *path, const char *mode, int options,
     688             :                                                                         char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
     689             : {
     690           2 :         php_stream *stream, *reuseid, *datastream = NULL;
     691             :         php_ftp_dirstream_data *dirsdata;
     692           2 :         php_url *resource = NULL;
     693           2 :         int result = 0, use_ssl, use_ssl_on_data = 0;
     694           2 :         char *hoststart = NULL, tmp_line[512];
     695             :         char ip[sizeof("123.123.123.123")];
     696             :         unsigned short portno;
     697             : 
     698           2 :         tmp_line[0] = '\0';
     699             : 
     700           2 :         stream = php_ftp_fopen_connect(wrapper, path, mode, options, opened_path, context, &reuseid, &resource, &use_ssl, &use_ssl_on_data TSRMLS_CC);
     701           2 :         if (!stream) {
     702           2 :                 goto opendir_errexit;   
     703             :         }
     704             : 
     705             :         /* set the connection to be ascii */
     706           0 :         php_stream_write_string(stream, "TYPE A\r\n");
     707           0 :         result = GET_FTP_RESULT(stream);
     708           0 :         if (result > 299 || result < 200)
     709             :                 goto opendir_errexit;
     710             : 
     711             :         /* set up the passive connection */
     712           0 :         portno = php_fopen_do_pasv(stream, ip, sizeof(ip), &hoststart TSRMLS_CC);
     713             : 
     714           0 :         if (!portno) {
     715           0 :                 goto opendir_errexit;
     716             :         }
     717             : 
     718           0 :         php_stream_printf(stream TSRMLS_CC, "NLST %s\r\n", (resource->path != NULL ? resource->path : "/"));
     719             :         
     720             :         /* open the data channel */
     721           0 :         if (hoststart == NULL) {
     722           0 :                 hoststart = resource->host;
     723             :         }
     724           0 :         datastream = php_stream_sock_open_host(hoststart, portno, SOCK_STREAM, 0, 0);
     725           0 :         if (datastream == NULL) {
     726           0 :                 goto opendir_errexit;
     727             :         }
     728             : 
     729           0 :         result = GET_FTP_RESULT(stream);
     730           0 :         if (result != 150 && result != 125) {
     731             :                 /* Could not retrieve or send the file 
     732             :                  * this data will only be sent to us after connection on the data port was initiated.
     733             :                  */
     734           0 :                 php_stream_close(datastream);
     735           0 :                 datastream = NULL;
     736           0 :                 goto opendir_errexit;   
     737             :         }
     738             :         
     739           0 :         php_stream_context_set(datastream, context TSRMLS_CC);
     740             : 
     741           0 :         if (use_ssl_on_data && (php_stream_xport_crypto_setup(stream,
     742           0 :                         STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0 ||
     743           0 :                         php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0)) {
     744             : 
     745           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unable to activate SSL mode");
     746           0 :                 php_stream_close(datastream);
     747           0 :                 datastream = NULL;
     748           0 :                 goto opendir_errexit;
     749             :         }
     750             : 
     751           0 :         php_url_free(resource);
     752             : 
     753           0 :         dirsdata = emalloc(sizeof *dirsdata);
     754           0 :         dirsdata->datastream = datastream;
     755           0 :         dirsdata->controlstream = stream;
     756           0 :         dirsdata->dirstream = php_stream_alloc(&php_ftp_dirstream_ops, dirsdata, 0, mode);
     757             : 
     758           0 :         return dirsdata->dirstream;
     759             : 
     760             : opendir_errexit:
     761           2 :         if (resource) {
     762           0 :                 php_url_free(resource);
     763             :         }
     764           2 :         if (stream) {
     765           0 :                 php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
     766           0 :                 php_stream_close(stream);
     767             :         }
     768           2 :         if (tmp_line[0] != '\0') {
     769           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "FTP server reports %s", tmp_line);
     770             :         }
     771           2 :         return NULL;
     772             : }
     773             : /* }}} */
     774             : 
     775             : /* {{{ php_stream_ftp_url_stat
     776             :  */
     777           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)
     778             : {
     779           0 :         php_stream *stream = NULL;
     780           0 :         php_url *resource = NULL;
     781             :         int result;
     782             :         char tmp_line[512];
     783             : 
     784             :         /* If ssb is NULL then someone is misbehaving */
     785           0 :         if (!ssb) return -1;
     786             : 
     787           0 :         stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, context, NULL, &resource, NULL, NULL TSRMLS_CC);
     788           0 :         if (!stream) {
     789           0 :                 goto stat_errexit;
     790             :         }
     791             : 
     792           0 :         ssb->sb.st_mode = 0644;                                                                      /* FTP won't give us a valid mode, so aproximate one based on being readable */
     793           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) */
     794           0 :         result = GET_FTP_RESULT(stream);
     795           0 :         if (result < 200 || result > 299) {
     796           0 :                 ssb->sb.st_mode |= S_IFREG;
     797             :         } else {
     798           0 :                 ssb->sb.st_mode |= S_IFDIR;
     799             :         }
     800             : 
     801           0 :         php_stream_write_string(stream, "TYPE I\r\n"); /* we need this since some servers refuse to accept SIZE command in ASCII mode */
     802             :         
     803           0 :         result = GET_FTP_RESULT(stream);
     804             : 
     805           0 :         if(result < 200 || result > 299) {
     806             :                 goto stat_errexit;
     807             :         }
     808             :         
     809           0 :         php_stream_printf(stream TSRMLS_CC, "SIZE %s\r\n", (resource->path != NULL ? resource->path : "/"));
     810           0 :         result = GET_FTP_RESULT(stream);
     811           0 :         if (result < 200 || result > 299) {
     812             :                 /* Failure either means it doesn't exist 
     813             :                    or it's a directory and this server
     814             :                    fails on listing directory sizes */
     815           0 :                 if (ssb->sb.st_mode & S_IFDIR) {
     816           0 :                         ssb->sb.st_size = 0;
     817             :                 } else {
     818           0 :                         goto stat_errexit;
     819             :                 }
     820             :         } else {
     821           0 :                 ssb->sb.st_size = atoi(tmp_line + 4);
     822             :         }
     823             : 
     824           0 :         php_stream_printf(stream TSRMLS_CC, "MDTM %s\r\n", (resource->path != NULL ? resource->path : "/"));
     825           0 :         result = GET_FTP_RESULT(stream);
     826           0 :         if (result == 213) {
     827           0 :                 char *p = tmp_line + 4;
     828             :                 int n;
     829             :                 struct tm tm, tmbuf, *gmt;
     830             :                 time_t stamp;
     831             : 
     832           0 :                 while (p - tmp_line < sizeof(tmp_line) && !isdigit(*p)) {
     833           0 :                         p++;
     834             :                 }
     835             : 
     836           0 :                 if (p - tmp_line > sizeof(tmp_line)) {
     837           0 :                         goto mdtm_error;
     838             :                 }
     839             : 
     840           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);
     841           0 :                 if (n != 6) {
     842           0 :                         goto mdtm_error;
     843             :                 }
     844             : 
     845           0 :                 tm.tm_year -= 1900;
     846           0 :                 tm.tm_mon--;
     847           0 :                 tm.tm_isdst = -1;
     848             : 
     849             :                 /* figure out the GMT offset */
     850           0 :                 stamp = time(NULL);
     851           0 :                 gmt = php_gmtime_r(&stamp, &tmbuf);
     852           0 :                 if (!gmt) {
     853           0 :                         goto mdtm_error;
     854             :                 }
     855           0 :                 gmt->tm_isdst = -1;
     856             : 
     857             :                 /* apply the GMT offset */
     858           0 :                 tm.tm_sec += stamp - mktime(gmt);
     859           0 :                 tm.tm_isdst = gmt->tm_isdst;
     860             : 
     861           0 :                 ssb->sb.st_mtime = mktime(&tm);
     862             :         } else {
     863             :                 /* error or unsupported command */
     864             : mdtm_error:
     865           0 :                 ssb->sb.st_mtime = -1;
     866             :         }
     867             : 
     868           0 :         ssb->sb.st_ino = 0;                                          /* Unknown values */
     869           0 :         ssb->sb.st_dev = 0;
     870           0 :         ssb->sb.st_uid = 0;
     871           0 :         ssb->sb.st_gid = 0;
     872           0 :         ssb->sb.st_atime = -1;
     873           0 :         ssb->sb.st_ctime = -1;
     874             : 
     875           0 :         ssb->sb.st_nlink = 1;
     876           0 :         ssb->sb.st_rdev = -1;
     877             : #ifdef HAVE_ST_BLKSIZE
     878           0 :         ssb->sb.st_blksize = 4096;                           /* Guess since FTP won't expose this information */
     879             : #ifdef HAVE_ST_BLOCKS
     880           0 :         ssb->sb.st_blocks = (int)((4095 + ssb->sb.st_size) / ssb->sb.st_blksize); /* emulate ceil */
     881             : #endif
     882             : #endif
     883           0 :         php_stream_close(stream);
     884           0 :         php_url_free(resource);
     885           0 :         return 0;
     886             : 
     887             : stat_errexit:
     888           0 :         if (resource) {
     889           0 :                 php_url_free(resource);
     890             :         }
     891           0 :         if (stream) {
     892           0 :                 php_stream_close(stream);
     893             :         }
     894           0 :         return -1;
     895             : }
     896             : /* }}} */
     897             : 
     898             : /* {{{ php_stream_ftp_unlink
     899             :  */
     900           0 : static int php_stream_ftp_unlink(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context TSRMLS_DC)
     901             : {
     902           0 :         php_stream *stream = NULL;
     903           0 :         php_url *resource = NULL;
     904             :         int result;
     905             :         char tmp_line[512];
     906             : 
     907           0 :         stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, NULL, NULL, &resource, NULL, NULL TSRMLS_CC);
     908           0 :         if (!stream) {
     909           0 :                 if (options & REPORT_ERRORS) {
     910           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", url);
     911             :                 }
     912           0 :                 goto unlink_errexit;
     913             :         }
     914             : 
     915           0 :         if (resource->path == NULL) {
     916           0 :                 if (options & REPORT_ERRORS) {
     917           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path provided in %s", url);
     918             :                 }
     919           0 :                 goto unlink_errexit;
     920             :         }
     921             : 
     922             :         /* Attempt to delete the file */
     923           0 :         php_stream_printf(stream TSRMLS_CC, "DELE %s\r\n", (resource->path != NULL ? resource->path : "/"));
     924             : 
     925           0 :         result = GET_FTP_RESULT(stream);
     926           0 :         if (result < 200 || result > 299) {
     927           0 :                 if (options & REPORT_ERRORS) {
     928           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error Deleting file: %s", tmp_line);
     929             :                 }
     930           0 :                 goto unlink_errexit;
     931             :         }
     932             : 
     933           0 :         php_url_free(resource);
     934           0 :         php_stream_close(stream);
     935           0 :         return 1;
     936             : 
     937             : unlink_errexit:
     938           0 :         if (resource) {
     939           0 :                 php_url_free(resource);
     940             :         }
     941           0 :         if (stream) {
     942           0 :                 php_stream_close(stream);
     943             :         }
     944           0 :         return 0;
     945             : }
     946             : /* }}} */
     947             : 
     948             : /* {{{ php_stream_ftp_rename
     949             :  */
     950           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)
     951             : {
     952           0 :         php_stream *stream = NULL;
     953           0 :         php_url *resource_from = NULL, *resource_to = NULL;
     954             :         int result;
     955             :         char tmp_line[512];
     956             : 
     957           0 :         resource_from = php_url_parse(url_from);
     958           0 :         resource_to = php_url_parse(url_to);
     959             :         /* Must be same scheme (ftp/ftp or ftps/ftps), same host, and same port 
     960             :                 (or a 21/0 0/21 combination which is also "same") 
     961             :            Also require paths to/from */
     962           0 :         if (!resource_from ||
     963             :                 !resource_to ||
     964           0 :                 !resource_from->scheme ||
     965           0 :                 !resource_to->scheme ||
     966           0 :                 strcmp(resource_from->scheme, resource_to->scheme) ||
     967           0 :                 !resource_from->host ||
     968           0 :                 !resource_to->host ||
     969           0 :                 strcmp(resource_from->host, resource_to->host) ||
     970           0 :                 (resource_from->port != resource_to->port && 
     971           0 :                  resource_from->port * resource_to->port != 0 && 
     972           0 :                  resource_from->port + resource_to->port != 21) ||
     973           0 :                 !resource_from->path ||
     974           0 :                 !resource_to->path) {
     975             :                 goto rename_errexit;
     976             :         }
     977             : 
     978           0 :         stream = php_ftp_fopen_connect(wrapper, url_from, "r", 0, NULL, NULL, NULL, NULL, NULL, NULL TSRMLS_CC);
     979           0 :         if (!stream) {
     980           0 :                 if (options & REPORT_ERRORS) {
     981           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", resource_from->host);
     982             :                 }
     983           0 :                 goto rename_errexit;
     984             :         }
     985             : 
     986             :         /* Rename FROM */
     987           0 :         php_stream_printf(stream TSRMLS_CC, "RNFR %s\r\n", (resource_from->path != NULL ? resource_from->path : "/"));
     988             : 
     989           0 :         result = GET_FTP_RESULT(stream);
     990           0 :         if (result < 300 || result > 399) {
     991           0 :                 if (options & REPORT_ERRORS) {
     992           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error Renaming file: %s", tmp_line);
     993             :                 }
     994           0 :                 goto rename_errexit;
     995             :         }
     996             : 
     997             :         /* Rename TO */
     998           0 :         php_stream_printf(stream TSRMLS_CC, "RNTO %s\r\n", (resource_to->path != NULL ? resource_to->path : "/"));
     999             : 
    1000           0 :         result = GET_FTP_RESULT(stream);
    1001           0 :         if (result < 200 || result > 299) {
    1002           0 :                 if (options & REPORT_ERRORS) {
    1003           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error Renaming file: %s", tmp_line);
    1004             :                 }
    1005           0 :                 goto rename_errexit;
    1006             :         }
    1007             : 
    1008           0 :         php_url_free(resource_from);
    1009           0 :         php_url_free(resource_to);
    1010           0 :         php_stream_close(stream);
    1011           0 :         return 1;
    1012             : 
    1013             : rename_errexit:
    1014           0 :         if (resource_from) {
    1015           0 :                 php_url_free(resource_from);
    1016             :         }
    1017           0 :         if (resource_to) {
    1018           0 :                 php_url_free(resource_to);
    1019             :         }
    1020           0 :         if (stream) {
    1021           0 :                 php_stream_close(stream);
    1022             :         }
    1023           0 :         return 0;
    1024             : }
    1025             : /* }}} */
    1026             : 
    1027             : /* {{{ php_stream_ftp_mkdir
    1028             :  */
    1029           0 : static int php_stream_ftp_mkdir(php_stream_wrapper *wrapper, const char *url, int mode, int options, php_stream_context *context TSRMLS_DC)
    1030             : {
    1031           0 :         php_stream *stream = NULL;
    1032           0 :         php_url *resource = NULL;
    1033           0 :         int result, recursive = options & PHP_STREAM_MKDIR_RECURSIVE;
    1034             :         char tmp_line[512];
    1035             : 
    1036           0 :         stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, NULL, NULL, &resource, NULL, NULL TSRMLS_CC);
    1037           0 :         if (!stream) {
    1038           0 :                 if (options & REPORT_ERRORS) {
    1039           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", url);
    1040             :                 }
    1041           0 :                 goto mkdir_errexit;
    1042             :         }
    1043             : 
    1044           0 :         if (resource->path == NULL) {
    1045           0 :                 if (options & REPORT_ERRORS) {
    1046           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path provided in %s", url);
    1047             :                 }
    1048           0 :                 goto mkdir_errexit;
    1049             :         }
    1050             : 
    1051           0 :         if (!recursive) {
    1052           0 :                 php_stream_printf(stream TSRMLS_CC, "MKD %s\r\n", resource->path);
    1053           0 :                 result = GET_FTP_RESULT(stream);
    1054             :     } else {
    1055             :         /* we look for directory separator from the end of string, thus hopefuly reducing our work load */
    1056             :         char *p, *e, *buf;
    1057             : 
    1058           0 :         buf = estrdup(resource->path);
    1059           0 :         e = buf + strlen(buf);
    1060             : 
    1061             :         /* find a top level directory we need to create */
    1062           0 :         while ((p = strrchr(buf, '/'))) {
    1063           0 :             *p = '\0';
    1064           0 :                         php_stream_printf(stream TSRMLS_CC, "CWD %s\r\n", buf);
    1065           0 :                         result = GET_FTP_RESULT(stream);
    1066           0 :                         if (result >= 200 && result <= 299) {
    1067           0 :                                 *p = '/';
    1068           0 :                                 break;
    1069             :                         }
    1070             :         }
    1071           0 :         if (p == buf) {
    1072           0 :                         php_stream_printf(stream TSRMLS_CC, "MKD %s\r\n", resource->path);
    1073           0 :                         result = GET_FTP_RESULT(stream);
    1074             :         } else {
    1075           0 :                         php_stream_printf(stream TSRMLS_CC, "MKD %s\r\n", buf);
    1076           0 :                         result = GET_FTP_RESULT(stream);
    1077           0 :                         if (result >= 200 && result <= 299) {
    1078           0 :                                 if (!p) {
    1079           0 :                                         p = buf;
    1080             :                                 }
    1081             :                                 /* create any needed directories if the creation of the 1st directory worked */
    1082           0 :                                 while (++p != e) {
    1083           0 :                                         if (*p == '\0' && *(p + 1) != '\0') {
    1084           0 :                                                 *p = '/';
    1085           0 :                                                 php_stream_printf(stream TSRMLS_CC, "MKD %s\r\n", buf);
    1086           0 :                                                 result = GET_FTP_RESULT(stream);
    1087           0 :                                                 if (result < 200 || result > 299) {
    1088           0 :                                                         if (options & REPORT_ERRORS) {
    1089           0 :                                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", tmp_line);
    1090             :                                                         }
    1091           0 :                                                         break;
    1092             :                                                 }
    1093             :                                         }
    1094             :                                 }
    1095             :                         }
    1096             :                 }
    1097           0 :         efree(buf);
    1098             :     }
    1099             : 
    1100           0 :         php_url_free(resource);
    1101           0 :         php_stream_close(stream);
    1102             : 
    1103           0 :         if (result < 200 || result > 299) {
    1104             :                 /* Failure */
    1105           0 :                 return 0;
    1106             :         }
    1107             : 
    1108           0 :         return 1;
    1109             : 
    1110             : mkdir_errexit:
    1111           0 :         if (resource) {
    1112           0 :                 php_url_free(resource);
    1113             :         }
    1114           0 :         if (stream) {
    1115           0 :                 php_stream_close(stream);
    1116             :         }
    1117           0 :         return 0;
    1118             : }
    1119             : /* }}} */
    1120             : 
    1121             : /* {{{ php_stream_ftp_rmdir
    1122             :  */
    1123           0 : static int php_stream_ftp_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context TSRMLS_DC)
    1124             : {
    1125           0 :         php_stream *stream = NULL;
    1126           0 :         php_url *resource = NULL;
    1127             :         int result;
    1128             :         char tmp_line[512];
    1129             : 
    1130           0 :         stream = php_ftp_fopen_connect(wrapper, url, "r", 0, NULL, NULL, NULL, &resource, NULL, NULL TSRMLS_CC);
    1131           0 :         if (!stream) {
    1132           0 :                 if (options & REPORT_ERRORS) {
    1133           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to connect to %s", url);
    1134             :                 }
    1135           0 :                 goto rmdir_errexit;
    1136             :         }
    1137             : 
    1138           0 :         if (resource->path == NULL) {
    1139           0 :                 if (options & REPORT_ERRORS) {
    1140           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid path provided in %s", url);
    1141             :                 }
    1142           0 :                 goto rmdir_errexit;
    1143             :         }
    1144             : 
    1145           0 :         php_stream_printf(stream TSRMLS_CC, "RMD %s\r\n", resource->path);
    1146           0 :         result = GET_FTP_RESULT(stream);
    1147             : 
    1148           0 :         if (result < 200 || result > 299) {
    1149           0 :                 if (options & REPORT_ERRORS) {
    1150           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", tmp_line);
    1151             :                 }
    1152           0 :                 goto rmdir_errexit;
    1153             :         }
    1154             : 
    1155           0 :         php_url_free(resource);
    1156           0 :         php_stream_close(stream);
    1157             : 
    1158           0 :         return 1;
    1159             : 
    1160             : rmdir_errexit:
    1161           0 :         if (resource) {
    1162           0 :                 php_url_free(resource);
    1163             :         }
    1164           0 :         if (stream) {
    1165           0 :                 php_stream_close(stream);
    1166             :         }
    1167           0 :         return 0;
    1168             : }
    1169             : /* }}} */
    1170             : 
    1171             : static php_stream_wrapper_ops ftp_stream_wops = {
    1172             :         php_stream_url_wrap_ftp,
    1173             :         php_stream_ftp_stream_close, /* stream_close */
    1174             :         php_stream_ftp_stream_stat,
    1175             :         php_stream_ftp_url_stat, /* stat_url */
    1176             :         php_stream_ftp_opendir, /* opendir */
    1177             :         "ftp",
    1178             :         php_stream_ftp_unlink, /* unlink */
    1179             :         php_stream_ftp_rename, /* rename */
    1180             :         php_stream_ftp_mkdir,  /* mkdir */
    1181             :         php_stream_ftp_rmdir   /* rmdir */
    1182             : };
    1183             : 
    1184             : PHPAPI php_stream_wrapper php_stream_ftp_wrapper =      {
    1185             :         &ftp_stream_wops,
    1186             :         NULL,
    1187             :         1 /* is_url */
    1188             : };
    1189             : 
    1190             : 
    1191             : /*
    1192             :  * Local variables:
    1193             :  * tab-width: 4
    1194             :  * c-basic-offset: 4
    1195             :  * End:
    1196             :  * vim600: sw=4 ts=4 fdm=marker
    1197             :  * vim<600: sw=4 ts=4
    1198             :  */

Generated by: LCOV version 1.10

Generated at Wed, 22 Oct 2014 07:24:58 +0000 (3 days ago)

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