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