PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/spl/spl_directory.c

http://github.com/php/php-src
C | 2922 lines | 2286 code | 318 blank | 318 comment | 366 complexity | 008ab01183c483dd353e82d7af6a7ef3 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | http://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Marcus Boerger <helly@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. # include "config.h"
  18. #endif
  19. #include "php.h"
  20. #include "php_ini.h"
  21. #include "ext/standard/info.h"
  22. #include "ext/standard/file.h"
  23. #include "ext/standard/php_string.h"
  24. #include "zend_compile.h"
  25. #include "zend_exceptions.h"
  26. #include "zend_interfaces.h"
  27. #include "php_spl.h"
  28. #include "spl_functions.h"
  29. #include "spl_engine.h"
  30. #include "spl_iterators.h"
  31. #include "spl_directory.h"
  32. #include "spl_directory_arginfo.h"
  33. #include "spl_exceptions.h"
  34. #include "php.h"
  35. #include "fopen_wrappers.h"
  36. #include "ext/standard/basic_functions.h"
  37. #include "ext/standard/php_filestat.h"
  38. #define SPL_HAS_FLAG(flags, test_flag) ((flags & test_flag) ? 1 : 0)
  39. /* declare the class handlers */
  40. static zend_object_handlers spl_filesystem_object_handlers;
  41. /* includes handler to validate object state when retrieving methods */
  42. static zend_object_handlers spl_filesystem_object_check_handlers;
  43. /* decalre the class entry */
  44. PHPAPI zend_class_entry *spl_ce_SplFileInfo;
  45. PHPAPI zend_class_entry *spl_ce_DirectoryIterator;
  46. PHPAPI zend_class_entry *spl_ce_FilesystemIterator;
  47. PHPAPI zend_class_entry *spl_ce_RecursiveDirectoryIterator;
  48. PHPAPI zend_class_entry *spl_ce_GlobIterator;
  49. PHPAPI zend_class_entry *spl_ce_SplFileObject;
  50. PHPAPI zend_class_entry *spl_ce_SplTempFileObject;
  51. static void spl_filesystem_file_free_line(spl_filesystem_object *intern) /* {{{ */
  52. {
  53. if (intern->u.file.current_line) {
  54. efree(intern->u.file.current_line);
  55. intern->u.file.current_line = NULL;
  56. }
  57. if (!Z_ISUNDEF(intern->u.file.current_zval)) {
  58. zval_ptr_dtor(&intern->u.file.current_zval);
  59. ZVAL_UNDEF(&intern->u.file.current_zval);
  60. }
  61. } /* }}} */
  62. static void spl_filesystem_object_destroy_object(zend_object *object) /* {{{ */
  63. {
  64. spl_filesystem_object *intern = spl_filesystem_from_obj(object);
  65. zend_objects_destroy_object(object);
  66. switch(intern->type) {
  67. case SPL_FS_DIR:
  68. if (intern->u.dir.dirp) {
  69. php_stream_close(intern->u.dir.dirp);
  70. intern->u.dir.dirp = NULL;
  71. }
  72. break;
  73. case SPL_FS_FILE:
  74. if (intern->u.file.stream) {
  75. /*
  76. if (intern->u.file.zcontext) {
  77. zend_list_delref(Z_RESVAL_P(intern->zcontext));
  78. }
  79. */
  80. if (!intern->u.file.stream->is_persistent) {
  81. php_stream_close(intern->u.file.stream);
  82. } else {
  83. php_stream_pclose(intern->u.file.stream);
  84. }
  85. intern->u.file.stream = NULL;
  86. }
  87. break;
  88. default:
  89. break;
  90. }
  91. } /* }}} */
  92. static void spl_filesystem_object_free_storage(zend_object *object) /* {{{ */
  93. {
  94. spl_filesystem_object *intern = spl_filesystem_from_obj(object);
  95. if (intern->oth_handler && intern->oth_handler->dtor) {
  96. intern->oth_handler->dtor(intern);
  97. }
  98. zend_object_std_dtor(&intern->std);
  99. if (intern->_path) {
  100. efree(intern->_path);
  101. }
  102. if (intern->file_name) {
  103. efree(intern->file_name);
  104. }
  105. switch(intern->type) {
  106. case SPL_FS_INFO:
  107. break;
  108. case SPL_FS_DIR:
  109. if (intern->u.dir.sub_path) {
  110. efree(intern->u.dir.sub_path);
  111. }
  112. break;
  113. case SPL_FS_FILE:
  114. if (intern->u.file.open_mode) {
  115. efree(intern->u.file.open_mode);
  116. }
  117. if (intern->orig_path) {
  118. efree(intern->orig_path);
  119. }
  120. spl_filesystem_file_free_line(intern);
  121. break;
  122. }
  123. } /* }}} */
  124. /* {{{ spl_ce_dir_object_new */
  125. /* creates the object by
  126. - allocating memory
  127. - initializing the object members
  128. - storing the object
  129. - setting it's handlers
  130. called from
  131. - clone
  132. - new
  133. */
  134. static zend_object *spl_filesystem_object_new_ex(zend_class_entry *class_type)
  135. {
  136. spl_filesystem_object *intern;
  137. intern = zend_object_alloc(sizeof(spl_filesystem_object), class_type);
  138. /* intern->type = SPL_FS_INFO; done by set 0 */
  139. intern->file_class = spl_ce_SplFileObject;
  140. intern->info_class = spl_ce_SplFileInfo;
  141. zend_object_std_init(&intern->std, class_type);
  142. object_properties_init(&intern->std, class_type);
  143. intern->std.handlers = &spl_filesystem_object_handlers;
  144. return &intern->std;
  145. }
  146. /* }}} */
  147. /* {{{ spl_filesystem_object_new */
  148. /* See spl_filesystem_object_new_ex */
  149. static zend_object *spl_filesystem_object_new(zend_class_entry *class_type)
  150. {
  151. return spl_filesystem_object_new_ex(class_type);
  152. }
  153. /* }}} */
  154. /* {{{ spl_filesystem_object_new_check */
  155. static zend_object *spl_filesystem_object_new_check(zend_class_entry *class_type)
  156. {
  157. spl_filesystem_object *ret = spl_filesystem_from_obj(spl_filesystem_object_new_ex(class_type));
  158. ret->std.handlers = &spl_filesystem_object_check_handlers;
  159. return &ret->std;
  160. }
  161. /* }}} */
  162. PHPAPI char* spl_filesystem_object_get_path(spl_filesystem_object *intern, size_t *len) /* {{{ */
  163. {
  164. #ifdef HAVE_GLOB
  165. if (intern->type == SPL_FS_DIR) {
  166. if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
  167. return php_glob_stream_get_path(intern->u.dir.dirp, len);
  168. }
  169. }
  170. #endif
  171. if (len) {
  172. *len = intern->_path_len;
  173. }
  174. return intern->_path;
  175. } /* }}} */
  176. static inline void spl_filesystem_object_get_file_name(spl_filesystem_object *intern) /* {{{ */
  177. {
  178. char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
  179. switch (intern->type) {
  180. case SPL_FS_INFO:
  181. case SPL_FS_FILE:
  182. if (!intern->file_name) {
  183. php_error_docref(NULL, E_ERROR, "Object not initialized");
  184. }
  185. break;
  186. case SPL_FS_DIR:
  187. {
  188. size_t path_len = 0;
  189. char *path = spl_filesystem_object_get_path(intern, &path_len);
  190. if (intern->file_name) {
  191. efree(intern->file_name);
  192. }
  193. /* if there is parent path, amend it, otherwise just use the given path as is */
  194. if (path_len == 0) {
  195. intern->file_name_len = spprintf(
  196. &intern->file_name, 0, "%s", intern->u.dir.entry.d_name);
  197. } else {
  198. intern->file_name_len = spprintf(
  199. &intern->file_name, 0, "%s%c%s", path, slash, intern->u.dir.entry.d_name);
  200. }
  201. }
  202. break;
  203. }
  204. } /* }}} */
  205. static int spl_filesystem_dir_read(spl_filesystem_object *intern) /* {{{ */
  206. {
  207. if (!intern->u.dir.dirp || !php_stream_readdir(intern->u.dir.dirp, &intern->u.dir.entry)) {
  208. intern->u.dir.entry.d_name[0] = '\0';
  209. return 0;
  210. } else {
  211. return 1;
  212. }
  213. }
  214. /* }}} */
  215. #define IS_SLASH_AT(zs, pos) (IS_SLASH(zs[pos]))
  216. static inline int spl_filesystem_is_dot(const char * d_name) /* {{{ */
  217. {
  218. return !strcmp(d_name, ".") || !strcmp(d_name, "..");
  219. }
  220. /* }}} */
  221. /* {{{ spl_filesystem_dir_open */
  222. /* open a directory resource */
  223. static void spl_filesystem_dir_open(spl_filesystem_object* intern, char *path)
  224. {
  225. int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
  226. intern->type = SPL_FS_DIR;
  227. intern->_path_len = strlen(path);
  228. intern->u.dir.dirp = php_stream_opendir(path, REPORT_ERRORS, FG(default_context));
  229. if (intern->_path_len > 1 && IS_SLASH_AT(path, intern->_path_len-1)) {
  230. intern->_path = estrndup(path, --intern->_path_len);
  231. } else {
  232. intern->_path = estrndup(path, intern->_path_len);
  233. }
  234. intern->u.dir.index = 0;
  235. if (EG(exception) || intern->u.dir.dirp == NULL) {
  236. intern->u.dir.entry.d_name[0] = '\0';
  237. if (!EG(exception)) {
  238. /* open failed w/out notice (turned to exception due to EH_THROW) */
  239. zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0,
  240. "Failed to open directory \"%s\"", path);
  241. }
  242. } else {
  243. do {
  244. spl_filesystem_dir_read(intern);
  245. } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
  246. }
  247. }
  248. /* }}} */
  249. static int spl_filesystem_file_open(spl_filesystem_object *intern, int use_include_path, int silent) /* {{{ */
  250. {
  251. zval tmp;
  252. intern->type = SPL_FS_FILE;
  253. php_stat(intern->file_name, intern->file_name_len, FS_IS_DIR, &tmp);
  254. if (Z_TYPE(tmp) == IS_TRUE) {
  255. intern->u.file.open_mode = NULL;
  256. intern->file_name = NULL;
  257. zend_throw_exception_ex(spl_ce_LogicException, 0, "Cannot use SplFileObject with directories");
  258. return FAILURE;
  259. }
  260. intern->u.file.context = php_stream_context_from_zval(intern->u.file.zcontext, 0);
  261. intern->u.file.stream = php_stream_open_wrapper_ex(intern->file_name, intern->u.file.open_mode, (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, intern->u.file.context);
  262. if (!intern->file_name_len || !intern->u.file.stream) {
  263. if (!EG(exception)) {
  264. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot open file '%s'", intern->file_name_len ? intern->file_name : "");
  265. }
  266. intern->file_name = NULL; /* until here it is not a copy */
  267. intern->u.file.open_mode = NULL;
  268. return FAILURE;
  269. }
  270. /*
  271. if (intern->u.file.zcontext) {
  272. //zend_list_addref(Z_RES_VAL(intern->u.file.zcontext));
  273. Z_ADDREF_P(intern->u.file.zcontext);
  274. }
  275. */
  276. if (intern->file_name_len > 1 && IS_SLASH_AT(intern->file_name, intern->file_name_len-1)) {
  277. intern->file_name_len--;
  278. }
  279. intern->orig_path = estrndup(intern->u.file.stream->orig_path, strlen(intern->u.file.stream->orig_path));
  280. intern->file_name = estrndup(intern->file_name, intern->file_name_len);
  281. intern->u.file.open_mode = estrndup(intern->u.file.open_mode, intern->u.file.open_mode_len);
  282. /* avoid reference counting in debug mode, thus do it manually */
  283. ZVAL_RES(&intern->u.file.zresource, intern->u.file.stream->res);
  284. /*!!! TODO: maybe bug?
  285. Z_SET_REFCOUNT(intern->u.file.zresource, 1);
  286. */
  287. intern->u.file.delimiter = ',';
  288. intern->u.file.enclosure = '"';
  289. intern->u.file.escape = (unsigned char) '\\';
  290. intern->u.file.func_getCurr = zend_hash_str_find_ptr(&intern->std.ce->function_table, "getcurrentline", sizeof("getcurrentline") - 1);
  291. return SUCCESS;
  292. } /* }}} */
  293. /* {{{ spl_filesystem_object_clone */
  294. /* Local zend_object creation (on stack)
  295. Load the 'other' object
  296. Create a new empty object (See spl_filesystem_object_new_ex)
  297. Open the directory
  298. Clone other members (properties)
  299. */
  300. static zend_object *spl_filesystem_object_clone(zend_object *old_object)
  301. {
  302. zend_object *new_object;
  303. spl_filesystem_object *intern;
  304. spl_filesystem_object *source;
  305. int index, skip_dots;
  306. source = spl_filesystem_from_obj(old_object);
  307. new_object = spl_filesystem_object_new_ex(old_object->ce);
  308. intern = spl_filesystem_from_obj(new_object);
  309. intern->flags = source->flags;
  310. switch (source->type) {
  311. case SPL_FS_INFO:
  312. intern->_path_len = source->_path_len;
  313. intern->_path = estrndup(source->_path, source->_path_len);
  314. intern->file_name_len = source->file_name_len;
  315. intern->file_name = estrndup(source->file_name, intern->file_name_len);
  316. break;
  317. case SPL_FS_DIR:
  318. spl_filesystem_dir_open(intern, source->_path);
  319. /* read until we hit the position in which we were before */
  320. skip_dots = SPL_HAS_FLAG(source->flags, SPL_FILE_DIR_SKIPDOTS);
  321. for(index = 0; index < source->u.dir.index; ++index) {
  322. do {
  323. spl_filesystem_dir_read(intern);
  324. } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
  325. }
  326. intern->u.dir.index = index;
  327. break;
  328. case SPL_FS_FILE:
  329. ZEND_ASSERT(0);
  330. }
  331. intern->file_class = source->file_class;
  332. intern->info_class = source->info_class;
  333. intern->oth = source->oth;
  334. intern->oth_handler = source->oth_handler;
  335. zend_objects_clone_members(new_object, old_object);
  336. if (intern->oth_handler && intern->oth_handler->clone) {
  337. intern->oth_handler->clone(source, intern);
  338. }
  339. return new_object;
  340. }
  341. /* }}} */
  342. void spl_filesystem_info_set_filename(spl_filesystem_object *intern, char *path, size_t len, size_t use_copy) /* {{{ */
  343. {
  344. char *p1, *p2;
  345. if (intern->file_name) {
  346. efree(intern->file_name);
  347. }
  348. intern->file_name = use_copy ? estrndup(path, len) : path;
  349. intern->file_name_len = len;
  350. while (intern->file_name_len > 1 && IS_SLASH_AT(intern->file_name, intern->file_name_len-1)) {
  351. intern->file_name[intern->file_name_len-1] = 0;
  352. intern->file_name_len--;
  353. }
  354. p1 = strrchr(intern->file_name, '/');
  355. #if defined(PHP_WIN32)
  356. p2 = strrchr(intern->file_name, '\\');
  357. #else
  358. p2 = 0;
  359. #endif
  360. if (p1 || p2) {
  361. intern->_path_len = ((p1 > p2 ? p1 : p2) - intern->file_name);
  362. } else {
  363. intern->_path_len = 0;
  364. }
  365. if (intern->_path) {
  366. efree(intern->_path);
  367. }
  368. intern->_path = estrndup(path, intern->_path_len);
  369. } /* }}} */
  370. static spl_filesystem_object *spl_filesystem_object_create_info(spl_filesystem_object *source, char *file_path, size_t file_path_len, int use_copy, zend_class_entry *ce, zval *return_value) /* {{{ */
  371. {
  372. spl_filesystem_object *intern;
  373. zval arg1;
  374. zend_error_handling error_handling;
  375. if (!file_path || !file_path_len) {
  376. #if defined(PHP_WIN32)
  377. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot create SplFileInfo for empty path");
  378. if (file_path && !use_copy) {
  379. efree(file_path);
  380. }
  381. #else
  382. if (file_path && !use_copy) {
  383. efree(file_path);
  384. }
  385. file_path_len = 1;
  386. file_path = "/";
  387. #endif
  388. return NULL;
  389. }
  390. zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
  391. ce = ce ? ce : source->info_class;
  392. zend_update_class_constants(ce);
  393. intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
  394. ZVAL_OBJ(return_value, &intern->std);
  395. if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
  396. ZVAL_STRINGL(&arg1, file_path, file_path_len);
  397. zend_call_method_with_1_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1);
  398. zval_ptr_dtor(&arg1);
  399. } else {
  400. spl_filesystem_info_set_filename(intern, file_path, file_path_len, use_copy);
  401. }
  402. zend_restore_error_handling(&error_handling);
  403. return intern;
  404. } /* }}} */
  405. static spl_filesystem_object *spl_filesystem_object_create_type(int num_args, spl_filesystem_object *source, int type, zend_class_entry *ce, zval *return_value) /* {{{ */
  406. {
  407. spl_filesystem_object *intern;
  408. zend_bool use_include_path = 0;
  409. zval arg1, arg2;
  410. zend_error_handling error_handling;
  411. zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
  412. switch (source->type) {
  413. case SPL_FS_INFO:
  414. case SPL_FS_FILE:
  415. break;
  416. case SPL_FS_DIR:
  417. if (!source->u.dir.entry.d_name[0]) {
  418. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Could not open file");
  419. zend_restore_error_handling(&error_handling);
  420. return NULL;
  421. }
  422. }
  423. switch (type) {
  424. case SPL_FS_INFO:
  425. ce = ce ? ce : source->info_class;
  426. if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
  427. break;
  428. }
  429. intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
  430. ZVAL_OBJ(return_value, &intern->std);
  431. spl_filesystem_object_get_file_name(source);
  432. if (ce->constructor->common.scope != spl_ce_SplFileInfo) {
  433. ZVAL_STRINGL(&arg1, source->file_name, source->file_name_len);
  434. zend_call_method_with_1_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1);
  435. zval_ptr_dtor(&arg1);
  436. } else {
  437. intern->file_name = estrndup(source->file_name, source->file_name_len);
  438. intern->file_name_len = source->file_name_len;
  439. intern->_path = spl_filesystem_object_get_path(source, &intern->_path_len);
  440. intern->_path = estrndup(intern->_path, intern->_path_len);
  441. }
  442. break;
  443. case SPL_FS_FILE:
  444. {
  445. ce = ce ? ce : source->file_class;
  446. if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
  447. break;
  448. }
  449. char *open_mode = "r";
  450. size_t open_mode_len = 1;
  451. zval *resource = NULL;
  452. if (zend_parse_parameters(num_args, "|sbr",
  453. &open_mode, &open_mode_len, &use_include_path, &resource) == FAILURE
  454. ) {
  455. zend_restore_error_handling(&error_handling);
  456. return NULL;
  457. }
  458. intern = spl_filesystem_from_obj(spl_filesystem_object_new_ex(ce));
  459. ZVAL_OBJ(return_value, &intern->std);
  460. spl_filesystem_object_get_file_name(source);
  461. if (ce->constructor->common.scope != spl_ce_SplFileObject) {
  462. ZVAL_STRINGL(&arg1, source->file_name, source->file_name_len);
  463. ZVAL_STRINGL(&arg2, open_mode, open_mode_len);
  464. zend_call_method_with_2_params(Z_OBJ_P(return_value), ce, &ce->constructor, "__construct", NULL, &arg1, &arg2);
  465. zval_ptr_dtor(&arg1);
  466. zval_ptr_dtor(&arg2);
  467. } else {
  468. intern->file_name = source->file_name;
  469. intern->file_name_len = source->file_name_len;
  470. intern->_path = spl_filesystem_object_get_path(source, &intern->_path_len);
  471. intern->_path = estrndup(intern->_path, intern->_path_len);
  472. intern->u.file.open_mode = open_mode;
  473. intern->u.file.open_mode_len = open_mode_len;
  474. intern->u.file.zcontext = resource;
  475. if (spl_filesystem_file_open(intern, use_include_path, 0) == FAILURE) {
  476. zend_restore_error_handling(&error_handling);
  477. zval_ptr_dtor(return_value);
  478. ZVAL_NULL(return_value);
  479. return NULL;
  480. }
  481. }
  482. break;
  483. }
  484. case SPL_FS_DIR:
  485. zend_restore_error_handling(&error_handling);
  486. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Operation not supported");
  487. return NULL;
  488. }
  489. zend_restore_error_handling(&error_handling);
  490. return NULL;
  491. } /* }}} */
  492. static int spl_filesystem_is_invalid_or_dot(const char * d_name) /* {{{ */
  493. {
  494. return d_name[0] == '\0' || spl_filesystem_is_dot(d_name);
  495. }
  496. /* }}} */
  497. static char *spl_filesystem_object_get_pathname(spl_filesystem_object *intern, size_t *len) { /* {{{ */
  498. switch (intern->type) {
  499. case SPL_FS_INFO:
  500. case SPL_FS_FILE:
  501. *len = intern->file_name_len;
  502. return intern->file_name;
  503. case SPL_FS_DIR:
  504. if (intern->u.dir.entry.d_name[0]) {
  505. spl_filesystem_object_get_file_name(intern);
  506. *len = intern->file_name_len;
  507. return intern->file_name;
  508. }
  509. }
  510. *len = 0;
  511. return NULL;
  512. }
  513. /* }}} */
  514. static inline HashTable *spl_filesystem_object_get_debug_info(zend_object *object) /* {{{ */
  515. {
  516. spl_filesystem_object *intern = spl_filesystem_from_obj(object);
  517. zval tmp;
  518. HashTable *rv;
  519. zend_string *pnstr;
  520. char *path;
  521. size_t path_len;
  522. char stmp[2];
  523. if (!intern->std.properties) {
  524. rebuild_object_properties(&intern->std);
  525. }
  526. rv = zend_array_dup(intern->std.properties);
  527. pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "pathName", sizeof("pathName")-1);
  528. path = spl_filesystem_object_get_pathname(intern, &path_len);
  529. ZVAL_STRINGL(&tmp, path ? path : "", path_len);
  530. zend_symtable_update(rv, pnstr, &tmp);
  531. zend_string_release_ex(pnstr, 0);
  532. if (intern->file_name) {
  533. pnstr = spl_gen_private_prop_name(spl_ce_SplFileInfo, "fileName", sizeof("fileName")-1);
  534. spl_filesystem_object_get_path(intern, &path_len);
  535. if (path_len && path_len < intern->file_name_len) {
  536. ZVAL_STRINGL(&tmp, intern->file_name + path_len + 1, intern->file_name_len - (path_len + 1));
  537. } else {
  538. ZVAL_STRINGL(&tmp, intern->file_name, intern->file_name_len);
  539. }
  540. zend_symtable_update(rv, pnstr, &tmp);
  541. zend_string_release_ex(pnstr, 0);
  542. }
  543. if (intern->type == SPL_FS_DIR) {
  544. #ifdef HAVE_GLOB
  545. pnstr = spl_gen_private_prop_name(spl_ce_DirectoryIterator, "glob", sizeof("glob")-1);
  546. if (php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
  547. ZVAL_STRINGL(&tmp, intern->_path, intern->_path_len);
  548. } else {
  549. ZVAL_FALSE(&tmp);
  550. }
  551. zend_symtable_update(rv, pnstr, &tmp);
  552. zend_string_release_ex(pnstr, 0);
  553. #endif
  554. pnstr = spl_gen_private_prop_name(spl_ce_RecursiveDirectoryIterator, "subPathName", sizeof("subPathName")-1);
  555. if (intern->u.dir.sub_path) {
  556. ZVAL_STRINGL(&tmp, intern->u.dir.sub_path, intern->u.dir.sub_path_len);
  557. } else {
  558. ZVAL_EMPTY_STRING(&tmp);
  559. }
  560. zend_symtable_update(rv, pnstr, &tmp);
  561. zend_string_release_ex(pnstr, 0);
  562. }
  563. if (intern->type == SPL_FS_FILE) {
  564. pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "openMode", sizeof("openMode")-1);
  565. ZVAL_STRINGL(&tmp, intern->u.file.open_mode, intern->u.file.open_mode_len);
  566. zend_symtable_update(rv, pnstr, &tmp);
  567. zend_string_release_ex(pnstr, 0);
  568. stmp[1] = '\0';
  569. stmp[0] = intern->u.file.delimiter;
  570. pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "delimiter", sizeof("delimiter")-1);
  571. ZVAL_STRINGL(&tmp, stmp, 1);
  572. zend_symtable_update(rv, pnstr, &tmp);
  573. zend_string_release_ex(pnstr, 0);
  574. stmp[0] = intern->u.file.enclosure;
  575. pnstr = spl_gen_private_prop_name(spl_ce_SplFileObject, "enclosure", sizeof("enclosure")-1);
  576. ZVAL_STRINGL(&tmp, stmp, 1);
  577. zend_symtable_update(rv, pnstr, &tmp);
  578. zend_string_release_ex(pnstr, 0);
  579. }
  580. return rv;
  581. }
  582. /* }}} */
  583. zend_function *spl_filesystem_object_get_method_check(zend_object **object, zend_string *method, const zval *key) /* {{{ */
  584. {
  585. spl_filesystem_object *fsobj = spl_filesystem_from_obj(*object);
  586. if (fsobj->u.dir.dirp == NULL && fsobj->orig_path == NULL) {
  587. zend_function *func;
  588. zend_string *tmp = zend_string_init("_bad_state_ex", sizeof("_bad_state_ex") - 1, 0);
  589. func = zend_std_get_method(object, tmp, NULL);
  590. zend_string_release_ex(tmp, 0);
  591. return func;
  592. }
  593. return zend_std_get_method(object, method, key);
  594. }
  595. /* }}} */
  596. #define DIT_CTOR_FLAGS 0x00000001
  597. #define DIT_CTOR_GLOB 0x00000002
  598. void spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAMETERS, zend_long ctor_flags) /* {{{ */
  599. {
  600. spl_filesystem_object *intern;
  601. char *path;
  602. int parsed;
  603. size_t len;
  604. zend_long flags;
  605. zend_error_handling error_handling;
  606. if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_FLAGS)) {
  607. flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_FILEINFO;
  608. parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "p|l", &path, &len, &flags);
  609. } else {
  610. flags = SPL_FILE_DIR_KEY_AS_PATHNAME|SPL_FILE_DIR_CURRENT_AS_SELF;
  611. parsed = zend_parse_parameters(ZEND_NUM_ARGS(), "p", &path, &len);
  612. }
  613. if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_SKIPDOTS)) {
  614. flags |= SPL_FILE_DIR_SKIPDOTS;
  615. }
  616. if (SPL_HAS_FLAG(ctor_flags, SPL_FILE_DIR_UNIXPATHS)) {
  617. flags |= SPL_FILE_DIR_UNIXPATHS;
  618. }
  619. if (parsed == FAILURE) {
  620. return;
  621. }
  622. if (!len) {
  623. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Directory name must not be empty.");
  624. return;
  625. }
  626. intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  627. if (intern->_path) {
  628. /* object is already initialized */
  629. php_error_docref(NULL, E_WARNING, "Directory object is already initialized");
  630. return;
  631. }
  632. intern->flags = flags;
  633. zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling);
  634. #ifdef HAVE_GLOB
  635. if (SPL_HAS_FLAG(ctor_flags, DIT_CTOR_GLOB) && strstr(path, "glob://") != path) {
  636. spprintf(&path, 0, "glob://%s", path);
  637. spl_filesystem_dir_open(intern, path);
  638. efree(path);
  639. } else
  640. #endif
  641. {
  642. spl_filesystem_dir_open(intern, path);
  643. }
  644. intern->u.dir.is_recursive = instanceof_function(intern->std.ce, spl_ce_RecursiveDirectoryIterator) ? 1 : 0;
  645. zend_restore_error_handling(&error_handling);
  646. }
  647. /* }}} */
  648. /* {{{ proto DirectoryIterator::__construct(string path)
  649. Cronstructs a new dir iterator from a path. */
  650. PHP_METHOD(DirectoryIterator, __construct)
  651. {
  652. spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  653. }
  654. /* }}} */
  655. /* {{{ proto void DirectoryIterator::rewind()
  656. Rewind dir back to the start */
  657. PHP_METHOD(DirectoryIterator, rewind)
  658. {
  659. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  660. if (zend_parse_parameters_none() == FAILURE) {
  661. RETURN_THROWS();
  662. }
  663. intern->u.dir.index = 0;
  664. if (intern->u.dir.dirp) {
  665. php_stream_rewinddir(intern->u.dir.dirp);
  666. }
  667. spl_filesystem_dir_read(intern);
  668. }
  669. /* }}} */
  670. /* {{{ proto string DirectoryIterator::key()
  671. Return current dir entry */
  672. PHP_METHOD(DirectoryIterator, key)
  673. {
  674. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  675. if (zend_parse_parameters_none() == FAILURE) {
  676. RETURN_THROWS();
  677. }
  678. if (intern->u.dir.dirp) {
  679. RETURN_LONG(intern->u.dir.index);
  680. } else {
  681. RETURN_FALSE;
  682. }
  683. }
  684. /* }}} */
  685. /* {{{ proto DirectoryIterator DirectoryIterator::current()
  686. Return this (needed for Iterator interface) */
  687. PHP_METHOD(DirectoryIterator, current)
  688. {
  689. if (zend_parse_parameters_none() == FAILURE) {
  690. RETURN_THROWS();
  691. }
  692. ZVAL_OBJ(return_value, Z_OBJ_P(ZEND_THIS));
  693. Z_ADDREF_P(return_value);
  694. }
  695. /* }}} */
  696. /* {{{ proto void DirectoryIterator::next()
  697. Move to next entry */
  698. PHP_METHOD(DirectoryIterator, next)
  699. {
  700. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  701. int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
  702. if (zend_parse_parameters_none() == FAILURE) {
  703. RETURN_THROWS();
  704. }
  705. intern->u.dir.index++;
  706. do {
  707. spl_filesystem_dir_read(intern);
  708. } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
  709. if (intern->file_name) {
  710. efree(intern->file_name);
  711. intern->file_name = NULL;
  712. }
  713. }
  714. /* }}} */
  715. /* {{{ proto void DirectoryIterator::seek(int position)
  716. Seek to the given position */
  717. PHP_METHOD(DirectoryIterator, seek)
  718. {
  719. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  720. zval retval;
  721. zend_long pos;
  722. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &pos) == FAILURE) {
  723. RETURN_THROWS();
  724. }
  725. if (intern->u.dir.index > pos) {
  726. /* we first rewind */
  727. zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), &intern->u.dir.func_rewind, "rewind", NULL);
  728. }
  729. while (intern->u.dir.index < pos) {
  730. int valid = 0;
  731. zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), &intern->u.dir.func_valid, "valid", &retval);
  732. valid = zend_is_true(&retval);
  733. zval_ptr_dtor(&retval);
  734. if (!valid) {
  735. zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position " ZEND_LONG_FMT " is out of range", pos);
  736. RETURN_THROWS();
  737. }
  738. zend_call_method_with_0_params(Z_OBJ_P(ZEND_THIS), Z_OBJCE_P(ZEND_THIS), &intern->u.dir.func_next, "next", NULL);
  739. }
  740. } /* }}} */
  741. /* {{{ proto string DirectoryIterator::valid()
  742. Check whether dir contains more entries */
  743. PHP_METHOD(DirectoryIterator, valid)
  744. {
  745. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  746. if (zend_parse_parameters_none() == FAILURE) {
  747. RETURN_THROWS();
  748. }
  749. RETURN_BOOL(intern->u.dir.entry.d_name[0] != '\0');
  750. }
  751. /* }}} */
  752. /* {{{ proto string SplFileInfo::getPath()
  753. Return the path */
  754. PHP_METHOD(SplFileInfo, getPath)
  755. {
  756. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  757. char *path;
  758. size_t path_len;
  759. if (zend_parse_parameters_none() == FAILURE) {
  760. RETURN_THROWS();
  761. }
  762. path = spl_filesystem_object_get_path(intern, &path_len);
  763. if (path) {
  764. RETURN_STRINGL(path, path_len);
  765. } else {
  766. RETURN_EMPTY_STRING();
  767. }
  768. }
  769. /* }}} */
  770. /* {{{ proto string SplFileInfo::getFilename()
  771. Return filename only */
  772. PHP_METHOD(SplFileInfo, getFilename)
  773. {
  774. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  775. size_t path_len;
  776. if (zend_parse_parameters_none() == FAILURE) {
  777. RETURN_THROWS();
  778. }
  779. spl_filesystem_object_get_path(intern, &path_len);
  780. if (path_len && path_len < intern->file_name_len) {
  781. RETURN_STRINGL(intern->file_name + path_len + 1, intern->file_name_len - (path_len + 1));
  782. } else {
  783. RETURN_STRINGL(intern->file_name, intern->file_name_len);
  784. }
  785. }
  786. /* }}} */
  787. /* {{{ proto string DirectoryIterator::getFilename()
  788. Return filename of current dir entry */
  789. PHP_METHOD(DirectoryIterator, getFilename)
  790. {
  791. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  792. if (zend_parse_parameters_none() == FAILURE) {
  793. RETURN_THROWS();
  794. }
  795. RETURN_STRING(intern->u.dir.entry.d_name);
  796. }
  797. /* }}} */
  798. /* {{{ proto string SplFileInfo::getExtension()
  799. Returns file extension component of path */
  800. PHP_METHOD(SplFileInfo, getExtension)
  801. {
  802. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  803. char *fname = NULL;
  804. const char *p;
  805. size_t flen;
  806. size_t path_len;
  807. size_t idx;
  808. zend_string *ret;
  809. if (zend_parse_parameters_none() == FAILURE) {
  810. RETURN_THROWS();
  811. }
  812. spl_filesystem_object_get_path(intern, &path_len);
  813. if (path_len && path_len < intern->file_name_len) {
  814. fname = intern->file_name + path_len + 1;
  815. flen = intern->file_name_len - (path_len + 1);
  816. } else {
  817. fname = intern->file_name;
  818. flen = intern->file_name_len;
  819. }
  820. ret = php_basename(fname, flen, NULL, 0);
  821. p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
  822. if (p) {
  823. idx = p - ZSTR_VAL(ret);
  824. RETVAL_STRINGL(ZSTR_VAL(ret) + idx + 1, ZSTR_LEN(ret) - idx - 1);
  825. zend_string_release_ex(ret, 0);
  826. return;
  827. } else {
  828. zend_string_release_ex(ret, 0);
  829. RETURN_EMPTY_STRING();
  830. }
  831. }
  832. /* }}}*/
  833. /* {{{ proto string DirectoryIterator::getExtension()
  834. Returns the file extension component of path */
  835. PHP_METHOD(DirectoryIterator, getExtension)
  836. {
  837. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  838. const char *p;
  839. size_t idx;
  840. zend_string *fname;
  841. if (zend_parse_parameters_none() == FAILURE) {
  842. RETURN_THROWS();
  843. }
  844. fname = php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), NULL, 0);
  845. p = zend_memrchr(ZSTR_VAL(fname), '.', ZSTR_LEN(fname));
  846. if (p) {
  847. idx = p - ZSTR_VAL(fname);
  848. RETVAL_STRINGL(ZSTR_VAL(fname) + idx + 1, ZSTR_LEN(fname) - idx - 1);
  849. zend_string_release_ex(fname, 0);
  850. } else {
  851. zend_string_release_ex(fname, 0);
  852. RETURN_EMPTY_STRING();
  853. }
  854. }
  855. /* }}} */
  856. /* {{{ proto string SplFileInfo::getBasename([string $suffix])
  857. Returns filename component of path */
  858. PHP_METHOD(SplFileInfo, getBasename)
  859. {
  860. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  861. char *fname, *suffix = 0;
  862. size_t flen;
  863. size_t slen = 0, path_len;
  864. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &suffix, &slen) == FAILURE) {
  865. RETURN_THROWS();
  866. }
  867. spl_filesystem_object_get_path(intern, &path_len);
  868. if (path_len && path_len < intern->file_name_len) {
  869. fname = intern->file_name + path_len + 1;
  870. flen = intern->file_name_len - (path_len + 1);
  871. } else {
  872. fname = intern->file_name;
  873. flen = intern->file_name_len;
  874. }
  875. RETURN_STR(php_basename(fname, flen, suffix, slen));
  876. }
  877. /* }}}*/
  878. /* {{{ proto string DirectoryIterator::getBasename([string $suffix])
  879. Returns filename component of current dir entry */
  880. PHP_METHOD(DirectoryIterator, getBasename)
  881. {
  882. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  883. char *suffix = 0;
  884. size_t slen = 0;
  885. zend_string *fname;
  886. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &suffix, &slen) == FAILURE) {
  887. RETURN_THROWS();
  888. }
  889. fname = php_basename(intern->u.dir.entry.d_name, strlen(intern->u.dir.entry.d_name), suffix, slen);
  890. RETVAL_STR(fname);
  891. }
  892. /* }}} */
  893. /* {{{ proto string SplFileInfo::getPathname()
  894. Return path and filename */
  895. PHP_METHOD(SplFileInfo, getPathname)
  896. {
  897. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  898. char *path;
  899. size_t path_len;
  900. if (zend_parse_parameters_none() == FAILURE) {
  901. RETURN_THROWS();
  902. }
  903. path = spl_filesystem_object_get_pathname(intern, &path_len);
  904. if (path != NULL) {
  905. RETURN_STRINGL(path, path_len);
  906. } else {
  907. RETURN_FALSE;
  908. }
  909. }
  910. /* }}} */
  911. /* {{{ proto string FilesystemIterator::key()
  912. Return getPathname() or getFilename() depending on flags */
  913. PHP_METHOD(FilesystemIterator, key)
  914. {
  915. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  916. if (zend_parse_parameters_none() == FAILURE) {
  917. RETURN_THROWS();
  918. }
  919. if (SPL_FILE_DIR_KEY(intern, SPL_FILE_DIR_KEY_AS_FILENAME)) {
  920. RETURN_STRING(intern->u.dir.entry.d_name);
  921. } else {
  922. spl_filesystem_object_get_file_name(intern);
  923. RETURN_STRINGL(intern->file_name, intern->file_name_len);
  924. }
  925. }
  926. /* }}} */
  927. /* {{{ proto string FilesystemIterator::current()
  928. Return getFilename(), getFileInfo() or $this depending on flags */
  929. PHP_METHOD(FilesystemIterator, current)
  930. {
  931. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  932. if (zend_parse_parameters_none() == FAILURE) {
  933. RETURN_THROWS();
  934. }
  935. if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_PATHNAME)) {
  936. spl_filesystem_object_get_file_name(intern);
  937. RETURN_STRINGL(intern->file_name, intern->file_name_len);
  938. } else if (SPL_FILE_DIR_CURRENT(intern, SPL_FILE_DIR_CURRENT_AS_FILEINFO)) {
  939. spl_filesystem_object_get_file_name(intern);
  940. spl_filesystem_object_create_type(0, intern, SPL_FS_INFO, NULL, return_value);
  941. } else {
  942. ZVAL_OBJ(return_value, Z_OBJ_P(ZEND_THIS));
  943. Z_ADDREF_P(return_value);
  944. }
  945. }
  946. /* }}} */
  947. /* {{{ proto bool DirectoryIterator::isDot()
  948. Returns true if current entry is '.' or '..' */
  949. PHP_METHOD(DirectoryIterator, isDot)
  950. {
  951. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  952. if (zend_parse_parameters_none() == FAILURE) {
  953. RETURN_THROWS();
  954. }
  955. RETURN_BOOL(spl_filesystem_is_dot(intern->u.dir.entry.d_name));
  956. }
  957. /* }}} */
  958. /* {{{ proto SplFileInfo::__construct(string file_name)
  959. Cronstructs a new SplFileInfo from a path. */
  960. /* When the constructor gets called the object is already created
  961. by the engine, so we must only call 'additional' initializations.
  962. */
  963. PHP_METHOD(SplFileInfo, __construct)
  964. {
  965. spl_filesystem_object *intern;
  966. char *path;
  967. size_t len;
  968. if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &path, &len) == FAILURE) {
  969. RETURN_THROWS();
  970. }
  971. intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  972. spl_filesystem_info_set_filename(intern, path, len, 1);
  973. /* intern->type = SPL_FS_INFO; already set */
  974. }
  975. /* }}} */
  976. /* {{{ FileInfoFunction */
  977. #define FileInfoFunction(func_name, func_num) \
  978. PHP_METHOD(SplFileInfo, func_name) \
  979. { \
  980. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS); \
  981. zend_error_handling error_handling; \
  982. if (zend_parse_parameters_none() == FAILURE) { \
  983. RETURN_THROWS(); \
  984. } \
  985. \
  986. zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);\
  987. spl_filesystem_object_get_file_name(intern); \
  988. php_stat(intern->file_name, intern->file_name_len, func_num, return_value); \
  989. zend_restore_error_handling(&error_handling); \
  990. }
  991. /* }}} */
  992. /* {{{ proto int SplFileInfo::getPerms()
  993. Get file permissions */
  994. FileInfoFunction(getPerms, FS_PERMS)
  995. /* }}} */
  996. /* {{{ proto int SplFileInfo::getInode()
  997. Get file inode */
  998. FileInfoFunction(getInode, FS_INODE)
  999. /* }}} */
  1000. /* {{{ proto int SplFileInfo::getSize()
  1001. Get file size */
  1002. FileInfoFunction(getSize, FS_SIZE)
  1003. /* }}} */
  1004. /* {{{ proto int SplFileInfo::getOwner()
  1005. Get file owner */
  1006. FileInfoFunction(getOwner, FS_OWNER)
  1007. /* }}} */
  1008. /* {{{ proto int SplFileInfo::getGroup()
  1009. Get file group */
  1010. FileInfoFunction(getGroup, FS_GROUP)
  1011. /* }}} */
  1012. /* {{{ proto int SplFileInfo::getATime()
  1013. Get last access time of file */
  1014. FileInfoFunction(getATime, FS_ATIME)
  1015. /* }}} */
  1016. /* {{{ proto int SplFileInfo::getMTime()
  1017. Get last modification time of file */
  1018. FileInfoFunction(getMTime, FS_MTIME)
  1019. /* }}} */
  1020. /* {{{ proto int SplFileInfo::getCTime()
  1021. Get inode modification time of file */
  1022. FileInfoFunction(getCTime, FS_CTIME)
  1023. /* }}} */
  1024. /* {{{ proto string SplFileInfo::getType()
  1025. Get file type */
  1026. FileInfoFunction(getType, FS_TYPE)
  1027. /* }}} */
  1028. /* {{{ proto bool SplFileInfo::isWritable()
  1029. Returns true if file can be written */
  1030. FileInfoFunction(isWritable, FS_IS_W)
  1031. /* }}} */
  1032. /* {{{ proto bool SplFileInfo::isReadable()
  1033. Returns true if file can be read */
  1034. FileInfoFunction(isReadable, FS_IS_R)
  1035. /* }}} */
  1036. /* {{{ proto bool SplFileInfo::isExecutable()
  1037. Returns true if file is executable */
  1038. FileInfoFunction(isExecutable, FS_IS_X)
  1039. /* }}} */
  1040. /* {{{ proto bool SplFileInfo::isFile()
  1041. Returns true if file is a regular file */
  1042. FileInfoFunction(isFile, FS_IS_FILE)
  1043. /* }}} */
  1044. /* {{{ proto bool SplFileInfo::isDir()
  1045. Returns true if file is directory */
  1046. FileInfoFunction(isDir, FS_IS_DIR)
  1047. /* }}} */
  1048. /* {{{ proto bool SplFileInfo::isLink()
  1049. Returns true if file is symbolic link */
  1050. FileInfoFunction(isLink, FS_IS_LINK)
  1051. /* }}} */
  1052. /* {{{ proto string SplFileInfo::getLinkTarget()
  1053. Return the target of a symbolic link */
  1054. PHP_METHOD(SplFileInfo, getLinkTarget)
  1055. {
  1056. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1057. ssize_t ret;
  1058. char buff[MAXPATHLEN];
  1059. zend_error_handling error_handling;
  1060. if (zend_parse_parameters_none() == FAILURE) {
  1061. RETURN_THROWS();
  1062. }
  1063. zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
  1064. if (intern->file_name == NULL) {
  1065. spl_filesystem_object_get_file_name(intern);
  1066. }
  1067. #if defined(PHP_WIN32) || HAVE_SYMLINK
  1068. if (intern->file_name == NULL) {
  1069. php_error_docref(NULL, E_WARNING, "Empty filename");
  1070. RETURN_FALSE;
  1071. } else if (!IS_ABSOLUTE_PATH(intern->file_name, intern->file_name_len)) {
  1072. char expanded_path[MAXPATHLEN];
  1073. if (!expand_filepath_with_mode(intern->file_name, expanded_path, NULL, 0, CWD_EXPAND )) {
  1074. php_error_docref(NULL, E_WARNING, "No such file or directory");
  1075. RETURN_FALSE;
  1076. }
  1077. ret = php_sys_readlink(expanded_path, buff, MAXPATHLEN - 1);
  1078. } else {
  1079. ret = php_sys_readlink(intern->file_name, buff, MAXPATHLEN-1);
  1080. }
  1081. #else
  1082. ret = -1; /* always fail if not implemented */
  1083. #endif
  1084. if (ret == -1) {
  1085. zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Unable to read link %s, error: %s", intern->file_name, strerror(errno));
  1086. RETVAL_FALSE;
  1087. } else {
  1088. /* Append NULL to the end of the string */
  1089. buff[ret] = '\0';
  1090. RETVAL_STRINGL(buff, ret);
  1091. }
  1092. zend_restore_error_handling(&error_handling);
  1093. }
  1094. /* }}} */
  1095. /* {{{ proto string SplFileInfo::getRealPath()
  1096. Return the resolved path */
  1097. PHP_METHOD(SplFileInfo, getRealPath)
  1098. {
  1099. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1100. char buff[MAXPATHLEN];
  1101. char *filename;
  1102. zend_error_handling error_handling;
  1103. if (zend_parse_parameters_none() == FAILURE) {
  1104. RETURN_THROWS();
  1105. }
  1106. zend_replace_error_handling(EH_THROW, spl_ce_RuntimeException, &error_handling);
  1107. if (intern->type == SPL_FS_DIR && !intern->file_name && intern->u.dir.entry.d_name[0]) {
  1108. spl_filesystem_object_get_file_name(intern);
  1109. }
  1110. if (intern->orig_path) {
  1111. filename = intern->orig_path;
  1112. } else {
  1113. filename = intern->file_name;
  1114. }
  1115. if (filename && VCWD_REALPATH(filename, buff)) {
  1116. #ifdef ZTS
  1117. if (VCWD_ACCESS(buff, F_OK)) {
  1118. RETVAL_FALSE;
  1119. } else
  1120. #endif
  1121. RETVAL_STRING(buff);
  1122. } else {
  1123. RETVAL_FALSE;
  1124. }
  1125. zend_restore_error_handling(&error_handling);
  1126. }
  1127. /* }}} */
  1128. /* {{{ proto SplFileObject SplFileInfo::openFile([string mode = 'r' [, bool use_include_path [, resource context]]])
  1129. Open the current file */
  1130. PHP_METHOD(SplFileInfo, openFile)
  1131. {
  1132. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1133. spl_filesystem_object_create_type(ZEND_NUM_ARGS(), intern, SPL_FS_FILE, NULL, return_value);
  1134. }
  1135. /* }}} */
  1136. /* {{{ proto void SplFileInfo::setFileClass([string class_name])
  1137. Class to use in openFile() */
  1138. PHP_METHOD(SplFileInfo, setFileClass)
  1139. {
  1140. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1141. zend_class_entry *ce = spl_ce_SplFileObject;
  1142. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == FAILURE) {
  1143. RETURN_THROWS();
  1144. }
  1145. intern->file_class = ce;
  1146. }
  1147. /* }}} */
  1148. /* {{{ proto void SplFileInfo::setInfoClass([string class_name])
  1149. Class to use in getFileInfo(), getPathInfo() */
  1150. PHP_METHOD(SplFileInfo, setInfoClass)
  1151. {
  1152. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1153. zend_class_entry *ce = spl_ce_SplFileInfo;
  1154. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == FAILURE) {
  1155. RETURN_THROWS();
  1156. }
  1157. intern->info_class = ce;
  1158. }
  1159. /* }}} */
  1160. /* {{{ proto SplFileInfo SplFileInfo::getFileInfo([string $class_name])
  1161. Get/copy file info */
  1162. PHP_METHOD(SplFileInfo, getFileInfo)
  1163. {
  1164. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1165. zend_class_entry *ce = intern->info_class;
  1166. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == FAILURE) {
  1167. RETURN_THROWS();
  1168. }
  1169. spl_filesystem_object_create_type(ZEND_NUM_ARGS(), intern, SPL_FS_INFO, ce, return_value);
  1170. }
  1171. /* }}} */
  1172. /* {{{ proto SplFileInfo SplFileInfo::getPathInfo([string $class_name])
  1173. Get/copy file info */
  1174. PHP_METHOD(SplFileInfo, getPathInfo)
  1175. {
  1176. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1177. zend_class_entry *ce = intern->info_class;
  1178. size_t path_len;
  1179. char *path;
  1180. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &ce) == FAILURE) {
  1181. RETURN_THROWS();
  1182. }
  1183. path = spl_filesystem_object_get_pathname(intern, &path_len);
  1184. if (path) {
  1185. char *dpath = estrndup(path, path_len);
  1186. path_len = php_dirname(dpath, path_len);
  1187. spl_filesystem_object_create_info(intern, dpath, path_len, 1, ce, return_value);
  1188. efree(dpath);
  1189. }
  1190. }
  1191. /* }}} */
  1192. /* {{{ proto void SplFileInfo::__debugInfo() */
  1193. PHP_METHOD(SplFileInfo, __debugInfo)
  1194. {
  1195. if (zend_parse_parameters_none() == FAILURE) {
  1196. return;
  1197. }
  1198. RETURN_ARR(spl_filesystem_object_get_debug_info(Z_OBJ_P(ZEND_THIS)));
  1199. } /* }}} */
  1200. /* {{{ proto SplFileInfo::_bad_state_ex(void) */
  1201. PHP_METHOD(SplFileInfo, _bad_state_ex)
  1202. {
  1203. zend_throw_exception_ex(spl_ce_LogicException, 0,
  1204. "The parent constructor was not called: the object is in an "
  1205. "invalid state ");
  1206. }
  1207. /* }}} */
  1208. /* {{{ proto FilesystemIterator::__construct(string path [, int flags])
  1209. Cronstructs a new dir iterator from a path. */
  1210. PHP_METHOD(FilesystemIterator, __construct)
  1211. {
  1212. spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS | SPL_FILE_DIR_SKIPDOTS);
  1213. }
  1214. /* }}} */
  1215. /* {{{ proto void FilesystemIterator::rewind()
  1216. Rewind dir back to the start */
  1217. PHP_METHOD(FilesystemIterator, rewind)
  1218. {
  1219. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1220. int skip_dots = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_SKIPDOTS);
  1221. if (zend_parse_parameters_none() == FAILURE) {
  1222. RETURN_THROWS();
  1223. }
  1224. intern->u.dir.index = 0;
  1225. if (intern->u.dir.dirp) {
  1226. php_stream_rewinddir(intern->u.dir.dirp);
  1227. }
  1228. do {
  1229. spl_filesystem_dir_read(intern);
  1230. } while (skip_dots && spl_filesystem_is_dot(intern->u.dir.entry.d_name));
  1231. }
  1232. /* }}} */
  1233. /* {{{ proto int FilesystemIterator::getFlags()
  1234. Get handling flags */
  1235. PHP_METHOD(FilesystemIterator, getFlags)
  1236. {
  1237. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1238. if (zend_parse_parameters_none() == FAILURE) {
  1239. RETURN_THROWS();
  1240. }
  1241. RETURN_LONG(intern->flags & (SPL_FILE_DIR_KEY_MODE_MASK | SPL_FILE_DIR_CURRENT_MODE_MASK | SPL_FILE_DIR_OTHERS_MASK));
  1242. } /* }}} */
  1243. /* {{{ proto void FilesystemIterator::setFlags(long $flags)
  1244. Set handling flags */
  1245. PHP_METHOD(FilesystemIterator, setFlags)
  1246. {
  1247. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1248. zend_long flags;
  1249. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &flags) == FAILURE) {
  1250. RETURN_THROWS();
  1251. }
  1252. intern->flags &= ~(SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK);
  1253. intern->flags |= ((SPL_FILE_DIR_KEY_MODE_MASK|SPL_FILE_DIR_CURRENT_MODE_MASK|SPL_FILE_DIR_OTHERS_MASK) & flags);
  1254. } /* }}} */
  1255. /* {{{ proto bool RecursiveDirectoryIterator::hasChildren([bool $allow_links = false])
  1256. Returns whether current entry is a directory and not '.' or '..' */
  1257. PHP_METHOD(RecursiveDirectoryIterator, hasChildren)
  1258. {
  1259. zend_bool allow_links = 0;
  1260. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1261. if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &allow_links) == FAILURE) {
  1262. RETURN_THROWS();
  1263. }
  1264. if (spl_filesystem_is_invalid_or_dot(intern->u.dir.entry.d_name)) {
  1265. RETURN_FALSE;
  1266. } else {
  1267. spl_filesystem_object_get_file_name(intern);
  1268. if (!allow_links && !(intern->flags & SPL_FILE_DIR_FOLLOW_SYMLINKS)) {
  1269. php_stat(intern->file_name, intern->file_name_len, FS_IS_LINK, return_value);
  1270. if (zend_is_true(return_value)) {
  1271. RETURN_FALSE;
  1272. }
  1273. }
  1274. php_stat(intern->file_name, intern->file_name_len, FS_IS_DIR, return_value);
  1275. }
  1276. }
  1277. /* }}} */
  1278. /* {{{ proto RecursiveDirectoryIterator DirectoryIterator::getChildren()
  1279. Returns an iterator for the current entry if it is a directory */
  1280. PHP_METHOD(RecursiveDirectoryIterator, getChildren)
  1281. {
  1282. zval zpath, zflags;
  1283. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1284. spl_filesystem_object *subdir;
  1285. char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
  1286. if (zend_parse_parameters_none() == FAILURE) {
  1287. RETURN_THROWS();
  1288. }
  1289. spl_filesystem_object_get_file_name(intern);
  1290. ZVAL_LONG(&zflags, intern->flags);
  1291. ZVAL_STRINGL(&zpath, intern->file_name, intern->file_name_len);
  1292. spl_instantiate_arg_ex2(Z_OBJCE_P(ZEND_THIS), return_value, &zpath, &zflags);
  1293. zval_ptr_dtor(&zpath);
  1294. subdir = Z_SPLFILESYSTEM_P(return_value);
  1295. if (subdir) {
  1296. if (intern->u.dir.sub_path && intern->u.dir.sub_path[0]) {
  1297. subdir->u.dir.sub_path_len = spprintf(&subdir->u.dir.sub_path, 0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name);
  1298. } else {
  1299. subdir->u.dir.sub_path_len = strlen(intern->u.dir.entry.d_name);
  1300. subdir->u.dir.sub_path = estrndup(intern->u.dir.entry.d_name, subdir->u.dir.sub_path_len);
  1301. }
  1302. subdir->info_class = intern->info_class;
  1303. subdir->file_class = intern->file_class;
  1304. subdir->oth = intern->oth;
  1305. }
  1306. }
  1307. /* }}} */
  1308. /* {{{ proto void RecursiveDirectoryIterator::getSubPath()
  1309. Get sub path */
  1310. PHP_METHOD(RecursiveDirectoryIterator, getSubPath)
  1311. {
  1312. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1313. if (zend_parse_parameters_none() == FAILURE) {
  1314. RETURN_THROWS();
  1315. }
  1316. if (intern->u.dir.sub_path) {
  1317. RETURN_STRINGL(intern->u.dir.sub_path, intern->u.dir.sub_path_len);
  1318. } else {
  1319. RETURN_EMPTY_STRING();
  1320. }
  1321. }
  1322. /* }}} */
  1323. /* {{{ proto void RecursiveDirectoryIterator::getSubPathname()
  1324. Get sub path and file name */
  1325. PHP_METHOD(RecursiveDirectoryIterator, getSubPathname)
  1326. {
  1327. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1328. char slash = SPL_HAS_FLAG(intern->flags, SPL_FILE_DIR_UNIXPATHS) ? '/' : DEFAULT_SLASH;
  1329. if (zend_parse_parameters_none() == FAILURE) {
  1330. RETURN_THROWS();
  1331. }
  1332. if (intern->u.dir.sub_path) {
  1333. RETURN_NEW_STR(strpprintf(0, "%s%c%s", intern->u.dir.sub_path, slash, intern->u.dir.entry.d_name));
  1334. } else {
  1335. RETURN_STRING(intern->u.dir.entry.d_name);
  1336. }
  1337. }
  1338. /* }}} */
  1339. /* {{{ proto RecursiveDirectoryIterator::__construct(string path [, int flags])
  1340. Cronstructs a new dir iterator from a path. */
  1341. PHP_METHOD(RecursiveDirectoryIterator, __construct)
  1342. {
  1343. spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS);
  1344. }
  1345. /* }}} */
  1346. #ifdef HAVE_GLOB
  1347. /* {{{ proto GlobIterator::__construct(string path [, int flags])
  1348. Cronstructs a new dir iterator from a glob expression (no glob:// needed). */
  1349. PHP_METHOD(GlobIterator, __construct)
  1350. {
  1351. spl_filesystem_object_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIT_CTOR_FLAGS|DIT_CTOR_GLOB);
  1352. }
  1353. /* }}} */
  1354. /* {{{ proto int GlobIterator::count()
  1355. Return the number of directories and files found by globbing */
  1356. PHP_METHOD(GlobIterator, count)
  1357. {
  1358. spl_filesystem_object *intern = Z_SPLFILESYSTEM_P(ZEND_THIS);
  1359. if (zend_parse_parameters_none() == FAILURE) {
  1360. RETURN_THROWS();
  1361. }
  1362. if (intern->u.dir.dirp && php_stream_is(intern->u.dir.dirp ,&php_glob_stream_ops)) {
  1363. RETURN_LONG(php_glob_stream_get_count(intern->u.dir.dirp, NULL));
  1364. } else {
  1365. /* should not happen */
  1366. php_error_docref(NULL, E_ERROR, "GlobIterator lost glob state");
  1367. }
  1368. }
  1369. /* }}} */
  1370. #endif /* HAVE_GLOB */
  1371. /* {{{ forward declarations to the iterator handlers */
  1372. static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter);
  1373. static int spl_filesystem_dir_it_valid(zend_object_iterator *iter);
  1374. static zval *spl_filesystem_dir_it_current_data(zend_object_iterator *iter);
  1375. static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key);
  1376. static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter);
  1377. static void spl_filesystem_dir_it_rewind(zend_object_iterator *iter);
  1378. /* iterator handler table */
  1379. static const zend_object_iterator_funcs spl_filesystem_dir_it_funcs = {
  1380. spl_filesystem_dir_it_dtor,
  1381. spl_filesystem_dir_it_valid,
  1382. spl_filesystem_dir_it_current_data,
  1383. spl_filesystem_dir_it_current_key,
  1384. spl_filesystem_dir_it_move_forward,
  1385. spl_filesystem_dir_it_rewind,
  1386. NULL
  1387. };
  1388. /* }}} */
  1389. /* {{{ spl_ce_dir_get_iterator */
  1390. zend_object_iterator *spl_filesystem_dir_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
  1391. {
  1392. spl_filesystem_iterator *iterator;
  1393. spl_filesystem_object *dir_object;
  1394. if (by_ref) {
  1395. zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0);
  1396. return NULL;
  1397. }
  1398. dir_object = Z_SPLFILESYSTEM_P(object);
  1399. iterator = spl_filesystem_object_to_iterator(dir_object);
  1400. Z_ADDREF_P(object);
  1401. ZVAL_OBJ(&iterator->intern.data, Z_OBJ_P(object));
  1402. iterator->intern.funcs = &spl_filesystem_dir_it_funcs;
  1403. /* ->current must be initialized; rewind doesn't set it and valid
  1404. * doesn't check whether it's set */
  1405. iterator->current = *object;
  1406. return &iterator->intern;
  1407. }
  1408. /* }}} */
  1409. /* {{{ spl_filesystem_dir_it_dtor */
  1410. static void spl_filesystem_dir_it_dtor(zend_object_iterator *iter)
  1411. {
  1412. spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
  1413. if (!Z_ISUNDEF(iterator->intern.data)) {
  1414. zval *object = &iterator->intern.data;
  1415. zval_ptr_dtor(object);
  1416. }
  1417. /* Otherwise we were called from the owning object free storage handler as
  1418. * it sets iterator->intern.data to IS_UNDEF.
  1419. * We don't even need to destroy iterator->current as we didn't add a
  1420. * reference to it in move_forward or get_iterator */
  1421. }
  1422. /* }}} */
  1423. /* {{{ spl_filesystem_dir_it_valid */
  1424. static int spl_filesystem_dir_it_valid(zend_object_iterator *iter)
  1425. {
  1426. spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
  1427. return object->u.dir.entry.d_name[0] != '\0' ? SUCCESS : FAILURE;
  1428. }
  1429. /* }}} */
  1430. /* {{{ spl_filesystem_dir_it_current_data */
  1431. static zval *spl_filesystem_dir_it_current_data(zend_object_iterator *iter)
  1432. {
  1433. spl_filesystem_iterator *iterator = (spl_filesystem_iterator *)iter;
  1434. return &iterator->current;
  1435. }
  1436. /* }}} */
  1437. /* {{{ spl_filesystem_dir_it_current_key */
  1438. static void spl_filesystem_dir_it_current_key(zend_object_iterator *iter, zval *key)
  1439. {
  1440. spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
  1441. ZVAL_LONG(key, object->u.dir.index);
  1442. }
  1443. /* }}} */
  1444. /* {{{ spl_filesystem_dir_it_move_forward */
  1445. static void spl_filesystem_dir_it_move_forward(zend_object_iterator *iter)
  1446. {
  1447. spl_filesystem_object *object = spl_filesystem_iterator_to_object((spl_filesystem_iterator *)iter);
  1448. object->u.dir.index++;
  1449. spl_filesystem_dir_read(object);
  1450. if (object->file_name) {
  1451. efree(object->file_name);
  1452. object->file_name = NULL;
  1453. }
  1454. }
  1455. /* }}} */
  1456. /* {{{ spl_filesyste…

Large files files are truncated, but you can click here to view the full file