Annotation of embedaddon/php/ext/standard/ftp_fopen_wrapper.c, revision 1.1.1.2

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>