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