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

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

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