1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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 : | Author: Thies C. Arntzen <thies@thieso.net> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: dir.c 286624 2009-08-01 14:45:42Z kalle $ */
20 :
21 : /* {{{ includes/startup/misc */
22 :
23 : #include "php.h"
24 : #include "fopen_wrappers.h"
25 : #include "file.h"
26 : #include "php_dir.h"
27 : #include "php_string.h"
28 : #include "php_scandir.h"
29 : #include "basic_functions.h"
30 :
31 : #ifdef HAVE_DIRENT_H
32 : #include <dirent.h>
33 : #endif
34 :
35 : #if HAVE_UNISTD_H
36 : #include <unistd.h>
37 : #endif
38 :
39 : #include <errno.h>
40 :
41 : #ifdef PHP_WIN32
42 : #include "win32/readdir.h"
43 : #endif
44 :
45 :
46 : #ifdef HAVE_GLOB
47 : #ifndef PHP_WIN32
48 : #include <glob.h>
49 : #else
50 : #include "win32/glob.h"
51 : #endif
52 : #endif
53 :
54 : typedef struct {
55 : int default_dir;
56 : } php_dir_globals;
57 :
58 : #ifdef ZTS
59 : #define DIRG(v) TSRMG(dir_globals_id, php_dir_globals *, v)
60 : int dir_globals_id;
61 : #else
62 : #define DIRG(v) (dir_globals.v)
63 : php_dir_globals dir_globals;
64 : #endif
65 :
66 : #if 0
67 : typedef struct {
68 : int id;
69 : DIR *dir;
70 : } php_dir;
71 :
72 : static int le_dirp;
73 : #endif
74 :
75 : static zend_class_entry *dir_class_entry_ptr;
76 :
77 : #define FETCH_DIRP() \
78 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &id) == FAILURE) { \
79 : return; \
80 : } \
81 : if (ZEND_NUM_ARGS() == 0) { \
82 : myself = getThis(); \
83 : if (myself) { \
84 : if (zend_hash_find(Z_OBJPROP_P(myself), "handle", sizeof("handle"), (void **)&tmp) == FAILURE) { \
85 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find my handle property"); \
86 : RETURN_FALSE; \
87 : } \
88 : ZEND_FETCH_RESOURCE(dirp, php_stream *, tmp, -1, "Directory", php_file_le_stream()); \
89 : } else { \
90 : ZEND_FETCH_RESOURCE(dirp, php_stream *, 0, DIRG(default_dir), "Directory", php_file_le_stream()); \
91 : } \
92 : } else { \
93 : dirp = (php_stream *) zend_fetch_resource(&id TSRMLS_CC, -1, "Directory", NULL, 1, php_file_le_stream()); \
94 : if (!dirp) \
95 : RETURN_FALSE; \
96 : }
97 :
98 : static const zend_function_entry php_dir_class_functions[] = {
99 : PHP_FALIAS(close, closedir, NULL)
100 : PHP_FALIAS(rewind, rewinddir, NULL)
101 : PHP_NAMED_FE(read, php_if_readdir, NULL)
102 : {NULL, NULL, NULL}
103 : };
104 :
105 :
106 : static void php_set_default_dir(int id TSRMLS_DC)
107 5282 : {
108 5282 : if (DIRG(default_dir)!=-1) {
109 3139 : zend_list_delete(DIRG(default_dir));
110 : }
111 :
112 5282 : if (id != -1) {
113 3169 : zend_list_addref(id);
114 : }
115 :
116 5282 : DIRG(default_dir) = id;
117 5282 : }
118 :
119 : PHP_RINIT_FUNCTION(dir)
120 16993 : {
121 16993 : DIRG(default_dir) = -1;
122 16993 : return SUCCESS;
123 : }
124 :
125 : PHP_MINIT_FUNCTION(dir)
126 17007 : {
127 : static char dirsep_str[2], pathsep_str[2];
128 : zend_class_entry dir_class_entry;
129 :
130 17007 : INIT_CLASS_ENTRY(dir_class_entry, "Directory", php_dir_class_functions);
131 17007 : dir_class_entry_ptr = zend_register_internal_class(&dir_class_entry TSRMLS_CC);
132 :
133 : #ifdef ZTS
134 : ts_allocate_id(&dir_globals_id, sizeof(php_dir_globals), NULL, NULL);
135 : #endif
136 :
137 17007 : dirsep_str[0] = DEFAULT_SLASH;
138 17007 : dirsep_str[1] = '\0';
139 17007 : REGISTER_STRING_CONSTANT("DIRECTORY_SEPARATOR", dirsep_str, CONST_CS|CONST_PERSISTENT);
140 :
141 17007 : pathsep_str[0] = ZEND_PATHS_SEPARATOR;
142 17007 : pathsep_str[1] = '\0';
143 17007 : REGISTER_STRING_CONSTANT("PATH_SEPARATOR", pathsep_str, CONST_CS|CONST_PERSISTENT);
144 :
145 : #ifdef HAVE_GLOB
146 :
147 : #ifdef GLOB_BRACE
148 17007 : REGISTER_LONG_CONSTANT("GLOB_BRACE", GLOB_BRACE, CONST_CS | CONST_PERSISTENT);
149 : #else
150 : # define GLOB_BRACE 0
151 : #endif
152 :
153 : #ifdef GLOB_MARK
154 17007 : REGISTER_LONG_CONSTANT("GLOB_MARK", GLOB_MARK, CONST_CS | CONST_PERSISTENT);
155 : #else
156 : # define GLOB_MARK 0
157 : #endif
158 :
159 : #ifdef GLOB_NOSORT
160 17007 : REGISTER_LONG_CONSTANT("GLOB_NOSORT", GLOB_NOSORT, CONST_CS | CONST_PERSISTENT);
161 : #else
162 : # define GLOB_NOSORT 0
163 : #endif
164 :
165 : #ifdef GLOB_NOCHECK
166 17007 : REGISTER_LONG_CONSTANT("GLOB_NOCHECK", GLOB_NOCHECK, CONST_CS | CONST_PERSISTENT);
167 : #else
168 : # define GLOB_NOCHECK 0
169 : #endif
170 :
171 : #ifdef GLOB_NOESCAPE
172 17007 : REGISTER_LONG_CONSTANT("GLOB_NOESCAPE", GLOB_NOESCAPE, CONST_CS | CONST_PERSISTENT);
173 : #else
174 : # define GLOB_NOESCAPE 0
175 : #endif
176 :
177 : #ifdef GLOB_ERR
178 17007 : REGISTER_LONG_CONSTANT("GLOB_ERR", GLOB_ERR, CONST_CS | CONST_PERSISTENT);
179 : #else
180 : # define GLOB_ERR 0
181 : #endif
182 :
183 : #ifndef GLOB_ONLYDIR
184 : # define GLOB_ONLYDIR (1<<30)
185 : # define GLOB_EMULATE_ONLYDIR
186 : # define GLOB_FLAGMASK (~GLOB_ONLYDIR)
187 : #else
188 : # define GLOB_FLAGMASK (~0)
189 : #endif
190 :
191 : /* This is used for checking validity of passed flags (passing invalid flags causes segfault in glob()!! */
192 : #define GLOB_AVAILABLE_FLAGS (0 | GLOB_BRACE | GLOB_MARK | GLOB_NOSORT | GLOB_NOCHECK | GLOB_NOESCAPE | GLOB_ERR | GLOB_ONLYDIR)
193 :
194 17007 : REGISTER_LONG_CONSTANT("GLOB_ONLYDIR", GLOB_ONLYDIR, CONST_CS | CONST_PERSISTENT);
195 17007 : REGISTER_LONG_CONSTANT("GLOB_AVAILABLE_FLAGS", GLOB_AVAILABLE_FLAGS, CONST_CS | CONST_PERSISTENT);
196 :
197 : #endif /* HAVE_GLOB */
198 :
199 17007 : return SUCCESS;
200 : }
201 : /* }}} */
202 :
203 : /* {{{ internal functions */
204 : static void _php_do_opendir(INTERNAL_FUNCTION_PARAMETERS, int createobject)
205 3311 : {
206 : zval **ppdir;
207 3311 : UChar *udir = NULL;
208 : char *dir;
209 : int dir_len, udir_len;
210 3311 : zval *zcontext = NULL;
211 3311 : php_stream_context *context = NULL;
212 : php_stream *dirp;
213 :
214 3311 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|r", &ppdir, &zcontext) == FAILURE) {
215 56 : return;
216 : }
217 :
218 3255 : RETVAL_FALSE;
219 :
220 3255 : if (createobject && Z_TYPE_PP(ppdir) == IS_UNICODE) {
221 : /* Save for later */
222 45 : udir = eustrndup(Z_USTRVAL_PP(ppdir), Z_USTRLEN_PP(ppdir));
223 45 : udir_len = Z_USTRLEN_PP(ppdir);
224 : }
225 :
226 3255 : context = php_stream_context_from_zval(zcontext, 0);
227 3255 : if (FAILURE == php_stream_path_param_encode(ppdir, &dir, &dir_len, REPORT_ERRORS, context)) {
228 0 : goto opendir_cleanup;
229 : }
230 :
231 3255 : dirp = php_stream_opendir(dir, REPORT_ERRORS, context);
232 3255 : if (dirp == NULL) {
233 86 : goto opendir_cleanup;
234 : }
235 :
236 3169 : dirp->flags |= PHP_STREAM_FLAG_NO_FCLOSE;
237 :
238 3169 : php_set_default_dir(dirp->rsrc_id TSRMLS_CC);
239 :
240 3169 : if (createobject) {
241 22 : object_init_ex(return_value, dir_class_entry_ptr);
242 22 : if (udir) {
243 22 : add_property_unicodel(return_value, "path", udir, udir_len, 0);
244 :
245 : /* Avoid auto-cleanup */
246 22 : udir = NULL;
247 : } else {
248 0 : add_property_stringl(return_value, "path", dir, dir_len, 1);
249 : }
250 22 : add_property_resource(return_value, "handle", dirp->rsrc_id);
251 : php_stream_auto_cleanup(dirp); /* so we don't get warnings under debug */
252 : } else {
253 3147 : php_stream_to_zval(dirp, return_value);
254 : }
255 :
256 3255 : opendir_cleanup:
257 3255 : if (udir) {
258 23 : efree(udir);
259 : }
260 : }
261 : /* }}} */
262 :
263 : /* {{{ proto mixed opendir(string path[, resource context]) U
264 : Open a directory and return a dir_handle */
265 : PHP_FUNCTION(opendir)
266 3220 : {
267 3220 : _php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
268 3220 : }
269 : /* }}} */
270 :
271 : /* {{{ proto object dir(string directory[, resource context]) U
272 : Directory class with properties, handle and class and methods read, rewind and close */
273 : PHP_FUNCTION(getdir)
274 91 : {
275 91 : _php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
276 91 : }
277 : /* }}} */
278 :
279 : /* {{{ proto void closedir([resource dir_handle]) U
280 : Close directory connection identified by the dir_handle */
281 : PHP_FUNCTION(closedir)
282 3151 : {
283 3151 : zval *id = NULL, **tmp, *myself;
284 : php_stream *dirp;
285 : int rsrc_id;
286 :
287 3151 : FETCH_DIRP();
288 :
289 3122 : if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
290 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%d is not a valid Directory resource", dirp->rsrc_id);
291 1 : RETURN_FALSE;
292 : }
293 :
294 3121 : rsrc_id = dirp->rsrc_id;
295 3121 : zend_list_delete(dirp->rsrc_id);
296 :
297 3121 : if (rsrc_id == DIRG(default_dir)) {
298 2113 : php_set_default_dir(-1 TSRMLS_CC);
299 : }
300 : }
301 : /* }}} */
302 :
303 : #if defined(HAVE_CHROOT) && !defined(ZTS) && ENABLE_CHROOT_FUNC
304 : /* {{{ proto bool chroot(string directory) U
305 : Change root directory */
306 : PHP_FUNCTION(chroot)
307 0 : {
308 : zval **ppstr;
309 : char *str;
310 : int ret, str_len;
311 :
312 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &ppstr) == FAILURE ||
313 : php_stream_path_param_encode(ppstr, &str, &str_len, REPORT_ERRORS, FG(default_context)) == FAILURE) {
314 0 : return;
315 : }
316 :
317 0 : ret = chroot(str);
318 0 : if (ret != 0) {
319 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (errno %d)", strerror(errno), errno);
320 0 : RETURN_FALSE;
321 : }
322 :
323 0 : php_clear_stat_cache(1, NULL, 0 TSRMLS_CC);
324 :
325 0 : ret = chdir("/");
326 :
327 0 : if (ret != 0) {
328 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (errno %d)", strerror(errno), errno);
329 0 : RETURN_FALSE;
330 : }
331 :
332 0 : RETURN_TRUE;
333 : }
334 : /* }}} */
335 : #endif
336 :
337 : /* {{{ proto bool chdir(string directory) U
338 : Change the current directory */
339 : PHP_FUNCTION(chdir)
340 288 : {
341 : zval **ppstr;
342 : char *str;
343 : int ret, str_len;
344 :
345 288 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &ppstr) == FAILURE ||
346 : php_stream_path_param_encode(ppstr, &str, &str_len, REPORT_ERRORS, FG(default_context)) == FAILURE) {
347 2 : return;
348 : }
349 286 : if (php_check_open_basedir(str TSRMLS_CC)) {
350 6 : RETURN_FALSE;
351 : }
352 280 : ret = VCWD_CHDIR(str);
353 280 : if (ret != 0) {
354 23 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (errno %d)", strerror(errno), errno);
355 23 : RETURN_FALSE;
356 : }
357 :
358 257 : if (BG(CurrentStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentStatFile), strlen(BG(CurrentStatFile)))) {
359 1 : efree(BG(CurrentStatFile));
360 1 : BG(CurrentStatFile) = NULL;
361 : }
362 257 : if (BG(CurrentLStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentLStatFile), strlen(BG(CurrentLStatFile)))) {
363 0 : efree(BG(CurrentLStatFile));
364 0 : BG(CurrentLStatFile) = NULL;
365 : }
366 :
367 257 : RETURN_TRUE;
368 : }
369 : /* }}} */
370 :
371 : /* {{{ proto mixed getcwd(void) U
372 : Gets the current directory */
373 : PHP_FUNCTION(getcwd)
374 244 : {
375 : char path[MAXPATHLEN];
376 244 : char *ret=NULL;
377 :
378 244 : if (zend_parse_parameters_none() == FAILURE) {
379 1 : return;
380 : }
381 :
382 : #if HAVE_GETCWD
383 243 : ret = VCWD_GETCWD(path, MAXPATHLEN);
384 : #elif HAVE_GETWD
385 : ret = VCWD_GETWD(path);
386 : #endif
387 :
388 243 : if (ret) {
389 243 : RETURN_RT_STRING(path, ZSTR_DUPLICATE);
390 : } else {
391 0 : RETURN_FALSE;
392 : }
393 : }
394 : /* }}} */
395 :
396 : /* {{{ proto void rewinddir([resource dir_handle]) U
397 : Rewind dir_handle back to the start */
398 : PHP_FUNCTION(rewinddir)
399 33 : {
400 33 : zval *id = NULL, **tmp, *myself;
401 : php_stream *dirp;
402 :
403 33 : FETCH_DIRP();
404 :
405 4 : if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
406 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%d is not a valid Directory resource", dirp->rsrc_id);
407 1 : RETURN_FALSE;
408 : }
409 :
410 3 : php_stream_rewinddir(dirp);
411 : }
412 : /* }}} */
413 :
414 : /* {{{ proto string readdir([resource dir_handle]) U
415 : Read directory entry from dir_handle */
416 : PHP_NAMED_FUNCTION(php_if_readdir)
417 59177 : {
418 59177 : zval *id = NULL, **tmp, *myself;
419 : php_stream *dirp;
420 : php_stream_dirent entry;
421 :
422 59177 : FETCH_DIRP();
423 :
424 59147 : if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
425 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%d is not a valid Directory resource", dirp->rsrc_id);
426 1 : RETURN_FALSE;
427 : }
428 :
429 59146 : if (php_stream_readdir(dirp, &entry)) {
430 56097 : RETURN_RT_STRINGL(entry.d_name, strlen(entry.d_name), ZSTR_DUPLICATE);
431 : }
432 3049 : RETURN_FALSE;
433 : }
434 : /* }}} */
435 :
436 : #ifdef HAVE_GLOB
437 : /* {{{ proto array glob(string pattern [, int flags]) U
438 : Find pathnames matching a pattern */
439 : PHP_FUNCTION(glob)
440 120 : {
441 120 : int cwd_skip = 0;
442 : #ifdef ZTS
443 : char cwd[MAXPATHLEN];
444 : char work_pattern[MAXPATHLEN];
445 : char *result;
446 : #endif
447 : zval **pppattern;
448 120 : char *pattern = NULL;
449 : int pattern_len;
450 120 : long flags = 0;
451 : glob_t globbuf;
452 : int ret, n;
453 120 : zend_bool basedir_limit = 0;
454 :
455 120 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &pppattern, &flags) == FAILURE ||
456 : php_stream_path_param_encode(pppattern, &pattern, &pattern_len, REPORT_ERRORS, FG(default_context)) == FAILURE) {
457 4 : return;
458 : }
459 :
460 116 : if (pattern_len >= MAXPATHLEN) {
461 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Pattern exceeds the maximum allowed length of %d characters", MAXPATHLEN);
462 0 : RETURN_FALSE;
463 : }
464 :
465 116 : if ((GLOB_AVAILABLE_FLAGS & flags) != flags) {
466 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "At least one of the passed flags is invalid or not supported on this platform");
467 0 : RETURN_FALSE;
468 : }
469 :
470 : #ifdef ZTS
471 : if (!IS_ABSOLUTE_PATH(pattern, pattern_len)) {
472 : result = VCWD_GETCWD(cwd, MAXPATHLEN);
473 : if (!result) {
474 : cwd[0] = '\0';
475 : }
476 : #ifdef PHP_WIN32
477 : if (IS_SLASH(*pattern)) {
478 : cwd[2] = '\0';
479 : }
480 : #endif
481 : cwd_skip = strlen(cwd)+1;
482 :
483 : snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, pattern);
484 : pattern = work_pattern;
485 : }
486 : #endif
487 :
488 116 : memset(&globbuf, 0, sizeof(glob_t));
489 116 : globbuf.gl_offs = 0;
490 116 : if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) {
491 : #ifdef GLOB_NOMATCH
492 49 : if (GLOB_NOMATCH == ret) {
493 : /* Some glob implementation simply return no data if no matches
494 : were found, others return the GLOB_NOMATCH error code.
495 : We don't want to treat GLOB_NOMATCH as an error condition
496 : so that PHP glob() behaves the same on both types of
497 : implementations and so that 'foreach (glob() as ...'
498 : can be used for simple glob() calls without further error
499 : checking.
500 : */
501 49 : goto no_results;
502 : }
503 : #endif
504 0 : RETURN_FALSE;
505 : }
506 :
507 : /* now catch the FreeBSD style of "no matches" */
508 67 : if (!globbuf.gl_pathc || !globbuf.gl_pathv) {
509 49 : no_results:
510 49 : if (PG(open_basedir) && *PG(open_basedir)) {
511 : struct stat s;
512 :
513 1 : if (0 != VCWD_STAT(pattern, &s) || S_IFDIR != (s.st_mode & S_IFMT)) {
514 1 : RETURN_FALSE;
515 : }
516 : }
517 48 : array_init(return_value);
518 48 : return;
519 : }
520 :
521 67 : array_init(return_value);
522 198 : for (n = 0; n < globbuf.gl_pathc; n++) {
523 : UChar *path;
524 : int path_len;
525 :
526 131 : if (PG(open_basedir) && *PG(open_basedir)) {
527 17 : if (php_check_open_basedir_ex(globbuf.gl_pathv[n], 0 TSRMLS_CC)) {
528 10 : basedir_limit = 1;
529 10 : continue;
530 : }
531 : }
532 : /* we need to do this everytime since GLOB_ONLYDIR does not guarantee that
533 : * all directories will be filtered. GNU libc documentation states the
534 : * following:
535 : * If the information about the type of the file is easily available
536 : * non-directories will be rejected but no extra work will be done to
537 : * determine the information for each file. I.e., the caller must still be
538 : * able to filter directories out.
539 : */
540 121 : if (flags & GLOB_ONLYDIR) {
541 : struct stat s;
542 :
543 19 : if (0 != VCWD_STAT(globbuf.gl_pathv[n], &s)) {
544 0 : continue;
545 : }
546 :
547 19 : if (S_IFDIR != (s.st_mode & S_IFMT)) {
548 0 : continue;
549 : }
550 : }
551 :
552 121 : if (SUCCESS == php_stream_path_decode(&php_plain_files_wrapper, &path, &path_len, globbuf.gl_pathv[n]+cwd_skip,
553 : strlen(globbuf.gl_pathv[n]+cwd_skip), REPORT_ERRORS, FG(default_context))) {
554 121 : add_next_index_unicodel(return_value, path, path_len, 0);
555 : } else {
556 : /* Fallback on string version, path_decode will emit warning */
557 0 : add_next_index_string(return_value, globbuf.gl_pathv[n]+cwd_skip, 1);
558 : }
559 : }
560 :
561 67 : globfree(&globbuf);
562 :
563 67 : if (basedir_limit && !zend_hash_num_elements(Z_ARRVAL_P(return_value))) {
564 9 : zval_dtor(return_value);
565 9 : RETURN_FALSE;
566 : }
567 : }
568 : /* }}} */
569 : #endif
570 :
571 : /* {{{ proto array scandir(string dir [, int sorting_order [, resource context]]) U
572 : List files & directories inside the specified path */
573 : PHP_FUNCTION(scandir)
574 120 : {
575 : zval **ppdirn;
576 : char *dirn;
577 : int dirn_len;
578 120 : long flags = 0;
579 : char **namelist;
580 : int n, i;
581 120 : zval *zcontext = NULL;
582 120 : php_stream_context *context = NULL;
583 :
584 120 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lr", &ppdirn, &flags, &zcontext) == FAILURE) {
585 34 : return;
586 : }
587 :
588 86 : if (zcontext) {
589 2 : context = php_stream_context_from_zval(zcontext, 0);
590 : }
591 :
592 86 : if (FAILURE == php_stream_path_param_encode(ppdirn, &dirn, &dirn_len, REPORT_ERRORS, context)) {
593 0 : RETURN_FALSE;
594 : }
595 :
596 86 : if (!flags) {
597 75 : n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasort);
598 : } else {
599 11 : n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasortr);
600 : }
601 86 : if (n < 0) {
602 41 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "(errno %d): %s", errno, strerror(errno));
603 41 : RETURN_FALSE;
604 : }
605 :
606 45 : array_init(return_value);
607 :
608 184 : for (i = 0; i < n; i++) {
609 : UChar *path;
610 : int path_len;
611 :
612 139 : if (SUCCESS == php_stream_path_decode(NULL, &path, &path_len, namelist[i], strlen(namelist[i]), REPORT_ERRORS, context)) {
613 139 : add_next_index_unicodel(return_value, path, path_len, 0);
614 139 : efree(namelist[i]);
615 : } else {
616 : /* Fallback on using the non-unicode version, path_decode will emit the warning for us */
617 0 : add_next_index_string(return_value, namelist[i], 0);
618 : }
619 : }
620 :
621 45 : if (n) {
622 45 : efree(namelist);
623 : }
624 : }
625 : /* }}} */
626 :
627 : /*
628 : * Local variables:
629 : * tab-width: 4
630 : * c-basic-offset: 4
631 : * End:
632 : * vim600: sw=4 ts=4 fdm=marker
633 : * vim<600: sw=4 ts=4
634 : */
|