Annotation of embedaddon/php/ext/ftp/ftp.c, revision 1.1

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

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