glob_wrapper.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Marcus Boerger <helly@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "php.h"
  17. #include "php_streams_int.h"
  18. #ifdef HAVE_GLOB
  19. # ifndef PHP_WIN32
  20. # include <glob.h>
  21. # else
  22. # include "win32/glob.h"
  23. # endif
  24. #endif
  25. #ifdef HAVE_GLOB
  26. #ifndef GLOB_ONLYDIR
  27. #define GLOB_ONLYDIR (1<<30)
  28. #define GLOB_FLAGMASK (~GLOB_ONLYDIR)
  29. #else
  30. #define GLOB_FLAGMASK (~0)
  31. #endif
  32. typedef struct {
  33. glob_t glob;
  34. size_t index;
  35. int flags;
  36. char *path;
  37. size_t path_len;
  38. char *pattern;
  39. size_t pattern_len;
  40. } glob_s_t;
  41. PHPAPI char* _php_glob_stream_get_path(php_stream *stream, size_t *plen STREAMS_DC) /* {{{ */
  42. {
  43. glob_s_t *pglob = (glob_s_t *)stream->abstract;
  44. if (pglob && pglob->path) {
  45. if (plen) {
  46. *plen = pglob->path_len;
  47. }
  48. return pglob->path;
  49. } else {
  50. if (plen) {
  51. *plen = 0;
  52. }
  53. return NULL;
  54. }
  55. }
  56. /* }}} */
  57. PHPAPI char* _php_glob_stream_get_pattern(php_stream *stream, size_t *plen STREAMS_DC) /* {{{ */
  58. {
  59. glob_s_t *pglob = (glob_s_t *)stream->abstract;
  60. if (pglob && pglob->pattern) {
  61. if (plen) {
  62. *plen = pglob->pattern_len;
  63. }
  64. return pglob->pattern;
  65. } else {
  66. if (plen) {
  67. *plen = 0;
  68. }
  69. return NULL;
  70. }
  71. }
  72. /* }}} */
  73. PHPAPI int _php_glob_stream_get_count(php_stream *stream, int *pflags STREAMS_DC) /* {{{ */
  74. {
  75. glob_s_t *pglob = (glob_s_t *)stream->abstract;
  76. if (pglob) {
  77. if (pflags) {
  78. *pflags = pglob->flags;
  79. }
  80. return pglob->glob.gl_pathc;
  81. } else {
  82. if (pflags) {
  83. *pflags = 0;
  84. }
  85. return 0;
  86. }
  87. }
  88. /* }}} */
  89. static void php_glob_stream_path_split(glob_s_t *pglob, const char *path, int get_path, const char **p_file) /* {{{ */
  90. {
  91. const char *pos, *gpath = path;
  92. if ((pos = strrchr(path, '/')) != NULL) {
  93. path = pos+1;
  94. }
  95. #ifdef PHP_WIN32
  96. if ((pos = strrchr(path, '\\')) != NULL) {
  97. path = pos+1;
  98. }
  99. #endif
  100. *p_file = path;
  101. if (get_path) {
  102. if (pglob->path) {
  103. efree(pglob->path);
  104. }
  105. if ((path - gpath) > 1) {
  106. path--;
  107. }
  108. pglob->path_len = path - gpath;
  109. pglob->path = estrndup(gpath, pglob->path_len);
  110. }
  111. }
  112. /* }}} */
  113. static ssize_t php_glob_stream_read(php_stream *stream, char *buf, size_t count) /* {{{ */
  114. {
  115. glob_s_t *pglob = (glob_s_t *)stream->abstract;
  116. php_stream_dirent *ent = (php_stream_dirent*)buf;
  117. const char *path;
  118. /* avoid problems if someone mis-uses the stream */
  119. if (count == sizeof(php_stream_dirent) && pglob) {
  120. if (pglob->index < (size_t)pglob->glob.gl_pathc) {
  121. php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[pglob->index++], pglob->flags & GLOB_APPEND, &path);
  122. PHP_STRLCPY(ent->d_name, path, sizeof(ent->d_name), strlen(path));
  123. return sizeof(php_stream_dirent);
  124. }
  125. pglob->index = pglob->glob.gl_pathc;
  126. if (pglob->path) {
  127. efree(pglob->path);
  128. pglob->path = NULL;
  129. }
  130. }
  131. return -1;
  132. }
  133. /* }}} */
  134. static int php_glob_stream_close(php_stream *stream, int close_handle) /* {{{ */
  135. {
  136. glob_s_t *pglob = (glob_s_t *)stream->abstract;
  137. if (pglob) {
  138. pglob->index = 0;
  139. globfree(&pglob->glob);
  140. if (pglob->path) {
  141. efree(pglob->path);
  142. }
  143. if (pglob->pattern) {
  144. efree(pglob->pattern);
  145. }
  146. }
  147. efree(stream->abstract);
  148. return 0;
  149. }
  150. /* {{{ */
  151. static int php_glob_stream_rewind(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs) /* {{{ */
  152. {
  153. glob_s_t *pglob = (glob_s_t *)stream->abstract;
  154. if (pglob) {
  155. pglob->index = 0;
  156. if (pglob->path) {
  157. efree(pglob->path);
  158. pglob->path = NULL;
  159. }
  160. }
  161. return 0;
  162. }
  163. /* }}} */
  164. const php_stream_ops php_glob_stream_ops = {
  165. NULL, php_glob_stream_read,
  166. php_glob_stream_close, NULL,
  167. "glob",
  168. php_glob_stream_rewind,
  169. NULL, /* cast */
  170. NULL, /* stat */
  171. NULL /* set_option */
  172. };
  173. /* {{{ php_glob_stream_opener */
  174. static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const char *path, const char *mode,
  175. int options, zend_string **opened_path, php_stream_context *context STREAMS_DC)
  176. {
  177. glob_s_t *pglob;
  178. int ret;
  179. const char *tmp, *pos;
  180. if (!strncmp(path, "glob://", sizeof("glob://")-1)) {
  181. path += sizeof("glob://")-1;
  182. if (opened_path) {
  183. *opened_path = zend_string_init(path, strlen(path), 0);
  184. }
  185. }
  186. if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path)) {
  187. return NULL;
  188. }
  189. pglob = ecalloc(sizeof(*pglob), 1);
  190. if (0 != (ret = glob(path, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) {
  191. #ifdef GLOB_NOMATCH
  192. if (GLOB_NOMATCH != ret)
  193. #endif
  194. {
  195. efree(pglob);
  196. return NULL;
  197. }
  198. }
  199. pos = path;
  200. if ((tmp = strrchr(pos, '/')) != NULL) {
  201. pos = tmp+1;
  202. }
  203. #ifdef PHP_WIN32
  204. if ((tmp = strrchr(pos, '\\')) != NULL) {
  205. pos = tmp+1;
  206. }
  207. #endif
  208. pglob->pattern_len = strlen(pos);
  209. pglob->pattern = estrndup(pos, pglob->pattern_len);
  210. pglob->flags |= GLOB_APPEND;
  211. if (pglob->glob.gl_pathc) {
  212. php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[0], 1, &tmp);
  213. } else {
  214. php_glob_stream_path_split(pglob, path, 1, &tmp);
  215. }
  216. return php_stream_alloc(&php_glob_stream_ops, pglob, 0, mode);
  217. }
  218. /* }}} */
  219. static const php_stream_wrapper_ops php_glob_stream_wrapper_ops = {
  220. NULL,
  221. NULL,
  222. NULL,
  223. NULL,
  224. php_glob_stream_opener,
  225. "glob",
  226. NULL,
  227. NULL,
  228. NULL,
  229. NULL,
  230. NULL
  231. };
  232. const php_stream_wrapper php_glob_stream_wrapper = {
  233. &php_glob_stream_wrapper_ops,
  234. NULL,
  235. 0
  236. };
  237. #endif /* HAVE_GLOB */