LTP GCOV extension - code coverage report
Current view: directory - ext/standard - ftp_fopen_wrapper.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 515
Code covered: 0.0 % Executed lines: 0
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5