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

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