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