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