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