userspace.c 43 KB

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