Annotation of embedaddon/php/main/streams/userspace.c, revision 1.1
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:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>