You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1322 lines
35 KiB

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