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

Generated by: LCOV version 1.10

Generated at Mon, 24 Jan 2022 01:16:37 +0000 (5 days ago)

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