Annotation of embedaddon/php/ext/standard/dir.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 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: 
1.1.1.2 ! misho      19: /* $Id$ */
1.1       misho      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: /* {{{ arginfo */
                     99: ZEND_BEGIN_ARG_INFO_EX(arginfo_dir, 0, 0, 0)
                    100:        ZEND_ARG_INFO(0, dir_handle)
                    101: ZEND_END_ARG_INFO()
                    102: /* }}} */
                    103: 
                    104: static const zend_function_entry php_dir_class_functions[] = {
                    105:        PHP_FALIAS(close,       closedir,               arginfo_dir)
                    106:        PHP_FALIAS(rewind,      rewinddir,              arginfo_dir)
                    107:        PHP_NAMED_FE(read,  php_if_readdir, arginfo_dir)
                    108:        {NULL, NULL, NULL}
                    109: };
                    110: 
                    111: 
                    112: static void php_set_default_dir(int id TSRMLS_DC)
                    113: {
                    114:        if (DIRG(default_dir)!=-1) {
                    115:                zend_list_delete(DIRG(default_dir));
                    116:        }
                    117: 
                    118:        if (id != -1) {
                    119:                zend_list_addref(id);
                    120:        }
                    121:        
                    122:        DIRG(default_dir) = id;
                    123: }
                    124: 
                    125: PHP_RINIT_FUNCTION(dir)
                    126: {
                    127:        DIRG(default_dir) = -1;
                    128:        return SUCCESS;
                    129: }
                    130: 
                    131: PHP_MINIT_FUNCTION(dir)
                    132: {
                    133:        static char dirsep_str[2], pathsep_str[2];
                    134:        zend_class_entry dir_class_entry;
                    135: 
                    136:        INIT_CLASS_ENTRY(dir_class_entry, "Directory", php_dir_class_functions);
                    137:        dir_class_entry_ptr = zend_register_internal_class(&dir_class_entry TSRMLS_CC);
                    138: 
                    139: #ifdef ZTS
                    140:        ts_allocate_id(&dir_globals_id, sizeof(php_dir_globals), NULL, NULL);
                    141: #endif
                    142: 
                    143:        dirsep_str[0] = DEFAULT_SLASH;
                    144:        dirsep_str[1] = '\0';
                    145:        REGISTER_STRING_CONSTANT("DIRECTORY_SEPARATOR", dirsep_str, CONST_CS|CONST_PERSISTENT);
                    146: 
                    147:        pathsep_str[0] = ZEND_PATHS_SEPARATOR;
                    148:        pathsep_str[1] = '\0';
                    149:        REGISTER_STRING_CONSTANT("PATH_SEPARATOR", pathsep_str, CONST_CS|CONST_PERSISTENT);
                    150: 
1.1.1.2 ! misho     151:        REGISTER_LONG_CONSTANT("SCANDIR_SORT_ASCENDING",  PHP_SCANDIR_SORT_ASCENDING,  CONST_CS | CONST_PERSISTENT);
        !           152:        REGISTER_LONG_CONSTANT("SCANDIR_SORT_DESCENDING", PHP_SCANDIR_SORT_DESCENDING, CONST_CS | CONST_PERSISTENT);
        !           153:        REGISTER_LONG_CONSTANT("SCANDIR_SORT_NONE",       PHP_SCANDIR_SORT_NONE,       CONST_CS | CONST_PERSISTENT);
        !           154: 
1.1       misho     155: #ifdef HAVE_GLOB
                    156: 
                    157: #ifdef GLOB_BRACE
                    158:        REGISTER_LONG_CONSTANT("GLOB_BRACE", GLOB_BRACE, CONST_CS | CONST_PERSISTENT);
                    159: #else
                    160: # define GLOB_BRACE 0
                    161: #endif
                    162: 
                    163: #ifdef GLOB_MARK
                    164:        REGISTER_LONG_CONSTANT("GLOB_MARK", GLOB_MARK, CONST_CS | CONST_PERSISTENT);
                    165: #else
                    166: # define GLOB_MARK 0
                    167: #endif
                    168: 
                    169: #ifdef GLOB_NOSORT
                    170:        REGISTER_LONG_CONSTANT("GLOB_NOSORT", GLOB_NOSORT, CONST_CS | CONST_PERSISTENT);
                    171: #else 
                    172: # define GLOB_NOSORT 0
                    173: #endif
                    174: 
                    175: #ifdef GLOB_NOCHECK
                    176:        REGISTER_LONG_CONSTANT("GLOB_NOCHECK", GLOB_NOCHECK, CONST_CS | CONST_PERSISTENT);
                    177: #else 
                    178: # define GLOB_NOCHECK 0
                    179: #endif
                    180: 
                    181: #ifdef GLOB_NOESCAPE
                    182:        REGISTER_LONG_CONSTANT("GLOB_NOESCAPE", GLOB_NOESCAPE, CONST_CS | CONST_PERSISTENT);
                    183: #else 
                    184: # define GLOB_NOESCAPE 0
                    185: #endif
                    186: 
                    187: #ifdef GLOB_ERR
                    188:        REGISTER_LONG_CONSTANT("GLOB_ERR", GLOB_ERR, CONST_CS | CONST_PERSISTENT);
                    189: #else 
                    190: # define GLOB_ERR 0
                    191: #endif
                    192: 
                    193: #ifndef GLOB_ONLYDIR
                    194: # define GLOB_ONLYDIR (1<<30)
                    195: # define GLOB_EMULATE_ONLYDIR
                    196: # define GLOB_FLAGMASK (~GLOB_ONLYDIR)
                    197: #else
                    198: # define GLOB_FLAGMASK (~0)
                    199: #endif
                    200: 
                    201: /* This is used for checking validity of passed flags (passing invalid flags causes segfault in glob()!! */
                    202: #define GLOB_AVAILABLE_FLAGS (0 | GLOB_BRACE | GLOB_MARK | GLOB_NOSORT | GLOB_NOCHECK | GLOB_NOESCAPE | GLOB_ERR | GLOB_ONLYDIR)
                    203: 
                    204:        REGISTER_LONG_CONSTANT("GLOB_ONLYDIR", GLOB_ONLYDIR, CONST_CS | CONST_PERSISTENT);
                    205:        REGISTER_LONG_CONSTANT("GLOB_AVAILABLE_FLAGS", GLOB_AVAILABLE_FLAGS, CONST_CS | CONST_PERSISTENT);
                    206: 
                    207: #endif /* HAVE_GLOB */
                    208: 
                    209:        return SUCCESS;
                    210: }
                    211: /* }}} */
                    212: 
                    213: /* {{{ internal functions */
                    214: static void _php_do_opendir(INTERNAL_FUNCTION_PARAMETERS, int createobject)
                    215: {
                    216:        char *dirname;
                    217:        int dir_len;
                    218:        zval *zcontext = NULL;
                    219:        php_stream_context *context = NULL;
                    220:        php_stream *dirp;
                    221: 
                    222:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r", &dirname, &dir_len, &zcontext) == FAILURE) {
                    223:                RETURN_NULL();
                    224:        }
                    225: 
                    226:        context = php_stream_context_from_zval(zcontext, 0);
                    227:        
1.1.1.2 ! misho     228:        dirp = php_stream_opendir(dirname, REPORT_ERRORS, context);
1.1       misho     229: 
                    230:        if (dirp == NULL) {
                    231:                RETURN_FALSE;
                    232:        }
                    233: 
                    234:        dirp->flags |= PHP_STREAM_FLAG_NO_FCLOSE;
                    235:                
                    236:        php_set_default_dir(dirp->rsrc_id TSRMLS_CC);
                    237: 
                    238:        if (createobject) {
                    239:                object_init_ex(return_value, dir_class_entry_ptr);
                    240:                add_property_stringl(return_value, "path", dirname, dir_len, 1);
                    241:                add_property_resource(return_value, "handle", dirp->rsrc_id);
                    242:                php_stream_auto_cleanup(dirp); /* so we don't get warnings under debug */
                    243:        } else {
                    244:                php_stream_to_zval(dirp, return_value);
                    245:        }
                    246: }
                    247: /* }}} */
                    248: 
                    249: /* {{{ proto mixed opendir(string path[, resource context])
                    250:    Open a directory and return a dir_handle */
                    251: PHP_FUNCTION(opendir)
                    252: {
                    253:        _php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
                    254: }
                    255: /* }}} */
                    256: 
                    257: /* {{{ proto object dir(string directory[, resource context])
                    258:    Directory class with properties, handle and class and methods read, rewind and close */
                    259: PHP_FUNCTION(getdir)
                    260: {
                    261:        _php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
                    262: }
                    263: /* }}} */
                    264: 
                    265: /* {{{ proto void closedir([resource dir_handle])
                    266:    Close directory connection identified by the dir_handle */
                    267: PHP_FUNCTION(closedir)
                    268: {
                    269:        zval *id = NULL, **tmp, *myself;
                    270:        php_stream *dirp;
                    271:        int rsrc_id;
                    272: 
                    273:        FETCH_DIRP();
                    274: 
                    275:        if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
                    276:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%d is not a valid Directory resource", dirp->rsrc_id);
                    277:                RETURN_FALSE;
                    278:        }
                    279: 
                    280:        rsrc_id = dirp->rsrc_id;
                    281:        zend_list_delete(dirp->rsrc_id);
                    282: 
                    283:        if (rsrc_id == DIRG(default_dir)) {
                    284:                php_set_default_dir(-1 TSRMLS_CC);
                    285:        }
                    286: }
                    287: /* }}} */
                    288: 
                    289: #if defined(HAVE_CHROOT) && !defined(ZTS) && ENABLE_CHROOT_FUNC
                    290: /* {{{ proto bool chroot(string directory)
                    291:    Change root directory */
                    292: PHP_FUNCTION(chroot)
                    293: {
                    294:        char *str;
                    295:        int ret, str_len;
                    296:        
                    297:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
                    298:                RETURN_FALSE;
                    299:        }
                    300:        
                    301:        ret = chroot(str);
                    302:        if (ret != 0) {
                    303:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (errno %d)", strerror(errno), errno);
                    304:                RETURN_FALSE;
                    305:        }
                    306: 
                    307:        php_clear_stat_cache(1, NULL, 0 TSRMLS_CC);
                    308:        
                    309:        ret = chdir("/");
                    310:        
                    311:        if (ret != 0) {
                    312:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (errno %d)", strerror(errno), errno);
                    313:                RETURN_FALSE;
                    314:        }
                    315: 
                    316:        RETURN_TRUE;
                    317: }
                    318: /* }}} */
                    319: #endif
                    320: 
                    321: /* {{{ proto bool chdir(string directory)
                    322:    Change the current directory */
                    323: PHP_FUNCTION(chdir)
                    324: {
                    325:        char *str;
                    326:        int ret, str_len;
                    327:        
1.1.1.2 ! misho     328:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &str, &str_len) == FAILURE) {
1.1       misho     329:                RETURN_FALSE;
                    330:        }
                    331: 
1.1.1.2 ! misho     332:        if (php_check_open_basedir(str TSRMLS_CC)) {
1.1       misho     333:                RETURN_FALSE;
                    334:        }
                    335:        ret = VCWD_CHDIR(str);
                    336:        
                    337:        if (ret != 0) {
                    338:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (errno %d)", strerror(errno), errno);
                    339:                RETURN_FALSE;
                    340:        }
                    341: 
                    342:        if (BG(CurrentStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentStatFile), strlen(BG(CurrentStatFile)))) {
                    343:                efree(BG(CurrentStatFile));
                    344:                BG(CurrentStatFile) = NULL;
                    345:        }
                    346:        if (BG(CurrentLStatFile) && !IS_ABSOLUTE_PATH(BG(CurrentLStatFile), strlen(BG(CurrentLStatFile)))) {
                    347:                efree(BG(CurrentLStatFile));
                    348:                BG(CurrentLStatFile) = NULL;
                    349:        }
                    350: 
                    351:        RETURN_TRUE;
                    352: }
                    353: /* }}} */
                    354: 
                    355: /* {{{ proto mixed getcwd(void)
                    356:    Gets the current directory */
                    357: PHP_FUNCTION(getcwd)
                    358: {
                    359:        char path[MAXPATHLEN];
                    360:        char *ret=NULL;
                    361:        
                    362:        if (zend_parse_parameters_none() == FAILURE) {
                    363:                return;
                    364:        }
                    365: 
                    366: #if HAVE_GETCWD
                    367:        ret = VCWD_GETCWD(path, MAXPATHLEN);
                    368: #elif HAVE_GETWD
                    369:        ret = VCWD_GETWD(path);
                    370: #endif
                    371: 
                    372:        if (ret) {
                    373:                RETURN_STRING(path, 1);
                    374:        } else {
                    375:                RETURN_FALSE;
                    376:        }
                    377: }
                    378: /* }}} */
                    379: 
                    380: /* {{{ proto void rewinddir([resource dir_handle])
                    381:    Rewind dir_handle back to the start */
                    382: PHP_FUNCTION(rewinddir)
                    383: {
                    384:        zval *id = NULL, **tmp, *myself;
                    385:        php_stream *dirp;
                    386:        
                    387:        FETCH_DIRP();
                    388: 
                    389:        if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
                    390:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%d is not a valid Directory resource", dirp->rsrc_id);
                    391:                RETURN_FALSE;
                    392:        }
                    393: 
                    394:        php_stream_rewinddir(dirp);
                    395: }
                    396: /* }}} */
                    397: 
                    398: /* {{{ proto string readdir([resource dir_handle])
                    399:    Read directory entry from dir_handle */
                    400: PHP_NAMED_FUNCTION(php_if_readdir)
                    401: {
                    402:        zval *id = NULL, **tmp, *myself;
                    403:        php_stream *dirp;
                    404:        php_stream_dirent entry;
                    405: 
                    406:        FETCH_DIRP();
                    407: 
                    408:        if (!(dirp->flags & PHP_STREAM_FLAG_IS_DIR)) {
                    409:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%d is not a valid Directory resource", dirp->rsrc_id);
                    410:                RETURN_FALSE;
                    411:        }
                    412: 
                    413:        if (php_stream_readdir(dirp, &entry)) {
                    414:                RETURN_STRINGL(entry.d_name, strlen(entry.d_name), 1);
                    415:        }
                    416:        RETURN_FALSE;
                    417: }
                    418: /* }}} */
                    419: 
                    420: #ifdef HAVE_GLOB
                    421: /* {{{ proto array glob(string pattern [, int flags])
                    422:    Find pathnames matching a pattern */
                    423: PHP_FUNCTION(glob)
                    424: {
                    425:        int cwd_skip = 0;
                    426: #ifdef ZTS
                    427:        char cwd[MAXPATHLEN];
                    428:        char work_pattern[MAXPATHLEN];
                    429:        char *result;
                    430: #endif
                    431:        char *pattern = NULL;
                    432:        int pattern_len;
                    433:        long flags = 0;
                    434:        glob_t globbuf;
                    435:        int n;
                    436:        int ret;
                    437:        zend_bool basedir_limit = 0;
                    438: 
1.1.1.2 ! misho     439:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|l", &pattern, &pattern_len, &flags) == FAILURE) {
1.1       misho     440:                return;
                    441:        }
                    442: 
                    443:        if (pattern_len >= MAXPATHLEN) {
                    444:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Pattern exceeds the maximum allowed length of %d characters", MAXPATHLEN);
                    445:                RETURN_FALSE;
                    446:        }
                    447: 
                    448:        if ((GLOB_AVAILABLE_FLAGS & flags) != flags) {
                    449:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "At least one of the passed flags is invalid or not supported on this platform");
                    450:                RETURN_FALSE;
                    451:        }
                    452: 
                    453: #ifdef ZTS 
                    454:        if (!IS_ABSOLUTE_PATH(pattern, pattern_len)) {
                    455:                result = VCWD_GETCWD(cwd, MAXPATHLEN);  
                    456:                if (!result) {
                    457:                        cwd[0] = '\0';
                    458:                }
                    459: #ifdef PHP_WIN32
                    460:                if (IS_SLASH(*pattern)) {
                    461:                        cwd[2] = '\0';
                    462:                }
                    463: #endif
                    464:                cwd_skip = strlen(cwd)+1;
                    465: 
                    466:                snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, pattern);
                    467:                pattern = work_pattern;
                    468:        } 
                    469: #endif
                    470: 
                    471:        
                    472:        memset(&globbuf, 0, sizeof(glob_t));
                    473:        globbuf.gl_offs = 0;
                    474:        if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) {
                    475: #ifdef GLOB_NOMATCH
                    476:                if (GLOB_NOMATCH == ret) {
                    477:                        /* Some glob implementation simply return no data if no matches
                    478:                           were found, others return the GLOB_NOMATCH error code.
                    479:                           We don't want to treat GLOB_NOMATCH as an error condition
                    480:                           so that PHP glob() behaves the same on both types of 
                    481:                           implementations and so that 'foreach (glob() as ...'
                    482:                           can be used for simple glob() calls without further error
                    483:                           checking.
                    484:                        */
                    485:                        goto no_results;
                    486:                }
                    487: #endif
                    488:                RETURN_FALSE;
                    489:        }
                    490: 
                    491:        /* now catch the FreeBSD style of "no matches" */
                    492:        if (!globbuf.gl_pathc || !globbuf.gl_pathv) {
                    493: no_results:
1.1.1.2 ! misho     494:                if (PG(open_basedir) && *PG(open_basedir)) {
1.1       misho     495:                        struct stat s;
                    496: 
                    497:                        if (0 != VCWD_STAT(pattern, &s) || S_IFDIR != (s.st_mode & S_IFMT)) {
                    498:                                RETURN_FALSE;
                    499:                        }
                    500:                }
                    501:                array_init(return_value);
                    502:                return;
                    503:        }
                    504: 
                    505:        array_init(return_value);
                    506:        for (n = 0; n < globbuf.gl_pathc; n++) {
1.1.1.2 ! misho     507:                if (PG(open_basedir) && *PG(open_basedir)) {
        !           508:                        if (php_check_open_basedir_ex(globbuf.gl_pathv[n], 0 TSRMLS_CC)) {
1.1       misho     509:                                basedir_limit = 1;
                    510:                                continue;
                    511:                        }
                    512:                }
                    513:                /* we need to do this everytime since GLOB_ONLYDIR does not guarantee that
                    514:                 * all directories will be filtered. GNU libc documentation states the
                    515:                 * following: 
                    516:                 * If the information about the type of the file is easily available 
                    517:                 * non-directories will be rejected but no extra work will be done to 
                    518:                 * determine the information for each file. I.e., the caller must still be 
                    519:                 * able to filter directories out. 
                    520:                 */
                    521:                if (flags & GLOB_ONLYDIR) {
                    522:                        struct stat s;
                    523: 
                    524:                        if (0 != VCWD_STAT(globbuf.gl_pathv[n], &s)) {
                    525:                                continue;
                    526:                        }
                    527: 
                    528:                        if (S_IFDIR != (s.st_mode & S_IFMT)) {
                    529:                                continue;
                    530:                        }
                    531:                }
                    532:                add_next_index_string(return_value, globbuf.gl_pathv[n]+cwd_skip, 1);
                    533:        }
                    534: 
                    535:        globfree(&globbuf);
                    536: 
                    537:        if (basedir_limit && !zend_hash_num_elements(Z_ARRVAL_P(return_value))) {
                    538:                zval_dtor(return_value);
                    539:                RETURN_FALSE;
                    540:        }
                    541: }
                    542: /* }}} */
                    543: #endif 
                    544: 
                    545: /* {{{ proto array scandir(string dir [, int sorting_order [, resource context]])
                    546:    List files & directories inside the specified path */
                    547: PHP_FUNCTION(scandir)
                    548: {
                    549:        char *dirn;
                    550:        int dirn_len;
                    551:        long flags = 0;
                    552:        char **namelist;
                    553:        int n, i;
                    554:        zval *zcontext = NULL;
                    555:        php_stream_context *context = NULL;
                    556: 
1.1.1.2 ! misho     557:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|lr", &dirn, &dirn_len, &flags, &zcontext) == FAILURE) {
1.1       misho     558:                return;
                    559:        }
                    560: 
                    561:        if (dirn_len < 1) {
                    562:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Directory name cannot be empty");
                    563:                RETURN_FALSE;
                    564:        }
                    565: 
                    566:        if (zcontext) {
                    567:                context = php_stream_context_from_zval(zcontext, 0);
                    568:        }
                    569: 
1.1.1.2 ! misho     570:        if (flags == PHP_SCANDIR_SORT_ASCENDING) {
1.1       misho     571:                n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasort);
1.1.1.2 ! misho     572:        } else if (flags == PHP_SCANDIR_SORT_NONE) {
        !           573:                n = php_stream_scandir(dirn, &namelist, context, NULL);
1.1       misho     574:        } else {
                    575:                n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasortr);
                    576:        }
                    577:        if (n < 0) {
                    578:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "(errno %d): %s", errno, strerror(errno));
                    579:                RETURN_FALSE;
                    580:        }
                    581:        
                    582:        array_init(return_value);
                    583: 
                    584:        for (i = 0; i < n; i++) {
                    585:                add_next_index_string(return_value, namelist[i], 0);
                    586:        }
                    587: 
                    588:        if (n) {
                    589:                efree(namelist);
                    590:        }
                    591: }
                    592: /* }}} */
                    593: 
                    594: /*
                    595:  * Local variables:
                    596:  * tab-width: 4
                    597:  * c-basic-offset: 4
                    598:  * End:
                    599:  * vim600: sw=4 ts=4 fdm=marker
                    600:  * vim<600: sw=4 ts=4
                    601:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>