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

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_HEAD/main/streams - userspace.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 636
Code covered: 87.1 % Executed lines: 554
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:47 +0000 (33 hours ago)

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