/src/php-src/ext/standard/dir.c
Line | Count | Source (jump to first uncovered line) |
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 | | | http://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 | | | Author: Thies C. Arntzen <thies@thieso.net> | |
14 | | +----------------------------------------------------------------------+ |
15 | | */ |
16 | | |
17 | | /* {{{ includes/startup/misc */ |
18 | | |
19 | | #include "php.h" |
20 | | #include "fopen_wrappers.h" |
21 | | #include "file.h" |
22 | | #include "php_dir.h" |
23 | | #include "php_string.h" |
24 | | #include "php_scandir.h" |
25 | | #include "basic_functions.h" |
26 | | #include "dir_arginfo.h" |
27 | | |
28 | | #if HAVE_UNISTD_H |
29 | | #include <unistd.h> |
30 | | #endif |
31 | | |
32 | | #include <errno.h> |
33 | | |
34 | | #ifdef PHP_WIN32 |
35 | | #include "win32/readdir.h" |
36 | | #endif |
37 | | |
38 | | |
39 | | #ifdef HAVE_GLOB |
40 | | #ifndef PHP_WIN32 |
41 | | #include <glob.h> |
42 | | #else |
43 | | #include "win32/glob.h" |
44 | | #endif |
45 | | #endif |
46 | | |
47 | | typedef struct { |
48 | | zend_resource *default_dir; |
49 | | } php_dir_globals; |
50 | | |
51 | | #ifdef ZTS |
52 | | #define DIRG(v) ZEND_TSRMG(dir_globals_id, php_dir_globals *, v) |
53 | | int dir_globals_id; |
54 | | #else |
55 | 390k | #define DIRG(v) (dir_globals.v) |
56 | | php_dir_globals dir_globals; |
57 | | #endif |
58 | | |
59 | | static zend_class_entry *dir_class_entry_ptr; |
60 | | |
61 | | #define FETCH_DIRP() \ |
62 | 0 | ZEND_PARSE_PARAMETERS_START(0, 1) \ |
63 | 0 | Z_PARAM_OPTIONAL \ |
64 | 0 | Z_PARAM_RESOURCE(id) \ |
65 | 0 | ZEND_PARSE_PARAMETERS_END(); \ |
66 | 0 | if (ZEND_NUM_ARGS() == 0) { \ |
67 | 0 | myself = getThis(); \ |
68 | 0 | if (myself) { \ |
69 | 0 | if ((tmp = zend_hash_str_find(Z_OBJPROP_P(myself), "handle", sizeof("handle")-1)) == NULL) { \ |
70 | 0 | zend_throw_error(NULL, "Unable to find my handle property"); \ |
71 | 0 | RETURN_THROWS(); \ |
72 | 0 | } \ |
73 | 0 | if ((dirp = (php_stream *)zend_fetch_resource_ex(tmp, "Directory", php_file_le_stream())) == NULL) { \ |
74 | 0 | RETURN_THROWS(); \ |
75 | 0 | } \ |
76 | 0 | } else { \ |
77 | 0 | if (!DIRG(default_dir)) { \ |
78 | 0 | zend_type_error("No resource supplied"); \ |
79 | 0 | RETURN_THROWS(); \ |
80 | 0 | } else if ((dirp = (php_stream *)zend_fetch_resource(DIRG(default_dir), "Directory", php_file_le_stream())) == NULL) { \ |
81 | 0 | RETURN_THROWS(); \ |
82 | 0 | } \ |
83 | 0 | } \ |
84 | 0 | } else { \ |
85 | 0 | if ((dirp = (php_stream *)zend_fetch_resource(Z_RES_P(id), "Directory", php_file_le_stream())) == NULL) { \ |
86 | 0 | RETURN_THROWS(); \ |
87 | 0 | } \ |
88 | 0 | } |
89 | | |
90 | | |
91 | | static void php_set_default_dir(zend_resource *res) |
92 | 0 | { |
93 | 0 | if (DIRG(default_dir)) { |
94 | 0 | zend_list_delete(DIRG(default_dir)); |
95 | 0 | } |
96 | |
|
97 | 0 | if (res) { |
98 | 0 | GC_ADDREF(res); |
99 | 0 | } |
100 | |
|
101 | 0 | DIRG(default_dir) = res; |
102 | 0 | } |
103 | | |
104 | | PHP_RINIT_FUNCTION(dir) |
105 | 390k | { |
106 | 390k | DIRG(default_dir) = NULL; |
107 | 390k | return SUCCESS; |
108 | 390k | } |
109 | | |
110 | | PHP_MINIT_FUNCTION(dir) |
111 | 3.47k | { |
112 | 3.47k | static char dirsep_str[2], pathsep_str[2]; |
113 | 3.47k | zend_class_entry dir_class_entry; |
114 | | |
115 | 3.47k | INIT_CLASS_ENTRY(dir_class_entry, "Directory", class_Directory_methods); |
116 | 3.47k | dir_class_entry_ptr = zend_register_internal_class(&dir_class_entry); |
117 | | |
118 | | #ifdef ZTS |
119 | | ts_allocate_id(&dir_globals_id, sizeof(php_dir_globals), NULL, NULL); |
120 | | #endif |
121 | | |
122 | 3.47k | dirsep_str[0] = DEFAULT_SLASH; |
123 | 3.47k | dirsep_str[1] = '\0'; |
124 | 3.47k | REGISTER_STRING_CONSTANT("DIRECTORY_SEPARATOR", dirsep_str, CONST_CS|CONST_PERSISTENT); |
125 | | |
126 | 3.47k | pathsep_str[0] = ZEND_PATHS_SEPARATOR; |
127 | 3.47k | pathsep_str[1] = '\0'; |
128 | 3.47k | REGISTER_STRING_CONSTANT("PATH_SEPARATOR", pathsep_str, CONST_CS|CONST_PERSISTENT); |
129 | | |
130 | 3.47k | REGISTER_LONG_CONSTANT("SCANDIR_SORT_ASCENDING", PHP_SCANDIR_SORT_ASCENDING, CONST_CS | CONST_PERSISTENT); |
131 | 3.47k | REGISTER_LONG_CONSTANT("SCANDIR_SORT_DESCENDING", PHP_SCANDIR_SORT_DESCENDING, CONST_CS | CONST_PERSISTENT); |
132 | 3.47k | REGISTER_LONG_CONSTANT("SCANDIR_SORT_NONE", PHP_SCANDIR_SORT_NONE, CONST_CS | CONST_PERSISTENT); |
133 | | |
134 | 3.47k | #ifdef HAVE_GLOB |
135 | | |
136 | 3.47k | #ifdef GLOB_BRACE |
137 | 3.47k | REGISTER_LONG_CONSTANT("GLOB_BRACE", GLOB_BRACE, CONST_CS | CONST_PERSISTENT); |
138 | | #else |
139 | | # define GLOB_BRACE 0 |
140 | | #endif |
141 | | |
142 | 3.47k | #ifdef GLOB_MARK |
143 | 3.47k | REGISTER_LONG_CONSTANT("GLOB_MARK", GLOB_MARK, CONST_CS | CONST_PERSISTENT); |
144 | | #else |
145 | | # define GLOB_MARK 0 |
146 | | #endif |
147 | | |
148 | 3.47k | #ifdef GLOB_NOSORT |
149 | 3.47k | REGISTER_LONG_CONSTANT("GLOB_NOSORT", GLOB_NOSORT, CONST_CS | CONST_PERSISTENT); |
150 | | #else |
151 | | # define GLOB_NOSORT 0 |
152 | | #endif |
153 | | |
154 | 3.47k | #ifdef GLOB_NOCHECK |
155 | 3.47k | REGISTER_LONG_CONSTANT("GLOB_NOCHECK", GLOB_NOCHECK, CONST_CS | CONST_PERSISTENT); |
156 | | #else |
157 | | # define GLOB_NOCHECK 0 |
158 | | #endif |
159 | | |
160 | 3.47k | #ifdef GLOB_NOESCAPE |
161 | 3.47k | REGISTER_LONG_CONSTANT("GLOB_NOESCAPE", GLOB_NOESCAPE, CONST_CS | CONST_PERSISTENT); |
162 | | #else |
163 | | # define GLOB_NOESCAPE 0 |
164 | | #endif |
165 | | |
166 | 3.47k | #ifdef GLOB_ERR |
167 | 3.47k | REGISTER_LONG_CONSTANT("GLOB_ERR", GLOB_ERR, CONST_CS | CONST_PERSISTENT); |
168 | | #else |
169 | | # define GLOB_ERR 0 |
170 | | #endif |
171 | | |
172 | | #ifndef GLOB_ONLYDIR |
173 | | # define GLOB_ONLYDIR (1<<30) |
174 | | # define GLOB_EMULATE_ONLYDIR |
175 | | # define GLOB_FLAGMASK (~GLOB_ONLYDIR) |
176 | | #else |
177 | 0 | # define GLOB_FLAGMASK (~0) |
178 | 3.47k | #endif |
179 | | |
180 | | /* This is used for checking validity of passed flags (passing invalid flags causes segfault in glob()!! */ |
181 | 0 | #define GLOB_AVAILABLE_FLAGS (0 | GLOB_BRACE | GLOB_MARK | GLOB_NOSORT | GLOB_NOCHECK | GLOB_NOESCAPE | GLOB_ERR | GLOB_ONLYDIR) |
182 | | |
183 | 3.47k | REGISTER_LONG_CONSTANT("GLOB_ONLYDIR", GLOB_ONLYDIR, CONST_CS | CONST_PERSISTENT); |
184 | 3.47k | REGISTER_LONG_CONSTANT("GLOB_AVAILABLE_FLAGS", GLOB_AVAILABLE_FLAGS, CONST_CS | CONST_PERSISTENT); |
185 | | |
186 | 3.47k | #endif /* HAVE_GLOB */ |
187 | | |
188 | 3.47k | return SUCCESS; |
189 | 3.47k | } |
190 | | /* }}} */ |
191 | | |
192 | | /* {{{ internal functions */ |
193 | | static void _php_do_opendir(INTERNAL_FUNCTION_PARAMETERS, int createobject) |
194 | 0 | { |
195 | 0 | char *dirname; |
196 | 0 | size_t dir_len; |
197 | 0 | zval *zcontext = NULL; |
198 | 0 | php_stream_context *context = NULL; |
199 | 0 | php_stream *dirp; |
200 | |
|
201 | 0 | ZEND_PARSE_PARAMETERS_START(1, 2) |
202 | 0 | Z_PARAM_PATH(dirname, dir_len) |
203 | 0 | Z_PARAM_OPTIONAL |
204 | 0 | Z_PARAM_RESOURCE(zcontext) |
205 | 0 | ZEND_PARSE_PARAMETERS_END(); |
206 | |
|
207 | 0 | context = php_stream_context_from_zval(zcontext, 0); |
208 | |
|
209 | 0 | dirp = php_stream_opendir(dirname, REPORT_ERRORS, context); |
210 | |
|
211 | 0 | if (dirp == NULL) { |
212 | 0 | RETURN_FALSE; |
213 | 0 | } |
214 | |
|
215 | 0 | dirp->flags |= PHP_STREAM_FLAG_NO_FCLOSE; |
216 | |
|
217 | 0 | php_set_default_dir(dirp->res); |
218 | |
|
219 | 0 | if (createobject) { |
220 | 0 | object_init_ex(return_value, dir_class_entry_ptr); |
221 | 0 | add_property_stringl(return_value, "path", dirname, dir_len); |
222 | 0 | add_property_resource(return_value, "handle", dirp->res); |
223 | 0 | php_stream_auto_cleanup(dirp); /* so we don't get warnings under debug */ |
224 | 0 | } else { |
225 | 0 | php_stream_to_zval(dirp, return_value); |
226 | 0 | } |
227 | 0 | } |
228 | | /* }}} */ |
229 | | |
230 | | /* {{{ proto resource|false opendir(string path[, resource context]) |
231 | | Open a directory and return a dir_handle */ |
232 | | PHP_FUNCTION(opendir) |
233 | 0 | { |
234 | 0 | _php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); |
235 | 0 | } |
236 | | /* }}} */ |
237 | | |
238 | | /* {{{ proto object|false dir(string directory[, resource context]) |
239 | | Directory class with properties, handle and class and methods read, rewind and close */ |
240 | | PHP_FUNCTION(getdir) |
241 | 0 | { |
242 | 0 | _php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); |
243 | 0 | } |
244 | | /* }}} */ |
245 | | |
246 | | /* {{{ proto bool closedir([resource dir_handle]) |
247 | | Close directory connection identified by the dir_handle */ |
248 | | PHP_FUNCTION(closedir) |
249 | 0 | { |
250 | 0 | zval *id = NULL, *tmp, *myself; |
251 | 0 | php_stream *dirp; |
252 | 0 | zend_resource *res; |
253 | |
|
254 | 0 | FETCH_DIRP(); |
255 | |
|
256 | 0 | if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) { |
257 | 0 | zend_argument_type_error(1, "must be a valid Directory resource"); |
258 | 0 | RETURN_THROWS(); |
259 | 0 | } |
260 | |
|
261 | 0 | res = dirp->res; |
262 | 0 | zend_list_close(dirp->res); |
263 | |
|
264 | 0 | if (res == DIRG(default_dir)) { |
265 | 0 | php_set_default_dir(NULL); |
266 | 0 | } |
267 | 0 | } |
268 | | /* }}} */ |
269 | | |
270 | | #if defined(HAVE_CHROOT) && !defined(ZTS) && ENABLE_CHROOT_FUNC |
271 | | /* {{{ proto bool chroot(string directory) |
272 | | Change root directory */ |
273 | | PHP_FUNCTION(chroot) |
274 | | { |
275 | | char *str; |
276 | | int ret; |
277 | | size_t str_len; |
278 | | |
279 | | ZEND_PARSE_PARAMETERS_START(1, 1) |
280 | | Z_PARAM_PATH(str, str_len) |
281 | | ZEND_PARSE_PARAMETERS_END(); |
282 | | |
283 | | ret = chroot(str); |
284 | | if (ret != 0) { |
285 | | php_error_docref(NULL, E_WARNING, "%s (errno %d)", strerror(errno), errno); |
286 | | RETURN_FALSE; |
287 | | } |
288 | | |
289 | | php_clear_stat_cache(1, NULL, 0); |
290 | | |
291 | | ret = chdir("/"); |
292 | | |
293 | | if (ret != 0) { |
294 | | php_error_docref(NULL, E_WARNING, "%s (errno %d)", strerror(errno), errno); |
295 | | RETURN_FALSE; |
296 | | } |
297 | | |
298 | | RETURN_TRUE; |
299 | | } |
300 | | /* }}} */ |
301 | | #endif |
302 | | |
303 | | /* {{{ proto bool chdir(string directory) |
304 | | Change the current directory */ |
305 | | PHP_FUNCTION(chdir) |
306 | 0 | { |
307 | 0 | char *str; |
308 | 0 | int ret; |
309 | 0 | size_t str_len; |
310 | |
|
311 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
312 | 0 | Z_PARAM_PATH(str, str_len) |
313 | 0 | ZEND_PARSE_PARAMETERS_END(); |
314 | |
|
315 | 0 | if (php_check_open_basedir(str)) { |
316 | 0 | RETURN_FALSE; |
317 | 0 | } |
318 | 0 | ret = VCWD_CHDIR(str); |
319 | |
|
320 | 0 | if (ret != 0) { |
321 | 0 | php_error_docref(NULL, E_WARNING, "%s (errno %d)", strerror(errno), errno); |
322 | 0 | RETURN_FALSE; |
323 | 0 | } |
324 | |
|
325 | 0 | if (BG(CurrentStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentStatFile), strlen(BG(CurrentStatFile)))) { |
326 | 0 | efree(BG(CurrentStatFile)); |
327 | 0 | BG(CurrentStatFile) = NULL; |
328 | 0 | } |
329 | 0 | if (BG(CurrentLStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentLStatFile), strlen(BG(CurrentLStatFile)))) { |
330 | 0 | efree(BG(CurrentLStatFile)); |
331 | 0 | BG(CurrentLStatFile) = NULL; |
332 | 0 | } |
333 | |
|
334 | 0 | RETURN_TRUE; |
335 | 0 | } |
336 | | /* }}} */ |
337 | | |
338 | | /* {{{ proto mixed getcwd(void) |
339 | | Gets the current directory */ |
340 | | PHP_FUNCTION(getcwd) |
341 | 0 | { |
342 | 0 | char path[MAXPATHLEN]; |
343 | 0 | char *ret=NULL; |
344 | |
|
345 | 0 | ZEND_PARSE_PARAMETERS_NONE(); |
346 | |
|
347 | 0 | #if HAVE_GETCWD |
348 | 0 | ret = VCWD_GETCWD(path, MAXPATHLEN); |
349 | | #elif HAVE_GETWD |
350 | | ret = VCWD_GETWD(path); |
351 | | #endif |
352 | |
|
353 | 0 | if (ret) { |
354 | 0 | RETURN_STRING(path); |
355 | 0 | } else { |
356 | 0 | RETURN_FALSE; |
357 | 0 | } |
358 | 0 | } |
359 | | /* }}} */ |
360 | | |
361 | | /* {{{ proto void rewinddir([resource dir_handle]) |
362 | | Rewind dir_handle back to the start */ |
363 | | PHP_FUNCTION(rewinddir) |
364 | 0 | { |
365 | 0 | zval *id = NULL, *tmp, *myself; |
366 | 0 | php_stream *dirp; |
367 | |
|
368 | 0 | FETCH_DIRP(); |
369 | |
|
370 | 0 | if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) { |
371 | 0 | zend_argument_type_error(1, "must be a valid Directory resource"); |
372 | 0 | RETURN_THROWS(); |
373 | 0 | } |
374 | |
|
375 | 0 | php_stream_rewinddir(dirp); |
376 | 0 | } |
377 | | /* }}} */ |
378 | | |
379 | | /* {{{ proto string|false readdir([resource dir_handle]) |
380 | | Read directory entry from dir_handle */ |
381 | | PHP_FUNCTION(readdir) |
382 | 0 | { |
383 | 0 | zval *id = NULL, *tmp, *myself; |
384 | 0 | php_stream *dirp; |
385 | 0 | php_stream_dirent entry; |
386 | |
|
387 | 0 | FETCH_DIRP(); |
388 | |
|
389 | 0 | if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) { |
390 | 0 | zend_argument_type_error(1, "must be a valid Directory resource"); |
391 | 0 | RETURN_THROWS(); |
392 | 0 | } |
393 | |
|
394 | 0 | if (php_stream_readdir(dirp, &entry)) { |
395 | 0 | RETURN_STRINGL(entry.d_name, strlen(entry.d_name)); |
396 | 0 | } |
397 | 0 | RETURN_FALSE; |
398 | 0 | } |
399 | | /* }}} */ |
400 | | |
401 | | #ifdef HAVE_GLOB |
402 | | /* {{{ proto array|false glob(string pattern [, int flags]) |
403 | | Find pathnames matching a pattern */ |
404 | | PHP_FUNCTION(glob) |
405 | 0 | { |
406 | 0 | size_t cwd_skip = 0; |
407 | | #ifdef ZTS |
408 | | char cwd[MAXPATHLEN]; |
409 | | char work_pattern[MAXPATHLEN]; |
410 | | char *result; |
411 | | #endif |
412 | 0 | char *pattern = NULL; |
413 | 0 | size_t pattern_len; |
414 | 0 | zend_long flags = 0; |
415 | 0 | glob_t globbuf; |
416 | 0 | size_t n; |
417 | 0 | int ret; |
418 | 0 | zend_bool basedir_limit = 0; |
419 | |
|
420 | 0 | ZEND_PARSE_PARAMETERS_START(1, 2) |
421 | 0 | Z_PARAM_PATH(pattern, pattern_len) |
422 | 0 | Z_PARAM_OPTIONAL |
423 | 0 | Z_PARAM_LONG(flags) |
424 | 0 | ZEND_PARSE_PARAMETERS_END(); |
425 | |
|
426 | 0 | if (pattern_len >= MAXPATHLEN) { |
427 | 0 | php_error_docref(NULL, E_WARNING, "Pattern exceeds the maximum allowed length of %d characters", MAXPATHLEN); |
428 | 0 | RETURN_FALSE; |
429 | 0 | } |
430 | |
|
431 | 0 | if ((GLOB_AVAILABLE_FLAGS & flags) != flags) { |
432 | 0 | php_error_docref(NULL, E_WARNING, "At least one of the passed flags is invalid or not supported on this platform"); |
433 | 0 | RETURN_FALSE; |
434 | 0 | } |
435 | |
|
436 | | #ifdef ZTS |
437 | | if (!IS_ABSOLUTE_PATH(pattern, pattern_len)) { |
438 | | result = VCWD_GETCWD(cwd, MAXPATHLEN); |
439 | | if (!result) { |
440 | | cwd[0] = '\0'; |
441 | | } |
442 | | #ifdef PHP_WIN32 |
443 | | if (IS_SLASH(*pattern)) { |
444 | | cwd[2] = '\0'; |
445 | | } |
446 | | #endif |
447 | | cwd_skip = strlen(cwd)+1; |
448 | | |
449 | | snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, pattern); |
450 | | pattern = work_pattern; |
451 | | } |
452 | | #endif |
453 | | |
454 | |
|
455 | 0 | memset(&globbuf, 0, sizeof(glob_t)); |
456 | 0 | globbuf.gl_offs = 0; |
457 | 0 | if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) { |
458 | 0 | #ifdef GLOB_NOMATCH |
459 | 0 | if (GLOB_NOMATCH == ret) { |
460 | | /* Some glob implementation simply return no data if no matches |
461 | | were found, others return the GLOB_NOMATCH error code. |
462 | | We don't want to treat GLOB_NOMATCH as an error condition |
463 | | so that PHP glob() behaves the same on both types of |
464 | | implementations and so that 'foreach (glob() as ...' |
465 | | can be used for simple glob() calls without further error |
466 | | checking. |
467 | | */ |
468 | 0 | goto no_results; |
469 | 0 | } |
470 | 0 | #endif |
471 | 0 | RETURN_FALSE; |
472 | 0 | } |
473 | | |
474 | | /* now catch the FreeBSD style of "no matches" */ |
475 | 0 | if (!globbuf.gl_pathc || !globbuf.gl_pathv) { |
476 | 0 | #ifdef GLOB_NOMATCH |
477 | 0 | no_results: |
478 | 0 | #endif |
479 | 0 | #ifndef PHP_WIN32 |
480 | | /* Paths containing '*', '?' and some other chars are |
481 | | illegal on Windows but legit on other platforms. For |
482 | | this reason the direct basedir check against the glob |
483 | | query is senseless on windows. For instance while *.txt |
484 | | is a pretty valid filename on EXT3, it's invalid on NTFS. */ |
485 | 0 | if (PG(open_basedir) && *PG(open_basedir)) { |
486 | 0 | if (php_check_open_basedir_ex(pattern, 0)) { |
487 | 0 | RETURN_FALSE; |
488 | 0 | } |
489 | 0 | } |
490 | 0 | #endif |
491 | 0 | array_init(return_value); |
492 | 0 | return; |
493 | 0 | } |
494 | | |
495 | 0 | array_init(return_value); |
496 | 0 | for (n = 0; n < (size_t)globbuf.gl_pathc; n++) { |
497 | 0 | if (PG(open_basedir) && *PG(open_basedir)) { |
498 | 0 | if (php_check_open_basedir_ex(globbuf.gl_pathv[n], 0)) { |
499 | 0 | basedir_limit = 1; |
500 | 0 | continue; |
501 | 0 | } |
502 | 0 | } |
503 | | /* we need to do this every time since GLOB_ONLYDIR does not guarantee that |
504 | | * all directories will be filtered. GNU libc documentation states the |
505 | | * following: |
506 | | * If the information about the type of the file is easily available |
507 | | * non-directories will be rejected but no extra work will be done to |
508 | | * determine the information for each file. I.e., the caller must still be |
509 | | * able to filter directories out. |
510 | | */ |
511 | 0 | if (flags & GLOB_ONLYDIR) { |
512 | 0 | zend_stat_t s; |
513 | |
|
514 | 0 | if (0 != VCWD_STAT(globbuf.gl_pathv[n], &s)) { |
515 | 0 | continue; |
516 | 0 | } |
517 | | |
518 | 0 | if (S_IFDIR != (s.st_mode & S_IFMT)) { |
519 | 0 | continue; |
520 | 0 | } |
521 | 0 | } |
522 | 0 | add_next_index_string(return_value, globbuf.gl_pathv[n]+cwd_skip); |
523 | 0 | } |
524 | |
|
525 | 0 | globfree(&globbuf); |
526 | |
|
527 | 0 | if (basedir_limit && !zend_hash_num_elements(Z_ARRVAL_P(return_value))) { |
528 | 0 | zend_array_destroy(Z_ARR_P(return_value)); |
529 | 0 | RETURN_FALSE; |
530 | 0 | } |
531 | 0 | } |
532 | | /* }}} */ |
533 | | #endif |
534 | | |
535 | | /* {{{ proto array|false scandir(string dir [, int sorting_order [, resource context]]) |
536 | | List files & directories inside the specified path */ |
537 | | PHP_FUNCTION(scandir) |
538 | 0 | { |
539 | 0 | char *dirn; |
540 | 0 | size_t dirn_len; |
541 | 0 | zend_long flags = 0; |
542 | 0 | zend_string **namelist; |
543 | 0 | int n, i; |
544 | 0 | zval *zcontext = NULL; |
545 | 0 | php_stream_context *context = NULL; |
546 | |
|
547 | 0 | ZEND_PARSE_PARAMETERS_START(1, 3) |
548 | 0 | Z_PARAM_PATH(dirn, dirn_len) |
549 | 0 | Z_PARAM_OPTIONAL |
550 | 0 | Z_PARAM_LONG(flags) |
551 | 0 | Z_PARAM_RESOURCE(zcontext) |
552 | 0 | ZEND_PARSE_PARAMETERS_END(); |
553 | |
|
554 | 0 | if (dirn_len < 1) { |
555 | 0 | zend_argument_value_error(1, "cannot be empty"); |
556 | 0 | RETURN_THROWS(); |
557 | 0 | } |
558 | |
|
559 | 0 | if (zcontext) { |
560 | 0 | context = php_stream_context_from_zval(zcontext, 0); |
561 | 0 | } |
562 | |
|
563 | 0 | if (flags == PHP_SCANDIR_SORT_ASCENDING) { |
564 | 0 | n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasort); |
565 | 0 | } else if (flags == PHP_SCANDIR_SORT_NONE) { |
566 | 0 | n = php_stream_scandir(dirn, &namelist, context, NULL); |
567 | 0 | } else { |
568 | 0 | n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasortr); |
569 | 0 | } |
570 | 0 | if (n < 0) { |
571 | 0 | php_error_docref(NULL, E_WARNING, "(errno %d): %s", errno, strerror(errno)); |
572 | 0 | RETURN_FALSE; |
573 | 0 | } |
574 | |
|
575 | 0 | array_init(return_value); |
576 | |
|
577 | 0 | for (i = 0; i < n; i++) { |
578 | 0 | add_next_index_str(return_value, namelist[i]); |
579 | 0 | } |
580 | |
|
581 | 0 | if (n) { |
582 | 0 | efree(namelist); |
583 | 0 | } |
584 | 0 | } |
585 | | /* }}} */ |