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