xref: /PHP-7.3/main/streams/glob_wrapper.c (revision ec28d4c2)
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