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: 260 337 77.2 %
Date: 2014-04-18 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:33 +0000 (16 hours ago)

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