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