Annotation of embedaddon/php/main/streams/userspace.c, revision 1.1.1.2

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

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