Annotation of embedaddon/php/main/streams/userspace.c, revision 1.1.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>