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