xref: /PHP-7.4/main/streams/glob_wrapper.c (revision d59aac58)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 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,size_t * plen STREAMS_DC)48 PHPAPI char* _php_glob_stream_get_path(php_stream *stream, 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 		return pglob->path;
57 	} else {
58 		if (plen) {
59 			*plen = 0;
60 		}
61 		return NULL;
62 	}
63 }
64 /* }}} */
65 
_php_glob_stream_get_pattern(php_stream * stream,size_t * plen STREAMS_DC)66 PHPAPI char* _php_glob_stream_get_pattern(php_stream *stream, size_t *plen STREAMS_DC) /* {{{ */
67 {
68 	glob_s_t *pglob = (glob_s_t *)stream->abstract;
69 
70 	if (pglob && pglob->pattern) {
71 		if (plen) {
72 			*plen = pglob->pattern_len;
73 		}
74 		return pglob->pattern;
75 	} else {
76 		if (plen) {
77 			*plen = 0;
78 		}
79 		return NULL;
80 	}
81 }
82 /* }}} */
83 
_php_glob_stream_get_count(php_stream * stream,int * pflags STREAMS_DC)84 PHPAPI int _php_glob_stream_get_count(php_stream *stream, int *pflags STREAMS_DC) /* {{{ */
85 {
86 	glob_s_t *pglob = (glob_s_t *)stream->abstract;
87 
88 	if (pglob) {
89 		if (pflags) {
90 			*pflags = pglob->flags;
91 		}
92 		return pglob->glob.gl_pathc;
93 	} else {
94 		if (pflags) {
95 			*pflags = 0;
96 		}
97 		return 0;
98 	}
99 }
100 /* }}} */
101 
php_glob_stream_path_split(glob_s_t * pglob,const char * path,int get_path,const char ** p_file)102 static void php_glob_stream_path_split(glob_s_t *pglob, const char *path, int get_path, const char **p_file) /* {{{ */
103 {
104 	const char *pos, *gpath = path;
105 
106 	if ((pos = strrchr(path, '/')) != NULL) {
107 		path = pos+1;
108 	}
109 #ifdef PHP_WIN32
110 	if ((pos = strrchr(path, '\\')) != NULL) {
111 		path = pos+1;
112 	}
113 #endif
114 
115 	*p_file = path;
116 
117 	if (get_path) {
118 		if (pglob->path) {
119 			efree(pglob->path);
120 		}
121 		if ((path - gpath) > 1) {
122 			path--;
123 		}
124 		pglob->path_len = path - gpath;
125 		pglob->path = estrndup(gpath, pglob->path_len);
126 	}
127 }
128 /* }}} */
129 
php_glob_stream_read(php_stream * stream,char * buf,size_t count)130 static ssize_t php_glob_stream_read(php_stream *stream, char *buf, size_t count) /* {{{ */
131 {
132 	glob_s_t *pglob = (glob_s_t *)stream->abstract;
133 	php_stream_dirent *ent = (php_stream_dirent*)buf;
134 	const char *path;
135 
136 	/* avoid problems if someone mis-uses the stream */
137 	if (count == sizeof(php_stream_dirent) && pglob) {
138 		if (pglob->index < (size_t)pglob->glob.gl_pathc) {
139 			php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[pglob->index++], pglob->flags & GLOB_APPEND, &path);
140 			PHP_STRLCPY(ent->d_name, path, sizeof(ent->d_name), strlen(path));
141 			return sizeof(php_stream_dirent);
142 		}
143 		pglob->index = pglob->glob.gl_pathc;
144 		if (pglob->path) {
145 			efree(pglob->path);
146 			pglob->path = NULL;
147 		}
148 	}
149 
150 	return -1;
151 }
152 /* }}} */
153 
php_glob_stream_close(php_stream * stream,int close_handle)154 static int php_glob_stream_close(php_stream *stream, int close_handle)  /* {{{ */
155 {
156 	glob_s_t *pglob = (glob_s_t *)stream->abstract;
157 
158 	if (pglob) {
159 		pglob->index = 0;
160 		globfree(&pglob->glob);
161 		if (pglob->path) {
162 			efree(pglob->path);
163 		}
164 		if (pglob->pattern) {
165 			efree(pglob->pattern);
166 		}
167 	}
168 	efree(stream->abstract);
169 	return 0;
170 }
171 /* {{{ */
172 
php_glob_stream_rewind(php_stream * stream,zend_off_t offset,int whence,zend_off_t * newoffs)173 static int php_glob_stream_rewind(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs) /* {{{ */
174 {
175 	glob_s_t *pglob = (glob_s_t *)stream->abstract;
176 
177 	if (pglob) {
178 		pglob->index = 0;
179 		if (pglob->path) {
180 			efree(pglob->path);
181 			pglob->path = NULL;
182 		}
183 	}
184 	return 0;
185 }
186 /* }}} */
187 
188 const php_stream_ops  php_glob_stream_ops = {
189 	NULL, php_glob_stream_read,
190 	php_glob_stream_close, NULL,
191 	"glob",
192 	php_glob_stream_rewind,
193 	NULL, /* cast */
194 	NULL, /* stat */
195 	NULL  /* set_option */
196 };
197 
198  /* {{{ 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)199 static php_stream *php_glob_stream_opener(php_stream_wrapper *wrapper, const char *path, const char *mode,
200 		int options, zend_string **opened_path, php_stream_context *context STREAMS_DC)
201 {
202 	glob_s_t *pglob;
203 	int ret;
204 	const char *tmp, *pos;
205 
206 	if (!strncmp(path, "glob://", sizeof("glob://")-1)) {
207 		path += sizeof("glob://")-1;
208 		if (opened_path) {
209 			*opened_path = zend_string_init(path, strlen(path), 0);
210 		}
211 	}
212 
213 	if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path)) {
214 		return NULL;
215 	}
216 
217 	pglob = ecalloc(sizeof(*pglob), 1);
218 
219 	if (0 != (ret = glob(path, pglob->flags & GLOB_FLAGMASK, NULL, &pglob->glob))) {
220 #ifdef GLOB_NOMATCH
221 		if (GLOB_NOMATCH != ret)
222 #endif
223 		{
224 			efree(pglob);
225 			return NULL;
226 		}
227 	}
228 
229 	pos = path;
230 	if ((tmp = strrchr(pos, '/')) != NULL) {
231 		pos = tmp+1;
232 	}
233 #ifdef PHP_WIN32
234 	if ((tmp = strrchr(pos, '\\')) != NULL) {
235 		pos = tmp+1;
236 	}
237 #endif
238 
239 	pglob->pattern_len = strlen(pos);
240 	pglob->pattern = estrndup(pos, pglob->pattern_len);
241 
242 	pglob->flags |= GLOB_APPEND;
243 
244 	if (pglob->glob.gl_pathc) {
245 		php_glob_stream_path_split(pglob, pglob->glob.gl_pathv[0], 1, &tmp);
246 	} else {
247 		php_glob_stream_path_split(pglob, path, 1, &tmp);
248 	}
249 
250 	return php_stream_alloc(&php_glob_stream_ops, pglob, 0, mode);
251 }
252 /* }}} */
253 
254 static const php_stream_wrapper_ops  php_glob_stream_wrapper_ops = {
255 	NULL,
256 	NULL,
257 	NULL,
258 	NULL,
259 	php_glob_stream_opener,
260 	"glob",
261 	NULL,
262 	NULL,
263 	NULL,
264 	NULL,
265 	NULL
266 };
267 
268 const php_stream_wrapper  php_glob_stream_wrapper = {
269 	&php_glob_stream_wrapper_ops,
270 	NULL,
271 	0
272 };
273 #endif /* HAVE_GLOB */
274