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