LTP GCOV extension - code coverage report
Current view: directory - ext/standard - dir.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 141
Code covered: 55.3 % Executed lines: 78
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2007 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,v 1.147.2.3.2.4 2007/02/24 17:16:23 iliaa Exp $ */
      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_scandir.h"
      28                 : 
      29                 : #ifdef HAVE_DIRENT_H
      30                 : #include <dirent.h>
      31                 : #endif
      32                 : 
      33                 : #if HAVE_UNISTD_H
      34                 : #include <unistd.h>
      35                 : #endif
      36                 : 
      37                 : #include <errno.h>
      38                 : 
      39                 : #ifdef PHP_WIN32
      40                 : #include "win32/readdir.h"
      41                 : #endif
      42                 : 
      43                 : 
      44                 : #ifdef HAVE_GLOB
      45                 : #ifndef PHP_WIN32
      46                 : #include <glob.h>
      47                 : #else
      48                 : #include "win32/glob.h"
      49                 : #endif
      50                 : #endif
      51                 : 
      52                 : typedef struct {
      53                 :         int default_dir;
      54                 : } php_dir_globals;
      55                 : 
      56                 : #ifdef ZTS
      57                 : #define DIRG(v) TSRMG(dir_globals_id, php_dir_globals *, v)
      58                 : int dir_globals_id;
      59                 : #else
      60                 : #define DIRG(v) (dir_globals.v)
      61                 : php_dir_globals dir_globals;
      62                 : #endif
      63                 : 
      64                 : #if 0
      65                 : typedef struct {
      66                 :         int id;
      67                 :         DIR *dir;
      68                 : } php_dir;
      69                 : 
      70                 : static int le_dirp;
      71                 : #endif
      72                 : 
      73                 : static zend_class_entry *dir_class_entry_ptr;
      74                 : 
      75                 : #define FETCH_DIRP() \
      76                 :         if (ZEND_NUM_ARGS() == 0) { \
      77                 :                 myself = getThis(); \
      78                 :                 if (myself) { \
      79                 :                         if (zend_hash_find(Z_OBJPROP_P(myself), "handle", sizeof("handle"), (void **)&tmp) == FAILURE) { \
      80                 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find my handle property"); \
      81                 :                                 RETURN_FALSE; \
      82                 :                         } \
      83                 :                         ZEND_FETCH_RESOURCE(dirp, php_stream *, tmp, -1, "Directory", php_file_le_stream()); \
      84                 :                 } else { \
      85                 :                         ZEND_FETCH_RESOURCE(dirp, php_stream *, 0, DIRG(default_dir), "Directory", php_file_le_stream()); \
      86                 :                 } \
      87                 :         } else if ((ZEND_NUM_ARGS() != 1) || zend_get_parameters_ex(1, &id) == FAILURE) { \
      88                 :                 WRONG_PARAM_COUNT; \
      89                 :         } else { \
      90                 :                 dirp = (php_stream *) zend_fetch_resource(id TSRMLS_CC, -1, "Directory", NULL, 1, php_file_le_stream()); \
      91                 :                 if (!dirp) \
      92                 :                         RETURN_FALSE; \
      93                 :         } 
      94                 : 
      95                 : static zend_function_entry php_dir_class_functions[] = {
      96                 :         PHP_FALIAS(close,       closedir,       NULL)
      97                 :         PHP_FALIAS(rewind,      rewinddir,      NULL)
      98                 :         PHP_NAMED_FE(read,  php_if_readdir, NULL)
      99                 :         {NULL, NULL, NULL}
     100                 : };
     101                 : 
     102                 : 
     103                 : static void php_set_default_dir(int id TSRMLS_DC)
     104              24 : {
     105              24 :         if (DIRG(default_dir)!=-1) {
     106              14 :                 zend_list_delete(DIRG(default_dir));
     107                 :         }
     108                 : 
     109              24 :         if (id != -1) {
     110              14 :                 zend_list_addref(id);
     111                 :         }
     112                 :         
     113              24 :         DIRG(default_dir) = id;
     114              24 : }
     115                 : 
     116                 : PHP_RINIT_FUNCTION(dir)
     117             219 : {
     118             219 :         DIRG(default_dir) = -1;
     119             219 :         return SUCCESS;
     120                 : }
     121                 : 
     122                 : PHP_MINIT_FUNCTION(dir)
     123             220 : {
     124                 :         static char dirsep_str[2], pathsep_str[2];
     125                 :         zend_class_entry dir_class_entry;
     126                 : 
     127             220 :         INIT_CLASS_ENTRY(dir_class_entry, "Directory", php_dir_class_functions);
     128             220 :         dir_class_entry_ptr = zend_register_internal_class(&dir_class_entry TSRMLS_CC);
     129                 : 
     130                 : #ifdef ZTS
     131                 :         ts_allocate_id(&dir_globals_id, sizeof(php_dir_globals), NULL, NULL);
     132                 : #endif
     133                 : 
     134             220 :         dirsep_str[0] = DEFAULT_SLASH;
     135             220 :         dirsep_str[1] = '\0';
     136             220 :         REGISTER_STRING_CONSTANT("DIRECTORY_SEPARATOR", dirsep_str, CONST_CS|CONST_PERSISTENT);
     137                 : 
     138             220 :         pathsep_str[0] = ZEND_PATHS_SEPARATOR;
     139             220 :         pathsep_str[1] = '\0';
     140             220 :         REGISTER_STRING_CONSTANT("PATH_SEPARATOR", pathsep_str, CONST_CS|CONST_PERSISTENT);
     141                 : 
     142                 : #ifdef HAVE_GLOB
     143                 : #ifdef GLOB_BRACE
     144             220 :         REGISTER_LONG_CONSTANT("GLOB_BRACE", GLOB_BRACE, CONST_CS | CONST_PERSISTENT);
     145                 : #endif
     146                 : #ifdef GLOB_MARK
     147             220 :         REGISTER_LONG_CONSTANT("GLOB_MARK", GLOB_MARK, CONST_CS | CONST_PERSISTENT);
     148                 : #endif
     149                 : #ifdef GLOB_NOSORT
     150             220 :         REGISTER_LONG_CONSTANT("GLOB_NOSORT", GLOB_NOSORT, CONST_CS | CONST_PERSISTENT);
     151                 : #endif
     152                 : #ifdef GLOB_NOCHECK
     153             220 :         REGISTER_LONG_CONSTANT("GLOB_NOCHECK", GLOB_NOCHECK, CONST_CS | CONST_PERSISTENT);
     154                 : #endif
     155                 : #ifdef GLOB_NOESCAPE
     156             220 :         REGISTER_LONG_CONSTANT("GLOB_NOESCAPE", GLOB_NOESCAPE, CONST_CS | CONST_PERSISTENT);
     157                 : #endif
     158                 : #ifdef GLOB_ERR
     159             220 :         REGISTER_LONG_CONSTANT("GLOB_ERR", GLOB_ERR, CONST_CS | CONST_PERSISTENT);
     160                 : #endif
     161                 : 
     162                 : #ifndef GLOB_ONLYDIR
     163                 : #define GLOB_ONLYDIR (1<<30)
     164                 : #define GLOB_EMULATE_ONLYDIR
     165                 : #define GLOB_FLAGMASK (~GLOB_ONLYDIR)
     166                 : #else
     167                 : #define GLOB_FLAGMASK (~0)
     168                 : #endif
     169                 : 
     170             220 :         REGISTER_LONG_CONSTANT("GLOB_ONLYDIR", GLOB_ONLYDIR, CONST_CS | CONST_PERSISTENT);
     171                 : 
     172                 : #endif /* HAVE_GLOB */
     173                 : 
     174             220 :         return SUCCESS;
     175                 : }
     176                 : /* }}} */
     177                 : 
     178                 : /* {{{ internal functions */
     179                 : static void _php_do_opendir(INTERNAL_FUNCTION_PARAMETERS, int createobject)
     180              14 : {
     181                 :         char *dirname;
     182                 :         int dir_len;
     183              14 :         zval *zcontext = NULL;
     184              14 :         php_stream_context *context = NULL;
     185                 :         php_stream *dirp;
     186                 : 
     187              14 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|r", &dirname, &dir_len, &zcontext) == FAILURE) {
     188               0 :                 RETURN_NULL();
     189                 :         }
     190                 : 
     191              14 :         if (zcontext) {
     192               0 :                 context = php_stream_context_from_zval(zcontext, 0);
     193                 :         }
     194                 :         
     195              14 :         dirp = php_stream_opendir(dirname, ENFORCE_SAFE_MODE|REPORT_ERRORS, context);
     196                 : 
     197              14 :         if (dirp == NULL) {
     198               0 :                 RETURN_FALSE;
     199                 :         }
     200                 :                 
     201              14 :         php_set_default_dir(dirp->rsrc_id TSRMLS_CC);
     202                 : 
     203              14 :         if (createobject) {
     204               0 :                 object_init_ex(return_value, dir_class_entry_ptr);
     205               0 :                 add_property_stringl(return_value, "path", dirname, dir_len, 1);
     206               0 :                 add_property_resource(return_value, "handle", dirp->rsrc_id);
     207                 :                 php_stream_auto_cleanup(dirp); /* so we don't get warnings under debug */
     208                 :         } else {
     209              14 :                 php_stream_to_zval(dirp, return_value);
     210                 :         }
     211                 : }
     212                 : /* }}} */
     213                 : 
     214                 : /* {{{ proto mixed opendir(string path[, resource context])
     215                 :    Open a directory and return a dir_handle */
     216                 : PHP_FUNCTION(opendir)
     217              14 : {
     218              14 :         _php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
     219              14 : }
     220                 : /* }}} */
     221                 : 
     222                 : /* {{{ proto object dir(string directory[, resource context])
     223                 :    Directory class with properties, handle and class and methods read, rewind and close */
     224                 : PHP_FUNCTION(getdir)
     225               0 : {
     226               0 :         _php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
     227               0 : }
     228                 : /* }}} */
     229                 : 
     230                 : /* {{{ proto void closedir([resource dir_handle])
     231                 :    Close directory connection identified by the dir_handle */
     232                 : PHP_FUNCTION(closedir)
     233              14 : {
     234                 :         zval **id, **tmp, *myself;
     235                 :         php_stream *dirp;
     236                 : 
     237              14 :         FETCH_DIRP();
     238                 : 
     239              14 :         if (dirp->rsrc_id == DIRG(default_dir)) {
     240              10 :                 php_set_default_dir(-1 TSRMLS_CC);
     241                 :         }
     242                 : 
     243              14 :         zend_list_delete(dirp->rsrc_id);
     244                 : }
     245                 : /* }}} */
     246                 : 
     247                 : #if defined(HAVE_CHROOT) && !defined(ZTS) && ENABLE_CHROOT_FUNC
     248                 : /* {{{ proto bool chroot(string directory)
     249                 :    Change root directory */
     250                 : PHP_FUNCTION(chroot)
     251               0 : {
     252                 :         char *str;
     253                 :         int ret, str_len;
     254                 :         
     255               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
     256               0 :                 RETURN_FALSE;
     257                 :         }
     258                 :         
     259               0 :         ret = chroot(str);
     260               0 :         if (ret != 0) {
     261               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (errno %d)", strerror(errno), errno);
     262               0 :                 RETURN_FALSE;
     263                 :         }
     264                 : 
     265               0 :         realpath_cache_clean(TSRMLS_C);
     266                 :         
     267               0 :         ret = chdir("/");
     268                 :         
     269               0 :         if (ret != 0) {
     270               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (errno %d)", strerror(errno), errno);
     271               0 :                 RETURN_FALSE;
     272                 :         }
     273                 : 
     274               0 :         RETURN_TRUE;
     275                 : }
     276                 : /* }}} */
     277                 : #endif
     278                 : 
     279                 : /* {{{ proto bool chdir(string directory)
     280                 :    Change the current directory */
     281                 : PHP_FUNCTION(chdir)
     282               2 : {
     283                 :         char *str;
     284                 :         int ret, str_len;
     285                 :         
     286               2 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
     287               0 :                 RETURN_FALSE;
     288                 :         }
     289                 : 
     290               2 :         if ((PG(safe_mode) && !php_checkuid(str, NULL, CHECKUID_CHECK_FILE_AND_DIR)) || php_check_open_basedir(str TSRMLS_CC)) {
     291               0 :                 RETURN_FALSE;
     292                 :         }
     293               2 :         ret = VCWD_CHDIR(str);
     294                 :         
     295               2 :         if (ret != 0) {
     296               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s (errno %d)", strerror(errno), errno);
     297               0 :                 RETURN_FALSE;
     298                 :         }
     299                 : 
     300               2 :         RETURN_TRUE;
     301                 : }
     302                 : /* }}} */
     303                 : 
     304                 : /* {{{ proto mixed getcwd(void)
     305                 :    Gets the current directory */
     306                 : PHP_FUNCTION(getcwd)
     307               2 : {
     308                 :         char path[MAXPATHLEN];
     309               2 :         char *ret=NULL;
     310                 :         
     311               2 :         if (ZEND_NUM_ARGS() != 0) {
     312               0 :                 WRONG_PARAM_COUNT;
     313                 :         }
     314                 : 
     315                 : #if HAVE_GETCWD
     316               2 :         ret = VCWD_GETCWD(path, MAXPATHLEN);
     317                 : #elif HAVE_GETWD
     318                 :         ret = VCWD_GETWD(path);
     319                 : #endif
     320                 : 
     321               2 :         if (ret) {
     322               2 :                 RETURN_STRING(path, 1);
     323                 :         } else {
     324               0 :                 RETURN_FALSE;
     325                 :         }
     326                 : }
     327                 : /* }}} */
     328                 : 
     329                 : /* {{{ proto void rewinddir([resource dir_handle])
     330                 :    Rewind dir_handle back to the start */
     331                 : PHP_FUNCTION(rewinddir)
     332               0 : {
     333                 :         zval **id, **tmp, *myself;
     334                 :         php_stream *dirp;
     335                 :         
     336               0 :         FETCH_DIRP();
     337                 : 
     338               0 :         php_stream_rewinddir(dirp);
     339                 : }
     340                 : /* }}} */
     341                 : 
     342                 : /* {{{ proto string readdir([resource dir_handle])
     343                 :    Read directory entry from dir_handle */
     344                 : PHP_NAMED_FUNCTION(php_if_readdir)
     345             730 : {
     346                 :         zval **id, **tmp, *myself;
     347                 :         php_stream *dirp;
     348                 :         php_stream_dirent entry;
     349                 : 
     350             730 :         FETCH_DIRP();
     351                 : 
     352             730 :         if (php_stream_readdir(dirp, &entry)) {
     353             716 :                 RETURN_STRINGL(entry.d_name, strlen(entry.d_name), 1);
     354                 :         }
     355              14 :         RETURN_FALSE;
     356                 : }
     357                 : /* }}} */
     358                 : 
     359                 : #ifdef HAVE_GLOB
     360                 : /* {{{ proto array glob(string pattern [, int flags])
     361                 :    Find pathnames matching a pattern */
     362                 : PHP_FUNCTION(glob)
     363               1 : {
     364                 :         char cwd[MAXPATHLEN];
     365               1 :         int cwd_skip = 0;
     366                 : #ifdef ZTS
     367                 :         char work_pattern[MAXPATHLEN];
     368                 :         char *result;
     369                 : #endif
     370               1 :         char *pattern = NULL;
     371                 :         int pattern_len;
     372               1 :         long flags = 0;
     373                 :         glob_t globbuf;
     374                 :         int n;
     375                 :         int ret;
     376                 : 
     377               1 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &pattern, &pattern_len, &flags) == FAILURE) 
     378               0 :                 return;
     379                 : 
     380                 : #ifdef ZTS 
     381                 :         if (!IS_ABSOLUTE_PATH(pattern, pattern_len)) {
     382                 :                 result = VCWD_GETCWD(cwd, MAXPATHLEN);  
     383                 :                 if (!result) {
     384                 :                         cwd[0] = '\0';
     385                 :                 }
     386                 : #ifdef PHP_WIN32
     387                 :                 if (IS_SLASH(*pattern)) {
     388                 :                         cwd[2] = '\0';
     389                 :                 }
     390                 : #endif
     391                 :                 cwd_skip = strlen(cwd)+1;
     392                 : 
     393                 :                 snprintf(work_pattern, MAXPATHLEN, "%s%c%s", cwd, DEFAULT_SLASH, pattern);
     394                 :                 pattern = work_pattern;
     395                 :         } 
     396                 : #endif
     397                 : 
     398               1 :         globbuf.gl_offs = 0;
     399               1 :         if (0 != (ret = glob(pattern, flags & GLOB_FLAGMASK, NULL, &globbuf))) {
     400                 : #ifdef GLOB_NOMATCH
     401               0 :                 if (GLOB_NOMATCH == ret) {
     402                 :                         /* Some glob implementation simply return no data if no matches
     403                 :                            were found, others return the GLOB_NOMATCH error code.
     404                 :                            We don't want to treat GLOB_NOMATCH as an error condition
     405                 :                            so that PHP glob() behaves the same on both types of 
     406                 :                            implementations and so that 'foreach (glob() as ...'
     407                 :                            can be used for simple glob() calls without further error
     408                 :                            checking.
     409                 :                         */
     410               0 :                         array_init(return_value);
     411               0 :                         return;
     412                 :                 }
     413                 : #endif
     414               0 :                 RETURN_FALSE;
     415                 :         }
     416                 : 
     417                 :         /* now catch the FreeBSD style of "no matches" */
     418               1 :         if (!globbuf.gl_pathc || !globbuf.gl_pathv) {
     419               0 :                 array_init(return_value);
     420               0 :                 return;
     421                 :         }
     422                 : 
     423                 :         /* we assume that any glob pattern will match files from one directory only
     424                 :            so checking the dirname of the first match should be sufficient */
     425               1 :         strlcpy(cwd, globbuf.gl_pathv[0], MAXPATHLEN);
     426               1 :         if (PG(safe_mode) && (!php_checkuid(cwd, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
     427               0 :                 RETURN_FALSE;
     428                 :         }
     429               1 :         if (php_check_open_basedir(cwd TSRMLS_CC)) {
     430               0 :                 RETURN_FALSE;
     431                 :         }
     432                 : 
     433               1 :         array_init(return_value);
     434             111 :         for (n = 0; n < globbuf.gl_pathc; n++) {
     435                 :                 /* we need to do this everytime since GLOB_ONLYDIR does not guarantee that
     436                 :                  * all directories will be filtered. GNU libc documentation states the
     437                 :                  * following: 
     438                 :                  * If the information about the type of the file is easily available 
     439                 :                  * non-directories will be rejected but no extra work will be done to 
     440                 :                  * determine the information for each file. I.e., the caller must still be 
     441                 :                  * able to filter directories out. 
     442                 :                  */
     443             110 :                 if (flags & GLOB_ONLYDIR) {
     444                 :                         struct stat s;
     445                 : 
     446               0 :                         if (0 != VCWD_STAT(globbuf.gl_pathv[n], &s)) {
     447               0 :                                 continue;
     448                 :                         }
     449                 : 
     450               0 :                         if (S_IFDIR != (s.st_mode & S_IFMT)) {
     451               0 :                                 continue;
     452                 :                         }
     453                 :                 }
     454             110 :                 add_next_index_string(return_value, globbuf.gl_pathv[n]+cwd_skip, 1);
     455                 :         }
     456                 : 
     457               1 :         globfree(&globbuf);
     458                 : }
     459                 : /* }}} */
     460                 : #endif 
     461                 : 
     462                 : /* {{{ proto array scandir(string dir [, int sorting_order [, resource context]])
     463                 :    List files & directories inside the specified path */
     464                 : PHP_FUNCTION(scandir)
     465               0 : {
     466                 :         char *dirn;
     467                 :         int dirn_len;
     468               0 :         long flags = 0;
     469                 :         char **namelist;
     470                 :         int n, i;
     471               0 :         zval *zcontext = NULL;
     472               0 :         php_stream_context *context = NULL;
     473                 : 
     474               0 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lr", &dirn, &dirn_len, &flags, &zcontext) == FAILURE) {
     475               0 :                 return;
     476                 :         }
     477                 : 
     478               0 :         if (zcontext) {
     479               0 :                 context = php_stream_context_from_zval(zcontext, 0);
     480                 :         }
     481                 : 
     482               0 :         if (!flags) {
     483               0 :                 n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasort);
     484                 :         } else {
     485               0 :                 n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasortr);
     486                 :         }
     487               0 :         if (n < 0) {
     488               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "(errno %d): %s", errno, strerror(errno));
     489               0 :                 RETURN_FALSE;
     490                 :         }
     491                 :         
     492               0 :         array_init(return_value);
     493                 : 
     494               0 :         for (i = 0; i < n; i++) {
     495               0 :                 add_next_index_string(return_value, namelist[i], 0);
     496                 :         }
     497                 : 
     498               0 :         if (n) {
     499               0 :                 efree(namelist);
     500                 :         }
     501                 : }
     502                 : /* }}} */
     503                 : 
     504                 : /*
     505                 :  * Local variables:
     506                 :  * tab-width: 4
     507                 :  * c-basic-offset: 4
     508                 :  * End:
     509                 :  * vim600: sw=4 ts=4 fdm=marker
     510                 :  * vim<600: sw=4 ts=4
     511                 :  */

Generated by: LTP GCOV extension version 1.5