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