PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/phar - dirstream.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 255 333 76.6 %
Date: 2016-05-22 Functions: 10 11 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | phar:// stream wrapper support                                       |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2005-2016 The PHP Group                                |
       6             :   +----------------------------------------------------------------------+
       7             :   | This source file is subject to version 3.01 of the PHP license,      |
       8             :   | that is bundled with this package in the file LICENSE, and is        |
       9             :   | available through the world-wide-web at the following url:           |
      10             :   | http://www.php.net/license/3_01.txt.                                 |
      11             :   | If you did not receive a copy of the PHP license and are unable to   |
      12             :   | obtain it through the world-wide-web, please send a note to          |
      13             :   | license@php.net so we can mail you a copy immediately.               |
      14             :   +----------------------------------------------------------------------+
      15             :   | Authors: Gregory Beaver <cellog@php.net>                             |
      16             :   |          Marcus Boerger <helly@php.net>                              |
      17             :   +----------------------------------------------------------------------+
      18             : */
      19             : 
      20             : #define PHAR_DIRSTREAM 1
      21             : #include "phar_internal.h"
      22             : #include "dirstream.h"
      23             : 
      24             : BEGIN_EXTERN_C()
      25             : void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, zend_bool is_dir);
      26             : END_EXTERN_C()
      27             : 
      28             : php_stream_ops phar_dir_ops = {
      29             :         phar_dir_write, /* write */
      30             :         phar_dir_read,  /* read  */
      31             :         phar_dir_close, /* close */
      32             :         phar_dir_flush, /* flush */
      33             :         "phar dir",
      34             :         phar_dir_seek,  /* seek */
      35             :         NULL,           /* cast */
      36             :         NULL,           /* stat */
      37             :         NULL, /* set option */
      38             : };
      39             : 
      40             : /**
      41             :  * Used for closedir($fp) where $fp is an opendir('phar://...') directory handle
      42             :  */
      43         462 : static int phar_dir_close(php_stream *stream, int close_handle)  /* {{{ */
      44             : {
      45         462 :         HashTable *data = (HashTable *)stream->abstract;
      46             : 
      47         462 :         if (data && data->u.flags) {
      48         462 :                 zend_hash_destroy(data);
      49         462 :                 data->u.flags = 0;
      50         462 :                 FREE_HASHTABLE(data);
      51         462 :                 stream->abstract = NULL;
      52             :         }
      53             : 
      54         462 :         return 0;
      55             : }
      56             : /* }}} */
      57             : 
      58             : /**
      59             :  * Used for seeking on a phar directory handle
      60             :  */
      61          64 : static int phar_dir_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset) /* {{{ */
      62             : {
      63          64 :         HashTable *data = (HashTable *)stream->abstract;
      64             : 
      65          64 :         if (!data) {
      66           0 :                 return -1;
      67             :         }
      68             : 
      69          64 :         if (whence == SEEK_END) {
      70           1 :                 whence = SEEK_SET;
      71           1 :                 offset = zend_hash_num_elements(data) + offset;
      72             :         }
      73             : 
      74          64 :         if (whence == SEEK_SET) {
      75          64 :                 zend_hash_internal_pointer_reset(data);
      76             :         }
      77             : 
      78          64 :         if (offset < 0) {
      79           1 :                 return -1;
      80             :         } else {
      81          63 :                 *newoffset = 0;
      82         131 :                 while (*newoffset < offset && zend_hash_move_forward(data) == SUCCESS) {
      83           5 :                         ++(*newoffset);
      84             :                 }
      85          63 :                 return 0;
      86             :         }
      87             : }
      88             : /* }}} */
      89             : 
      90             : /**
      91             :  * Used for readdir() on an opendir()ed phar directory handle
      92             :  */
      93         695 : static size_t phar_dir_read(php_stream *stream, char *buf, size_t count) /* {{{ */
      94             : {
      95             :         size_t to_read;
      96         695 :         HashTable *data = (HashTable *)stream->abstract;
      97             :         zend_string *str_key;
      98             :         zend_ulong unused;
      99             : 
     100         695 :         if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key(data, &str_key, &unused)) {
     101         259 :                 return 0;
     102             :         }
     103             : 
     104         436 :         zend_hash_move_forward(data);
     105         436 :         to_read = MIN(ZSTR_LEN(str_key), count);
     106             : 
     107         436 :         if (to_read == 0 || count < ZSTR_LEN(str_key)) {
     108           0 :                 return 0;
     109             :         }
     110             : 
     111         436 :         memset(buf, 0, sizeof(php_stream_dirent));
     112         436 :         memcpy(((php_stream_dirent *) buf)->d_name, ZSTR_VAL(str_key), to_read);
     113         436 :         ((php_stream_dirent *) buf)->d_name[to_read + 1] = '\0';
     114             : 
     115         436 :         return sizeof(php_stream_dirent);
     116             : }
     117             : /* }}} */
     118             : 
     119             : /**
     120             :  * Dummy: Used for writing to a phar directory (i.e. not used)
     121             :  */
     122           1 : static size_t phar_dir_write(php_stream *stream, const char *buf, size_t count) /* {{{ */
     123             : {
     124           1 :         return 0;
     125             : }
     126             : /* }}} */
     127             : 
     128             : /**
     129             :  * Dummy: Used for flushing writes to a phar directory (i.e. not used)
     130             :  */
     131           0 : static int phar_dir_flush(php_stream *stream) /* {{{ */
     132             : {
     133           0 :         return EOF;
     134             : }
     135             : /* }}} */
     136             : 
     137             : /**
     138             :  * add an empty element with a char * key to a hash table, avoiding duplicates
     139             :  *
     140             :  * This is used to get a unique listing of virtual directories within a phar,
     141             :  * for iterating over opendir()ed phar directories.
     142             :  */
     143        1031 : static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength)  /* {{{ */
     144             : {
     145             :         zval dummy;
     146             : 
     147        1031 :         ZVAL_NULL(&dummy);
     148        1031 :         return (zend_hash_str_update(ht, arKey, nKeyLength, &dummy) != NULL) ? SUCCESS : FAILURE;
     149             : }
     150             : /* }}} */
     151             : 
     152             : /**
     153             :  * Used for sorting directories alphabetically
     154             :  */
     155         496 : static int phar_compare_dir_name(const void *a, const void *b)  /* {{{ */
     156             : {
     157             :         Bucket *f;
     158             :         Bucket *s;
     159             :         int result;
     160             : 
     161         496 :         f = (Bucket *) a;
     162         496 :         s = (Bucket *) b;
     163         496 :         result = zend_binary_strcmp(ZSTR_VAL(f->key), ZSTR_LEN(f->key), ZSTR_VAL(s->key), ZSTR_LEN(s->key));
     164             : 
     165         496 :         if (result < 0) {
     166         373 :                 return -1;
     167         123 :         } else if (result > 0) {
     168         123 :                 return 1;
     169             :         } else {
     170           0 :                 return 0;
     171             :         }
     172             : }
     173             : /* }}} */
     174             : 
     175             : /**
     176             :  * Create a opendir() directory stream handle by iterating over each of the
     177             :  * files in a phar and retrieving its relative path.  From this, construct
     178             :  * a list of files/directories that are "in" the directory represented by dir
     179             :  */
     180         462 : static php_stream *phar_make_dirstream(char *dir, HashTable *manifest) /* {{{ */
     181             : {
     182             :         HashTable *data;
     183         462 :         int dirlen = strlen(dir);
     184             :         char *entry, *found, *save;
     185             :         zend_string *str_key;
     186             :         uint keylen;
     187             :         zend_ulong unused;
     188             : 
     189         462 :         ALLOC_HASHTABLE(data);
     190         462 :         zend_hash_init(data, 64, NULL, NULL, 0);
     191             : 
     192         462 :         if ((*dir == '/' && dirlen == 1 && (manifest->nNumOfElements == 0)) || (dirlen >= sizeof(".phar")-1 && !memcmp(dir, ".phar", sizeof(".phar")-1))) {
     193             :                 /* make empty root directory for empty phar */
     194             :                 /* make empty directory for .phar magic directory */
     195         164 :                 efree(dir);
     196         164 :                 return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
     197             :         }
     198             : 
     199         298 :         zend_hash_internal_pointer_reset(manifest);
     200             : 
     201         298 :         while (FAILURE != zend_hash_has_more_elements(manifest)) {
     202        1877 :                 keylen = 0;
     203        1877 :                 if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key(manifest, &str_key, &unused)) {
     204           0 :                         break;
     205             :                 }
     206             : 
     207        1877 :                 keylen = ZSTR_LEN(str_key);
     208        1877 :                 if (keylen <= (uint)dirlen) {
     209         634 :                         if (keylen == 0 || keylen < (uint)dirlen || !strncmp(ZSTR_VAL(str_key), dir, dirlen)) {
     210         291 :                                 if (SUCCESS != zend_hash_move_forward(manifest)) {
     211           0 :                                         break;
     212             :                                 }
     213         291 :                                 continue;
     214             :                         }
     215             :                 }
     216             : 
     217        1586 :                 if (*dir == '/') {
     218             :                         /* root directory */
     219         969 :                         if (keylen >= sizeof(".phar")-1 && !memcmp(ZSTR_VAL(str_key), ".phar", sizeof(".phar")-1)) {
     220             :                                 /* do not add any magic entries to this directory */
     221         107 :                                 if (SUCCESS != zend_hash_move_forward(manifest)) {
     222           0 :                                         break;
     223             :                                 }
     224         107 :                                 continue;
     225             :                         }
     226             : 
     227         862 :                         if (NULL != (found = (char *) memchr(ZSTR_VAL(str_key), '/', keylen))) {
     228             :                                 /* the entry has a path separator and is a subdirectory */
     229         324 :                                 entry = (char *) safe_emalloc(found - ZSTR_VAL(str_key), 1, 1);
     230         324 :                                 memcpy(entry, ZSTR_VAL(str_key), found - ZSTR_VAL(str_key));
     231         324 :                                 keylen = found - ZSTR_VAL(str_key);
     232         324 :                                 entry[keylen] = '\0';
     233             :                         } else {
     234         538 :                                 entry = (char *) safe_emalloc(keylen, 1, 1);
     235         538 :                                 memcpy(entry, ZSTR_VAL(str_key), keylen);
     236         538 :                                 entry[keylen] = '\0';
     237             :                         }
     238             : 
     239         862 :                         goto PHAR_ADD_ENTRY;
     240             :                 } else {
     241         617 :                         if (0 != memcmp(ZSTR_VAL(str_key), dir, dirlen)) {
     242             :                                 /* entry in directory not found */
     243         442 :                                 if (SUCCESS != zend_hash_move_forward(manifest)) {
     244           0 :                                         break;
     245             :                                 }
     246         442 :                                 continue;
     247             :                         } else {
     248         175 :                                 if (ZSTR_VAL(str_key)[dirlen] != '/') {
     249           6 :                                         if (SUCCESS != zend_hash_move_forward(manifest)) {
     250           0 :                                                 break;
     251             :                                         }
     252           6 :                                         continue;
     253             :                                 }
     254             :                         }
     255             :                 }
     256             : 
     257         169 :                 save = ZSTR_VAL(str_key);
     258         169 :                 save += dirlen + 1; /* seek to just past the path separator */
     259             : 
     260         169 :                 if (NULL != (found = (char *) memchr(save, '/', keylen - dirlen - 1))) {
     261             :                         /* is subdirectory */
     262          97 :                         save -= dirlen + 1;
     263          97 :                         entry = (char *) safe_emalloc(found - save + dirlen, 1, 1);
     264          97 :                         memcpy(entry, save + dirlen + 1, found - save - dirlen - 1);
     265          97 :                         keylen = found - save - dirlen - 1;
     266          97 :                         entry[keylen] = '\0';
     267             :                 } else {
     268             :                         /* is file */
     269          72 :                         save -= dirlen + 1;
     270          72 :                         entry = (char *) safe_emalloc(keylen - dirlen, 1, 1);
     271          72 :                         memcpy(entry, save + dirlen + 1, keylen - dirlen - 1);
     272          72 :                         entry[keylen - dirlen - 1] = '\0';
     273          72 :                         keylen = keylen - dirlen - 1;
     274             :                 }
     275             : PHAR_ADD_ENTRY:
     276        1031 :                 if (keylen) {
     277        1031 :                         phar_add_empty(data, entry, keylen);
     278             :                 }
     279             : 
     280        1031 :                 efree(entry);
     281             : 
     282        1031 :                 if (SUCCESS != zend_hash_move_forward(manifest)) {
     283           0 :                         break;
     284             :                 }
     285             :         }
     286             : 
     287         298 :         if (FAILURE != zend_hash_has_more_elements(data)) {
     288         282 :                 efree(dir);
     289         282 :                 if (zend_hash_sort(data, phar_compare_dir_name, 0) == FAILURE) {
     290           0 :                         FREE_HASHTABLE(data);
     291           0 :                         return NULL;
     292             :                 }
     293         282 :                 return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
     294             :         } else {
     295          16 :                 efree(dir);
     296          16 :                 return php_stream_alloc(&phar_dir_ops, data, NULL, "r");
     297             :         }
     298             : }
     299             : /* }}}*/
     300             : 
     301             : /**
     302             :  * Open a directory handle within a phar archive
     303             :  */
     304         471 : php_stream *phar_wrapper_open_dir(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC) /* {{{ */
     305             : {
     306         471 :         php_url *resource = NULL;
     307             :         php_stream *ret;
     308             :         char *internal_file, *error;
     309             :         zend_string *str_key;
     310             :         zend_ulong unused;
     311             :         phar_archive_data *phar;
     312         471 :         phar_entry_info *entry = NULL;
     313             :         uint host_len;
     314             : 
     315         471 :         if ((resource = phar_parse_url(wrapper, path, mode, options)) == NULL) {
     316           6 :                 php_stream_wrapper_log_error(wrapper, options, "phar url \"%s\" is unknown", path);
     317           6 :                 return NULL;
     318             :         }
     319             : 
     320             :         /* we must have at the very least phar://alias.phar/ */
     321         465 :         if (!resource->scheme || !resource->host || !resource->path) {
     322           0 :                 if (resource->host && !resource->path) {
     323           0 :                         php_stream_wrapper_log_error(wrapper, options, "phar error: no directory in \"%s\", must have at least phar://%s/ for root directory (always use full path to a new phar)", path, resource->host);
     324           0 :                         php_url_free(resource);
     325           0 :                         return NULL;
     326             :                 }
     327           0 :                 php_url_free(resource);
     328           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\", must have at least phar://%s/", path, path);
     329           0 :                 return NULL;
     330             :         }
     331             : 
     332         465 :         if (strcasecmp("phar", resource->scheme)) {
     333           0 :                 php_url_free(resource);
     334           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar url \"%s\"", path);
     335           0 :                 return NULL;
     336             :         }
     337             : 
     338         465 :         host_len = strlen(resource->host);
     339         465 :         phar_request_initialize();
     340         465 :         internal_file = resource->path + 1; /* strip leading "/" */
     341             : 
     342         465 :         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error)) {
     343           0 :                 if (error) {
     344           0 :                         php_stream_wrapper_log_error(wrapper, options, "%s", error);
     345           0 :                         efree(error);
     346             :                 } else {
     347           0 :                         php_stream_wrapper_log_error(wrapper, options, "phar file \"%s\" is unknown", resource->host);
     348             :                 }
     349           0 :                 php_url_free(resource);
     350           0 :                 return NULL;
     351             :         }
     352             : 
     353         465 :         if (error) {
     354           0 :                 efree(error);
     355             :         }
     356             : 
     357         465 :         if (*internal_file == '\0') {
     358             :                 /* root directory requested */
     359         411 :                 internal_file = estrndup(internal_file - 1, 1);
     360         411 :                 ret = phar_make_dirstream(internal_file, &phar->manifest);
     361         411 :                 php_url_free(resource);
     362         411 :                 return ret;
     363             :         }
     364             : 
     365          54 :         if (!phar->manifest.u.flags) {
     366           0 :                 php_url_free(resource);
     367           0 :                 return NULL;
     368             :         }
     369             : 
     370         108 :         if (NULL != (entry = zend_hash_str_find_ptr(&phar->manifest, internal_file, strlen(internal_file))) && !entry->is_dir) {
     371           0 :                 php_url_free(resource);
     372           0 :                 return NULL;
     373          54 :         } else if (entry && entry->is_dir) {
     374          24 :                 if (entry->is_mounted) {
     375           2 :                         php_url_free(resource);
     376           2 :                         return php_stream_opendir(entry->tmp, options, context);
     377             :                 }
     378          22 :                 internal_file = estrdup(internal_file);
     379          22 :                 php_url_free(resource);
     380          22 :                 return phar_make_dirstream(internal_file, &phar->manifest);
     381             :         } else {
     382          30 :                 int i_len = strlen(internal_file);
     383             : 
     384             :                 /* search for directory */
     385          30 :                 zend_hash_internal_pointer_reset(&phar->manifest);
     386          30 :                 while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
     387         251 :                         if (HASH_KEY_NON_EXISTENT !=
     388         251 :                                         zend_hash_get_current_key(&phar->manifest, &str_key, &unused)) {
     389         251 :                                 if (ZSTR_LEN(str_key) > (uint)i_len && 0 == memcmp(ZSTR_VAL(str_key), internal_file, i_len)) {
     390             :                                         /* directory found */
     391          29 :                                         internal_file = estrndup(internal_file,
     392             :                                                         i_len);
     393          29 :                                         php_url_free(resource);
     394          29 :                                         return phar_make_dirstream(internal_file, &phar->manifest);
     395             :                                 }
     396             :                         }
     397             : 
     398         222 :                         if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
     399           0 :                                 break;
     400             :                         }
     401             :                 }
     402             :         }
     403             : 
     404           1 :         php_url_free(resource);
     405           1 :         return NULL;
     406             : }
     407             : /* }}} */
     408             : 
     409             : /**
     410             :  * Make a new directory within a phar archive
     411             :  */
     412          16 : int phar_wrapper_mkdir(php_stream_wrapper *wrapper, const char *url_from, int mode, int options, php_stream_context *context) /* {{{ */
     413             : {
     414             :         phar_entry_info entry, *e;
     415          16 :         phar_archive_data *phar = NULL;
     416             :         char *error, *arch, *entry2;
     417             :         int arch_len, entry_len;
     418          16 :         php_url *resource = NULL;
     419             :         uint host_len;
     420             : 
     421             :         /* pre-readonly check, we need to know if this is a data phar */
     422          16 :         if (FAILURE == phar_split_fname(url_from, strlen(url_from), &arch, &arch_len, &entry2, &entry_len, 2, 2)) {
     423           2 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\", no phar archive specified", url_from);
     424           2 :                 return 0;
     425             :         }
     426             : 
     427          14 :         if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
     428           4 :                 phar = NULL;
     429             :         }
     430             : 
     431          14 :         efree(arch);
     432          14 :         efree(entry2);
     433             : 
     434          14 :         if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
     435           1 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\", write operations disabled", url_from);
     436           1 :                 return 0;
     437             :         }
     438             : 
     439          13 :         if ((resource = phar_parse_url(wrapper, url_from, "w", options)) == NULL) {
     440           1 :                 return 0;
     441             :         }
     442             : 
     443             :         /* we must have at the very least phar://alias.phar/internalfile.php */
     444          12 :         if (!resource->scheme || !resource->host || !resource->path) {
     445           0 :                 php_url_free(resource);
     446           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\"", url_from);
     447           0 :                 return 0;
     448             :         }
     449             : 
     450          12 :         if (strcasecmp("phar", resource->scheme)) {
     451           0 :                 php_url_free(resource);
     452           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar stream url \"%s\"", url_from);
     453           0 :                 return 0;
     454             :         }
     455             : 
     456          12 :         host_len = strlen(resource->host);
     457             : 
     458          12 :         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error)) {
     459           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
     460           0 :                 efree(error);
     461           0 :                 php_url_free(resource);
     462           0 :                 return 0;
     463             :         }
     464             : 
     465          12 :         if ((e = phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 2, &error, 1))) {
     466             :                 /* directory exists, or is a subdirectory of an existing file */
     467           2 :                 if (e->is_temp_dir) {
     468           1 :                         efree(e->filename);
     469           1 :                         efree(e);
     470             :                 }
     471           2 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", directory already exists", resource->path+1, resource->host);
     472           2 :                 php_url_free(resource);
     473           2 :                 return 0;
     474             :         }
     475             : 
     476          10 :         if (error) {
     477           2 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
     478           2 :                 efree(error);
     479           2 :                 php_url_free(resource);
     480           2 :                 return 0;
     481             :         }
     482             : 
     483           8 :         if (phar_get_entry_info_dir(phar, resource->path + 1, strlen(resource->path + 1), 0, &error, 1)) {
     484             :                 /* entry exists as a file */
     485           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", file already exists", resource->path+1, resource->host);
     486           0 :                 php_url_free(resource);
     487           0 :                 return 0;
     488             :         }
     489             : 
     490           8 :         if (error) {
     491           2 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
     492           2 :                 efree(error);
     493           2 :                 php_url_free(resource);
     494           2 :                 return 0;
     495             :         }
     496             : 
     497           6 :         memset((void *) &entry, 0, sizeof(phar_entry_info));
     498             : 
     499             :         /* strip leading "/" */
     500           6 :         if (phar->is_zip) {
     501           1 :                 entry.is_zip = 1;
     502             :         }
     503             : 
     504           6 :         entry.filename = estrdup(resource->path + 1);
     505             : 
     506           6 :         if (phar->is_tar) {
     507           1 :                 entry.is_tar = 1;
     508           1 :                 entry.tar_type = TAR_DIR;
     509             :         }
     510             : 
     511           6 :         entry.filename_len = strlen(resource->path + 1);
     512           6 :         php_url_free(resource);
     513           6 :         entry.is_dir = 1;
     514           6 :         entry.phar = phar;
     515           6 :         entry.is_modified = 1;
     516           6 :         entry.is_crc_checked = 1;
     517           6 :         entry.flags = PHAR_ENT_PERM_DEF_DIR;
     518           6 :         entry.old_flags = PHAR_ENT_PERM_DEF_DIR;
     519             : 
     520          12 :         if (NULL == zend_hash_str_add_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
     521           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", adding to manifest failed", entry.filename, phar->fname);
     522           0 :                 efree(error);
     523           0 :                 efree(entry.filename);
     524           0 :                 return 0;
     525             :         }
     526             : 
     527           6 :         phar_flush(phar, 0, 0, 0, &error);
     528             : 
     529           6 :         if (error) {
     530           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot create directory \"%s\" in phar \"%s\", %s", entry.filename, phar->fname, error);
     531           0 :                 zend_hash_str_del(&phar->manifest, entry.filename, entry.filename_len);
     532           0 :                 efree(error);
     533           0 :                 return 0;
     534             :         }
     535             : 
     536           6 :         phar_add_virtual_dirs(phar, entry.filename, entry.filename_len);
     537           6 :         return 1;
     538             : }
     539             : /* }}} */
     540             : 
     541             : /**
     542             :  * Remove a directory within a phar archive
     543             :  */
     544          18 : int phar_wrapper_rmdir(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context) /* {{{ */
     545             : {
     546             :         phar_entry_info *entry;
     547          18 :         phar_archive_data *phar = NULL;
     548             :         char *error, *arch, *entry2;
     549             :         int arch_len, entry_len;
     550          18 :         php_url *resource = NULL;
     551             :         uint host_len;
     552             :         zend_string *str_key;
     553             :         zend_ulong unused;
     554             :         uint path_len;
     555             : 
     556             :         /* pre-readonly check, we need to know if this is a data phar */
     557          18 :         if (FAILURE == phar_split_fname(url, strlen(url), &arch, &arch_len, &entry2, &entry_len, 2, 2)) {
     558           2 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\", no phar archive specified, or phar archive does not exist", url);
     559           2 :                 return 0;
     560             :         }
     561             : 
     562          16 :         if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL)) {
     563           1 :                 phar = NULL;
     564             :         }
     565             : 
     566          16 :         efree(arch);
     567          16 :         efree(entry2);
     568             : 
     569          16 :         if (PHAR_G(readonly) && (!phar || !phar->is_data)) {
     570           1 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot rmdir directory \"%s\", write operations disabled", url);
     571           1 :                 return 0;
     572             :         }
     573             : 
     574          15 :         if ((resource = phar_parse_url(wrapper, url, "w", options)) == NULL) {
     575           0 :                 return 0;
     576             :         }
     577             : 
     578             :         /* we must have at the very least phar://alias.phar/internalfile.php */
     579          15 :         if (!resource->scheme || !resource->host || !resource->path) {
     580           0 :                 php_url_free(resource);
     581           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: invalid url \"%s\"", url);
     582           0 :                 return 0;
     583             :         }
     584             : 
     585          15 :         if (strcasecmp("phar", resource->scheme)) {
     586           0 :                 php_url_free(resource);
     587           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: not a phar stream url \"%s\"", url);
     588           0 :                 return 0;
     589             :         }
     590             : 
     591          15 :         host_len = strlen(resource->host);
     592             : 
     593          15 :         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error)) {
     594           0 :                 php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
     595           0 :                 efree(error);
     596           0 :                 php_url_free(resource);
     597           0 :                 return 0;
     598             :         }
     599             : 
     600          15 :         path_len = strlen(resource->path+1);
     601             : 
     602          15 :         if (!(entry = phar_get_entry_info_dir(phar, resource->path + 1, path_len, 2, &error, 1))) {
     603           5 :                 if (error) {
     604           1 :                         php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", resource->path+1, resource->host, error);
     605           1 :                         efree(error);
     606             :                 } else {
     607           4 :                         php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", directory does not exist", resource->path+1, resource->host);
     608             :                 }
     609           5 :                 php_url_free(resource);
     610           5 :                 return 0;
     611             :         }
     612             : 
     613          10 :         if (!entry->is_deleted) {
     614          37 :                 for (zend_hash_internal_pointer_reset(&phar->manifest);
     615          27 :                         HASH_KEY_NON_EXISTENT != zend_hash_get_current_key(&phar->manifest, &str_key, &unused);
     616          17 :                         zend_hash_move_forward(&phar->manifest)
     617          17 :                 ) {
     618          34 :                         if (ZSTR_LEN(str_key) > path_len &&
     619          10 :                                 memcmp(ZSTR_VAL(str_key), resource->path+1, path_len) == 0 &&
     620           4 :                                 IS_SLASH(ZSTR_VAL(str_key)[path_len])) {
     621           3 :                                 php_stream_wrapper_log_error(wrapper, options, "phar error: Directory not empty");
     622           3 :                                 if (entry->is_temp_dir) {
     623           1 :                                         efree(entry->filename);
     624           1 :                                         efree(entry);
     625             :                                 }
     626           3 :                                 php_url_free(resource);
     627           3 :                                 return 0;
     628             :                         }
     629             :                 }
     630             : 
     631          23 :                 for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
     632          16 :                         HASH_KEY_NON_EXISTENT != zend_hash_get_current_key(&phar->virtual_dirs, &str_key, &unused);
     633           9 :                         zend_hash_move_forward(&phar->virtual_dirs)) {
     634             : 
     635          11 :                         if (ZSTR_LEN(str_key) > path_len &&
     636           2 :                                 memcmp(ZSTR_VAL(str_key), resource->path+1, path_len) == 0 &&
     637           0 :                                 IS_SLASH(ZSTR_VAL(str_key)[path_len])) {
     638           0 :                                 php_stream_wrapper_log_error(wrapper, options, "phar error: Directory not empty");
     639           0 :                                 if (entry->is_temp_dir) {
     640           0 :                                         efree(entry->filename);
     641           0 :                                         efree(entry);
     642             :                                 }
     643           0 :                                 php_url_free(resource);
     644           0 :                                 return 0;
     645             :                         }
     646             :                 }
     647             :         }
     648             : 
     649           7 :         if (entry->is_temp_dir) {
     650           1 :                 zend_hash_str_del(&phar->virtual_dirs, resource->path+1, path_len);
     651           1 :                 efree(entry->filename);
     652           1 :                 efree(entry);
     653             :         } else {
     654           6 :                 entry->is_deleted = 1;
     655           6 :                 entry->is_modified = 1;
     656           6 :                 phar_flush(phar, 0, 0, 0, &error);
     657             : 
     658           6 :                 if (error) {
     659           0 :                         php_stream_wrapper_log_error(wrapper, options, "phar error: cannot remove directory \"%s\" in phar \"%s\", %s", entry->filename, phar->fname, error);
     660           0 :                         php_url_free(resource);
     661           0 :                         efree(error);
     662           0 :                         return 0;
     663             :                 }
     664             :         }
     665             : 
     666           7 :         php_url_free(resource);
     667           7 :         return 1;
     668             : }
     669             : /* }}} */
     670             : 
     671             : /*
     672             :  * Local variables:
     673             :  * tab-width: 4
     674             :  * c-basic-offset: 4
     675             :  * End:
     676             :  * vim600: noet sw=4 ts=4 fdm=marker
     677             :  * vim<600: noet sw=4 ts=4
     678             :  */

Generated by: LCOV version 1.10

Generated at Sun, 22 May 2016 10:53:01 +0000 (2 days ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.