PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - main/streams - userspace.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 566 655 86.4 %
Date: 2014-04-08 Functions: 23 24 95.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Tue, 08 Apr 2014 11:59:51 +0000 (8 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.