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: 603 701 86.0 %
Date: 2014-08-04 Functions: 25 26 96.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Mon, 04 Aug 2014 15:49:19 +0000 (42 days ago)

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