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