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: 529 626 84.5 %
Date: 2014-10-22 Functions: 25 26 96.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 22 Oct 2014 07:25:04 +0000 (17 hours ago)

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