root/main/streams/userspace.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. stream_wrapper_dtor
  2. PHP_MINIT_FUNCTION
  3. user_stream_create_object
  4. user_wrapper_opener
  5. user_wrapper_opendir
  6. PHP_FUNCTION
  7. PHP_FUNCTION
  8. PHP_FUNCTION
  9. php_userstreamop_write
  10. php_userstreamop_read
  11. php_userstreamop_close
  12. php_userstreamop_flush
  13. php_userstreamop_seek
  14. statbuf_from_array
  15. php_userstreamop_stat
  16. php_userstreamop_set_option
  17. user_wrapper_unlink
  18. user_wrapper_rename
  19. user_wrapper_mkdir
  20. user_wrapper_rmdir
  21. user_wrapper_metadata
  22. user_wrapper_stat_url
  23. php_userstreamop_readdir
  24. php_userstreamop_closedir
  25. php_userstreamop_rewinddir
  26. php_userstreamop_cast

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

/* [<][>][^][v][top][bottom][index][help] */