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