userspace.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Wez Furlong <wez@thebrainroom.com> |
  14. | Sara Golemon <pollita@php.net> |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "php.h"
  18. #include "php_globals.h"
  19. #include "ext/standard/file.h"
  20. #include "ext/standard/flock_compat.h"
  21. #ifdef HAVE_SYS_FILE_H
  22. #include <sys/file.h>
  23. #endif
  24. #include <stddef.h>
  25. #if HAVE_UTIME
  26. # ifdef PHP_WIN32
  27. # include <sys/utime.h>
  28. # else
  29. # include <utime.h>
  30. # endif
  31. #endif
  32. static int le_protocols;
  33. struct php_user_stream_wrapper {
  34. char * protoname;
  35. zend_class_entry *ce;
  36. php_stream_wrapper wrapper;
  37. };
  38. 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);
  39. static int user_wrapper_stat_url(php_stream_wrapper *wrapper, const char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context);
  40. static int user_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context);
  41. static int user_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to, int options, php_stream_context *context);
  42. static int user_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url, int mode, int options, php_stream_context *context);
  43. static int user_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context);
  44. static int user_wrapper_metadata(php_stream_wrapper *wrapper, const char *url, int option, void *value, php_stream_context *context);
  45. static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char *filename, const char *mode,
  46. int options, zend_string **opened_path, php_stream_context *context STREAMS_DC);
  47. static const php_stream_wrapper_ops user_stream_wops = {
  48. user_wrapper_opener,
  49. NULL, /* close - the streams themselves know how */
  50. NULL, /* stat - the streams themselves know how */
  51. user_wrapper_stat_url,
  52. user_wrapper_opendir,
  53. "user-space",
  54. user_wrapper_unlink,
  55. user_wrapper_rename,
  56. user_wrapper_mkdir,
  57. user_wrapper_rmdir,
  58. user_wrapper_metadata
  59. };
  60. static void stream_wrapper_dtor(zend_resource *rsrc)
  61. {
  62. struct php_user_stream_wrapper * uwrap = (struct php_user_stream_wrapper*)rsrc->ptr;
  63. efree(uwrap->protoname);
  64. efree(uwrap);
  65. }
  66. PHP_MINIT_FUNCTION(user_streams)
  67. {
  68. le_protocols = zend_register_list_destructors_ex(stream_wrapper_dtor, NULL, "stream factory", 0);
  69. if (le_protocols == FAILURE)
  70. return FAILURE;
  71. REGISTER_LONG_CONSTANT("STREAM_USE_PATH", USE_PATH, CONST_CS|CONST_PERSISTENT);
  72. REGISTER_LONG_CONSTANT("STREAM_IGNORE_URL", IGNORE_URL, CONST_CS|CONST_PERSISTENT);
  73. REGISTER_LONG_CONSTANT("STREAM_REPORT_ERRORS", REPORT_ERRORS, CONST_CS|CONST_PERSISTENT);
  74. REGISTER_LONG_CONSTANT("STREAM_MUST_SEEK", STREAM_MUST_SEEK, CONST_CS|CONST_PERSISTENT);
  75. REGISTER_LONG_CONSTANT("STREAM_URL_STAT_LINK", PHP_STREAM_URL_STAT_LINK, CONST_CS|CONST_PERSISTENT);
  76. REGISTER_LONG_CONSTANT("STREAM_URL_STAT_QUIET", PHP_STREAM_URL_STAT_QUIET, CONST_CS|CONST_PERSISTENT);
  77. REGISTER_LONG_CONSTANT("STREAM_MKDIR_RECURSIVE", PHP_STREAM_MKDIR_RECURSIVE, CONST_CS|CONST_PERSISTENT);
  78. REGISTER_LONG_CONSTANT("STREAM_IS_URL", PHP_STREAM_IS_URL, CONST_CS|CONST_PERSISTENT);
  79. REGISTER_LONG_CONSTANT("STREAM_OPTION_BLOCKING", PHP_STREAM_OPTION_BLOCKING, CONST_CS|CONST_PERSISTENT);
  80. REGISTER_LONG_CONSTANT("STREAM_OPTION_READ_TIMEOUT", PHP_STREAM_OPTION_READ_TIMEOUT, CONST_CS|CONST_PERSISTENT);
  81. REGISTER_LONG_CONSTANT("STREAM_OPTION_READ_BUFFER", PHP_STREAM_OPTION_READ_BUFFER, CONST_CS|CONST_PERSISTENT);
  82. REGISTER_LONG_CONSTANT("STREAM_OPTION_WRITE_BUFFER", PHP_STREAM_OPTION_WRITE_BUFFER, CONST_CS|CONST_PERSISTENT);
  83. REGISTER_LONG_CONSTANT("STREAM_BUFFER_NONE", PHP_STREAM_BUFFER_NONE, CONST_CS|CONST_PERSISTENT);
  84. REGISTER_LONG_CONSTANT("STREAM_BUFFER_LINE", PHP_STREAM_BUFFER_LINE, CONST_CS|CONST_PERSISTENT);
  85. REGISTER_LONG_CONSTANT("STREAM_BUFFER_FULL", PHP_STREAM_BUFFER_FULL, CONST_CS|CONST_PERSISTENT);
  86. REGISTER_LONG_CONSTANT("STREAM_CAST_AS_STREAM", PHP_STREAM_AS_STDIO, CONST_CS|CONST_PERSISTENT);
  87. REGISTER_LONG_CONSTANT("STREAM_CAST_FOR_SELECT", PHP_STREAM_AS_FD_FOR_SELECT, CONST_CS|CONST_PERSISTENT);
  88. REGISTER_LONG_CONSTANT("STREAM_META_TOUCH", PHP_STREAM_META_TOUCH, CONST_CS|CONST_PERSISTENT);
  89. REGISTER_LONG_CONSTANT("STREAM_META_OWNER", PHP_STREAM_META_OWNER, CONST_CS|CONST_PERSISTENT);
  90. REGISTER_LONG_CONSTANT("STREAM_META_OWNER_NAME", PHP_STREAM_META_OWNER_NAME, CONST_CS|CONST_PERSISTENT);
  91. REGISTER_LONG_CONSTANT("STREAM_META_GROUP", PHP_STREAM_META_GROUP, CONST_CS|CONST_PERSISTENT);
  92. REGISTER_LONG_CONSTANT("STREAM_META_GROUP_NAME", PHP_STREAM_META_GROUP_NAME, CONST_CS|CONST_PERSISTENT);
  93. REGISTER_LONG_CONSTANT("STREAM_META_ACCESS", PHP_STREAM_META_ACCESS, CONST_CS|CONST_PERSISTENT);
  94. return SUCCESS;
  95. }
  96. struct _php_userstream_data {
  97. struct php_user_stream_wrapper * wrapper;
  98. zval object;
  99. };
  100. typedef struct _php_userstream_data php_userstream_data_t;
  101. /* names of methods */
  102. #define USERSTREAM_OPEN "stream_open"
  103. #define USERSTREAM_CLOSE "stream_close"
  104. #define USERSTREAM_READ "stream_read"
  105. #define USERSTREAM_WRITE "stream_write"
  106. #define USERSTREAM_FLUSH "stream_flush"
  107. #define USERSTREAM_SEEK "stream_seek"
  108. #define USERSTREAM_TELL "stream_tell"
  109. #define USERSTREAM_EOF "stream_eof"
  110. #define USERSTREAM_STAT "stream_stat"
  111. #define USERSTREAM_STATURL "url_stat"
  112. #define USERSTREAM_UNLINK "unlink"
  113. #define USERSTREAM_RENAME "rename"
  114. #define USERSTREAM_MKDIR "mkdir"
  115. #define USERSTREAM_RMDIR "rmdir"
  116. #define USERSTREAM_DIR_OPEN "dir_opendir"
  117. #define USERSTREAM_DIR_READ "dir_readdir"
  118. #define USERSTREAM_DIR_REWIND "dir_rewinddir"
  119. #define USERSTREAM_DIR_CLOSE "dir_closedir"
  120. #define USERSTREAM_LOCK "stream_lock"
  121. #define USERSTREAM_CAST "stream_cast"
  122. #define USERSTREAM_SET_OPTION "stream_set_option"
  123. #define USERSTREAM_TRUNCATE "stream_truncate"
  124. #define USERSTREAM_METADATA "stream_metadata"
  125. /* {{{ class should have methods like these:
  126. function stream_open($path, $mode, $options, &$opened_path)
  127. {
  128. return true/false;
  129. }
  130. function stream_read($count)
  131. {
  132. return false on error;
  133. else return string;
  134. }
  135. function stream_write($data)
  136. {
  137. return false on error;
  138. else return count written;
  139. }
  140. function stream_close()
  141. {
  142. }
  143. function stream_flush()
  144. {
  145. return true/false;
  146. }
  147. function stream_seek($offset, $whence)
  148. {
  149. return true/false;
  150. }
  151. function stream_tell()
  152. {
  153. return (int)$position;
  154. }
  155. function stream_eof()
  156. {
  157. return true/false;
  158. }
  159. function stream_stat()
  160. {
  161. return array( just like that returned by fstat() );
  162. }
  163. function stream_cast($castas)
  164. {
  165. if ($castas == STREAM_CAST_FOR_SELECT) {
  166. return $this->underlying_stream;
  167. }
  168. return false;
  169. }
  170. function stream_set_option($option, $arg1, $arg2)
  171. {
  172. switch($option) {
  173. case STREAM_OPTION_BLOCKING:
  174. $blocking = $arg1;
  175. ...
  176. case STREAM_OPTION_READ_TIMEOUT:
  177. $sec = $arg1;
  178. $usec = $arg2;
  179. ...
  180. case STREAM_OPTION_WRITE_BUFFER:
  181. $mode = $arg1;
  182. $size = $arg2;
  183. ...
  184. default:
  185. return false;
  186. }
  187. }
  188. function url_stat(string $url, int $flags)
  189. {
  190. return array( just like that returned by stat() );
  191. }
  192. function unlink(string $url)
  193. {
  194. return true / false;
  195. }
  196. function rename(string $from, string $to)
  197. {
  198. return true / false;
  199. }
  200. function mkdir($dir, $mode, $options)
  201. {
  202. return true / false;
  203. }
  204. function rmdir($dir, $options)
  205. {
  206. return true / false;
  207. }
  208. function dir_opendir(string $url, int $options)
  209. {
  210. return true / false;
  211. }
  212. function dir_readdir()
  213. {
  214. return string next filename in dir ;
  215. }
  216. function dir_closedir()
  217. {
  218. release dir related resources;
  219. }
  220. function dir_rewinddir()
  221. {
  222. reset to start of dir list;
  223. }
  224. function stream_lock($operation)
  225. {
  226. return true / false;
  227. }
  228. function stream_truncate($new_size)
  229. {
  230. return true / false;
  231. }
  232. }}} **/
  233. static void user_stream_create_object(struct php_user_stream_wrapper *uwrap, php_stream_context *context, zval *object)
  234. {
  235. if (uwrap->ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
  236. ZVAL_UNDEF(object);
  237. return;
  238. }
  239. /* create an instance of our class */
  240. if (object_init_ex(object, uwrap->ce) == FAILURE) {
  241. ZVAL_UNDEF(object);
  242. return;
  243. }
  244. if (context) {
  245. GC_ADDREF(context->res);
  246. add_property_resource(object, "context", context->res);
  247. } else {
  248. add_property_null(object, "context");
  249. }
  250. if (uwrap->ce->constructor) {
  251. zend_call_known_instance_method_with_0_params(
  252. uwrap->ce->constructor, Z_OBJ_P(object), NULL);
  253. }
  254. }
  255. static php_stream *user_wrapper_opener(php_stream_wrapper *wrapper, const char *filename, const char *mode,
  256. int options, zend_string **opened_path, php_stream_context *context STREAMS_DC)
  257. {
  258. struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
  259. php_userstream_data_t *us;
  260. zval zretval, zfuncname;
  261. zval args[4];
  262. int call_result;
  263. php_stream *stream = NULL;
  264. bool old_in_user_include;
  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, "infinite recursion prevented");
  268. return NULL;
  269. }
  270. FG(user_stream_current_filename) = filename;
  271. /* if the user stream was registered as local and we are in include context,
  272. we add allow_url_include restrictions to allow_url_fopen ones */
  273. /* we need only is_url == 0 here since if is_url == 1 and remote wrappers
  274. were restricted we wouldn't get here */
  275. old_in_user_include = PG(in_user_include);
  276. if(uwrap->wrapper.is_url == 0 &&
  277. (options & STREAM_OPEN_FOR_INCLUDE) &&
  278. !PG(allow_url_include)) {
  279. PG(in_user_include) = 1;
  280. }
  281. us = emalloc(sizeof(*us));
  282. us->wrapper = uwrap;
  283. user_stream_create_object(uwrap, context, &us->object);
  284. if (Z_TYPE(us->object) == IS_UNDEF) {
  285. FG(user_stream_current_filename) = NULL;
  286. PG(in_user_include) = old_in_user_include;
  287. efree(us);
  288. return NULL;
  289. }
  290. /* call it's stream_open method - set up params first */
  291. ZVAL_STRING(&args[0], filename);
  292. ZVAL_STRING(&args[1], mode);
  293. ZVAL_LONG(&args[2], options);
  294. ZVAL_NEW_REF(&args[3], &EG(uninitialized_zval));
  295. ZVAL_STRING(&zfuncname, USERSTREAM_OPEN);
  296. zend_try {
  297. call_result = call_user_function(NULL,
  298. Z_ISUNDEF(us->object)? NULL : &us->object,
  299. &zfuncname,
  300. &zretval,
  301. 4, args);
  302. } zend_catch {
  303. FG(user_stream_current_filename) = NULL;
  304. zend_bailout();
  305. } zend_end_try();
  306. if (call_result == SUCCESS && Z_TYPE(zretval) != IS_UNDEF && zval_is_true(&zretval)) {
  307. /* the stream is now open! */
  308. stream = php_stream_alloc_rel(&php_stream_userspace_ops, us, 0, mode);
  309. /* if the opened path is set, copy it out */
  310. if (Z_ISREF(args[3]) && Z_TYPE_P(Z_REFVAL(args[3])) == IS_STRING && opened_path) {
  311. *opened_path = zend_string_copy(Z_STR_P(Z_REFVAL(args[3])));
  312. }
  313. /* set wrapper data to be a reference to our object */
  314. ZVAL_COPY(&stream->wrapperdata, &us->object);
  315. } else {
  316. php_stream_wrapper_log_error(wrapper, options, "\"%s::" USERSTREAM_OPEN "\" call failed",
  317. ZSTR_VAL(us->wrapper->ce->name));
  318. }
  319. /* destroy everything else */
  320. if (stream == NULL) {
  321. zval_ptr_dtor(&us->object);
  322. ZVAL_UNDEF(&us->object);
  323. efree(us);
  324. }
  325. zval_ptr_dtor(&zretval);
  326. zval_ptr_dtor(&zfuncname);
  327. zval_ptr_dtor(&args[3]);
  328. zval_ptr_dtor(&args[2]);
  329. zval_ptr_dtor(&args[1]);
  330. zval_ptr_dtor(&args[0]);
  331. FG(user_stream_current_filename) = NULL;
  332. PG(in_user_include) = old_in_user_include;
  333. return stream;
  334. }
  335. static php_stream *user_wrapper_opendir(php_stream_wrapper *wrapper, const char *filename, const char *mode,
  336. int options, zend_string **opened_path, php_stream_context *context STREAMS_DC)
  337. {
  338. struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
  339. php_userstream_data_t *us;
  340. zval zretval, zfuncname;
  341. zval args[2];
  342. int call_result;
  343. php_stream *stream = NULL;
  344. /* Try to catch bad usage without preventing flexibility */
  345. if (FG(user_stream_current_filename) != NULL && strcmp(filename, FG(user_stream_current_filename)) == 0) {
  346. php_stream_wrapper_log_error(wrapper, options, "infinite recursion prevented");
  347. return NULL;
  348. }
  349. FG(user_stream_current_filename) = filename;
  350. us = emalloc(sizeof(*us));
  351. us->wrapper = uwrap;
  352. user_stream_create_object(uwrap, context, &us->object);
  353. if (Z_TYPE(us->object) == IS_UNDEF) {
  354. FG(user_stream_current_filename) = NULL;
  355. efree(us);
  356. return NULL;
  357. }
  358. /* call it's dir_open method - set up params first */
  359. ZVAL_STRING(&args[0], filename);
  360. ZVAL_LONG(&args[1], options);
  361. ZVAL_STRING(&zfuncname, USERSTREAM_DIR_OPEN);
  362. call_result = call_user_function(NULL,
  363. Z_ISUNDEF(us->object)? NULL : &us->object,
  364. &zfuncname,
  365. &zretval,
  366. 2, args);
  367. if (call_result == SUCCESS && Z_TYPE(zretval) != IS_UNDEF && zval_is_true(&zretval)) {
  368. /* the stream is now open! */
  369. stream = php_stream_alloc_rel(&php_stream_userspace_dir_ops, us, 0, mode);
  370. /* set wrapper data to be a reference to our object */
  371. ZVAL_COPY(&stream->wrapperdata, &us->object);
  372. } else {
  373. php_stream_wrapper_log_error(wrapper, options, "\"%s::" USERSTREAM_DIR_OPEN "\" call failed",
  374. ZSTR_VAL(us->wrapper->ce->name));
  375. }
  376. /* destroy everything else */
  377. if (stream == NULL) {
  378. zval_ptr_dtor(&us->object);
  379. ZVAL_UNDEF(&us->object);
  380. efree(us);
  381. }
  382. zval_ptr_dtor(&zretval);
  383. zval_ptr_dtor(&zfuncname);
  384. zval_ptr_dtor(&args[1]);
  385. zval_ptr_dtor(&args[0]);
  386. FG(user_stream_current_filename) = NULL;
  387. return stream;
  388. }
  389. /* {{{ Registers a custom URL protocol handler class */
  390. PHP_FUNCTION(stream_wrapper_register)
  391. {
  392. zend_string *protocol;
  393. struct php_user_stream_wrapper *uwrap;
  394. zend_class_entry *ce = NULL;
  395. zend_resource *rsrc;
  396. zend_long flags = 0;
  397. if (zend_parse_parameters(ZEND_NUM_ARGS(), "SC|l", &protocol, &ce, &flags) == FAILURE) {
  398. RETURN_THROWS();
  399. }
  400. uwrap = (struct php_user_stream_wrapper *)ecalloc(1, sizeof(*uwrap));
  401. uwrap->ce = ce;
  402. uwrap->protoname = estrndup(ZSTR_VAL(protocol), ZSTR_LEN(protocol));
  403. uwrap->wrapper.wops = &user_stream_wops;
  404. uwrap->wrapper.abstract = uwrap;
  405. uwrap->wrapper.is_url = ((flags & PHP_STREAM_IS_URL) != 0);
  406. rsrc = zend_register_resource(uwrap, le_protocols);
  407. if (php_register_url_stream_wrapper_volatile(protocol, &uwrap->wrapper) == SUCCESS) {
  408. RETURN_TRUE;
  409. }
  410. /* We failed. But why? */
  411. if (zend_hash_exists(php_stream_get_url_stream_wrappers_hash(), protocol)) {
  412. php_error_docref(NULL, E_WARNING, "Protocol %s:// is already defined.", ZSTR_VAL(protocol));
  413. } else {
  414. /* Hash doesn't exist so it must have been an invalid protocol scheme */
  415. php_error_docref(NULL, E_WARNING, "Invalid protocol scheme specified. Unable to register wrapper class %s to %s://", ZSTR_VAL(uwrap->ce->name), ZSTR_VAL(protocol));
  416. }
  417. zend_list_delete(rsrc);
  418. RETURN_FALSE;
  419. }
  420. /* }}} */
  421. /* {{{ Unregister a wrapper for the life of the current request. */
  422. PHP_FUNCTION(stream_wrapper_unregister)
  423. {
  424. zend_string *protocol;
  425. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &protocol) == FAILURE) {
  426. RETURN_THROWS();
  427. }
  428. if (php_unregister_url_stream_wrapper_volatile(protocol) == FAILURE) {
  429. /* We failed */
  430. php_error_docref(NULL, E_WARNING, "Unable to unregister protocol %s://", ZSTR_VAL(protocol));
  431. RETURN_FALSE;
  432. }
  433. RETURN_TRUE;
  434. }
  435. /* }}} */
  436. /* {{{ Restore the original protocol handler, overriding if necessary */
  437. PHP_FUNCTION(stream_wrapper_restore)
  438. {
  439. zend_string *protocol;
  440. php_stream_wrapper *wrapper;
  441. HashTable *global_wrapper_hash, *wrapper_hash;
  442. if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &protocol) == FAILURE) {
  443. RETURN_THROWS();
  444. }
  445. global_wrapper_hash = php_stream_get_url_stream_wrappers_hash_global();
  446. if ((wrapper = zend_hash_find_ptr(global_wrapper_hash, protocol)) == NULL) {
  447. php_error_docref(NULL, E_WARNING, "%s:// never existed, nothing to restore", ZSTR_VAL(protocol));
  448. RETURN_FALSE;
  449. }
  450. wrapper_hash = php_stream_get_url_stream_wrappers_hash();
  451. if (wrapper_hash == global_wrapper_hash || zend_hash_find_ptr(wrapper_hash, protocol) == wrapper) {
  452. php_error_docref(NULL, E_NOTICE, "%s:// was never changed, nothing to restore", ZSTR_VAL(protocol));
  453. RETURN_TRUE;
  454. }
  455. /* A failure here could be okay given that the protocol might have been merely unregistered */
  456. php_unregister_url_stream_wrapper_volatile(protocol);
  457. if (php_register_url_stream_wrapper_volatile(protocol, wrapper) == FAILURE) {
  458. php_error_docref(NULL, E_WARNING, "Unable to restore original %s:// wrapper", ZSTR_VAL(protocol));
  459. RETURN_FALSE;
  460. }
  461. RETURN_TRUE;
  462. }
  463. /* }}} */
  464. static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_t count)
  465. {
  466. zval func_name;
  467. zval retval;
  468. int call_result;
  469. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  470. zval args[1];
  471. ssize_t didwrite;
  472. assert(us != NULL);
  473. ZVAL_STRINGL(&func_name, USERSTREAM_WRITE, sizeof(USERSTREAM_WRITE)-1);
  474. ZVAL_STRINGL(&args[0], (char*)buf, count);
  475. call_result = call_user_function(NULL,
  476. Z_ISUNDEF(us->object)? NULL : &us->object,
  477. &func_name,
  478. &retval,
  479. 1, args);
  480. zval_ptr_dtor(&args[0]);
  481. zval_ptr_dtor(&func_name);
  482. if (EG(exception)) {
  483. return -1;
  484. }
  485. if (call_result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
  486. if (Z_TYPE(retval) == IS_FALSE) {
  487. didwrite = -1;
  488. } else {
  489. convert_to_long(&retval);
  490. didwrite = Z_LVAL(retval);
  491. }
  492. } else {
  493. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_WRITE " is not implemented!",
  494. ZSTR_VAL(us->wrapper->ce->name));
  495. didwrite = -1;
  496. }
  497. /* don't allow strange buffer overruns due to bogus return */
  498. if (didwrite > 0 && didwrite > count) {
  499. 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)",
  500. ZSTR_VAL(us->wrapper->ce->name),
  501. (zend_long)(didwrite - count), (zend_long)didwrite, (zend_long)count);
  502. didwrite = count;
  503. }
  504. zval_ptr_dtor(&retval);
  505. return didwrite;
  506. }
  507. static ssize_t php_userstreamop_read(php_stream *stream, char *buf, size_t count)
  508. {
  509. zval func_name;
  510. zval retval;
  511. zval args[1];
  512. int call_result;
  513. size_t didread = 0;
  514. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  515. assert(us != NULL);
  516. ZVAL_STRINGL(&func_name, USERSTREAM_READ, sizeof(USERSTREAM_READ)-1);
  517. ZVAL_LONG(&args[0], count);
  518. call_result = call_user_function(NULL,
  519. Z_ISUNDEF(us->object)? NULL : &us->object,
  520. &func_name,
  521. &retval,
  522. 1, args);
  523. zval_ptr_dtor(&args[0]);
  524. zval_ptr_dtor(&func_name);
  525. if (EG(exception)) {
  526. return -1;
  527. }
  528. if (call_result == FAILURE) {
  529. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_READ " is not implemented!",
  530. ZSTR_VAL(us->wrapper->ce->name));
  531. return -1;
  532. }
  533. if (Z_TYPE(retval) == IS_FALSE) {
  534. return -1;
  535. }
  536. if (!try_convert_to_string(&retval)) {
  537. zval_ptr_dtor(&retval);
  538. return -1;
  539. }
  540. didread = Z_STRLEN(retval);
  541. if (didread > 0) {
  542. if (didread > count) {
  543. 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",
  544. ZSTR_VAL(us->wrapper->ce->name), (zend_long)(didread - count), (zend_long)didread, (zend_long)count);
  545. didread = count;
  546. }
  547. memcpy(buf, Z_STRVAL(retval), didread);
  548. }
  549. zval_ptr_dtor(&retval);
  550. ZVAL_UNDEF(&retval);
  551. /* since the user stream has no way of setting the eof flag directly, we need to ask it if we hit eof */
  552. ZVAL_STRINGL(&func_name, USERSTREAM_EOF, sizeof(USERSTREAM_EOF)-1);
  553. call_result = call_user_function(NULL,
  554. Z_ISUNDEF(us->object)? NULL : &us->object,
  555. &func_name,
  556. &retval,
  557. 0, NULL);
  558. zval_ptr_dtor(&func_name);
  559. if (EG(exception)) {
  560. stream->eof = 1;
  561. return -1;
  562. }
  563. if (call_result == SUCCESS && Z_TYPE(retval) != IS_UNDEF && zval_is_true(&retval)) {
  564. stream->eof = 1;
  565. } else if (call_result == FAILURE) {
  566. php_error_docref(NULL, E_WARNING,
  567. "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF",
  568. ZSTR_VAL(us->wrapper->ce->name));
  569. stream->eof = 1;
  570. }
  571. zval_ptr_dtor(&retval);
  572. return didread;
  573. }
  574. static int php_userstreamop_close(php_stream *stream, int close_handle)
  575. {
  576. zval func_name;
  577. zval retval;
  578. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  579. assert(us != NULL);
  580. ZVAL_STRINGL(&func_name, USERSTREAM_CLOSE, sizeof(USERSTREAM_CLOSE)-1);
  581. call_user_function(NULL,
  582. Z_ISUNDEF(us->object)? NULL : &us->object,
  583. &func_name,
  584. &retval,
  585. 0, NULL);
  586. zval_ptr_dtor(&retval);
  587. zval_ptr_dtor(&func_name);
  588. zval_ptr_dtor(&us->object);
  589. ZVAL_UNDEF(&us->object);
  590. efree(us);
  591. return 0;
  592. }
  593. static int php_userstreamop_flush(php_stream *stream)
  594. {
  595. zval func_name;
  596. zval retval;
  597. int call_result;
  598. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  599. assert(us != NULL);
  600. ZVAL_STRINGL(&func_name, USERSTREAM_FLUSH, sizeof(USERSTREAM_FLUSH)-1);
  601. call_result = call_user_function(NULL,
  602. Z_ISUNDEF(us->object)? NULL : &us->object,
  603. &func_name,
  604. &retval,
  605. 0, NULL);
  606. if (call_result == SUCCESS && Z_TYPE(retval) != IS_UNDEF && zval_is_true(&retval))
  607. call_result = 0;
  608. else
  609. call_result = -1;
  610. zval_ptr_dtor(&retval);
  611. zval_ptr_dtor(&func_name);
  612. return call_result;
  613. }
  614. static int php_userstreamop_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs)
  615. {
  616. zval func_name;
  617. zval retval;
  618. int call_result, ret;
  619. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  620. zval args[2];
  621. assert(us != NULL);
  622. ZVAL_STRINGL(&func_name, USERSTREAM_SEEK, sizeof(USERSTREAM_SEEK)-1);
  623. ZVAL_LONG(&args[0], offset);
  624. ZVAL_LONG(&args[1], whence);
  625. call_result = call_user_function(NULL,
  626. Z_ISUNDEF(us->object)? NULL : &us->object,
  627. &func_name,
  628. &retval,
  629. 2, args);
  630. zval_ptr_dtor(&args[0]);
  631. zval_ptr_dtor(&args[1]);
  632. zval_ptr_dtor(&func_name);
  633. if (call_result == FAILURE) {
  634. /* stream_seek is not implemented, so disable seeks for this stream */
  635. stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
  636. /* there should be no retval to clean up */
  637. zval_ptr_dtor(&retval);
  638. return -1;
  639. } else if (call_result == SUCCESS && Z_TYPE(retval) != IS_UNDEF && zval_is_true(&retval)) {
  640. ret = 0;
  641. } else {
  642. ret = -1;
  643. }
  644. zval_ptr_dtor(&retval);
  645. ZVAL_UNDEF(&retval);
  646. if (ret) {
  647. return ret;
  648. }
  649. /* now determine where we are */
  650. ZVAL_STRINGL(&func_name, USERSTREAM_TELL, sizeof(USERSTREAM_TELL)-1);
  651. call_result = call_user_function(NULL,
  652. Z_ISUNDEF(us->object)? NULL : &us->object,
  653. &func_name,
  654. &retval,
  655. 0, NULL);
  656. if (call_result == SUCCESS && Z_TYPE(retval) == IS_LONG) {
  657. *newoffs = Z_LVAL(retval);
  658. ret = 0;
  659. } else if (call_result == FAILURE) {
  660. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_TELL " is not implemented!", ZSTR_VAL(us->wrapper->ce->name));
  661. ret = -1;
  662. } else {
  663. ret = -1;
  664. }
  665. zval_ptr_dtor(&retval);
  666. zval_ptr_dtor(&func_name);
  667. return ret;
  668. }
  669. /* parse the return value from one of the stat functions and store the
  670. * relevant fields into the statbuf provided */
  671. static int statbuf_from_array(zval *array, php_stream_statbuf *ssb)
  672. {
  673. zval *elem;
  674. #define STAT_PROP_ENTRY_EX(name, name2) \
  675. if (NULL != (elem = zend_hash_str_find(Z_ARRVAL_P(array), #name, sizeof(#name)-1))) { \
  676. ssb->sb.st_##name2 = zval_get_long(elem); \
  677. }
  678. #define STAT_PROP_ENTRY(name) STAT_PROP_ENTRY_EX(name,name)
  679. memset(ssb, 0, sizeof(php_stream_statbuf));
  680. STAT_PROP_ENTRY(dev);
  681. STAT_PROP_ENTRY(ino);
  682. STAT_PROP_ENTRY(mode);
  683. STAT_PROP_ENTRY(nlink);
  684. STAT_PROP_ENTRY(uid);
  685. STAT_PROP_ENTRY(gid);
  686. #if HAVE_STRUCT_STAT_ST_RDEV
  687. STAT_PROP_ENTRY(rdev);
  688. #endif
  689. STAT_PROP_ENTRY(size);
  690. STAT_PROP_ENTRY(atime);
  691. STAT_PROP_ENTRY(mtime);
  692. STAT_PROP_ENTRY(ctime);
  693. #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
  694. STAT_PROP_ENTRY(blksize);
  695. #endif
  696. #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
  697. STAT_PROP_ENTRY(blocks);
  698. #endif
  699. #undef STAT_PROP_ENTRY
  700. #undef STAT_PROP_ENTRY_EX
  701. return SUCCESS;
  702. }
  703. static int php_userstreamop_stat(php_stream *stream, php_stream_statbuf *ssb)
  704. {
  705. zval func_name;
  706. zval retval;
  707. int call_result;
  708. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  709. int ret = -1;
  710. ZVAL_STRINGL(&func_name, USERSTREAM_STAT, sizeof(USERSTREAM_STAT)-1);
  711. call_result = call_user_function(NULL,
  712. Z_ISUNDEF(us->object)? NULL : &us->object,
  713. &func_name,
  714. &retval,
  715. 0, NULL);
  716. if (call_result == SUCCESS && Z_TYPE(retval) == IS_ARRAY) {
  717. if (SUCCESS == statbuf_from_array(&retval, ssb))
  718. ret = 0;
  719. } else {
  720. if (call_result == FAILURE) {
  721. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_STAT " is not implemented!",
  722. ZSTR_VAL(us->wrapper->ce->name));
  723. }
  724. }
  725. zval_ptr_dtor(&retval);
  726. zval_ptr_dtor(&func_name);
  727. return ret;
  728. }
  729. static int php_userstreamop_set_option(php_stream *stream, int option, int value, void *ptrparam) {
  730. zval func_name;
  731. zval retval;
  732. int call_result;
  733. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  734. int ret = PHP_STREAM_OPTION_RETURN_NOTIMPL;
  735. zval args[3];
  736. switch (option) {
  737. case PHP_STREAM_OPTION_CHECK_LIVENESS:
  738. ZVAL_STRINGL(&func_name, USERSTREAM_EOF, sizeof(USERSTREAM_EOF)-1);
  739. call_result = call_user_function(NULL, Z_ISUNDEF(us->object)? NULL : &us->object, &func_name, &retval, 0, NULL);
  740. if (call_result == SUCCESS && (Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE)) {
  741. ret = zval_is_true(&retval) ? PHP_STREAM_OPTION_RETURN_ERR : PHP_STREAM_OPTION_RETURN_OK;
  742. } else {
  743. ret = PHP_STREAM_OPTION_RETURN_ERR;
  744. php_error_docref(NULL, E_WARNING,
  745. "%s::" USERSTREAM_EOF " is not implemented! Assuming EOF",
  746. ZSTR_VAL(us->wrapper->ce->name));
  747. }
  748. zval_ptr_dtor(&retval);
  749. zval_ptr_dtor(&func_name);
  750. break;
  751. case PHP_STREAM_OPTION_LOCKING:
  752. ZVAL_LONG(&args[0], 0);
  753. if (value & LOCK_NB) {
  754. Z_LVAL_P(&args[0]) |= PHP_LOCK_NB;
  755. }
  756. switch(value & ~LOCK_NB) {
  757. case LOCK_SH:
  758. Z_LVAL_P(&args[0]) |= PHP_LOCK_SH;
  759. break;
  760. case LOCK_EX:
  761. Z_LVAL_P(&args[0]) |= PHP_LOCK_EX;
  762. break;
  763. case LOCK_UN:
  764. Z_LVAL_P(&args[0]) |= PHP_LOCK_UN;
  765. break;
  766. }
  767. /* TODO wouldblock */
  768. ZVAL_STRINGL(&func_name, USERSTREAM_LOCK, sizeof(USERSTREAM_LOCK)-1);
  769. call_result = call_user_function(NULL,
  770. Z_ISUNDEF(us->object)? NULL : &us->object,
  771. &func_name,
  772. &retval,
  773. 1, args);
  774. if (call_result == SUCCESS && (Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE)) {
  775. ret = (Z_TYPE(retval) == IS_FALSE);
  776. } else if (call_result == FAILURE) {
  777. if (value == 0) {
  778. /* lock support test (TODO: more check) */
  779. ret = PHP_STREAM_OPTION_RETURN_OK;
  780. } else {
  781. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_LOCK " is not implemented!",
  782. ZSTR_VAL(us->wrapper->ce->name));
  783. ret = PHP_STREAM_OPTION_RETURN_ERR;
  784. }
  785. }
  786. zval_ptr_dtor(&retval);
  787. zval_ptr_dtor(&func_name);
  788. zval_ptr_dtor(&args[0]);
  789. break;
  790. case PHP_STREAM_OPTION_TRUNCATE_API:
  791. ZVAL_STRINGL(&func_name, USERSTREAM_TRUNCATE, sizeof(USERSTREAM_TRUNCATE)-1);
  792. switch (value) {
  793. case PHP_STREAM_TRUNCATE_SUPPORTED:
  794. if (zend_is_callable_ex(&func_name,
  795. Z_ISUNDEF(us->object)? NULL : Z_OBJ(us->object),
  796. 0, NULL, NULL, NULL))
  797. ret = PHP_STREAM_OPTION_RETURN_OK;
  798. else
  799. ret = PHP_STREAM_OPTION_RETURN_ERR;
  800. break;
  801. case PHP_STREAM_TRUNCATE_SET_SIZE: {
  802. ptrdiff_t new_size = *(ptrdiff_t*) ptrparam;
  803. if (new_size >= 0 && new_size <= (ptrdiff_t)LONG_MAX) {
  804. ZVAL_LONG(&args[0], (zend_long)new_size);
  805. call_result = call_user_function(NULL,
  806. Z_ISUNDEF(us->object)? NULL : &us->object,
  807. &func_name,
  808. &retval,
  809. 1, args);
  810. if (call_result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
  811. if (Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE) {
  812. ret = (Z_TYPE(retval) == IS_TRUE) ? PHP_STREAM_OPTION_RETURN_OK :
  813. PHP_STREAM_OPTION_RETURN_ERR;
  814. } else {
  815. php_error_docref(NULL, E_WARNING,
  816. "%s::" USERSTREAM_TRUNCATE " did not return a boolean!",
  817. ZSTR_VAL(us->wrapper->ce->name));
  818. }
  819. } else {
  820. php_error_docref(NULL, E_WARNING,
  821. "%s::" USERSTREAM_TRUNCATE " is not implemented!",
  822. ZSTR_VAL(us->wrapper->ce->name));
  823. }
  824. zval_ptr_dtor(&retval);
  825. zval_ptr_dtor(&args[0]);
  826. } else { /* bad new size */
  827. ret = PHP_STREAM_OPTION_RETURN_ERR;
  828. }
  829. break;
  830. }
  831. }
  832. zval_ptr_dtor(&func_name);
  833. break;
  834. case PHP_STREAM_OPTION_READ_BUFFER:
  835. case PHP_STREAM_OPTION_WRITE_BUFFER:
  836. case PHP_STREAM_OPTION_READ_TIMEOUT:
  837. case PHP_STREAM_OPTION_BLOCKING: {
  838. ZVAL_STRINGL(&func_name, USERSTREAM_SET_OPTION, sizeof(USERSTREAM_SET_OPTION)-1);
  839. ZVAL_LONG(&args[0], option);
  840. ZVAL_NULL(&args[1]);
  841. ZVAL_NULL(&args[2]);
  842. switch(option) {
  843. case PHP_STREAM_OPTION_READ_BUFFER:
  844. case PHP_STREAM_OPTION_WRITE_BUFFER:
  845. ZVAL_LONG(&args[1], value);
  846. if (ptrparam) {
  847. ZVAL_LONG(&args[2], *(long *)ptrparam);
  848. } else {
  849. ZVAL_LONG(&args[2], BUFSIZ);
  850. }
  851. break;
  852. case PHP_STREAM_OPTION_READ_TIMEOUT: {
  853. struct timeval tv = *(struct timeval*)ptrparam;
  854. ZVAL_LONG(&args[1], tv.tv_sec);
  855. ZVAL_LONG(&args[2], tv.tv_usec);
  856. break;
  857. }
  858. case PHP_STREAM_OPTION_BLOCKING:
  859. ZVAL_LONG(&args[1], value);
  860. break;
  861. default:
  862. break;
  863. }
  864. call_result = call_user_function(NULL,
  865. Z_ISUNDEF(us->object)? NULL : &us->object,
  866. &func_name,
  867. &retval,
  868. 3, args);
  869. if (call_result == FAILURE) {
  870. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_SET_OPTION " is not implemented!",
  871. ZSTR_VAL(us->wrapper->ce->name));
  872. ret = PHP_STREAM_OPTION_RETURN_ERR;
  873. } else if (zend_is_true(&retval)) {
  874. ret = PHP_STREAM_OPTION_RETURN_OK;
  875. } else {
  876. ret = PHP_STREAM_OPTION_RETURN_ERR;
  877. }
  878. zval_ptr_dtor(&retval);
  879. zval_ptr_dtor(&args[2]);
  880. zval_ptr_dtor(&args[1]);
  881. zval_ptr_dtor(&args[0]);
  882. zval_ptr_dtor(&func_name);
  883. break;
  884. }
  885. }
  886. return ret;
  887. }
  888. static int user_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context)
  889. {
  890. struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
  891. zval zfuncname, zretval;
  892. zval args[1];
  893. int call_result;
  894. zval object;
  895. int ret = 0;
  896. /* create an instance of our class */
  897. user_stream_create_object(uwrap, context, &object);
  898. if (Z_TYPE(object) == IS_UNDEF) {
  899. return ret;
  900. }
  901. /* call the unlink method */
  902. ZVAL_STRING(&args[0], url);
  903. ZVAL_STRING(&zfuncname, USERSTREAM_UNLINK);
  904. call_result = call_user_function(NULL,
  905. &object,
  906. &zfuncname,
  907. &zretval,
  908. 1, args);
  909. if (call_result == SUCCESS && (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE)) {
  910. ret = (Z_TYPE(zretval) == IS_TRUE);
  911. } else if (call_result == FAILURE) {
  912. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_UNLINK " is not implemented!", ZSTR_VAL(uwrap->ce->name));
  913. }
  914. /* clean up */
  915. zval_ptr_dtor(&object);
  916. zval_ptr_dtor(&zretval);
  917. zval_ptr_dtor(&zfuncname);
  918. zval_ptr_dtor(&args[0]);
  919. return ret;
  920. }
  921. static int user_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to,
  922. int options, php_stream_context *context)
  923. {
  924. struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
  925. zval zfuncname, zretval;
  926. zval args[2];
  927. int call_result;
  928. zval object;
  929. int ret = 0;
  930. /* create an instance of our class */
  931. user_stream_create_object(uwrap, context, &object);
  932. if (Z_TYPE(object) == IS_UNDEF) {
  933. return ret;
  934. }
  935. /* call the rename method */
  936. ZVAL_STRING(&args[0], url_from);
  937. ZVAL_STRING(&args[1], url_to);
  938. ZVAL_STRING(&zfuncname, USERSTREAM_RENAME);
  939. call_result = call_user_function(NULL,
  940. &object,
  941. &zfuncname,
  942. &zretval,
  943. 2, args);
  944. if (call_result == SUCCESS && (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE)) {
  945. ret = (Z_TYPE(zretval) == IS_TRUE);
  946. } else if (call_result == FAILURE) {
  947. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_RENAME " is not implemented!", ZSTR_VAL(uwrap->ce->name));
  948. }
  949. /* clean up */
  950. zval_ptr_dtor(&object);
  951. zval_ptr_dtor(&zretval);
  952. zval_ptr_dtor(&zfuncname);
  953. zval_ptr_dtor(&args[1]);
  954. zval_ptr_dtor(&args[0]);
  955. return ret;
  956. }
  957. static int user_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url, int mode,
  958. int options, php_stream_context *context)
  959. {
  960. struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
  961. zval zfuncname, zretval;
  962. zval args[3];
  963. int call_result;
  964. zval object;
  965. int ret = 0;
  966. /* create an instance of our class */
  967. user_stream_create_object(uwrap, context, &object);
  968. if (Z_TYPE(object) == IS_UNDEF) {
  969. return ret;
  970. }
  971. /* call the mkdir method */
  972. ZVAL_STRING(&args[0], url);
  973. ZVAL_LONG(&args[1], mode);
  974. ZVAL_LONG(&args[2], options);
  975. ZVAL_STRING(&zfuncname, USERSTREAM_MKDIR);
  976. call_result = call_user_function(NULL,
  977. &object,
  978. &zfuncname,
  979. &zretval,
  980. 3, args);
  981. if (call_result == SUCCESS && (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE)) {
  982. ret = (Z_TYPE(zretval) == IS_TRUE);
  983. } else if (call_result == FAILURE) {
  984. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_MKDIR " is not implemented!", ZSTR_VAL(uwrap->ce->name));
  985. }
  986. /* clean up */
  987. zval_ptr_dtor(&object);
  988. zval_ptr_dtor(&zretval);
  989. zval_ptr_dtor(&zfuncname);
  990. zval_ptr_dtor(&args[2]);
  991. zval_ptr_dtor(&args[1]);
  992. zval_ptr_dtor(&args[0]);
  993. return ret;
  994. }
  995. static int user_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url,
  996. int options, php_stream_context *context)
  997. {
  998. struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
  999. zval zfuncname, zretval;
  1000. zval args[2];
  1001. int call_result;
  1002. zval object;
  1003. int ret = 0;
  1004. /* create an instance of our class */
  1005. user_stream_create_object(uwrap, context, &object);
  1006. if (Z_TYPE(object) == IS_UNDEF) {
  1007. return ret;
  1008. }
  1009. /* call the rmdir method */
  1010. ZVAL_STRING(&args[0], url);
  1011. ZVAL_LONG(&args[1], options);
  1012. ZVAL_STRING(&zfuncname, USERSTREAM_RMDIR);
  1013. call_result = call_user_function(NULL,
  1014. &object,
  1015. &zfuncname,
  1016. &zretval,
  1017. 2, args);
  1018. if (call_result == SUCCESS && (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE)) {
  1019. ret = (Z_TYPE(zretval) == IS_TRUE);
  1020. } else if (call_result == FAILURE) {
  1021. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_RMDIR " is not implemented!", ZSTR_VAL(uwrap->ce->name));
  1022. }
  1023. /* clean up */
  1024. zval_ptr_dtor(&object);
  1025. zval_ptr_dtor(&zretval);
  1026. zval_ptr_dtor(&zfuncname);
  1027. zval_ptr_dtor(&args[1]);
  1028. zval_ptr_dtor(&args[0]);
  1029. return ret;
  1030. }
  1031. static int user_wrapper_metadata(php_stream_wrapper *wrapper, const char *url, int option,
  1032. void *value, php_stream_context *context)
  1033. {
  1034. struct php_user_stream_wrapper *uwrap = (struct php_user_stream_wrapper*)wrapper->abstract;
  1035. zval zfuncname, zretval;
  1036. zval args[3];
  1037. int call_result;
  1038. zval object;
  1039. int ret = 0;
  1040. switch(option) {
  1041. case PHP_STREAM_META_TOUCH:
  1042. array_init(&args[2]);
  1043. if(value) {
  1044. struct utimbuf *newtime = (struct utimbuf *)value;
  1045. add_index_long(&args[2], 0, newtime->modtime);
  1046. add_index_long(&args[2], 1, newtime->actime);
  1047. }
  1048. break;
  1049. case PHP_STREAM_META_GROUP:
  1050. case PHP_STREAM_META_OWNER:
  1051. case PHP_STREAM_META_ACCESS:
  1052. ZVAL_LONG(&args[2], *(long *)value);
  1053. break;
  1054. case PHP_STREAM_META_GROUP_NAME:
  1055. case PHP_STREAM_META_OWNER_NAME:
  1056. ZVAL_STRING(&args[2], value);
  1057. break;
  1058. default:
  1059. php_error_docref(NULL, E_WARNING, "Unknown option %d for " USERSTREAM_METADATA, option);
  1060. zval_ptr_dtor(&args[2]);
  1061. return ret;
  1062. }
  1063. /* create an instance of our class */
  1064. user_stream_create_object(uwrap, context, &object);
  1065. if (Z_TYPE(object) == IS_UNDEF) {
  1066. zval_ptr_dtor(&args[2]);
  1067. return ret;
  1068. }
  1069. /* call the mkdir method */
  1070. ZVAL_STRING(&args[0], url);
  1071. ZVAL_LONG(&args[1], option);
  1072. ZVAL_STRING(&zfuncname, USERSTREAM_METADATA);
  1073. call_result = call_user_function(NULL,
  1074. &object,
  1075. &zfuncname,
  1076. &zretval,
  1077. 3, args);
  1078. if (call_result == SUCCESS && (Z_TYPE(zretval) == IS_FALSE || Z_TYPE(zretval) == IS_TRUE)) {
  1079. ret = Z_TYPE(zretval) == IS_TRUE;
  1080. } else if (call_result == FAILURE) {
  1081. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_METADATA " is not implemented!", ZSTR_VAL(uwrap->ce->name));
  1082. }
  1083. /* clean up */
  1084. zval_ptr_dtor(&object);
  1085. zval_ptr_dtor(&zretval);
  1086. zval_ptr_dtor(&zfuncname);
  1087. zval_ptr_dtor(&args[0]);
  1088. zval_ptr_dtor(&args[1]);
  1089. zval_ptr_dtor(&args[2]);
  1090. return ret;
  1091. }
  1092. static int user_wrapper_stat_url(php_stream_wrapper *wrapper, const char *url, int flags,
  1093. php_stream_statbuf *ssb, 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[2];
  1098. int call_result;
  1099. zval object;
  1100. int ret = -1;
  1101. /* create an instance of our class */
  1102. user_stream_create_object(uwrap, context, &object);
  1103. if (Z_TYPE(object) == IS_UNDEF) {
  1104. return ret;
  1105. }
  1106. /* call it's stat_url method - set up params first */
  1107. ZVAL_STRING(&args[0], url);
  1108. ZVAL_LONG(&args[1], flags);
  1109. ZVAL_STRING(&zfuncname, USERSTREAM_STATURL);
  1110. call_result = call_user_function(NULL,
  1111. &object,
  1112. &zfuncname,
  1113. &zretval,
  1114. 2, args);
  1115. if (call_result == SUCCESS && Z_TYPE(zretval) == IS_ARRAY) {
  1116. /* We got the info we needed */
  1117. if (SUCCESS == statbuf_from_array(&zretval, ssb))
  1118. ret = 0;
  1119. } else {
  1120. if (call_result == FAILURE) {
  1121. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_STATURL " is not implemented!",
  1122. ZSTR_VAL(uwrap->ce->name));
  1123. }
  1124. }
  1125. /* clean up */
  1126. zval_ptr_dtor(&object);
  1127. zval_ptr_dtor(&zretval);
  1128. zval_ptr_dtor(&zfuncname);
  1129. zval_ptr_dtor(&args[1]);
  1130. zval_ptr_dtor(&args[0]);
  1131. return ret;
  1132. }
  1133. static ssize_t php_userstreamop_readdir(php_stream *stream, char *buf, size_t count)
  1134. {
  1135. zval func_name;
  1136. zval retval;
  1137. int call_result;
  1138. size_t didread = 0;
  1139. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  1140. php_stream_dirent *ent = (php_stream_dirent*)buf;
  1141. /* avoid problems if someone mis-uses the stream */
  1142. if (count != sizeof(php_stream_dirent))
  1143. return -1;
  1144. ZVAL_STRINGL(&func_name, USERSTREAM_DIR_READ, sizeof(USERSTREAM_DIR_READ)-1);
  1145. call_result = call_user_function(NULL,
  1146. Z_ISUNDEF(us->object)? NULL : &us->object,
  1147. &func_name,
  1148. &retval,
  1149. 0, NULL);
  1150. if (call_result == SUCCESS && Z_TYPE(retval) != IS_FALSE && Z_TYPE(retval) != IS_TRUE) {
  1151. convert_to_string(&retval);
  1152. PHP_STRLCPY(ent->d_name, Z_STRVAL(retval), sizeof(ent->d_name), Z_STRLEN(retval));
  1153. didread = sizeof(php_stream_dirent);
  1154. } else if (call_result == FAILURE) {
  1155. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_DIR_READ " is not implemented!",
  1156. ZSTR_VAL(us->wrapper->ce->name));
  1157. }
  1158. zval_ptr_dtor(&retval);
  1159. zval_ptr_dtor(&func_name);
  1160. return didread;
  1161. }
  1162. static int php_userstreamop_closedir(php_stream *stream, int close_handle)
  1163. {
  1164. zval func_name;
  1165. zval retval;
  1166. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  1167. assert(us != NULL);
  1168. ZVAL_STRINGL(&func_name, USERSTREAM_DIR_CLOSE, sizeof(USERSTREAM_DIR_CLOSE)-1);
  1169. call_user_function(NULL,
  1170. Z_ISUNDEF(us->object)? NULL : &us->object,
  1171. &func_name,
  1172. &retval,
  1173. 0, NULL);
  1174. zval_ptr_dtor(&retval);
  1175. zval_ptr_dtor(&func_name);
  1176. zval_ptr_dtor(&us->object);
  1177. ZVAL_UNDEF(&us->object);
  1178. efree(us);
  1179. return 0;
  1180. }
  1181. static int php_userstreamop_rewinddir(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs)
  1182. {
  1183. zval func_name;
  1184. zval retval;
  1185. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  1186. ZVAL_STRINGL(&func_name, USERSTREAM_DIR_REWIND, sizeof(USERSTREAM_DIR_REWIND)-1);
  1187. call_user_function(NULL,
  1188. Z_ISUNDEF(us->object)? NULL : &us->object,
  1189. &func_name,
  1190. &retval,
  1191. 0, NULL);
  1192. zval_ptr_dtor(&retval);
  1193. zval_ptr_dtor(&func_name);
  1194. return 0;
  1195. }
  1196. static int php_userstreamop_cast(php_stream *stream, int castas, void **retptr)
  1197. {
  1198. php_userstream_data_t *us = (php_userstream_data_t *)stream->abstract;
  1199. zval func_name;
  1200. zval retval;
  1201. zval args[1];
  1202. php_stream * intstream = NULL;
  1203. int call_result;
  1204. int ret = FAILURE;
  1205. ZVAL_STRINGL(&func_name, USERSTREAM_CAST, sizeof(USERSTREAM_CAST)-1);
  1206. switch(castas) {
  1207. case PHP_STREAM_AS_FD_FOR_SELECT:
  1208. ZVAL_LONG(&args[0], PHP_STREAM_AS_FD_FOR_SELECT);
  1209. break;
  1210. default:
  1211. ZVAL_LONG(&args[0], PHP_STREAM_AS_STDIO);
  1212. break;
  1213. }
  1214. call_result = call_user_function(NULL,
  1215. Z_ISUNDEF(us->object)? NULL : &us->object,
  1216. &func_name,
  1217. &retval,
  1218. 1, args);
  1219. do {
  1220. if (call_result == FAILURE) {
  1221. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_CAST " is not implemented!",
  1222. ZSTR_VAL(us->wrapper->ce->name));
  1223. break;
  1224. }
  1225. if (!zend_is_true(&retval)) {
  1226. break;
  1227. }
  1228. php_stream_from_zval_no_verify(intstream, &retval);
  1229. if (!intstream) {
  1230. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_CAST " must return a stream resource",
  1231. ZSTR_VAL(us->wrapper->ce->name));
  1232. break;
  1233. }
  1234. if (intstream == stream) {
  1235. php_error_docref(NULL, E_WARNING, "%s::" USERSTREAM_CAST " must not return itself",
  1236. ZSTR_VAL(us->wrapper->ce->name));
  1237. intstream = NULL;
  1238. break;
  1239. }
  1240. ret = php_stream_cast(intstream, castas, retptr, 1);
  1241. } while (0);
  1242. zval_ptr_dtor(&retval);
  1243. zval_ptr_dtor(&func_name);
  1244. zval_ptr_dtor(&args[0]);
  1245. return ret;
  1246. }
  1247. const php_stream_ops php_stream_userspace_ops = {
  1248. php_userstreamop_write, php_userstreamop_read,
  1249. php_userstreamop_close, php_userstreamop_flush,
  1250. "user-space",
  1251. php_userstreamop_seek,
  1252. php_userstreamop_cast,
  1253. php_userstreamop_stat,
  1254. php_userstreamop_set_option,
  1255. };
  1256. const php_stream_ops php_stream_userspace_dir_ops = {
  1257. NULL, /* write */
  1258. php_userstreamop_readdir,
  1259. php_userstreamop_closedir,
  1260. NULL, /* flush */
  1261. "user-space-dir",
  1262. php_userstreamop_rewinddir,
  1263. NULL, /* cast */
  1264. NULL, /* stat */
  1265. NULL /* set_option */
  1266. };