userspace.c 45 KB

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