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