Annotation of embedaddon/php/main/streams/userspace.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: Wez Furlong <wez@thebrainroom.com>                          |
        !            16:    |          Sara Golemon <pollita@php.net>                              |
        !            17:    +----------------------------------------------------------------------+
        !            18: */
        !            19: 
        !            20: /* $Id: userspace.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            21: 
        !            22: #include "php.h"
        !            23: #include "php_globals.h"
        !            24: #include "ext/standard/file.h"
        !            25: #include "ext/standard/flock_compat.h"
        !            26: #ifdef HAVE_SYS_FILE_H
        !            27: #include <sys/file.h>
        !            28: #endif
        !            29: 
        !            30: static int le_protocols;
        !            31: 
        !            32: struct php_user_stream_wrapper {
        !            33:        char * protoname;
        !            34:        char * classname;
        !            35:        zend_class_entry *ce;
        !            36:        php_stream_wrapper wrapper;
        !            37: };
        !            38: 
        !            39: static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
        !            40: static int user_wrapper_stat_url(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC);
        !            41: static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
        !            42: static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC);
        !            43: static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC);
        !            44: static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC);
        !            45: static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filename, char *mode,
        !            46:                int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
        !            47: 
        !            48: static php_stream_wrapper_ops user_stream_wops = {
        !            49:        user_wrapper_opener,
        !            50:        NULL, /* close - the streams themselves know how */
        !            51:        NULL, /* stat - the streams themselves know how */
        !            52:        user_wrapper_stat_url,
        !            53:        user_wrapper_opendir,
        !            54:        "user-space",
        !            55:        user_wrapper_unlink,
        !            56:        user_wrapper_rename,
        !            57:        user_wrapper_mkdir,
        !            58:        user_wrapper_rmdir
        !            59: };
        !            60: 
        !            61: 
        !            62: static void stream_wrapper_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
        !            63: {
        !            64:        struct php_user_stream_wrapper * uwrap = (struct php_user_stream_wrapper*)rsrc->ptr;
        !            65: 
        !            66:        efree(uwrap->protoname);
        !            67:        efree(uwrap->classname);
        !            68:        efree(uwrap);
        !            69: }
        !            70: 
        !            71: 
        !            72: PHP_MINIT_FUNCTION(user_streams)
        !            73: {
        !            74:        le_protocols = zend_register_list_destructors_ex(stream_wrapper_dtor, NULL, "stream factory", 0);
        !            75:        if (le_protocols == FAILURE)
        !            76:                return FAILURE;
        !            77: 
        !            78:        REGISTER_LONG_CONSTANT("STREAM_USE_PATH",                       USE_PATH, CONST_CS|CONST_PERSISTENT);
        !            79:        REGISTER_LONG_CONSTANT("STREAM_IGNORE_URL",             IGNORE_URL, CONST_CS|CONST_PERSISTENT);
        !            80:        REGISTER_LONG_CONSTANT("STREAM_ENFORCE_SAFE_MODE",      ENFORCE_SAFE_MODE, CONST_CS|CONST_PERSISTENT);
        !            81:        REGISTER_LONG_CONSTANT("STREAM_REPORT_ERRORS",          REPORT_ERRORS, CONST_CS|CONST_PERSISTENT);
        !            82:        REGISTER_LONG_CONSTANT("STREAM_MUST_SEEK",                      STREAM_MUST_SEEK, CONST_CS|CONST_PERSISTENT);
        !            83: 
        !            84:        REGISTER_LONG_CONSTANT("STREAM_URL_STAT_LINK",          PHP_STREAM_URL_STAT_LINK,               CONST_CS|CONST_PERSISTENT);
        !            85:        REGISTER_LONG_CONSTANT("STREAM_URL_STAT_QUIET",         PHP_STREAM_URL_STAT_QUIET,              CONST_CS|CONST_PERSISTENT);
        !            86:        REGISTER_LONG_CONSTANT("STREAM_MKDIR_RECURSIVE",        PHP_STREAM_MKDIR_RECURSIVE,             CONST_CS|CONST_PERSISTENT);
        !            87: 
        !            88:        REGISTER_LONG_CONSTANT("STREAM_IS_URL", PHP_STREAM_IS_URL,              CONST_CS|CONST_PERSISTENT);
        !            89: 
        !            90:        REGISTER_LONG_CONSTANT("STREAM_OPTION_BLOCKING",        PHP_STREAM_OPTION_BLOCKING,             CONST_CS|CONST_PERSISTENT);
        !            91:        REGISTER_LONG_CONSTANT("STREAM_OPTION_READ_TIMEOUT",    PHP_STREAM_OPTION_READ_TIMEOUT,         CONST_CS|CONST_PERSISTENT);
        !            92:        REGISTER_LONG_CONSTANT("STREAM_OPTION_READ_BUFFER",     PHP_STREAM_OPTION_READ_BUFFER,          CONST_CS|CONST_PERSISTENT);
        !            93:        REGISTER_LONG_CONSTANT("STREAM_OPTION_WRITE_BUFFER",    PHP_STREAM_OPTION_WRITE_BUFFER,         CONST_CS|CONST_PERSISTENT);
        !            94: 
        !            95:        REGISTER_LONG_CONSTANT("STREAM_BUFFER_NONE",            PHP_STREAM_BUFFER_NONE,                 CONST_CS|CONST_PERSISTENT);
        !            96:        REGISTER_LONG_CONSTANT("STREAM_BUFFER_LINE",            PHP_STREAM_BUFFER_LINE,                 CONST_CS|CONST_PERSISTENT);
        !            97:        REGISTER_LONG_CONSTANT("STREAM_BUFFER_FULL",            PHP_STREAM_BUFFER_FULL,                 CONST_CS|CONST_PERSISTENT);
        !            98: 
        !            99:        REGISTER_LONG_CONSTANT("STREAM_CAST_AS_STREAM",         PHP_STREAM_AS_STDIO,                    CONST_CS|CONST_PERSISTENT);
        !           100:        REGISTER_LONG_CONSTANT("STREAM_CAST_FOR_SELECT",        PHP_STREAM_AS_FD_FOR_SELECT,            CONST_CS|CONST_PERSISTENT);
        !           101: 
        !           102:        return SUCCESS;
        !           103: }
        !           104: 
        !           105: struct _php_userstream_data {
        !           106:        struct php_user_stream_wrapper * wrapper;
        !           107:        zval * object;
        !           108: };
        !           109: typedef struct _php_userstream_data php_userstream_data_t;
        !           110: 
        !           111: /* names of methods */
        !           112: #define USERSTREAM_OPEN                "stream_open"
        !           113: #define USERSTREAM_CLOSE       "stream_close"
        !           114: #define USERSTREAM_READ                "stream_read"
        !           115: #define USERSTREAM_WRITE       "stream_write"
        !           116: #define USERSTREAM_FLUSH       "stream_flush"
        !           117: #define USERSTREAM_SEEK                "stream_seek"
        !           118: #define USERSTREAM_TELL                "stream_tell"
        !           119: #define USERSTREAM_EOF         "stream_eof"
        !           120: #define USERSTREAM_STAT                "stream_stat"
        !           121: #define USERSTREAM_STATURL     "url_stat"
        !           122: #define USERSTREAM_UNLINK      "unlink"
        !           123: #define USERSTREAM_RENAME      "rename"
        !           124: #define USERSTREAM_MKDIR       "mkdir"
        !           125: #define USERSTREAM_RMDIR       "rmdir"
        !           126: #define USERSTREAM_DIR_OPEN            "dir_opendir"
        !           127: #define USERSTREAM_DIR_READ            "dir_readdir"
        !           128: #define USERSTREAM_DIR_REWIND  "dir_rewinddir"
        !           129: #define USERSTREAM_DIR_CLOSE   "dir_closedir"
        !           130: #define USERSTREAM_LOCK     "stream_lock"
        !           131: #define USERSTREAM_CAST                "stream_cast"
        !           132: #define USERSTREAM_SET_OPTION  "stream_set_option"
        !           133: 
        !           134: /* {{{ class should have methods like these:
        !           135:  
        !           136:        function stream_open($path, $mode, $options, &$opened_path)
        !           137:        {
        !           138:                return true/false;
        !           139:        }
        !           140:        
        !           141:        function stream_read($count)
        !           142:        {
        !           143:                return false on error;
        !           144:                else return string;
        !           145:        }
        !           146:        
        !           147:        function stream_write($data)
        !           148:        {
        !           149:                return false on error;
        !           150:                else return count written;
        !           151:        }
        !           152:        
        !           153:        function stream_close()
        !           154:        {
        !           155:        }
        !           156:        
        !           157:        function stream_flush()
        !           158:        {
        !           159:                return true/false;
        !           160:        }
        !           161:        
        !           162:        function stream_seek($offset, $whence)
        !           163:        {
        !           164:                return true/false;
        !           165:        }
        !           166: 
        !           167:        function stream_tell()
        !           168:        {
        !           169:                return (int)$position;
        !           170:        }
        !           171: 
        !           172:        function stream_eof()
        !           173:        {
        !           174:                return true/false;
        !           175:        }
        !           176: 
        !           177:        function stream_stat()
        !           178:        {
        !           179:                return array( just like that returned by fstat() );
        !           180:        }
        !           181: 
        !           182:        function stream_cast($castas)
        !           183:        {
        !           184:                if ($castas == STREAM_CAST_FOR_SELECT) {
        !           185:                        return $this->underlying_stream;
        !           186:                }
        !           187:                return false;
        !           188:        }
        !           189: 
        !           190:        function stream_set_option($option, $arg1, $arg2)
        !           191:        {
        !           192:                switch($option) {
        !           193:                case STREAM_OPTION_BLOCKING:
        !           194:                        $blocking = $arg1;
        !           195:                        ...
        !           196:                case STREAM_OPTION_READ_TIMEOUT:
        !           197:                        $sec = $arg1;
        !           198:                        $usec = $arg2;
        !           199:                        ...
        !           200:                case STREAM_OPTION_WRITE_BUFFER:
        !           201:                        $mode = $arg1;
        !           202:                        $size = $arg2;
        !           203:                        ...
        !           204:                default:
        !           205:                        return false;
        !           206:                }
        !           207:        }
        !           208: 
        !           209:        function url_stat(string $url, int $flags)
        !           210:        {
        !           211:                return array( just like that returned by stat() );
        !           212:        }
        !           213: 
        !           214:        function unlink(string $url)
        !           215:        {
        !           216:                return true / false;
        !           217:        }
        !           218: 
        !           219:        function rename(string $from, string $to)
        !           220:        {
        !           221:                return true / false;
        !           222:        }
        !           223: 
        !           224:        function mkdir($dir, $mode, $options)
        !           225:        {
        !           226:                return true / false;
        !           227:        }
        !           228: 
        !           229:        function rmdir($dir, $options)
        !           230:        {
        !           231:                return true / false;
        !           232:        }
        !           233: 
        !           234:        function dir_opendir(string $url, int $options)
        !           235:        {
        !           236:                return true / false;
        !           237:        }
        !           238: 
        !           239:        function dir_readdir()
        !           240:        {
        !           241:                return string next filename in dir ;
        !           242:        }
        !           243: 
        !           244:        function dir_closedir()
        !           245:        {
        !           246:                release dir related resources;
        !           247:        }
        !           248: 
        !           249:        function dir_rewinddir()
        !           250:        {
        !           251:                reset to start of dir list;
        !           252:        }
        !           253: 
        !           254:        function stream_lock($operation)
        !           255:        {
        !           256:                return true / false;
        !           257:        }
        !           258:   
        !           259:        }}} **/
        !           260: 
        !           261: static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, char *filename, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
        !           262: {
        !           263:        struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
        !           264:        php_userstream_data_t *us;
        !           265:        zval *zfilename, *zmode, *zopened, *zoptions, *zretval = NULL, *zfuncname;
        !           266:        zval **args[4]; 
        !           267:        int call_result;
        !           268:        php_stream *stream = NULL;
        !           269:        zend_bool old_in_user_include;
        !           270: 
        !           271:        /* Try to catch bad usage without preventing flexibility */
        !           272:        if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) {
        !           273:                php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "infinite recursion prevented");
        !           274:                return NULL;
        !           275:        }
        !           276:        FG(user_stream_current_filename) = filename;
        !           277:        
        !           278:        /* if the user stream was registered as local and we are in include context,
        !           279:                we add allow_url_include restrictions to allow_url_fopen ones */
        !           280:        /* we need only is_url == 0 here since if is_url == 1 and remote wrappers
        !           281:                were restricted we wouldn't get here */
        !           282:        old_in_user_include = PG(in_user_include);
        !           283:        if(uwrap->wrapper.is_url == 0 && 
        !           284:                (options & STREAM_OPEN_FOR_INCLUDE) &&
        !           285:                !PG(allow_url_include)) {
        !           286:                PG(in_user_include) = 1;
        !           287:        }
        !           288: 
        !           289:        us = emalloc(sizeof(*us));
        !           290:        us->wrapper = uwrap;    
        !           291: 
        !           292:        /* create an instance of our class */
        !           293:        ALLOC_ZVAL(us->object);
        !           294:        object_init_ex(us->object, uwrap->ce);
        !           295:        Z_SET_REFCOUNT_P(us->object, 1);
        !           296:        Z_SET_ISREF_P(us->object);
        !           297:        
        !           298:        if (uwrap->ce->constructor) {
        !           299:                zend_fcall_info fci;
        !           300:                zend_fcall_info_cache fcc;
        !           301:                zval *retval_ptr;
        !           302:                
        !           303:                fci.size = sizeof(fci);
        !           304:                fci.function_table = &uwrap->ce->function_table;
        !           305:                fci.function_name = NULL;
        !           306:                fci.symbol_table = NULL;
        !           307:                fci.object_ptr = us->object;
        !           308:                fci.retval_ptr_ptr = &retval_ptr;
        !           309:                fci.param_count = 0;
        !           310:                fci.params = NULL;
        !           311:                fci.no_separation = 1;
        !           312:                
        !           313:                fcc.initialized = 1;
        !           314:                fcc.function_handler = uwrap->ce->constructor;
        !           315:                fcc.calling_scope = EG(scope);
        !           316:                fcc.called_scope = Z_OBJCE_P(us->object);
        !           317:                fcc.object_ptr = us->object;
        !           318: 
        !           319:                if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
        !           320:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not execute %s::%s()", uwrap->ce->name, uwrap->ce->constructor->common.function_name);
        !           321:                        zval_dtor(us->object);
        !           322:                        FREE_ZVAL(us->object);
        !           323:                        efree(us);
        !           324:                        FG(user_stream_current_filename) = NULL;
        !           325:                        PG(in_user_include) = old_in_user_include;
        !           326:                        return NULL;
        !           327:                } else {
        !           328:                        if (retval_ptr) {
        !           329:                                zval_ptr_dtor(&retval_ptr);
        !           330:                        }
        !           331:                }
        !           332:        }
        !           333: 
        !           334:        if (context) {
        !           335:                add_property_resource(us->object, "context", context->rsrc_id);
        !           336:                zend_list_addref(context->rsrc_id);
        !           337:        } else {
        !           338:                add_property_null(us->object, "context");
        !           339:        }
        !           340:        
        !           341:        /* call it's stream_open method - set up params first */
        !           342:        MAKE_STD_ZVAL(zfilename);
        !           343:        ZVAL_STRING(zfilename, filename, 1);
        !           344:        args[0] = &zfilename;
        !           345: 
        !           346:        MAKE_STD_ZVAL(zmode);
        !           347:        ZVAL_STRING(zmode, mode, 1);
        !           348:        args[1] = &zmode;
        !           349: 
        !           350:        MAKE_STD_ZVAL(zoptions);
        !           351:        ZVAL_LONG(zoptions, options);
        !           352:        args[2] = &zoptions;
        !           353: 
        !           354:        MAKE_STD_ZVAL(zopened);
        !           355:        Z_SET_REFCOUNT_P(zopened, 1);
        !           356:        Z_SET_ISREF_P(zopened);
        !           357:        ZVAL_NULL(zopened);
        !           358:        args[3] = &zopened;
        !           359: 
        !           360:        MAKE_STD_ZVAL(zfuncname);
        !           361:        ZVAL_STRING(zfuncname, USERSTREAM_OPEN, 1);
        !           362:        
        !           363:        call_result = call_user_function_ex(NULL,
        !           364:                        &us->object,
        !           365:                        zfuncname,
        !           366:                        &zretval,
        !           367:                        4, args,
        !           368:                        0, NULL TSRMLS_CC);
        !           369:        
        !           370:        if (call_result == SUCCESS && zretval != NULL && zval_is_true(zretval)) {
        !           371:                /* the stream is now open! */
        !           372:                stream = php_stream_alloc_rel(&php_stream_userspace_ops, us, 0, mode);
        !           373: 
        !           374:                /* if the opened path is set, copy it out */
        !           375:                if (Z_TYPE_P(zopened) == IS_STRING && opened_path) {
        !           376:                        *opened_path = estrndup(Z_STRVAL_P(zopened), Z_STRLEN_P(zopened));
        !           377:                }
        !           378: 
        !           379:                /* set wrapper data to be a reference to our object */
        !           380:                stream->wrapperdata = us->object;
        !           381:                zval_add_ref(&stream->wrapperdata);
        !           382:        } else {
        !           383:                php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "\"%s::" USERSTREAM_OPEN "\" call failed",
        !           384:                        us->wrapper->classname);
        !           385:        }
        !           386:        
        !           387:        /* destroy everything else */
        !           388:        if (stream == NULL) {
        !           389:                zval_ptr_dtor(&us->object);
        !           390:                efree(us);
        !           391:        }
        !           392:        if (zretval)
        !           393:                zval_ptr_dtor(&zretval);
        !           394:        
        !           395:        zval_ptr_dtor(&zfuncname);
        !           396:        zval_ptr_dtor(&zopened);
        !           397:        zval_ptr_dtor(&zoptions);
        !           398:        zval_ptr_dtor(&zmode);
        !           399:        zval_ptr_dtor(&zfilename);
        !           400: 
        !           401:        FG(user_stream_current_filename) = NULL;
        !           402:                
        !           403:        PG(in_user_include) = old_in_user_include;
        !           404:        return stream;
        !           405: }
        !           406: 
        !           407: static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, char *filename, char *mode,
        !           408:                int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
        !           409: {
        !           410:        struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
        !           411:        php_userstream_data_t *us;
        !           412:        zval *zfilename, *zoptions, *zretval = NULL, *zfuncname;
        !           413:        zval **args[2]; 
        !           414:        int call_result;
        !           415:        php_stream *stream = NULL;
        !           416: 
        !           417:        /* Try to catch bad usage without preventing flexibility */
        !           418:        if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) {
        !           419:                php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "infinite recursion prevented");
        !           420:                return NULL;
        !           421:        }
        !           422:        FG(user_stream_current_filename) = filename;
        !           423:        
        !           424:        us = emalloc(sizeof(*us));
        !           425:        us->wrapper = uwrap;    
        !           426: 
        !           427:        /* create an instance of our class */
        !           428:        ALLOC_ZVAL(us->object);
        !           429:        object_init_ex(us->object, uwrap->ce);
        !           430:        Z_SET_REFCOUNT_P(us->object, 1);
        !           431:        Z_SET_ISREF_P(us->object);
        !           432: 
        !           433:        if (context) {
        !           434:                add_property_resource(us->object, "context", context->rsrc_id);
        !           435:                zend_list_addref(context->rsrc_id);
        !           436:        } else {
        !           437:                add_property_null(us->object, "context");
        !           438:        }
        !           439:        
        !           440:        /* call it's dir_open method - set up params first */
        !           441:        MAKE_STD_ZVAL(zfilename);
        !           442:        ZVAL_STRING(zfilename, filename, 1);
        !           443:        args[0] = &zfilename;
        !           444: 
        !           445:        MAKE_STD_ZVAL(zoptions);
        !           446:        ZVAL_LONG(zoptions, options);
        !           447:        args[1] = &zoptions;
        !           448: 
        !           449:        MAKE_STD_ZVAL(zfuncname);
        !           450:        ZVAL_STRING(zfuncname, USERSTREAM_DIR_OPEN, 1);
        !           451:        
        !           452:        call_result = call_user_function_ex(NULL,
        !           453:                        &us->object,
        !           454:                        zfuncname,
        !           455:                        &zretval,
        !           456:                        2, args,
        !           457:                        0, NULL TSRMLS_CC);
        !           458:        
        !           459:        if (call_result == SUCCESS && zretval != NULL && zval_is_true(zretval)) {
        !           460:                /* the stream is now open! */
        !           461:                stream = php_stream_alloc_rel(&php_stream_userspace_dir_ops, us, 0, mode);
        !           462: 
        !           463:                /* set wrapper data to be a reference to our object */
        !           464:                stream->wrapperdata = us->object;
        !           465:                zval_add_ref(&stream->wrapperdata);
        !           466:        } else {
        !           467:                php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "\"%s::" USERSTREAM_DIR_OPEN "\" call failed",
        !           468:                        us->wrapper->classname);
        !           469:        }
        !           470:        
        !           471:        /* destroy everything else */
        !           472:        if (stream == NULL) {
        !           473:                zval_ptr_dtor(&us->object);
        !           474:                efree(us);
        !           475:        }
        !           476:        if (zretval)
        !           477:                zval_ptr_dtor(&zretval);
        !           478:        
        !           479:        zval_ptr_dtor(&zfuncname);
        !           480:        zval_ptr_dtor(&zoptions);
        !           481:        zval_ptr_dtor(&zfilename);
        !           482: 
        !           483:        FG(user_stream_current_filename) = NULL;
        !           484:                
        !           485:        return stream;
        !           486: }
        !           487: 
        !           488: 
        !           489: /* {{{ proto bool stream_wrapper_register(string protocol, string classname[, integer flags])
        !           490:    Registers a custom URL protocol handler class */
        !           491: PHP_FUNCTION(stream_wrapper_register)
        !           492: {
        !           493:        char *protocol, *classname;
        !           494:        int protocol_len, classname_len;
        !           495:        struct php_user_stream_wrapper * uwrap;
        !           496:        int rsrc_id;
        !           497:        long flags = 0;
        !           498:        
        !           499:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &protocol, &protocol_len, &classname, &classname_len, &flags) == FAILURE) {
        !           500:                RETURN_FALSE;
        !           501:        }
        !           502:        
        !           503:        uwrap = (struct php_user_stream_wrapper *)ecalloc(1, sizeof(*uwrap));
        !           504:        uwrap->protoname = estrndup(protocol, protocol_len);
        !           505:        uwrap->classname = estrndup(classname, classname_len);
        !           506:        uwrap->wrapper.wops = &user_stream_wops;
        !           507:        uwrap->wrapper.abstract = uwrap;
        !           508:        uwrap->wrapper.is_url = ((flags & PHP_STREAM_IS_URL) != 0);
        !           509: 
        !           510:        rsrc_id = ZEND_REGISTER_RESOURCE(NULL, uwrap, le_protocols);
        !           511: 
        !           512:        if (zend_lookup_class(uwrap->classname, classname_len, (zend_class_entry***)&uwrap->ce TSRMLS_CC) == SUCCESS) {
        !           513:                uwrap->ce = *(zend_class_entry**)uwrap->ce;
        !           514:                if (php_register_url_stream_wrapper_volatile(protocol, &uwrap->wrapper TSRMLS_CC) == SUCCESS) {
        !           515:                        RETURN_TRUE;
        !           516:                } else {
        !           517:                        /* We failed.  But why? */
        !           518:                        if (zend_hash_exists(php_stream_get_url_stream_wrappers_hash(), protocol, protocol_len + 1)) {
        !           519:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Protocol %s:// is already defined.", protocol);
        !           520:                        } else {
        !           521:                                /* Hash doesn't exist so it must have been an invalid protocol scheme */
        !           522:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid protocol scheme specified. Unable to register wrapper class %s to %s://", classname, protocol);
        !           523:                        }
        !           524:                }
        !           525:        } else {
        !           526:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "class '%s' is undefined", classname);
        !           527:        }
        !           528: 
        !           529:        zend_list_delete(rsrc_id);
        !           530:        RETURN_FALSE;
        !           531: }
        !           532: /* }}} */
        !           533: 
        !           534: /* {{{ proto bool stream_wrapper_unregister(string protocol)
        !           535:        Unregister a wrapper for the life of the current request. */
        !           536: PHP_FUNCTION(stream_wrapper_unregister)
        !           537: {
        !           538:        char *protocol;
        !           539:        int protocol_len;
        !           540: 
        !           541:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &protocol, &protocol_len) == FAILURE) {
        !           542:                RETURN_FALSE;
        !           543:        }
        !           544: 
        !           545:        if (php_unregister_url_stream_wrapper_volatile(protocol TSRMLS_CC) == FAILURE) {
        !           546:                /* We failed */
        !           547:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to unregister protocol %s://", protocol);
        !           548:                RETURN_FALSE;
        !           549:        }
        !           550: 
        !           551:        RETURN_TRUE;
        !           552: }
        !           553: /* }}} */
        !           554: 
        !           555: /* {{{ proto bool stream_wrapper_restore(string protocol)
        !           556:        Restore the original protocol handler, overriding if necessary */
        !           557: PHP_FUNCTION(stream_wrapper_restore)
        !           558: {
        !           559:        char *protocol;
        !           560:        int protocol_len;
        !           561:        php_stream_wrapper **wrapperpp = NULL, *wrapper;
        !           562:        HashTable *global_wrapper_hash;
        !           563: 
        !           564:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &protocol, &protocol_len) == FAILURE) {
        !           565:                RETURN_FALSE;
        !           566:        }
        !           567: 
        !           568:        global_wrapper_hash = php_stream_get_url_stream_wrappers_hash_global();
        !           569:        if (php_stream_get_url_stream_wrappers_hash() == global_wrapper_hash) {
        !           570:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s:// was never changed, nothing to restore", protocol);
        !           571:                RETURN_TRUE;
        !           572:        }
        !           573: 
        !           574:        if ((zend_hash_find(global_wrapper_hash, protocol, protocol_len + 1, (void**)&wrapperpp) == FAILURE) || !wrapperpp) {
        !           575:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s:// never existed, nothing to restore", protocol);
        !           576:                RETURN_FALSE;
        !           577:        }
        !           578: 
        !           579:        /* next line might delete the pointer that wrapperpp points at, so deref it now */
        !           580:        wrapper = *wrapperpp;
        !           581: 
        !           582:        /* A failure here could be okay given that the protocol might have been merely unregistered */
        !           583:        php_unregister_url_stream_wrapper_volatile(protocol TSRMLS_CC);
        !           584: 
        !           585:        if (php_register_url_stream_wrapper_volatile(protocol, wrapper TSRMLS_CC) == FAILURE) {
        !           586:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to restore original %s:// wrapper", protocol);
        !           587:                RETURN_FALSE;
        !           588:        }       
        !           589: 
        !           590:        RETURN_TRUE;
        !           591: }
        !           592: /* }}} */
        !           593: 
        !           594: static size_t php_userstreamop_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
        !           595: {
        !           596:        zval func_name;
        !           597:        zval *retval = NULL;
        !           598:        int call_result;
        !           599:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !           600:        zval **args[1];
        !           601:        zval *zbufptr;
        !           602:        size_t didwrite = 0;
        !           603: 
        !           604:        assert(us != NULL);
        !           605: 
        !           606:        ZVAL_STRINGL(&func_name, USERSTREAM_WRITE, sizeof(USERSTREAM_WRITE)-1, 0);
        !           607: 
        !           608:        MAKE_STD_ZVAL(zbufptr);
        !           609:        ZVAL_STRINGL(zbufptr, (char*)buf, count, 1);;
        !           610:        args[0] = &zbufptr;
        !           611: 
        !           612:        call_result = call_user_function_ex(NULL,
        !           613:                        &us->object,
        !           614:                        &func_name,
        !           615:                        &retval,
        !           616:                        1, args,
        !           617:                        0, NULL TSRMLS_CC);
        !           618:        zval_ptr_dtor(&zbufptr);
        !           619: 
        !           620:        didwrite = 0;
        !           621:        if (call_result == SUCCESS && retval != NULL) {
        !           622:                convert_to_long(retval);
        !           623:                didwrite = Z_LVAL_P(retval);
        !           624:        } else if (call_result == FAILURE) {
        !           625:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_WRITE " is not implemented!",
        !           626:                                us->wrapper->classname);
        !           627:        }
        !           628: 
        !           629:        /* don't allow strange buffer overruns due to bogus return */
        !           630:        if (didwrite > count) {
        !           631:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_WRITE " wrote %ld bytes more data than requested (%ld written, %ld max)",
        !           632:                                us->wrapper->classname,
        !           633:                                (long)(didwrite - count), (long)didwrite, (long)count);
        !           634:                didwrite = count;
        !           635:        }
        !           636:        
        !           637:        if (retval)
        !           638:                zval_ptr_dtor(&retval);
        !           639:        
        !           640:        return didwrite;
        !           641: }
        !           642: 
        !           643: static size_t php_userstreamop_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
        !           644: {
        !           645:        zval func_name;
        !           646:        zval *retval = NULL;
        !           647:        zval **args[1];
        !           648:        int call_result;
        !           649:        size_t didread = 0;
        !           650:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !           651:        zval *zcount;
        !           652: 
        !           653:        assert(us != NULL);
        !           654: 
        !           655:        ZVAL_STRINGL(&func_name, USERSTREAM_READ, sizeof(USERSTREAM_READ)-1, 0);
        !           656: 
        !           657:        MAKE_STD_ZVAL(zcount);
        !           658:        ZVAL_LONG(zcount, count);
        !           659:        args[0] = &zcount;
        !           660: 
        !           661:        call_result = call_user_function_ex(NULL,
        !           662:                        &us->object,
        !           663:                        &func_name,
        !           664:                        &retval,
        !           665:                        1, args,
        !           666:                        0, NULL TSRMLS_CC);
        !           667: 
        !           668:        if (call_result == SUCCESS && retval != NULL) {
        !           669:                convert_to_string(retval);
        !           670:                didread = Z_STRLEN_P(retval);
        !           671:                if (didread > count) {
        !           672:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_READ " - read %ld bytes more data than requested (%ld read, %ld max) - excess data will be lost",
        !           673:                                        us->wrapper->classname, (long)(didread - count), (long)didread, (long)count);
        !           674:                        didread = count;
        !           675:                }
        !           676:                if (didread > 0)
        !           677:                        memcpy(buf, Z_STRVAL_P(retval), didread);
        !           678:        } else if (call_result == FAILURE) {
        !           679:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_READ " is not implemented!",
        !           680:                                us->wrapper->classname);
        !           681:        }
        !           682:        zval_ptr_dtor(&zcount);
        !           683: 
        !           684:        if (retval) {
        !           685:                zval_ptr_dtor(&retval);
        !           686:                retval = NULL;
        !           687:        }
        !           688: 
        !           689:        /* since the user stream has no way of setting the eof flag directly, we need to ask it if we hit eof */
        !           690: 
        !           691:        ZVAL_STRINGL(&func_name, USERSTREAM_EOF, sizeof(USERSTREAM_EOF)-1, 0);
        !           692: 
        !           693:        call_result = call_user_function_ex(NULL,
        !           694:                        &us->object,
        !           695:                        &func_name,
        !           696:                        &retval,
        !           697:                        0, NULL, 0, NULL TSRMLS_CC);
        !           698: 
        !           699:        if (call_result == SUCCESS && retval != NULL && zval_is_true(retval)) {
        !           700:                stream->eof = 1;
        !           701:        } else if (call_result == FAILURE) {
        !           702:                php_error_docref(NULL TSRMLS_CC, E_WARNING,
        !           703:                                "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF",
        !           704:                                us->wrapper->classname);
        !           705: 
        !           706:                stream->eof = 1;
        !           707:        }
        !           708: 
        !           709:        if (retval) {
        !           710:                zval_ptr_dtor(&retval);
        !           711:                retval = NULL;
        !           712:        }
        !           713: 
        !           714:        return didread;
        !           715: }
        !           716: 
        !           717: static int php_userstreamop_close(php_stream *stream, int close_handle TSRMLS_DC)
        !           718: {
        !           719:        zval func_name;
        !           720:        zval *retval = NULL;
        !           721:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !           722: 
        !           723:        assert(us != NULL);
        !           724:        
        !           725:        ZVAL_STRINGL(&func_name, USERSTREAM_CLOSE, sizeof(USERSTREAM_CLOSE)-1, 0);
        !           726:        
        !           727:        call_user_function_ex(NULL,
        !           728:                        &us->object,
        !           729:                        &func_name,
        !           730:                        &retval,
        !           731:                        0, NULL, 0, NULL TSRMLS_CC);
        !           732: 
        !           733:        if (retval)
        !           734:                zval_ptr_dtor(&retval);
        !           735:        
        !           736:        zval_ptr_dtor(&us->object);
        !           737: 
        !           738:        efree(us);
        !           739:        
        !           740:        return 0;
        !           741: }
        !           742: 
        !           743: static int php_userstreamop_flush(php_stream *stream TSRMLS_DC)
        !           744: {
        !           745:        zval func_name;
        !           746:        zval *retval = NULL;
        !           747:        int call_result;
        !           748:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !           749: 
        !           750:        assert(us != NULL);
        !           751: 
        !           752:        ZVAL_STRINGL(&func_name, USERSTREAM_FLUSH, sizeof(USERSTREAM_FLUSH)-1, 0);
        !           753:        
        !           754:        call_result = call_user_function_ex(NULL,
        !           755:                        &us->object,
        !           756:                        &func_name,
        !           757:                        &retval,
        !           758:                        0, NULL, 0, NULL TSRMLS_CC);
        !           759: 
        !           760:        if (call_result == SUCCESS && retval != NULL && zval_is_true(retval))
        !           761:                call_result = 0;
        !           762:        else
        !           763:                call_result = -1;
        !           764:        
        !           765:        if (retval)
        !           766:                zval_ptr_dtor(&retval);
        !           767:        
        !           768:        return call_result;
        !           769: }
        !           770: 
        !           771: static int php_userstreamop_seek(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC)
        !           772: {
        !           773:        zval func_name;
        !           774:        zval *retval = NULL;
        !           775:        int call_result, ret;
        !           776:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !           777:        zval **args[2];
        !           778:        zval *zoffs, *zwhence;
        !           779: 
        !           780:        assert(us != NULL);
        !           781: 
        !           782:        ZVAL_STRINGL(&func_name, USERSTREAM_SEEK, sizeof(USERSTREAM_SEEK)-1, 0);
        !           783: 
        !           784:        MAKE_STD_ZVAL(zoffs);
        !           785:        ZVAL_LONG(zoffs, offset);
        !           786:        args[0] = &zoffs;
        !           787: 
        !           788:        MAKE_STD_ZVAL(zwhence);
        !           789:        ZVAL_LONG(zwhence, whence);
        !           790:        args[1] = &zwhence;
        !           791: 
        !           792:        call_result = call_user_function_ex(NULL,
        !           793:                        &us->object,
        !           794:                        &func_name,
        !           795:                        &retval,
        !           796:                        2, args,
        !           797:                        0, NULL TSRMLS_CC);
        !           798: 
        !           799:        zval_ptr_dtor(&zoffs);
        !           800:        zval_ptr_dtor(&zwhence);
        !           801: 
        !           802:        if (call_result == FAILURE) {
        !           803:                /* stream_seek is not implemented, so disable seeks for this stream */
        !           804:                stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
        !           805:                /* there should be no retval to clean up */
        !           806:                
        !           807:                if (retval) 
        !           808:                        zval_ptr_dtor(&retval);
        !           809:                
        !           810:                return -1;
        !           811:        } else if (call_result == SUCCESS && retval != NULL && zval_is_true(retval)) {
        !           812:                ret = 0;
        !           813:        } else {
        !           814:                ret = -1;
        !           815:        }
        !           816: 
        !           817:        if (retval) {
        !           818:                zval_ptr_dtor(&retval);
        !           819:                retval = NULL;
        !           820:        }
        !           821: 
        !           822:        if (ret) {
        !           823:                return ret;
        !           824:        }
        !           825: 
        !           826:        /* now determine where we are */
        !           827:        ZVAL_STRINGL(&func_name, USERSTREAM_TELL, sizeof(USERSTREAM_TELL)-1, 0);
        !           828: 
        !           829:        call_result = call_user_function_ex(NULL,
        !           830:                &us->object,
        !           831:                &func_name,
        !           832:                &retval,
        !           833:                0, NULL, 0, NULL TSRMLS_CC);
        !           834: 
        !           835:        if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_LONG) {
        !           836:                *newoffs = Z_LVAL_P(retval);
        !           837:                ret = 0;
        !           838:        } else if (call_result == FAILURE) {
        !           839:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_TELL " is not implemented!", us->wrapper->classname);
        !           840:                ret = -1;
        !           841:        } else {
        !           842:                ret = -1;
        !           843:        }
        !           844: 
        !           845:        if (retval) {
        !           846:                zval_ptr_dtor(&retval);
        !           847:        }
        !           848:        return ret;
        !           849: }
        !           850: 
        !           851: /* parse the return value from one of the stat functions and store the
        !           852:  * relevant fields into the statbuf provided */
        !           853: static int statbuf_from_array(zval *array, php_stream_statbuf *ssb TSRMLS_DC)
        !           854: {
        !           855:        zval **elem;
        !           856: 
        !           857: #define STAT_PROP_ENTRY_EX(name, name2)                        \
        !           858:        if (SUCCESS == zend_hash_find(Z_ARRVAL_P(array), #name, sizeof(#name), (void**)&elem)) {     \
        !           859:                SEPARATE_ZVAL(elem);                                                                                                                                     \
        !           860:                convert_to_long(*elem);                                                                   \
        !           861:                ssb->sb.st_##name2 = Z_LVAL_PP(elem);                                                      \
        !           862:        }
        !           863: 
        !           864: #define STAT_PROP_ENTRY(name) STAT_PROP_ENTRY_EX(name,name)
        !           865: 
        !           866:        memset(ssb, 0, sizeof(php_stream_statbuf));
        !           867:        STAT_PROP_ENTRY(dev);
        !           868:        STAT_PROP_ENTRY(ino);
        !           869:        STAT_PROP_ENTRY(mode);
        !           870:        STAT_PROP_ENTRY(nlink);
        !           871:        STAT_PROP_ENTRY(uid);
        !           872:        STAT_PROP_ENTRY(gid);
        !           873: #if HAVE_ST_RDEV
        !           874:        STAT_PROP_ENTRY(rdev);
        !           875: #endif
        !           876:        STAT_PROP_ENTRY(size);
        !           877: #ifdef NETWARE
        !           878:        STAT_PROP_ENTRY_EX(atime, atime.tv_sec);
        !           879:        STAT_PROP_ENTRY_EX(mtime, mtime.tv_sec);
        !           880:        STAT_PROP_ENTRY_EX(ctime, ctime.tv_sec);
        !           881: #else
        !           882:        STAT_PROP_ENTRY(atime);
        !           883:        STAT_PROP_ENTRY(mtime);
        !           884:        STAT_PROP_ENTRY(ctime);
        !           885: #endif
        !           886: #ifdef HAVE_ST_BLKSIZE
        !           887:        STAT_PROP_ENTRY(blksize);
        !           888: #endif
        !           889: #ifdef HAVE_ST_BLOCKS
        !           890:        STAT_PROP_ENTRY(blocks);
        !           891: #endif
        !           892: 
        !           893: #undef STAT_PROP_ENTRY 
        !           894: #undef STAT_PROP_ENTRY_EX      
        !           895:        return SUCCESS;
        !           896: }
        !           897: 
        !           898: static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC)
        !           899: {
        !           900:        zval func_name;
        !           901:        zval *retval = NULL;
        !           902:        int call_result;
        !           903:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !           904:        int ret = -1;
        !           905: 
        !           906:        ZVAL_STRINGL(&func_name, USERSTREAM_STAT, sizeof(USERSTREAM_STAT)-1, 0);
        !           907: 
        !           908:        call_result = call_user_function_ex(NULL,
        !           909:                        &us->object,
        !           910:                        &func_name,
        !           911:                        &retval,
        !           912:                        0, NULL, 0, NULL TSRMLS_CC);
        !           913: 
        !           914:        if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_ARRAY) {
        !           915:                if (SUCCESS == statbuf_from_array(retval, ssb TSRMLS_CC))
        !           916:                        ret = 0;
        !           917:        } else {
        !           918:                if (call_result == FAILURE) {
        !           919:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_STAT " is not implemented!",
        !           920:                                        us->wrapper->classname);
        !           921:                }
        !           922:        }
        !           923: 
        !           924:        if (retval) 
        !           925:                zval_ptr_dtor(&retval);
        !           926:        
        !           927:        return ret;
        !           928: }
        !           929: 
        !           930: 
        !           931: static int php_userstreamop_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC) {
        !           932:        zval func_name;
        !           933:        zval *retval = NULL;
        !           934:        int call_result;
        !           935:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !           936:        int ret = -1;
        !           937:        zval *zvalue = NULL;
        !           938:        zval **args[3];
        !           939: 
        !           940:        switch (option) {
        !           941:        case PHP_STREAM_OPTION_CHECK_LIVENESS:
        !           942:                ZVAL_STRINGL(&func_name, USERSTREAM_EOF, sizeof(USERSTREAM_EOF)-1, 0);
        !           943:                call_result = call_user_function_ex(NULL, &us->object, &func_name, &retval, 0, NULL, 0, NULL TSRMLS_CC);
        !           944:                if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_BOOL) {
        !           945:                        ret = zval_is_true(retval) ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
        !           946:                } else {
        !           947:                        ret = PHP_STREAM_OPTION_RETURN_ERR;
        !           948:                        php_error_docref(NULL TSRMLS_CC, E_WARNING,
        !           949:                                        "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF",
        !           950:                                        us->wrapper->classname);
        !           951:                }
        !           952:                break;
        !           953: 
        !           954:        case PHP_STREAM_OPTION_LOCKING:
        !           955:                MAKE_STD_ZVAL(zvalue);
        !           956:                ZVAL_LONG(zvalue, 0);
        !           957: 
        !           958:                if (value & LOCK_NB) {
        !           959:                        Z_LVAL_P(zvalue) |= PHP_LOCK_NB;
        !           960:                }
        !           961:                switch(value & ~LOCK_NB) {
        !           962:                case LOCK_SH:
        !           963:                        Z_LVAL_P(zvalue) |= PHP_LOCK_SH;
        !           964:                        break;
        !           965:                case LOCK_EX:
        !           966:                        Z_LVAL_P(zvalue) |= PHP_LOCK_EX;
        !           967:                        break;
        !           968:                case LOCK_UN:
        !           969:                        Z_LVAL_P(zvalue) |= PHP_LOCK_UN;
        !           970:                        break;
        !           971:                }
        !           972: 
        !           973:                args[0] = &zvalue;
        !           974:                
        !           975:                /* TODO wouldblock */
        !           976:                ZVAL_STRINGL(&func_name, USERSTREAM_LOCK, sizeof(USERSTREAM_LOCK)-1, 0);
        !           977:                
        !           978:                call_result = call_user_function_ex(NULL,
        !           979:                                                                                        &us->object,
        !           980:                                                                                        &func_name,
        !           981:                                                                                        &retval,
        !           982:                                                                                        1, args, 0, NULL TSRMLS_CC);
        !           983:                
        !           984:                if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) == IS_BOOL) {
        !           985:                        ret = !Z_LVAL_P(retval);
        !           986:                } else if (call_result == FAILURE) {
        !           987:                        if (value == 0) { 
        !           988:                                /* lock support test (TODO: more check) */
        !           989:                                ret = 0;
        !           990:                        } else {
        !           991:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_LOCK " is not implemented!", 
        !           992:                                                                 us->wrapper->classname);
        !           993:                        }
        !           994:                }
        !           995: 
        !           996:                break;
        !           997:        
        !           998:        case PHP_STREAM_OPTION_READ_BUFFER:
        !           999:        case PHP_STREAM_OPTION_WRITE_BUFFER:
        !          1000:        case PHP_STREAM_OPTION_READ_TIMEOUT:
        !          1001:        case PHP_STREAM_OPTION_BLOCKING: {
        !          1002:                zval *zoption = NULL;
        !          1003:                zval *zptrparam = NULL;
        !          1004:                
        !          1005:                ZVAL_STRINGL(&func_name, USERSTREAM_SET_OPTION, sizeof(USERSTREAM_SET_OPTION)-1, 0);
        !          1006: 
        !          1007:                ALLOC_INIT_ZVAL(zoption);
        !          1008:                ZVAL_LONG(zoption, option);
        !          1009: 
        !          1010:                ALLOC_INIT_ZVAL(zvalue);
        !          1011:                ALLOC_INIT_ZVAL(zptrparam);
        !          1012: 
        !          1013:                args[0] = &zoption;
        !          1014:                args[1] = &zvalue;
        !          1015:                args[2] = &zptrparam;
        !          1016: 
        !          1017:                switch(option) {
        !          1018:                case PHP_STREAM_OPTION_READ_BUFFER:
        !          1019:                case PHP_STREAM_OPTION_WRITE_BUFFER:
        !          1020:                        ZVAL_LONG(zvalue, value);
        !          1021:                        if (ptrparam) {
        !          1022:                                ZVAL_LONG(zptrparam, *(long *)ptrparam);
        !          1023:                        } else {
        !          1024:                                ZVAL_LONG(zptrparam, BUFSIZ);
        !          1025:                        }
        !          1026:                        break;
        !          1027:                case PHP_STREAM_OPTION_READ_TIMEOUT: {
        !          1028:                        struct timeval tv = *(struct timeval*)ptrparam;
        !          1029:                        ZVAL_LONG(zvalue, tv.tv_sec);
        !          1030:                        ZVAL_LONG(zptrparam, tv.tv_usec);
        !          1031:                        break;
        !          1032:                        }
        !          1033:                case PHP_STREAM_OPTION_BLOCKING:
        !          1034:                        ZVAL_LONG(zvalue, value);
        !          1035:                        break;
        !          1036:                default:
        !          1037:                        break;
        !          1038:                }
        !          1039: 
        !          1040:                call_result = call_user_function_ex(NULL,
        !          1041:                        &us->object,
        !          1042:                        &func_name,
        !          1043:                        &retval,
        !          1044:                        3, args, 0, NULL TSRMLS_CC);
        !          1045:        
        !          1046:                do {
        !          1047:                        if (call_result == FAILURE) {
        !          1048:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_SET_OPTION " is not implemented!",
        !          1049:                                                us->wrapper->classname);
        !          1050:                                break;
        !          1051:                        }
        !          1052:                        if (retval && zend_is_true(retval)) {
        !          1053:                                ret = PHP_STREAM_OPTION_RETURN_OK;
        !          1054:                        }
        !          1055:                } while (0);
        !          1056: 
        !          1057:                if (zoption) {
        !          1058:                        zval_ptr_dtor(&zoption);
        !          1059:                }
        !          1060:                if (zptrparam) {
        !          1061:                        zval_ptr_dtor(&zptrparam);
        !          1062:                }
        !          1063: 
        !          1064:                break;
        !          1065:                }
        !          1066:        }
        !          1067: 
        !          1068:        /* clean up */
        !          1069:        if (retval) {
        !          1070:                zval_ptr_dtor(&retval);
        !          1071:        }
        !          1072:   
        !          1073: 
        !          1074:        if (zvalue) {
        !          1075:                zval_ptr_dtor(&zvalue);
        !          1076:        }
        !          1077: 
        !          1078:        return ret;
        !          1079: }
        !          1080: 
        !          1081: 
        !          1082: static int user_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
        !          1083: {
        !          1084:        struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
        !          1085:        zval *zfilename, *zfuncname, *zretval;
        !          1086:        zval **args[1];
        !          1087:        int call_result;
        !          1088:        zval *object;
        !          1089:        int ret = 0;
        !          1090: 
        !          1091:        /* create an instance of our class */
        !          1092:        ALLOC_ZVAL(object);
        !          1093:        object_init_ex(object, uwrap->ce);
        !          1094:        Z_SET_REFCOUNT_P(object, 1);
        !          1095:        Z_SET_ISREF_P(object);
        !          1096: 
        !          1097:        if (context) {
        !          1098:                add_property_resource(object, "context", context->rsrc_id);
        !          1099:                zend_list_addref(context->rsrc_id);
        !          1100:        } else {
        !          1101:                add_property_null(object, "context");
        !          1102:        }
        !          1103: 
        !          1104:        /* call the unlink method */
        !          1105:        MAKE_STD_ZVAL(zfilename);
        !          1106:        ZVAL_STRING(zfilename, url, 1);
        !          1107:        args[0] = &zfilename;
        !          1108: 
        !          1109:        MAKE_STD_ZVAL(zfuncname);
        !          1110:        ZVAL_STRING(zfuncname, USERSTREAM_UNLINK, 1);
        !          1111:        
        !          1112:        call_result = call_user_function_ex(NULL,
        !          1113:                        &object,
        !          1114:                        zfuncname,
        !          1115:                        &zretval,
        !          1116:                        1, args,
        !          1117:                        0, NULL TSRMLS_CC);
        !          1118: 
        !          1119:        if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
        !          1120:                ret = Z_LVAL_P(zretval);
        !          1121:        } else if (call_result == FAILURE) {
        !          1122:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_UNLINK " is not implemented!", uwrap->classname);
        !          1123:        }
        !          1124: 
        !          1125:        /* clean up */
        !          1126:        zval_ptr_dtor(&object);
        !          1127:        if (zretval)
        !          1128:                zval_ptr_dtor(&zretval);
        !          1129:        
        !          1130:        zval_ptr_dtor(&zfuncname);
        !          1131:        zval_ptr_dtor(&zfilename);
        !          1132: 
        !          1133:        return ret;
        !          1134: }
        !          1135: 
        !          1136: static int user_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC)
        !          1137: {
        !          1138:        struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
        !          1139:        zval *zold_name, *znew_name, *zfuncname, *zretval;
        !          1140:        zval **args[2];
        !          1141:        int call_result;
        !          1142:        zval *object;
        !          1143:        int ret = 0;
        !          1144: 
        !          1145:        /* create an instance of our class */
        !          1146:        ALLOC_ZVAL(object);
        !          1147:        object_init_ex(object, uwrap->ce);
        !          1148:        Z_SET_REFCOUNT_P(object, 1);
        !          1149:        Z_SET_ISREF_P(object);
        !          1150: 
        !          1151:        if (context) {
        !          1152:                add_property_resource(object, "context", context->rsrc_id);
        !          1153:                zend_list_addref(context->rsrc_id);
        !          1154:        } else {
        !          1155:                add_property_null(object, "context");
        !          1156:        }
        !          1157: 
        !          1158:        /* call the rename method */
        !          1159:        MAKE_STD_ZVAL(zold_name);
        !          1160:        ZVAL_STRING(zold_name, url_from, 1);
        !          1161:        args[0] = &zold_name;
        !          1162: 
        !          1163:        MAKE_STD_ZVAL(znew_name);
        !          1164:        ZVAL_STRING(znew_name, url_to, 1);
        !          1165:        args[1] = &znew_name;
        !          1166: 
        !          1167:        MAKE_STD_ZVAL(zfuncname);
        !          1168:        ZVAL_STRING(zfuncname, USERSTREAM_RENAME, 1);
        !          1169:        
        !          1170:        call_result = call_user_function_ex(NULL,
        !          1171:                        &object,
        !          1172:                        zfuncname,
        !          1173:                        &zretval,
        !          1174:                        2, args,
        !          1175:                        0, NULL TSRMLS_CC);
        !          1176: 
        !          1177:        if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
        !          1178:                ret = Z_LVAL_P(zretval);
        !          1179:        } else if (call_result == FAILURE) {
        !          1180:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_RENAME " is not implemented!", uwrap->classname);
        !          1181:        }
        !          1182: 
        !          1183:        /* clean up */
        !          1184:        zval_ptr_dtor(&object);
        !          1185:        if (zretval)
        !          1186:                zval_ptr_dtor(&zretval);
        !          1187:        
        !          1188:        zval_ptr_dtor(&zfuncname);
        !          1189:        zval_ptr_dtor(&zold_name);
        !          1190:        zval_ptr_dtor(&znew_name);
        !          1191: 
        !          1192:        return ret;
        !          1193: }
        !          1194: 
        !          1195: static int user_wrapper_mkdir(php_stream_wrapper *wrapper, char *url, int mode, int options, php_stream_context *context TSRMLS_DC)
        !          1196: {
        !          1197:        struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
        !          1198:        zval *zfilename, *zmode, *zoptions, *zfuncname, *zretval;
        !          1199:        zval **args[3];
        !          1200:        int call_result;
        !          1201:        zval *object;
        !          1202:        int ret = 0;
        !          1203: 
        !          1204:        /* create an instance of our class */
        !          1205:        ALLOC_ZVAL(object);
        !          1206:        object_init_ex(object, uwrap->ce);
        !          1207:        Z_SET_REFCOUNT_P(object, 1);
        !          1208:        Z_SET_ISREF_P(object);
        !          1209: 
        !          1210:        if (context) {
        !          1211:                add_property_resource(object, "context", context->rsrc_id);
        !          1212:                zend_list_addref(context->rsrc_id);
        !          1213:        } else {
        !          1214:                add_property_null(object, "context");
        !          1215:        }
        !          1216: 
        !          1217:        /* call the mkdir method */
        !          1218:        MAKE_STD_ZVAL(zfilename);
        !          1219:        ZVAL_STRING(zfilename, url, 1);
        !          1220:        args[0] = &zfilename;
        !          1221: 
        !          1222:        MAKE_STD_ZVAL(zmode);
        !          1223:        ZVAL_LONG(zmode, mode);
        !          1224:        args[1] = &zmode;
        !          1225: 
        !          1226:        MAKE_STD_ZVAL(zoptions);
        !          1227:        ZVAL_LONG(zoptions, options);
        !          1228:        args[2] = &zoptions;
        !          1229: 
        !          1230:        MAKE_STD_ZVAL(zfuncname);
        !          1231:        ZVAL_STRING(zfuncname, USERSTREAM_MKDIR, 1);
        !          1232:        
        !          1233:        call_result = call_user_function_ex(NULL,
        !          1234:                        &object,
        !          1235:                        zfuncname,
        !          1236:                        &zretval,
        !          1237:                        3, args,
        !          1238:                        0, NULL TSRMLS_CC);
        !          1239: 
        !          1240:        if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
        !          1241:                ret = Z_LVAL_P(zretval);
        !          1242:        } else if (call_result == FAILURE) {
        !          1243:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_MKDIR " is not implemented!", uwrap->classname);
        !          1244:        }
        !          1245: 
        !          1246:        /* clean up */
        !          1247:        zval_ptr_dtor(&object);
        !          1248:        if (zretval) {
        !          1249:                zval_ptr_dtor(&zretval);
        !          1250:        }
        !          1251:        
        !          1252:        zval_ptr_dtor(&zfuncname);
        !          1253:        zval_ptr_dtor(&zfilename);
        !          1254:        zval_ptr_dtor(&zmode);
        !          1255:        zval_ptr_dtor(&zoptions);
        !          1256: 
        !          1257:        return ret;
        !          1258: }
        !          1259: 
        !          1260: static int user_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC)
        !          1261: {
        !          1262:        struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
        !          1263:        zval *zfilename, *zoptions, *zfuncname, *zretval;
        !          1264:        zval **args[3];
        !          1265:        int call_result;
        !          1266:        zval *object;
        !          1267:        int ret = 0;
        !          1268: 
        !          1269:        /* create an instance of our class */
        !          1270:        ALLOC_ZVAL(object);
        !          1271:        object_init_ex(object, uwrap->ce);
        !          1272:        Z_SET_REFCOUNT_P(object, 1);
        !          1273:        Z_SET_ISREF_P(object);
        !          1274: 
        !          1275:        if (context) {
        !          1276:                add_property_resource(object, "context", context->rsrc_id);
        !          1277:                zend_list_addref(context->rsrc_id);
        !          1278:        } else {
        !          1279:                add_property_null(object, "context");
        !          1280:        }
        !          1281: 
        !          1282:        /* call the rmdir method */
        !          1283:        MAKE_STD_ZVAL(zfilename);
        !          1284:        ZVAL_STRING(zfilename, url, 1);
        !          1285:        args[0] = &zfilename;
        !          1286: 
        !          1287:        MAKE_STD_ZVAL(zoptions);
        !          1288:        ZVAL_LONG(zoptions, options);
        !          1289:        args[1] = &zoptions;
        !          1290: 
        !          1291:        MAKE_STD_ZVAL(zfuncname);
        !          1292:        ZVAL_STRING(zfuncname, USERSTREAM_RMDIR, 1);
        !          1293:        
        !          1294:        call_result = call_user_function_ex(NULL,
        !          1295:                        &object,
        !          1296:                        zfuncname,
        !          1297:                        &zretval,
        !          1298:                        2, args,
        !          1299:                        0, NULL TSRMLS_CC);
        !          1300: 
        !          1301:        if (call_result == SUCCESS && zretval && Z_TYPE_P(zretval) == IS_BOOL) {
        !          1302:                ret = Z_LVAL_P(zretval);
        !          1303:        } else if (call_result == FAILURE) {
        !          1304:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_RMDIR " is not implemented!", uwrap->classname);
        !          1305:        }
        !          1306: 
        !          1307:        /* clean up */
        !          1308:        zval_ptr_dtor(&object);
        !          1309:        if (zretval) {
        !          1310:                zval_ptr_dtor(&zretval);
        !          1311:        }
        !          1312:        
        !          1313:        zval_ptr_dtor(&zfuncname);
        !          1314:        zval_ptr_dtor(&zfilename);
        !          1315:        zval_ptr_dtor(&zoptions);
        !          1316: 
        !          1317:        return ret;
        !          1318: }
        !          1319: 
        !          1320: static int user_wrapper_stat_url(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
        !          1321: {
        !          1322:        struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
        !          1323:        zval *zfilename, *zfuncname, *zretval, *zflags;
        !          1324:        zval **args[2]; 
        !          1325:        int call_result;
        !          1326:        zval *object;
        !          1327:        int ret = -1;
        !          1328: 
        !          1329:        /* create an instance of our class */
        !          1330:        ALLOC_ZVAL(object);
        !          1331:        object_init_ex(object, uwrap->ce);
        !          1332:        Z_SET_REFCOUNT_P(object, 1);
        !          1333:        Z_SET_ISREF_P(object);
        !          1334: 
        !          1335:        if (context) {
        !          1336:                add_property_resource(object, "context", context->rsrc_id);
        !          1337:                zend_list_addref(context->rsrc_id);
        !          1338:        } else {
        !          1339:                add_property_null(object, "context");
        !          1340:        }
        !          1341: 
        !          1342:        /* call it's stat_url method - set up params first */
        !          1343:        MAKE_STD_ZVAL(zfilename);
        !          1344:        ZVAL_STRING(zfilename, url, 1);
        !          1345:        args[0] = &zfilename;
        !          1346: 
        !          1347:        MAKE_STD_ZVAL(zflags);
        !          1348:        ZVAL_LONG(zflags, flags);
        !          1349:        args[1] = &zflags;
        !          1350: 
        !          1351:        MAKE_STD_ZVAL(zfuncname);
        !          1352:        ZVAL_STRING(zfuncname, USERSTREAM_STATURL, 1);
        !          1353:        
        !          1354:        call_result = call_user_function_ex(NULL,
        !          1355:                        &object,
        !          1356:                        zfuncname,
        !          1357:                        &zretval,
        !          1358:                        2, args,
        !          1359:                        0, NULL TSRMLS_CC);
        !          1360:        
        !          1361:        if (call_result == SUCCESS && zretval != NULL && Z_TYPE_P(zretval) == IS_ARRAY) {
        !          1362:                /* We got the info we needed */
        !          1363:                if (SUCCESS == statbuf_from_array(zretval, ssb TSRMLS_CC))
        !          1364:                        ret = 0;
        !          1365:        } else {
        !          1366:                if (call_result == FAILURE) {
        !          1367:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_STATURL " is not implemented!",
        !          1368:                                        uwrap->classname);
        !          1369:                }
        !          1370:        }
        !          1371:        
        !          1372:        /* clean up */
        !          1373:        zval_ptr_dtor(&object);
        !          1374:        if (zretval)
        !          1375:                zval_ptr_dtor(&zretval);
        !          1376:        
        !          1377:        zval_ptr_dtor(&zfuncname);
        !          1378:        zval_ptr_dtor(&zfilename);
        !          1379:        zval_ptr_dtor(&zflags);
        !          1380:                
        !          1381:        return ret;
        !          1382: 
        !          1383: }
        !          1384: 
        !          1385: static size_t php_userstreamop_readdir(php_stream *stream, char *buf, size_t count TSRMLS_DC)
        !          1386: {
        !          1387:        zval func_name;
        !          1388:        zval *retval = NULL;
        !          1389:        int call_result;
        !          1390:        size_t didread = 0;
        !          1391:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !          1392:        php_stream_dirent *ent = (php_stream_dirent*)buf;
        !          1393: 
        !          1394:        /* avoid problems if someone mis-uses the stream */
        !          1395:        if (count != sizeof(php_stream_dirent))
        !          1396:                return 0;
        !          1397: 
        !          1398:        ZVAL_STRINGL(&func_name, USERSTREAM_DIR_READ, sizeof(USERSTREAM_DIR_READ)-1, 0);
        !          1399: 
        !          1400:        call_result = call_user_function_ex(NULL,
        !          1401:                        &us->object,
        !          1402:                        &func_name,
        !          1403:                        &retval,
        !          1404:                        0, NULL,
        !          1405:                        0, NULL TSRMLS_CC);
        !          1406: 
        !          1407:        if (call_result == SUCCESS && retval != NULL && Z_TYPE_P(retval) != IS_BOOL) {
        !          1408:                convert_to_string(retval);
        !          1409:                PHP_STRLCPY(ent->d_name, Z_STRVAL_P(retval), sizeof(ent->d_name), Z_STRLEN_P(retval));
        !          1410: 
        !          1411:                didread = sizeof(php_stream_dirent);
        !          1412:        } else if (call_result == FAILURE) {
        !          1413:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_DIR_READ " is not implemented!",
        !          1414:                                us->wrapper->classname);
        !          1415:        }
        !          1416: 
        !          1417:        if (retval)
        !          1418:                zval_ptr_dtor(&retval);
        !          1419: 
        !          1420:        return didread;
        !          1421: }
        !          1422: 
        !          1423: static int php_userstreamop_closedir(php_stream *stream, int close_handle TSRMLS_DC)
        !          1424: {
        !          1425:        zval func_name;
        !          1426:        zval *retval = NULL;
        !          1427:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !          1428: 
        !          1429:        assert(us != NULL);
        !          1430:        
        !          1431:        ZVAL_STRINGL(&func_name, USERSTREAM_DIR_CLOSE, sizeof(USERSTREAM_DIR_CLOSE)-1, 0);
        !          1432:        
        !          1433:        call_user_function_ex(NULL,
        !          1434:                        &us->object,
        !          1435:                        &func_name,
        !          1436:                        &retval,
        !          1437:                        0, NULL, 0, NULL TSRMLS_CC);
        !          1438: 
        !          1439:        if (retval)
        !          1440:                zval_ptr_dtor(&retval);
        !          1441:        
        !          1442:        zval_ptr_dtor(&us->object);
        !          1443: 
        !          1444:        efree(us);
        !          1445:        
        !          1446:        return 0;
        !          1447: }
        !          1448: 
        !          1449: static int php_userstreamop_rewinddir(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC)
        !          1450: {
        !          1451:        zval func_name;
        !          1452:        zval *retval = NULL;
        !          1453:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !          1454: 
        !          1455:        ZVAL_STRINGL(&func_name, USERSTREAM_DIR_REWIND, sizeof(USERSTREAM_DIR_REWIND)-1, 0);
        !          1456:        
        !          1457:        call_user_function_ex(NULL,
        !          1458:                        &us->object,
        !          1459:                        &func_name,
        !          1460:                        &retval,
        !          1461:                        0, NULL, 0, NULL TSRMLS_CC);
        !          1462: 
        !          1463:        if (retval)
        !          1464:                zval_ptr_dtor(&retval);
        !          1465:        
        !          1466:        return 0;
        !          1467: 
        !          1468: }
        !          1469: 
        !          1470: static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr TSRMLS_DC)
        !          1471: {
        !          1472:        php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
        !          1473:        zval func_name;
        !          1474:        zval *retval = NULL;
        !          1475:        zval *zcastas = NULL;
        !          1476:        zval **args[1];
        !          1477:        php_stream * intstream = NULL;
        !          1478:        int call_result;
        !          1479:        int ret = FAILURE;
        !          1480: 
        !          1481:        ZVAL_STRINGL(&func_name, USERSTREAM_CAST, sizeof(USERSTREAM_CAST)-1, 0);
        !          1482: 
        !          1483:        ALLOC_INIT_ZVAL(zcastas);
        !          1484:        switch(castas) {
        !          1485:        case PHP_STREAM_AS_FD_FOR_SELECT:
        !          1486:                ZVAL_LONG(zcastas, PHP_STREAM_AS_FD_FOR_SELECT);
        !          1487:                break;
        !          1488:        default:
        !          1489:                ZVAL_LONG(zcastas, PHP_STREAM_AS_STDIO);
        !          1490:                break;
        !          1491:        }
        !          1492:        args[0] = &zcastas;
        !          1493: 
        !          1494:        call_result = call_user_function_ex(NULL,
        !          1495:                        &us->object,
        !          1496:                        &func_name,
        !          1497:                        &retval,
        !          1498:                        1, args, 0, NULL TSRMLS_CC);
        !          1499: 
        !          1500:        do {
        !          1501:                if (call_result == FAILURE) {
        !          1502:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_CAST " is not implemented!",
        !          1503:                                        us->wrapper->classname);
        !          1504:                        break;
        !          1505:                }
        !          1506:                if (retval == NULL || !zend_is_true(retval)) {
        !          1507:                        break;
        !          1508:                }
        !          1509:                php_stream_from_zval_no_verify(intstream, &retval);
        !          1510:                if (!intstream) {
        !          1511:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_CAST " must return a stream resource",
        !          1512:                                        us->wrapper->classname);
        !          1513:                        break;
        !          1514:                }
        !          1515:                if (intstream == stream) {
        !          1516:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::" USERSTREAM_CAST " must not return itself",
        !          1517:                                        us->wrapper->classname);
        !          1518:                        intstream = NULL;
        !          1519:                        break;
        !          1520:                }
        !          1521:                ret = php_stream_cast(intstream, castas, retptr, 1);
        !          1522:        } while (0);
        !          1523: 
        !          1524:        if (retval) {
        !          1525:                zval_ptr_dtor(&retval);
        !          1526:        }
        !          1527:        if (zcastas) {
        !          1528:                zval_ptr_dtor(&zcastas);
        !          1529:        }
        !          1530: 
        !          1531:        return ret;
        !          1532: }
        !          1533: 
        !          1534: php_stream_ops php_stream_userspace_ops = {
        !          1535:        php_userstreamop_write, php_userstreamop_read,
        !          1536:        php_userstreamop_close, php_userstreamop_flush,
        !          1537:        "user-space",
        !          1538:        php_userstreamop_seek,
        !          1539:        php_userstreamop_cast,
        !          1540:        php_userstreamop_stat, 
        !          1541:        php_userstreamop_set_option,
        !          1542: };
        !          1543: 
        !          1544: php_stream_ops php_stream_userspace_dir_ops = {
        !          1545:        NULL, /* write */
        !          1546:        php_userstreamop_readdir,
        !          1547:        php_userstreamop_closedir,
        !          1548:        NULL, /* flush */
        !          1549:        "user-space-dir",
        !          1550:        php_userstreamop_rewinddir,
        !          1551:        NULL, /* cast */
        !          1552:        NULL, /* stat */
        !          1553:        NULL  /* set_option */
        !          1554: };
        !          1555: 
        !          1556: 

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