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 - phar.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 1397 1788 78.1 %
Date: 2014-11-22 Functions: 46 46 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | phar php single-file executable PHP extension                        |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2005-2014 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             : /* $Id: 0903f6c952f364820a926dbbc5fd070f9ad1920f $ */
      21             : 
      22             : #define PHAR_MAIN 1
      23             : #include "phar_internal.h"
      24             : #include "SAPI.h"
      25             : #include "func_interceptors.h"
      26             : 
      27             : static void destroy_phar_data(zval *zv);
      28             : 
      29             : ZEND_DECLARE_MODULE_GLOBALS(phar)
      30             : char *(*phar_save_resolve_path)(const char *filename, int filename_len TSRMLS_DC);
      31             : 
      32             : /**
      33             :  * set's phar->is_writeable based on the current INI value
      34             :  */
      35          95 : static int phar_set_writeable_bit(zval *zv, void *argument TSRMLS_DC) /* {{{ */
      36             : {
      37          95 :         zend_bool keep = *(zend_bool *)argument;
      38          95 :         phar_archive_data *phar = (phar_archive_data *)Z_PTR_P(zv);
      39             : 
      40          95 :         if (!phar->is_data) {
      41          68 :                 phar->is_writeable = !keep;
      42             :         }
      43             : 
      44          95 :         return ZEND_HASH_APPLY_KEEP;
      45             : }
      46             : /* }}} */
      47             : 
      48             : /* if the original value is 0 (disabled), then allow setting/unsetting at will. Otherwise only allow 1 (enabled), and error on disabling */
      49       41111 : ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */
      50             : {
      51             :         zend_bool old, ini;
      52             : 
      53       41111 :         if (entry->name->len == sizeof("phar.readonly")-1) {
      54       20589 :                 old = PHAR_G(readonly_orig);
      55             :         } else {
      56       20522 :                 old = PHAR_G(require_hash_orig);
      57             :         }
      58             : 
      59       41113 :         if (new_value->len == 2 && !strcasecmp("on", new_value->val)) {
      60           2 :                 ini = (zend_bool) 1;
      61             :         }
      62       41111 :         else if (new_value->len == 3 && !strcasecmp("yes", new_value->val)) {
      63           2 :                 ini = (zend_bool) 1;
      64             :         }
      65       41109 :         else if (new_value->len == 4 && !strcasecmp("true", new_value->val)) {
      66           2 :                 ini = (zend_bool) 1;
      67             :         }
      68             :         else {
      69       41105 :                 ini = (zend_bool) atoi(new_value->val);
      70             :         }
      71             : 
      72             :         /* do not allow unsetting in runtime */
      73       41111 :         if (stage == ZEND_INI_STAGE_STARTUP) {
      74       41014 :                 if (entry->name->len == sizeof("phar.readonly")-1) {
      75       20507 :                         PHAR_G(readonly_orig) = ini;
      76             :                 } else {
      77       20507 :                         PHAR_G(require_hash_orig) = ini;
      78             :                 }
      79          97 :         } else if (old && !ini) {
      80           2 :                 return FAILURE;
      81             :         }
      82             : 
      83       41109 :         if (entry->name->len == sizeof("phar.readonly")-1) {
      84       20588 :                 PHAR_G(readonly) = ini;
      85       20588 :                 if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arHash) {
      86          44 :                         zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_fname_map), phar_set_writeable_bit, (void *)&ini TSRMLS_CC);
      87             :                 }
      88             :         } else {
      89       20521 :                 PHAR_G(require_hash) = ini;
      90             :         }
      91             : 
      92       41109 :         return SUCCESS;
      93             : }
      94             : /* }}}*/
      95             : 
      96             : /* this global stores the global cached pre-parsed manifests */
      97             : HashTable cached_phars;
      98             : HashTable cached_alias;
      99             : 
     100       20507 : static void phar_split_cache_list(TSRMLS_D) /* {{{ */
     101             : {
     102             :         char *tmp;
     103             :         char *key, *lasts, *end;
     104             :         char ds[2];
     105             :         phar_archive_data *phar;
     106       20507 :         uint i = 0;
     107             : 
     108       20507 :         if (!PHAR_GLOBALS->cache_list || !(PHAR_GLOBALS->cache_list[0])) {
     109       20385 :                 return;
     110             :         }
     111             : 
     112         122 :         ds[0] = DEFAULT_DIR_SEPARATOR;
     113         122 :         ds[1] = '\0';
     114         122 :         tmp = estrdup(PHAR_GLOBALS->cache_list);
     115             : 
     116             :         /* fake request startup */
     117         122 :         PHAR_GLOBALS->request_init = 1;
     118         122 :         zend_hash_init(&EG(regular_list), 0, NULL, NULL, 0);
     119         122 :         EG(regular_list).nNextFreeElement=1;    /* we don't want resource id 0 */
     120             : 
     121         122 :         PHAR_G(has_bz2) = zend_hash_str_exists(&module_registry, "bz2", sizeof("bz2")-1);
     122         122 :         PHAR_G(has_zlib) = zend_hash_str_exists(&module_registry, "zlib", sizeof("zlib")-1);
     123             :         /* these two are dummies and will be destroyed later */
     124         122 :         zend_hash_init(&cached_phars, sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data,  1);
     125         122 :         zend_hash_init(&cached_alias, sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
     126             :         /* these two are real and will be copied over cached_phars/cached_alias later */
     127         122 :         zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data,  1);
     128         122 :         zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
     129         122 :         PHAR_GLOBALS->manifest_cached = 1;
     130         122 :         PHAR_GLOBALS->persist = 1;
     131             : 
     132         247 :         for (key = php_strtok_r(tmp, ds, &lasts);
     133             :                         key;
     134           3 :                         key = php_strtok_r(NULL, ds, &lasts)) {
     135         122 :                 end = strchr(key, DEFAULT_DIR_SEPARATOR);
     136             : 
     137         122 :                 if (end) {
     138           0 :                         if (SUCCESS == phar_open_from_filename(key, end - key, NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
     139             : finish_up:
     140           3 :                                 phar->phar_pos = i++;
     141           3 :                                 php_stream_close(phar->fp);
     142           3 :                                 phar->fp = NULL;
     143             :                         } else {
     144             : finish_error:
     145         119 :                                 PHAR_GLOBALS->persist = 0;
     146         119 :                                 PHAR_GLOBALS->manifest_cached = 0;
     147         119 :                                 efree(tmp);
     148         119 :                                 zend_hash_destroy(&(PHAR_G(phar_fname_map)));
     149         119 :                                 PHAR_GLOBALS->phar_fname_map.arHash = 0;
     150         119 :                                 zend_hash_destroy(&(PHAR_G(phar_alias_map)));
     151         119 :                                 PHAR_GLOBALS->phar_alias_map.arHash = 0;
     152         119 :                                 zend_hash_destroy(&cached_phars);
     153         119 :                                 zend_hash_destroy(&cached_alias);
     154         119 :                                 zend_hash_graceful_reverse_destroy(&EG(regular_list));
     155         119 :                                 memset(&EG(regular_list), 0, sizeof(HashTable));
     156             :                                 /* free cached manifests */
     157         119 :                                 PHAR_GLOBALS->request_init = 0;
     158         119 :                                 return;
     159             :                         }
     160             :                 } else {
     161         122 :                         if (SUCCESS == phar_open_from_filename(key, strlen(key), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
     162           3 :                                 goto finish_up;
     163             :                         } else {
     164         119 :                                 goto finish_error;
     165             :                         }
     166             :                 }
     167             :         }
     168             : 
     169           3 :         PHAR_GLOBALS->persist = 0;
     170           3 :         PHAR_GLOBALS->request_init = 0;
     171             :         /* destroy dummy values from before */
     172           3 :         zend_hash_destroy(&cached_phars);
     173           3 :         zend_hash_destroy(&cached_alias);
     174           3 :         cached_phars = PHAR_GLOBALS->phar_fname_map;
     175           3 :         cached_alias = PHAR_GLOBALS->phar_alias_map;
     176           3 :         PHAR_GLOBALS->phar_fname_map.arHash = 0;
     177           3 :         PHAR_GLOBALS->phar_alias_map.arHash = 0;
     178           3 :         zend_hash_graceful_reverse_destroy(&EG(regular_list));
     179           3 :         memset(&EG(regular_list), 0, sizeof(HashTable));
     180           3 :         efree(tmp);
     181             : }
     182             : /* }}} */
     183             : 
     184       20507 : ZEND_INI_MH(phar_ini_cache_list) /* {{{ */
     185             : {
     186       20507 :         PHAR_G(cache_list) = new_value->val;
     187             : 
     188       20507 :         if (stage == ZEND_INI_STAGE_STARTUP) {
     189       20507 :                 phar_split_cache_list(TSRMLS_C);
     190             :         }
     191             : 
     192       20507 :         return SUCCESS;
     193             : }
     194             : /* }}} */
     195             : 
     196             : PHP_INI_BEGIN()
     197             :         STD_PHP_INI_BOOLEAN( "phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals)
     198             :         STD_PHP_INI_BOOLEAN( "phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals)
     199             :         STD_PHP_INI_ENTRY("phar.cache_list", "", PHP_INI_SYSTEM, phar_ini_cache_list, cache_list, zend_phar_globals, phar_globals)
     200             : PHP_INI_END()
     201             : 
     202             : /**
     203             :  * When all uses of a phar have been concluded, this frees the manifest
     204             :  * and the phar slot
     205             :  */
     206         621 : void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */
     207             : {
     208         621 :         if (phar->alias && phar->alias != phar->fname) {
     209         494 :                 pefree(phar->alias, phar->is_persistent);
     210         494 :                 phar->alias = NULL;
     211             :         }
     212             : 
     213         621 :         if (phar->fname) {
     214         551 :                 pefree(phar->fname, phar->is_persistent);
     215         551 :                 phar->fname = NULL;
     216             :         }
     217             : 
     218         621 :         if (phar->signature) {
     219         392 :                 pefree(phar->signature, phar->is_persistent);
     220         392 :                 phar->signature = NULL;
     221             :         }
     222             : 
     223         621 :         if (phar->manifest.arHash) {
     224         564 :                 zend_hash_destroy(&phar->manifest);
     225         564 :                 phar->manifest.arHash = NULL;
     226             :         }
     227             : 
     228         621 :         if (phar->mounted_dirs.arHash) {
     229         564 :                 zend_hash_destroy(&phar->mounted_dirs);
     230         564 :                 phar->mounted_dirs.arHash = NULL;
     231             :         }
     232             : 
     233         621 :         if (phar->virtual_dirs.arHash) {
     234         564 :                 zend_hash_destroy(&phar->virtual_dirs);
     235         564 :                 phar->virtual_dirs.arHash = NULL;
     236             :         }
     237             : 
     238        1242 :         if (Z_TYPE(phar->metadata) != IS_UNDEF) {
     239          21 :                 if (phar->is_persistent) {
     240           3 :                         if (phar->metadata_len) {
     241             :                                 /* for zip comments that are strings */
     242           3 :                                 free(Z_PTR(phar->metadata));
     243             :                         } else {
     244           0 :                                 zval_internal_ptr_dtor(&phar->metadata);
     245             :                         }
     246             :                 } else {
     247          18 :                         zval_ptr_dtor(&phar->metadata);
     248             :                 }
     249          21 :                 phar->metadata_len = 0;
     250          21 :                 ZVAL_UNDEF(&phar->metadata);
     251             :         }
     252             : 
     253         621 :         if (phar->fp) {
     254         115 :                 php_stream_close(phar->fp);
     255         115 :                 phar->fp = 0;
     256             :         }
     257             : 
     258         621 :         if (phar->ufp) {
     259          20 :                 php_stream_close(phar->ufp);
     260          20 :                 phar->ufp = 0;
     261             :         }
     262             : 
     263         621 :         pefree(phar, phar->is_persistent);
     264         621 : }
     265             : /* }}}*/
     266             : 
     267             : /**
     268             :  * Delete refcount and destruct if needed. On destruct return 1 else 0.
     269             :  */
     270        8602 : int phar_archive_delref(phar_archive_data *phar TSRMLS_DC) /* {{{ */
     271             : {
     272        8602 :         if (phar->is_persistent) {
     273           0 :                 return 0;
     274             :         }
     275             : 
     276        8602 :         if (--phar->refcount < 0) {
     277          25 :                 if (PHAR_GLOBALS->request_done
     278          25 :                 || zend_hash_str_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
     279           7 :                         phar_destroy_phar_data(phar TSRMLS_CC);
     280             :                 }
     281          16 :                 return 1;
     282        8586 :         } else if (!phar->refcount) {
     283             :                 /* invalidate phar cache */
     284         644 :                 PHAR_G(last_phar) = NULL;
     285         644 :                 PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
     286             : 
     287         644 :                 if (phar->fp && !(phar->flags & PHAR_FILE_COMPRESSION_MASK)) {
     288             :                         /* close open file handle - allows removal or rename of
     289             :                         the file on windows, which has greedy locking
     290             :                         only close if the archive was not already compressed.  If it
     291             :                         was compressed, then the fp does not refer to the original file */
     292         559 :                         php_stream_close(phar->fp);
     293         559 :                         phar->fp = NULL;
     294             :                 }
     295             : 
     296         644 :                 if (!zend_hash_num_elements(&phar->manifest)) {
     297             :                         /* this is a new phar that has perhaps had an alias/metadata set, but has never
     298             :                         been flushed */
     299          33 :                         if (zend_hash_str_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
     300           0 :                                 phar_destroy_phar_data(phar TSRMLS_CC);
     301             :                         }
     302          33 :                         return 1;
     303             :                 }
     304             :         }
     305        8553 :         return 0;
     306             : }
     307             : /* }}}*/
     308             : 
     309             : /**
     310             :  * Destroy phar's in shutdown, here we don't care about aliases
     311             :  */
     312         494 : static void destroy_phar_data_only(zval *zv) /* {{{ */
     313             : {
     314         494 :         phar_archive_data *phar_data = (phar_archive_data *) Z_PTR_P(zv);
     315             :         TSRMLS_FETCH();
     316             : 
     317         494 :         if (EG(exception) || --phar_data->refcount < 0) {
     318         487 :                 phar_destroy_phar_data(phar_data TSRMLS_CC);
     319             :         }
     320         494 : }
     321             : /* }}}*/
     322             : 
     323             : /**
     324             :  * Delete aliases to phar's that got kicked out of the global table
     325             :  */
     326          19 : static int phar_unalias_apply(zval *zv, void *argument TSRMLS_DC) /* {{{ */
     327             : {
     328          19 :         return Z_PTR_P(zv) == argument ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_KEEP;
     329             : }
     330             : /* }}} */
     331             : 
     332             : /**
     333             :  * Delete aliases to phar's that got kicked out of the global table
     334             :  */
     335        5061 : static int phar_tmpclose_apply(zval *zv TSRMLS_DC) /* {{{ */
     336             : {
     337        5061 :         phar_entry_info *entry = (phar_entry_info *) Z_PTR_P(zv);
     338             : 
     339        5061 :         if (entry->fp_type != PHAR_TMP) {
     340        5044 :                 return ZEND_HASH_APPLY_KEEP;
     341             :         }
     342             : 
     343          17 :         if (entry->fp && !entry->fp_refcount) {
     344           7 :                 php_stream_close(entry->fp);
     345           7 :                 entry->fp = NULL;
     346             :         }
     347             : 
     348          17 :         return ZEND_HASH_APPLY_KEEP;
     349             : }
     350             : /* }}} */
     351             : 
     352             : /**
     353             :  * Filename map destructor
     354             :  */
     355         546 : static void destroy_phar_data(zval *zv) /* {{{ */
     356             : {
     357         546 :         phar_archive_data *phar_data = (phar_archive_data *)Z_PTR_P(zv);
     358             :         TSRMLS_FETCH();
     359             : 
     360         546 :         if (PHAR_GLOBALS->request_ends) {
     361             :                 /* first, iterate over the manifest and close all PHAR_TMP entry fp handles,
     362             :                 this prevents unnecessary unfreed stream resources */
     363         494 :                 zend_hash_apply(&(phar_data->manifest), phar_tmpclose_apply TSRMLS_CC);
     364         494 :                 destroy_phar_data_only(zv);
     365         494 :                 return;
     366             :         }
     367             : 
     368          52 :         zend_hash_apply_with_argument(&(PHAR_GLOBALS->phar_alias_map), phar_unalias_apply, phar_data TSRMLS_CC);
     369             : 
     370          52 :         if (--phar_data->refcount < 0) {
     371          52 :                 phar_destroy_phar_data(phar_data TSRMLS_CC);
     372             :         }
     373             : }
     374             : /* }}}*/
     375             : 
     376             : /**
     377             :  * destructor for the manifest hash, frees each file's entry
     378             :  */
     379        5296 : void destroy_phar_manifest_entry_int(phar_entry_info *entry) /* {{{ */
     380             : {
     381             :         TSRMLS_FETCH();
     382             : 
     383        5296 :         if (entry->cfp) {
     384           0 :                 php_stream_close(entry->cfp);
     385           0 :                 entry->cfp = 0;
     386             :         }
     387             : 
     388        5296 :         if (entry->fp) {
     389          14 :                 php_stream_close(entry->fp);
     390          14 :                 entry->fp = 0;
     391             :         }
     392             : 
     393       10592 :         if (Z_TYPE(entry->metadata) != IS_UNDEF) {
     394          55 :                 if (entry->is_persistent) {
     395           3 :                         if (entry->metadata_len) {
     396             :                                 /* for zip comments that are strings */
     397           3 :                                 free(Z_PTR(entry->metadata));
     398             :                         } else {
     399           0 :                                 zval_internal_ptr_dtor(&entry->metadata);
     400             :                         }
     401             :                 } else {
     402          52 :                         zval_ptr_dtor(&entry->metadata);
     403             :                 }
     404          55 :                 entry->metadata_len = 0;
     405          55 :                 ZVAL_UNDEF(&entry->metadata);
     406             :         }
     407             : 
     408        5296 :         if (entry->metadata_str.s) {
     409          29 :                 smart_str_free(&entry->metadata_str);
     410          29 :                 entry->metadata_str.s = NULL;
     411             :         }
     412             : 
     413        5296 :         pefree(entry->filename, entry->is_persistent);
     414             : 
     415        5296 :         if (entry->link) {
     416          10 :                 pefree(entry->link, entry->is_persistent);
     417          10 :                 entry->link = 0;
     418             :         }
     419             : 
     420        5296 :         if (entry->tmp) {
     421          17 :                 pefree(entry->tmp, entry->is_persistent);
     422          17 :                 entry->tmp = 0;
     423             :         }
     424        5296 : }
     425             : /* }}} */
     426             : 
     427        5294 : void destroy_phar_manifest_entry(zval *zv) /* {{{ */
     428             : {
     429        5294 :         phar_entry_info *entry = Z_PTR_P(zv);
     430        5294 :         destroy_phar_manifest_entry_int(entry);
     431        5294 :         pefree(entry, entry->is_persistent);
     432        5294 : }
     433             : /* }}} */
     434             : 
     435        8161 : int phar_entry_delref(phar_entry_data *idata TSRMLS_DC) /* {{{ */
     436             : {
     437        8161 :         int ret = 0;
     438             : 
     439        8161 :         if (idata->internal_file && !idata->internal_file->is_persistent) {
     440        8161 :                 if (--idata->internal_file->fp_refcount < 0) {
     441           0 :                         idata->internal_file->fp_refcount = 0;
     442             :                 }
     443             : 
     444        8161 :                 if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
     445          50 :                         php_stream_close(idata->fp);
     446             :                 }
     447             :                 /* if phar_get_or_create_entry_data returns a sub-directory, we have to free it */
     448        8161 :                 if (idata->internal_file->is_temp_dir) {
     449           2 :                         destroy_phar_manifest_entry_int(idata->internal_file);
     450           2 :                         efree(idata->internal_file);
     451             :                 }
     452             :         }
     453             : 
     454        8161 :         phar_archive_delref(idata->phar TSRMLS_CC);
     455        8161 :         efree(idata);
     456        8161 :         return ret;
     457             : }
     458             : /* }}} */
     459             : 
     460             : /**
     461             :  * Removes an entry, either by actually removing it or by marking it.
     462             :  */
     463           9 : void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC) /* {{{ */
     464             : {
     465             :         phar_archive_data *phar;
     466             : 
     467           9 :         phar = idata->phar;
     468             : 
     469           9 :         if (idata->internal_file->fp_refcount < 2) {
     470           9 :                 if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
     471           0 :                         php_stream_close(idata->fp);
     472             :                 }
     473           9 :                 zend_hash_str_del(&idata->phar->manifest, idata->internal_file->filename, idata->internal_file->filename_len);
     474           9 :                 idata->phar->refcount--;
     475           9 :                 efree(idata);
     476             :         } else {
     477           0 :                 idata->internal_file->is_deleted = 1;
     478           0 :                 phar_entry_delref(idata TSRMLS_CC);
     479             :         }
     480             : 
     481           9 :         if (!phar->donotflush) {
     482           9 :                 phar_flush(phar, 0, 0, 0, error TSRMLS_CC);
     483             :         }
     484           9 : }
     485             : /* }}} */
     486             : 
     487             : #define MAPPHAR_ALLOC_FAIL(msg) \
     488             :         if (fp) {\
     489             :                 php_stream_close(fp);\
     490             :         }\
     491             :         if (error) {\
     492             :                 spprintf(error, 0, msg, fname);\
     493             :         }\
     494             :         return FAILURE;
     495             : 
     496             : #define MAPPHAR_FAIL(msg) \
     497             :         efree(savebuf);\
     498             :         if (mydata) {\
     499             :                 phar_destroy_phar_data(mydata TSRMLS_CC);\
     500             :         }\
     501             :         if (signature) {\
     502             :                 pefree(signature, PHAR_G(persist));\
     503             :         }\
     504             :         MAPPHAR_ALLOC_FAIL(msg)
     505             : 
     506             : #ifdef WORDS_BIGENDIAN
     507             : # define PHAR_GET_32(buffer, var) \
     508             :         var = ((((unsigned char*)(buffer))[3]) << 24) \
     509             :                 | ((((unsigned char*)(buffer))[2]) << 16) \
     510             :                 | ((((unsigned char*)(buffer))[1]) <<  8) \
     511             :                 | (((unsigned char*)(buffer))[0]); \
     512             :         (buffer) += 4
     513             : # define PHAR_GET_16(buffer, var) \
     514             :         var = ((((unsigned char*)(buffer))[1]) <<  8) \
     515             :                 | (((unsigned char*)(buffer))[0]); \
     516             :         (buffer) += 2
     517             : #else
     518             : # define PHAR_GET_32(buffer, var) \
     519             :         memcpy(&var, buffer, sizeof(var)); \
     520             :         buffer += 4
     521             : # define PHAR_GET_16(buffer, var) \
     522             :         var = *(php_uint16*)(buffer); \
     523             :         buffer += 2
     524             : #endif
     525             : #define PHAR_ZIP_16(var) ((php_uint16)((((php_uint16)var[0]) & 0xff) | \
     526             :         (((php_uint16)var[1]) & 0xff) << 8))
     527             : #define PHAR_ZIP_32(var) ((php_uint32)((((php_uint32)var[0]) & 0xff) | \
     528             :         (((php_uint32)var[1]) & 0xff) << 8 | \
     529             :         (((php_uint32)var[2]) & 0xff) << 16 | \
     530             :         (((php_uint32)var[3]) & 0xff) << 24))
     531             : 
     532             : /**
     533             :  * Open an already loaded phar
     534             :  */
     535        2881 : int phar_open_parsed_phar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
     536             : {
     537             :         phar_archive_data *phar;
     538             : #ifdef PHP_WIN32
     539             :         char *unixfname;
     540             : #endif
     541             : 
     542        2881 :         if (error) {
     543        2447 :                 *error = NULL;
     544             :         }
     545             : #ifdef PHP_WIN32
     546             :         unixfname = estrndup(fname, fname_len);
     547             :         phar_unixify_path_separators(unixfname, fname_len);
     548             : 
     549             :         if (SUCCESS == phar_get_archive(&phar, unixfname, fname_len, alias, alias_len, error TSRMLS_CC)
     550             :                 && ((alias && fname_len == phar->fname_len
     551             :                 && !strncmp(unixfname, phar->fname, fname_len)) || !alias)
     552             :         ) {
     553             :                 phar_entry_info *stub;
     554             :                 efree(unixfname);
     555             : #else
     556        2965 :         if (SUCCESS == phar_get_archive(&phar, fname, fname_len, alias, alias_len, error TSRMLS_CC)
     557        2923 :                 && ((alias && fname_len == phar->fname_len
     558          84 :                 && !strncmp(fname, phar->fname, fname_len)) || !alias)
     559             :         ) {
     560             :                 phar_entry_info *stub;
     561             : #endif
     562             :                 /* logic above is as follows:
     563             :                    If an explicit alias was requested, ensure the filename passed in
     564             :                    matches the phar's filename.
     565             :                    If no alias was passed in, then it can match either and be valid
     566             :                  */
     567             : 
     568        2121 :                 if (!is_data) {
     569             :                         /* prevent any ".phar" without a stub getting through */
     570        1717 :                         if (!phar->halt_offset && !phar->is_brandnew && (phar->is_tar || phar->is_zip)) {
     571         746 :                                 if (PHAR_G(readonly) && NULL == (stub = zend_hash_str_find_ptr(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1))) {
     572           2 :                                         if (error) {
     573           2 :                                                 spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
     574             :                                         }
     575           2 :                                         return FAILURE;
     576             :                                 }
     577             :                         }
     578             :                 }
     579             : 
     580        2119 :                 if (pphar) {
     581         673 :                         *pphar = phar;
     582             :                 }
     583             : 
     584        2119 :                 return SUCCESS;
     585             :         } else {
     586             : #ifdef PHP_WIN32
     587             :                 efree(unixfname);
     588             : #endif
     589         760 :                 if (pphar) {
     590         633 :                         *pphar = NULL;
     591             :                 }
     592             : 
     593         760 :                 if (phar && error && !(options & REPORT_ERRORS)) {
     594           0 :                         efree(error);
     595             :                 }
     596             : 
     597         760 :                 return FAILURE;
     598             :         }
     599             : }
     600             : /* }}}*/
     601             : 
     602             : /**
     603             :  * Parse out metadata from the manifest for a single file
     604             :  *
     605             :  * Meta-data is in this format:
     606             :  * [len32][data...]
     607             :  * 
     608             :  * data is the serialized zval
     609             :  */
     610        1124 : int phar_parse_metadata(char **buffer, zval *metadata, int zip_metadata_len TSRMLS_DC) /* {{{ */
     611             : {
     612             :         const unsigned char *p;
     613             :         php_uint32 buf_len;
     614             :         php_unserialize_data_t var_hash;
     615             : 
     616        1124 :         if (!zip_metadata_len) {
     617        1091 :                 PHAR_GET_32(*buffer, buf_len);
     618             :         } else {
     619          33 :                 buf_len = zip_metadata_len;
     620             :         }
     621             : 
     622        1124 :         if (buf_len) {
     623         110 :                 ZVAL_NULL(metadata);
     624         110 :                 p = (const unsigned char*) *buffer;
     625         110 :                 PHP_VAR_UNSERIALIZE_INIT(var_hash);
     626             : 
     627         110 :                 if (!php_var_unserialize(metadata, &p, p + buf_len, &var_hash TSRMLS_CC)) {
     628          63 :                         PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
     629          63 :                         zval_ptr_dtor(metadata);
     630          63 :                         ZVAL_UNDEF(metadata);
     631          63 :                         return FAILURE;
     632             :                 }
     633             : 
     634          47 :                 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
     635             : 
     636          47 :                 if (PHAR_G(persist)) {
     637             :                         /* lazy init metadata */
     638           6 :                         zval_ptr_dtor(metadata);
     639          12 :                         Z_PTR_P(metadata) = pemalloc(buf_len, 1);
     640           6 :                         memcpy(Z_PTR_P(metadata), *buffer, buf_len);
     641           6 :                         *buffer += buf_len;
     642           6 :                         return SUCCESS;
     643             :                 }
     644             :         } else {
     645        1014 :                 ZVAL_UNDEF(metadata);
     646             :         }
     647             : 
     648        1055 :         if (!zip_metadata_len) {
     649        1034 :                 *buffer += buf_len;
     650             :         }
     651             : 
     652        1055 :         return SUCCESS;
     653             : }
     654             : /* }}}*/
     655             : 
     656             : /**
     657             :  * Does not check for a previously opened phar in the cache.
     658             :  *
     659             :  * Parse a new one and add it to the cache, returning either SUCCESS or
     660             :  * FAILURE, and setting pphar to the pointer to the manifest entry
     661             :  * 
     662             :  * This is used by phar_open_from_filename to process the manifest, but can be called
     663             :  * directly.
     664             :  */
     665         285 : static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, zend_long halt_offset, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */
     666             : {
     667             :         char b32[4], *buffer, *endbuffer, *savebuf;
     668         285 :         phar_archive_data *mydata = NULL;
     669             :         phar_entry_info entry;
     670             :         php_uint32 manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags;
     671             :         php_uint16 manifest_ver;
     672             :         zend_long offset;
     673         285 :         int sig_len, register_alias = 0, temp_alias = 0;
     674         285 :         char *signature = NULL;
     675             : 
     676         285 :         if (pphar) {
     677         173 :                 *pphar = NULL;
     678             :         }
     679             : 
     680         285 :         if (error) {
     681         182 :                 *error = NULL;
     682             :         }
     683             : 
     684             :         /* check for ?>\n and increment accordingly */
     685         285 :         if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
     686           0 :                 MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
     687             :         }
     688             : 
     689         285 :         buffer = b32;
     690             : 
     691         285 :         if (3 != php_stream_read(fp, buffer, 3)) {
     692           3 :                 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
     693             :         }
     694             : 
     695         282 :         if ((*buffer == ' ' || *buffer == '\n') && *(buffer + 1) == '?' && *(buffer + 2) == '>') {
     696             :                 int nextchar;
     697         278 :                 halt_offset += 3;
     698         278 :                 if (EOF == (nextchar = php_stream_getc(fp))) {
     699           0 :                         MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
     700             :                 }
     701             : 
     702         278 :                 if ((char) nextchar == '\r') {
     703             :                         /* if we have an \r we require an \n as well */
     704         156 :                         if (EOF == (nextchar = php_stream_getc(fp)) || (char)nextchar != '\n') {
     705           0 :                                 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
     706             :                         }
     707         156 :                         ++halt_offset;
     708             :                 }
     709             : 
     710         278 :                 if ((char) nextchar == '\n') {
     711         159 :                         ++halt_offset;
     712             :                 }
     713             :         }
     714             : 
     715             :         /* make sure we are at the right location to read the manifest */
     716         282 :         if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
     717           0 :                 MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
     718             :         }
     719             : 
     720             :         /* read in manifest */
     721         282 :         buffer = b32;
     722             : 
     723         282 :         if (4 != php_stream_read(fp, buffer, 4)) {
     724           4 :                 MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at manifest length)")
     725             :         }
     726             : 
     727         278 :         PHAR_GET_32(buffer, manifest_len);
     728             : 
     729         278 :         if (manifest_len > 1048576 * 100) {
     730             :                 /* prevent serious memory issues by limiting manifest to at most 100 MB in length */
     731           1 :                 MAPPHAR_ALLOC_FAIL("manifest cannot be larger than 100 MB in phar \"%s\"")
     732             :         }
     733             : 
     734         277 :         buffer = (char *)emalloc(manifest_len);
     735         277 :         savebuf = buffer;
     736         277 :         endbuffer = buffer + manifest_len;
     737             : 
     738         277 :         if (manifest_len < 10 || manifest_len != php_stream_read(fp, buffer, manifest_len)) {
     739           2 :                 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
     740             :         }
     741             : 
     742             :         /* extract the number of entries */
     743         275 :         PHAR_GET_32(buffer, manifest_count);
     744             : 
     745         275 :         if (manifest_count == 0) {
     746           0 :                 MAPPHAR_FAIL("in phar \"%s\", manifest claims to have zero entries.  Phars must have at least 1 entry");
     747             :         }
     748             : 
     749             :         /* extract API version, lowest nibble currently unused */
     750         550 :         manifest_ver = (((unsigned char)buffer[0]) << 8)
     751         275 :                                  + ((unsigned char)buffer[1]);
     752         275 :         buffer += 2;
     753             : 
     754         275 :         if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) {
     755           0 :                 efree(savebuf);
     756           0 :                 php_stream_close(fp);
     757           0 :                 if (error) {
     758           0 :                         spprintf(error, 0, "phar \"%s\" is API version %1.u.%1.u.%1.u, and cannot be processed", fname, manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0x0F);
     759             :                 }
     760           0 :                 return FAILURE;
     761             :         }
     762             : 
     763         275 :         PHAR_GET_32(buffer, manifest_flags);
     764             : 
     765         275 :         manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
     766         275 :         manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK;
     767             :         /* remember whether this entire phar was compressed with gz/bzip2 */
     768         275 :         manifest_flags |= compression;
     769             : 
     770             :         /* The lowest nibble contains the phar wide flags. The compression flags can */
     771             :         /* be ignored on reading because it is being generated anyways. */
     772         275 :         if (manifest_flags & PHAR_HDR_SIGNATURE) {
     773         179 :                 char sig_buf[8], *sig_ptr = sig_buf;
     774             :                 zend_off_t read_len;
     775             :                 size_t end_of_phar;
     776             : 
     777         716 :                 if (-1 == php_stream_seek(fp, -8, SEEK_END)
     778         358 :                 || (read_len = php_stream_tell(fp)) < 20
     779             :                 || 8 != php_stream_read(fp, sig_buf, 8)
     780         358 :                 || memcmp(sig_buf+4, "GBMB", 4)) {
     781           0 :                         efree(savebuf);
     782           0 :                         php_stream_close(fp);
     783           0 :                         if (error) {
     784           0 :                                 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
     785             :                         }
     786           0 :                         return FAILURE;
     787             :                 }
     788             : 
     789         179 :                 PHAR_GET_32(sig_ptr, sig_flags);
     790             : 
     791         179 :                 switch(sig_flags) {
     792             :                         case PHAR_SIG_OPENSSL: {
     793             :                                 php_uint32 signature_len;
     794             :                                 char *sig;
     795             :                                 zend_off_t whence;
     796             : 
     797             :                                 /* we store the signature followed by the signature length */
     798           2 :                                 if (-1 == php_stream_seek(fp, -12, SEEK_CUR)
     799           2 :                                 || 4 != php_stream_read(fp, sig_buf, 4)) {
     800           0 :                                         efree(savebuf);
     801           0 :                                         php_stream_close(fp);
     802           0 :                                         if (error) {
     803           0 :                                                 spprintf(error, 0, "phar \"%s\" openssl signature length could not be read", fname);
     804             :                                         }
     805           0 :                                         return FAILURE;
     806             :                                 }
     807             : 
     808           1 :                                 sig_ptr = sig_buf;
     809           1 :                                 PHAR_GET_32(sig_ptr, signature_len);
     810           1 :                                 sig = (char *) emalloc(signature_len);
     811           1 :                                 whence = signature_len + 4;
     812           1 :                                 whence = -whence;
     813             : 
     814           3 :                                 if (-1 == php_stream_seek(fp, whence, SEEK_CUR)
     815           2 :                                 || !(end_of_phar = php_stream_tell(fp))
     816           1 :                                 || signature_len != php_stream_read(fp, sig, signature_len)) {
     817           0 :                                         efree(savebuf);
     818           0 :                                         efree(sig);
     819           0 :                                         php_stream_close(fp);
     820           0 :                                         if (error) {
     821           0 :                                                 spprintf(error, 0, "phar \"%s\" openssl signature could not be read", fname);
     822             :                                         }
     823           0 :                                         return FAILURE;
     824             :                                 }
     825             : 
     826           1 :                                 if (FAILURE == phar_verify_signature(fp, end_of_phar, PHAR_SIG_OPENSSL, sig, signature_len, fname, &signature, &sig_len, error TSRMLS_CC)) {
     827           0 :                                         efree(savebuf);
     828           0 :                                         efree(sig);
     829           0 :                                         php_stream_close(fp);
     830           0 :                                         if (error) {
     831           0 :                                                 char *save = *error;
     832           0 :                                                 spprintf(error, 0, "phar \"%s\" openssl signature could not be verified: %s", fname, *error);
     833           0 :                                                 efree(save);
     834             :                                         }
     835           0 :                                         return FAILURE;
     836             :                                 }
     837           1 :                                 efree(sig);
     838             :                         }
     839           1 :                         break;
     840             : #if PHAR_HASH_OK
     841             :                         case PHAR_SIG_SHA512: {
     842             :                                 unsigned char digest[64];
     843             : 
     844           1 :                                 php_stream_seek(fp, -(8 + 64), SEEK_END);
     845           1 :                                 read_len = php_stream_tell(fp);
     846             : 
     847           1 :                                 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
     848           0 :                                         efree(savebuf);
     849           0 :                                         php_stream_close(fp);
     850           0 :                                         if (error) {
     851           0 :                                                 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
     852             :                                         }
     853           0 :                                         return FAILURE;
     854             :                                 }
     855             : 
     856           1 :                                 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA512, (char *)digest, 64, fname, &signature, &sig_len, error TSRMLS_CC)) {
     857           0 :                                         efree(savebuf);
     858           0 :                                         php_stream_close(fp);
     859           0 :                                         if (error) {
     860           0 :                                                 char *save = *error;
     861           0 :                                                 spprintf(error, 0, "phar \"%s\" SHA512 signature could not be verified: %s", fname, *error);
     862           0 :                                                 efree(save);
     863             :                                         }
     864           0 :                                         return FAILURE;
     865             :                                 }
     866           1 :                                 break;
     867             :                         }
     868             :                         case PHAR_SIG_SHA256: {
     869             :                                 unsigned char digest[32];
     870             : 
     871           1 :                                 php_stream_seek(fp, -(8 + 32), SEEK_END);
     872           1 :                                 read_len = php_stream_tell(fp);
     873             : 
     874           1 :                                 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
     875           0 :                                         efree(savebuf);
     876           0 :                                         php_stream_close(fp);
     877           0 :                                         if (error) {
     878           0 :                                                 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
     879             :                                         }
     880           0 :                                         return FAILURE;
     881             :                                 }
     882             : 
     883           1 :                                 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA256, (char *)digest, 32, fname, &signature, &sig_len, error TSRMLS_CC)) {
     884           0 :                                         efree(savebuf);
     885           0 :                                         php_stream_close(fp);
     886           0 :                                         if (error) {
     887           0 :                                                 char *save = *error;
     888           0 :                                                 spprintf(error, 0, "phar \"%s\" SHA256 signature could not be verified: %s", fname, *error);
     889           0 :                                                 efree(save);
     890             :                                         }
     891           0 :                                         return FAILURE;
     892             :                                 }
     893           1 :                                 break;
     894             :                         }
     895             : #else
     896             :                         case PHAR_SIG_SHA512:
     897             :                         case PHAR_SIG_SHA256:
     898             :                                 efree(savebuf);
     899             :                                 php_stream_close(fp);
     900             : 
     901             :                                 if (error) {
     902             :                                         spprintf(error, 0, "phar \"%s\" has a unsupported signature", fname);
     903             :                                 }
     904             :                                 return FAILURE;
     905             : #endif
     906             :                         case PHAR_SIG_SHA1: {
     907             :                                 unsigned char digest[20];
     908             : 
     909         175 :                                 php_stream_seek(fp, -(8 + 20), SEEK_END);
     910         175 :                                 read_len = php_stream_tell(fp);
     911             : 
     912         175 :                                 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
     913           0 :                                         efree(savebuf);
     914           0 :                                         php_stream_close(fp);
     915           0 :                                         if (error) {
     916           0 :                                                 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
     917             :                                         }
     918           0 :                                         return FAILURE;
     919             :                                 }
     920             : 
     921         175 :                                 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA1, (char *)digest, 20, fname, &signature, &sig_len, error TSRMLS_CC)) {
     922           0 :                                         efree(savebuf);
     923           0 :                                         php_stream_close(fp);
     924           0 :                                         if (error) {
     925           0 :                                                 char *save = *error;
     926           0 :                                                 spprintf(error, 0, "phar \"%s\" SHA1 signature could not be verified: %s", fname, *error);
     927           0 :                                                 efree(save);
     928             :                                         }
     929           0 :                                         return FAILURE;
     930             :                                 }
     931         175 :                                 break;
     932             :                         }
     933             :                         case PHAR_SIG_MD5: {
     934             :                                 unsigned char digest[16];
     935             : 
     936           1 :                                 php_stream_seek(fp, -(8 + 16), SEEK_END);
     937           1 :                                 read_len = php_stream_tell(fp);
     938             : 
     939           1 :                                 if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
     940           0 :                                         efree(savebuf);
     941           0 :                                         php_stream_close(fp);
     942           0 :                                         if (error) {
     943           0 :                                                 spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
     944             :                                         }
     945           0 :                                         return FAILURE;
     946             :                                 }
     947             : 
     948           1 :                                 if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_MD5, (char *)digest, 16, fname, &signature, &sig_len, error TSRMLS_CC)) {
     949           0 :                                         efree(savebuf);
     950           0 :                                         php_stream_close(fp);
     951           0 :                                         if (error) {
     952           0 :                                                 char *save = *error;
     953           0 :                                                 spprintf(error, 0, "phar \"%s\" MD5 signature could not be verified: %s", fname, *error);
     954           0 :                                                 efree(save);
     955             :                                         }
     956           0 :                                         return FAILURE;
     957             :                                 }
     958           1 :                                 break;
     959             :                         }
     960             :                         default:
     961           0 :                                 efree(savebuf);
     962           0 :                                 php_stream_close(fp);
     963             : 
     964           0 :                                 if (error) {
     965           0 :                                         spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname);
     966             :                                 }
     967           0 :                                 return FAILURE;
     968             :                 }
     969          96 :         } else if (PHAR_G(require_hash)) {
     970           1 :                 efree(savebuf);
     971           1 :                 php_stream_close(fp);
     972             : 
     973           1 :                 if (error) {
     974           1 :                         spprintf(error, 0, "phar \"%s\" does not have a signature", fname);
     975             :                 }
     976           1 :                 return FAILURE;
     977             :         } else {
     978          95 :                 sig_flags = 0;
     979          95 :                 sig_len = 0;
     980             :         }
     981             : 
     982             :         /* extract alias */
     983         274 :         PHAR_GET_32(buffer, tmp_len);
     984             : 
     985         274 :         if (buffer + tmp_len > endbuffer) {
     986           0 :                 MAPPHAR_FAIL("internal corruption of phar \"%s\" (buffer overrun)");
     987             :         }
     988             : 
     989         274 :         if (manifest_len < 10 + tmp_len) {
     990           0 :                 MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
     991             :         }
     992             : 
     993             :         /* tmp_len = 0 says alias length is 0, which means the alias is not stored in the phar */
     994         274 :         if (tmp_len) {
     995             :                 /* if the alias is stored we enforce it (implicit overrides explicit) */
     996         101 :                 if (alias && alias_len && (alias_len != (int)tmp_len || strncmp(alias, buffer, tmp_len)))
     997             :                 {
     998           0 :                         buffer[tmp_len] = '\0';
     999           0 :                         php_stream_close(fp);
    1000             : 
    1001           0 :                         if (signature) {
    1002           0 :                                 efree(signature);
    1003             :                         }
    1004             : 
    1005           0 :                         if (error) {
    1006           0 :                                 spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%s\" under different alias \"%s\"", fname, buffer, alias);
    1007             :                         }
    1008             : 
    1009           0 :                         efree(savebuf);
    1010           0 :                         return FAILURE;
    1011             :                 }
    1012             : 
    1013         101 :                 alias_len = tmp_len;
    1014         101 :                 alias = buffer;
    1015         101 :                 buffer += tmp_len;
    1016         101 :                 register_alias = 1;
    1017         297 :         } else if (!alias_len || !alias) {
    1018             :                 /* if we neither have an explicit nor an implicit alias, we use the filename */
    1019         124 :                 alias = NULL;
    1020         124 :                 alias_len = 0;
    1021         124 :                 register_alias = 0;
    1022          49 :         } else if (alias_len) {
    1023          49 :                 register_alias = 1;
    1024          49 :                 temp_alias = 1;
    1025             :         }
    1026             : 
    1027             :         /* we have 5 32-bit items plus 1 byte at least */
    1028         274 :         if (manifest_count > ((manifest_len - 10 - tmp_len) / (5 * 4 + 1))) {
    1029             :                 /* prevent serious memory issues */
    1030           4 :                 MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)")
    1031             :         }
    1032             : 
    1033         330 :         mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
    1034         270 :         mydata->is_persistent = PHAR_G(persist);
    1035             : 
    1036             :         /* check whether we have meta data, zero check works regardless of byte order */
    1037         270 :         if (mydata->is_persistent) {
    1038          60 :                 PHAR_GET_32(buffer, mydata->metadata_len);
    1039          60 :                 if (phar_parse_metadata(&buffer, &mydata->metadata, mydata->metadata_len TSRMLS_CC) == FAILURE) {
    1040          57 :                         MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
    1041             :                 }
    1042             :         } else {
    1043         210 :                 if (phar_parse_metadata(&buffer, &mydata->metadata, 0 TSRMLS_CC) == FAILURE) {
    1044           0 :                         MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
    1045             :                 }
    1046             :         }
    1047             : 
    1048             :         /* set up our manifest */
    1049         213 :         zend_hash_init(&mydata->manifest, manifest_count,
    1050             :                 zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)mydata->is_persistent);
    1051         213 :         zend_hash_init(&mydata->mounted_dirs, 5,
    1052             :                 zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
    1053         213 :         zend_hash_init(&mydata->virtual_dirs, manifest_count * 2,
    1054             :                 zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
    1055         213 :         mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
    1056             : #ifdef PHP_WIN32
    1057             :         phar_unixify_path_separators(mydata->fname, fname_len);
    1058             : #endif
    1059         213 :         mydata->fname_len = fname_len;
    1060         213 :         offset = halt_offset + manifest_len + 4;
    1061         213 :         memset(&entry, 0, sizeof(phar_entry_info));
    1062         213 :         entry.phar = mydata;
    1063         213 :         entry.fp_type = PHAR_FP;
    1064         213 :         entry.is_persistent = mydata->is_persistent;
    1065             : 
    1066        1038 :         for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
    1067         827 :                 if (buffer + 4 > endbuffer) {
    1068           0 :                         MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
    1069             :                 }
    1070             : 
    1071         827 :                 PHAR_GET_32(buffer, entry.filename_len);
    1072             : 
    1073         827 :                 if (entry.filename_len == 0) {
    1074           0 :                         MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\"");
    1075             :                 }
    1076             : 
    1077         827 :                 if (entry.is_persistent) {
    1078           4 :                         entry.manifest_pos = manifest_index;
    1079             :                 }
    1080             : 
    1081         827 :                 if (buffer + entry.filename_len + 20 > endbuffer) {
    1082           0 :                         MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
    1083             :                 }
    1084             : 
    1085         834 :                 if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') {
    1086           7 :                         entry.is_dir = 1;
    1087             :                 } else {
    1088         820 :                         entry.is_dir = 0;
    1089             :                 }
    1090             : 
    1091         827 :                 phar_add_virtual_dirs(mydata, buffer, entry.filename_len TSRMLS_CC);
    1092         827 :                 entry.filename = pestrndup(buffer, entry.filename_len, entry.is_persistent);
    1093         827 :                 buffer += entry.filename_len;
    1094         827 :                 PHAR_GET_32(buffer, entry.uncompressed_filesize);
    1095         827 :                 PHAR_GET_32(buffer, entry.timestamp);
    1096             : 
    1097         827 :                 if (offset == halt_offset + (int)manifest_len + 4) {
    1098         326 :                         mydata->min_timestamp = entry.timestamp;
    1099         326 :                         mydata->max_timestamp = entry.timestamp;
    1100             :                 } else {
    1101         501 :                         if (mydata->min_timestamp > entry.timestamp) {
    1102           0 :                                 mydata->min_timestamp = entry.timestamp;
    1103         501 :                         } else if (mydata->max_timestamp < entry.timestamp) {
    1104           0 :                                 mydata->max_timestamp = entry.timestamp;
    1105             :                         }
    1106             :                 }
    1107             : 
    1108         827 :                 PHAR_GET_32(buffer, entry.compressed_filesize);
    1109         827 :                 PHAR_GET_32(buffer, entry.crc32);
    1110         827 :                 PHAR_GET_32(buffer, entry.flags);
    1111             : 
    1112         827 :                 if (entry.is_dir) {
    1113           7 :                         entry.filename_len--;
    1114           7 :                         entry.flags |= PHAR_ENT_PERM_DEF_DIR;
    1115             :                 }
    1116             : 
    1117         827 :                 if (entry.is_persistent) {
    1118           4 :                         PHAR_GET_32(buffer, entry.metadata_len);
    1119           4 :                         if (!entry.metadata_len) buffer -= 4;
    1120           4 :                         if (phar_parse_metadata(&buffer, &entry.metadata, entry.metadata_len TSRMLS_CC) == FAILURE) {
    1121           0 :                                 pefree(entry.filename, entry.is_persistent);
    1122           0 :                                 MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
    1123             :                         }
    1124             :                 } else {
    1125         823 :                         if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) {
    1126           0 :                                 pefree(entry.filename, entry.is_persistent);
    1127           0 :                                 MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
    1128             :                         }
    1129             :                 }
    1130             : 
    1131         827 :                 entry.offset = entry.offset_abs = offset;
    1132         827 :                 offset += entry.compressed_filesize;
    1133             : 
    1134         827 :                 switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) {
    1135             :                         case PHAR_ENT_COMPRESSED_GZ:
    1136           9 :                                 if (!PHAR_G(has_zlib)) {
    1137           0 :                                         if (Z_TYPE(entry.metadata) != IS_UNDEF) {
    1138           0 :                                                 if (entry.is_persistent) {
    1139           0 :                                                         free(Z_PTR(entry.metadata));
    1140             :                                                 } else {
    1141           0 :                                                         zval_ptr_dtor(&entry.metadata);
    1142             :                                                 }
    1143             :                                         }
    1144           0 :                                         pefree(entry.filename, entry.is_persistent);
    1145           0 :                                         MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\"");
    1146             :                                 }
    1147           9 :                                 break;
    1148             :                         case PHAR_ENT_COMPRESSED_BZ2:
    1149           1 :                                 if (!PHAR_G(has_bz2)) {
    1150           0 :                                         if (Z_TYPE(entry.metadata) != IS_UNDEF) {
    1151           0 :                                                 if (entry.is_persistent) {
    1152           0 :                                                         free(Z_PTR(entry.metadata));
    1153             :                                                 } else {
    1154           0 :                                                         zval_ptr_dtor(&entry.metadata);
    1155             :                                                 }
    1156             :                                         }
    1157           0 :                                         pefree(entry.filename, entry.is_persistent);
    1158           0 :                                         MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\"");
    1159             :                                 }
    1160           1 :                                 break;
    1161             :                         default:
    1162         817 :                                 if (entry.uncompressed_filesize != entry.compressed_filesize) {
    1163           2 :                                         if (Z_TYPE(entry.metadata) != IS_UNDEF) {
    1164           0 :                                                 if (entry.is_persistent) {
    1165           0 :                                                         free(Z_PTR(entry.metadata));
    1166             :                                                 } else {
    1167           0 :                                                         zval_ptr_dtor(&entry.metadata);
    1168             :                                                 }
    1169             :                                         }
    1170           2 :                                         pefree(entry.filename, entry.is_persistent);
    1171           2 :                                         MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)");
    1172             :                                 }
    1173             :                                 break;
    1174             :                 }
    1175             : 
    1176         825 :                 manifest_flags |= (entry.flags & PHAR_ENT_COMPRESSION_MASK);
    1177             :                 /* if signature matched, no need to check CRC32 for each file */
    1178         825 :                 entry.is_crc_checked = (manifest_flags & PHAR_HDR_SIGNATURE ? 1 : 0);
    1179         825 :                 phar_set_inode(&entry TSRMLS_CC);
    1180         825 :                 zend_hash_str_add_mem(&mydata->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info));
    1181             :         }
    1182             : 
    1183         211 :         snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0xF);
    1184         211 :         mydata->internal_file_start = halt_offset + manifest_len + 4;
    1185         211 :         mydata->halt_offset = halt_offset;
    1186         211 :         mydata->flags = manifest_flags;
    1187         211 :         endbuffer = strrchr(mydata->fname, '/');
    1188             : 
    1189         211 :         if (endbuffer) {
    1190         211 :                 mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer);
    1191         211 :                 if (mydata->ext == endbuffer) {
    1192           0 :                         mydata->ext = memchr(endbuffer + 1, '.', (mydata->fname + fname_len) - endbuffer - 1);
    1193             :                 }
    1194         211 :                 if (mydata->ext) {
    1195         211 :                         mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext;
    1196             :                 }
    1197             :         }
    1198             : 
    1199         422 :         mydata->alias = alias ?
    1200         145 :                 pestrndup(alias, alias_len, mydata->is_persistent) :
    1201          66 :                 pestrndup(mydata->fname, fname_len, mydata->is_persistent);
    1202         211 :         mydata->alias_len = alias ? alias_len : fname_len;
    1203         211 :         mydata->sig_flags = sig_flags;
    1204         211 :         mydata->fp = fp;
    1205         211 :         mydata->sig_len = sig_len;
    1206         211 :         mydata->signature = signature;
    1207         211 :         phar_request_initialize(TSRMLS_C);
    1208             : 
    1209         211 :         if (register_alias) {
    1210             :                 phar_archive_data *fd_ptr;
    1211             : 
    1212         145 :                 mydata->is_temporary_alias = temp_alias;
    1213             : 
    1214         145 :                 if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
    1215           0 :                         signature = NULL;
    1216           0 :                         fp = NULL;
    1217           0 :                         MAPPHAR_FAIL("Cannot open archive \"%s\", invalid alias");
    1218             :                 }
    1219             : 
    1220         290 :                 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len))) {
    1221           5 :                         if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len TSRMLS_CC)) {
    1222           3 :                                 signature = NULL;
    1223           3 :                                 fp = NULL;
    1224           3 :                                 MAPPHAR_FAIL("Cannot open archive \"%s\", alias is already in use by existing archive");
    1225             :                         }
    1226             :                 }
    1227             : 
    1228         142 :                 zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, mydata);
    1229             :         } else {
    1230          66 :                 mydata->is_temporary_alias = 1;
    1231             :         }
    1232             : 
    1233         208 :         zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, mydata);
    1234         208 :         efree(savebuf);
    1235             : 
    1236         208 :         if (pphar) {
    1237         108 :                 *pphar = mydata;
    1238             :         }
    1239             : 
    1240         208 :         return SUCCESS;
    1241             : }
    1242             : /* }}} */
    1243             : 
    1244             : /**
    1245             :  * Create or open a phar for writing
    1246             :  */
    1247         605 : int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
    1248             : {
    1249             :         const char *ext_str, *z;
    1250             :         char *my_error;
    1251             :         int ext_len;
    1252         605 :         phar_archive_data **test, *unused = NULL;
    1253             : 
    1254         605 :         test = &unused;
    1255             : 
    1256         605 :         if (error) {
    1257         605 :                 *error = NULL;
    1258             :         }
    1259             : 
    1260             :         /* first try to open an existing file */
    1261         605 :         if (phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 0, 1 TSRMLS_CC) == SUCCESS) {
    1262         412 :                 goto check_file;
    1263             :         }
    1264             : 
    1265             :         /* next try to create a new file */
    1266         193 :         if (FAILURE == phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 1, 1 TSRMLS_CC)) {
    1267           7 :                 if (error) {
    1268           7 :                         if (ext_len == -2) {
    1269           2 :                                 spprintf(error, 0, "Cannot create a phar archive from a URL like \"%s\". Phar objects can only be created from local files", fname);
    1270             :                         } else {
    1271           5 :                                 spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised or the directory does not exist", fname);
    1272             :                         }
    1273             :                 }
    1274           7 :                 return FAILURE;
    1275             :         }
    1276             : check_file:
    1277         598 :         if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, test, &my_error TSRMLS_CC) == SUCCESS) {
    1278         250 :                 if (pphar) {
    1279         250 :                         *pphar = *test;
    1280             :                 }
    1281             : 
    1282         250 :                 if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) {
    1283           0 :                         if (error) {
    1284           0 :                                 spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
    1285             :                         }
    1286           0 :                         return FAILURE;
    1287             :                 }
    1288             : 
    1289         250 :                 if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) {
    1290             :                         phar_entry_info *stub;
    1291           0 :                         if (NULL == (stub = zend_hash_str_find_ptr(&((*test)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1))) {
    1292           0 :                                 spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
    1293           0 :                                 return FAILURE;
    1294             :                         }
    1295             :                 }
    1296             : 
    1297         250 :                 if (!PHAR_G(readonly) || (*test)->is_data) {
    1298         242 :                         (*test)->is_writeable = 1;
    1299             :                 }
    1300         250 :                 return SUCCESS;
    1301         348 :         } else if (my_error) {
    1302           7 :                 if (error) {
    1303           7 :                         *error = my_error;
    1304             :                 } else {
    1305           0 :                         efree(my_error);
    1306             :                 }
    1307           7 :                 return FAILURE;
    1308             :         }
    1309             : 
    1310         341 :         if (ext_len > 3 && (z = memchr(ext_str, 'z', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ip", 2)) {
    1311             :                 /* assume zip-based phar */
    1312          97 :                 return phar_open_or_create_zip(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
    1313             :         }
    1314             : 
    1315         244 :         if (ext_len > 3 && (z = memchr(ext_str, 't', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ar", 2)) {
    1316             :                 /* assume tar-based phar */
    1317          76 :                 return phar_open_or_create_tar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
    1318             :         }
    1319             : 
    1320         168 :         return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC);
    1321             : }
    1322             : /* }}} */
    1323             : 
    1324         341 : int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
    1325             : {
    1326             :         phar_archive_data *mydata;
    1327             :         php_stream *fp;
    1328         341 :         char *actual = NULL, *p;
    1329             : 
    1330         341 :         if (!pphar) {
    1331           0 :                 pphar = &mydata;
    1332             :         }
    1333             : #if PHP_API_VERSION < 20100412
    1334             :         if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
    1335             :                 return FAILURE;
    1336             :         }
    1337             : #endif
    1338         341 :         if (php_check_open_basedir(fname TSRMLS_CC)) {
    1339           0 :                 return FAILURE;
    1340             :         }
    1341             : 
    1342             :         /* first open readonly so it won't be created if not present */
    1343         341 :         fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, &actual);
    1344             : 
    1345         341 :         if (actual) {
    1346         163 :                 fname = actual;
    1347         163 :                 fname_len = strlen(actual);
    1348             :         }
    1349             : 
    1350         341 :         if (fp) {
    1351         163 :                 if (phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error TSRMLS_CC) == SUCCESS) {
    1352         116 :                         if ((*pphar)->is_data || !PHAR_G(readonly)) {
    1353          99 :                                 (*pphar)->is_writeable = 1;
    1354             :                         }
    1355         116 :                         if (actual) {
    1356         116 :                                 efree(actual);
    1357             :                         }
    1358         116 :                         return SUCCESS;
    1359             :                 } else {
    1360             :                         /* file exists, but is either corrupt or not a phar archive */
    1361          47 :                         if (actual) {
    1362          47 :                                 efree(actual);
    1363             :                         }
    1364          47 :                         return FAILURE;
    1365             :                 }
    1366             :         }
    1367             : 
    1368         178 :         if (actual) {
    1369           0 :                 efree(actual);
    1370             :         }
    1371             : 
    1372         178 :         if (PHAR_G(readonly) && !is_data) {
    1373           0 :                 if (options & REPORT_ERRORS) {
    1374           0 :                         if (error) {
    1375           0 :                                 spprintf(error, 0, "creating archive \"%s\" disabled by the php.ini setting phar.readonly", fname);
    1376             :                         }
    1377             :                 }
    1378           0 :                 return FAILURE;
    1379             :         }
    1380             : 
    1381             :         /* set up our manifest */
    1382         178 :         mydata = ecalloc(1, sizeof(phar_archive_data));
    1383         178 :         mydata->fname = expand_filepath(fname, NULL TSRMLS_CC);
    1384         178 :         fname_len = strlen(mydata->fname);
    1385             : #ifdef PHP_WIN32
    1386             :         phar_unixify_path_separators(mydata->fname, fname_len);
    1387             : #endif
    1388         178 :         p = strrchr(mydata->fname, '/');
    1389             : 
    1390         178 :         if (p) {
    1391         178 :                 mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p);
    1392         178 :                 if (mydata->ext == p) {
    1393           0 :                         mydata->ext = memchr(p + 1, '.', (mydata->fname + fname_len) - p - 1);
    1394             :                 }
    1395         178 :                 if (mydata->ext) {
    1396         178 :                         mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
    1397             :                 }
    1398             :         }
    1399             : 
    1400         178 :         if (pphar) {
    1401         178 :                 *pphar = mydata;
    1402             :         }
    1403             : 
    1404         178 :         zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
    1405             :                 zend_get_hash_value, destroy_phar_manifest_entry, 0);
    1406         178 :         zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
    1407             :                 zend_get_hash_value, NULL, 0);
    1408         178 :         zend_hash_init(&mydata->virtual_dirs, sizeof(char *),
    1409             :                 zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
    1410         178 :         mydata->fname_len = fname_len;
    1411         178 :         snprintf(mydata->version, sizeof(mydata->version), "%s", PHP_PHAR_API_VERSION);
    1412         178 :         mydata->is_temporary_alias = alias ? 0 : 1;
    1413         178 :         mydata->internal_file_start = -1;
    1414         178 :         mydata->fp = NULL;
    1415         178 :         mydata->is_writeable = 1;
    1416         178 :         mydata->is_brandnew = 1;
    1417         178 :         phar_request_initialize(TSRMLS_C);
    1418         178 :         zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, mydata);
    1419             : 
    1420         178 :         if (is_data) {
    1421          11 :                 alias = NULL;
    1422          11 :                 alias_len = 0;
    1423          11 :                 mydata->is_data = 1;
    1424             :                 /* assume tar format, PharData can specify other */
    1425          11 :                 mydata->is_tar = 1;
    1426             :         } else {
    1427             :                 phar_archive_data *fd_ptr;
    1428             : 
    1429         176 :                 if (alias && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len))) {
    1430           0 :                         if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len TSRMLS_CC)) {
    1431           0 :                                 if (error) {
    1432           0 :                                         spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias);
    1433             :                                 }
    1434             : 
    1435           0 :                                 zend_hash_str_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
    1436             : 
    1437           0 :                                 if (pphar) {
    1438           0 :                                         *pphar = NULL;
    1439             :                                 }
    1440             : 
    1441           0 :                                 return FAILURE;
    1442             :                         }
    1443             :                 }
    1444             : 
    1445         167 :                 mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
    1446         167 :                 mydata->alias_len = alias ? alias_len : fname_len;
    1447             :         }
    1448             : 
    1449         178 :         if (alias_len && alias) {
    1450          18 :                 if (NULL == zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, mydata)) {
    1451           0 :                         if (options & REPORT_ERRORS) {
    1452           0 :                                 if (error) {
    1453           0 :                                         spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias);
    1454             :                                 }
    1455             :                         }
    1456             : 
    1457           0 :                         zend_hash_str_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
    1458             : 
    1459           0 :                         if (pphar) {
    1460           0 :                                 *pphar = NULL;
    1461             :                         }
    1462             : 
    1463           0 :                         return FAILURE;
    1464             :                 }
    1465             :         }
    1466             : 
    1467         178 :         return SUCCESS;
    1468             : }
    1469             : /* }}}*/
    1470             : 
    1471             : /**
    1472             :  * Return an already opened filename.
    1473             :  *
    1474             :  * Or scan a phar file for the required __HALT_COMPILER(); ?> token and verify
    1475             :  * that the manifest is proper, then pass it to phar_parse_pharfile().  SUCCESS
    1476             :  * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
    1477             :  */
    1478        2149 : int phar_open_from_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
    1479             : {
    1480             :         php_stream *fp;
    1481             :         char *actual;
    1482        2149 :         int ret, is_data = 0;
    1483             : 
    1484        2149 :         if (error) {
    1485        1849 :                 *error = NULL;
    1486             :         }
    1487             : 
    1488        2149 :         if (!strstr(fname, ".phar")) {
    1489         438 :                 is_data = 1;
    1490             :         }
    1491             : 
    1492        2149 :         if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, pphar, error TSRMLS_CC) == SUCCESS) {
    1493        1808 :                 return SUCCESS;
    1494         341 :         } else if (error && *error) {
    1495           3 :                 return FAILURE;
    1496             :         }
    1497             : #if PHP_API_VERSION < 20100412
    1498             :         if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
    1499             :                 return FAILURE;
    1500             :         }
    1501             : #endif
    1502         338 :         if (php_check_open_basedir(fname TSRMLS_CC)) {
    1503           0 :                 return FAILURE;
    1504             :         }
    1505             : 
    1506         338 :         fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
    1507             : 
    1508         338 :         if (!fp) {
    1509          63 :                 if (options & REPORT_ERRORS) {
    1510           1 :                         if (error) {
    1511           1 :                                 spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
    1512             :                         }
    1513             :                 }
    1514          63 :                 if (actual) {
    1515           0 :                         efree(actual);
    1516             :                 }
    1517          63 :                 return FAILURE;
    1518             :         }
    1519             : 
    1520         275 :         if (actual) {
    1521         275 :                 fname = actual;
    1522         275 :                 fname_len = strlen(actual);
    1523             :         }
    1524             : 
    1525         275 :         ret =  phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error TSRMLS_CC);
    1526             : 
    1527         275 :         if (actual) {
    1528         275 :                 efree(actual);
    1529             :         }
    1530             : 
    1531         275 :         return ret;
    1532             : }
    1533             : /* }}}*/
    1534             : 
    1535         526 : static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len) /* {{{ */
    1536             : {
    1537             :         const char *c;
    1538         526 :         ptrdiff_t so_far = 0;
    1539             : 
    1540         526 :         if (buf_len < search_len) {
    1541           0 :                 return NULL;
    1542             :         }
    1543             : 
    1544         526 :         c = buf - 1;
    1545             : 
    1546             :         do {
    1547        4230 :                 if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) {
    1548         241 :                         return (char *) NULL;
    1549             :                 }
    1550             : 
    1551        3989 :                 so_far = c - buf;
    1552             : 
    1553        3989 :                 if (so_far >= (buf_len - search_len)) {
    1554           0 :                         return (char *) NULL;
    1555             :                 }
    1556             : 
    1557        3989 :                 if (!memcmp(c, search, search_len)) {
    1558         285 :                         return (char *) c;
    1559             :                 }
    1560        3704 :         } while (1);
    1561             : }
    1562             : /* }}} */
    1563             : 
    1564             : /**
    1565             :  * Scan an open fp for the required __HALT_COMPILER(); ?> token and verify
    1566             :  * that the manifest is proper, then pass it to phar_parse_pharfile().  SUCCESS
    1567             :  * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
    1568             :  */
    1569         510 : static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, int is_data, char **error TSRMLS_DC) /* {{{ */
    1570             : {
    1571         510 :         const char token[] = "__HALT_COMPILER();";
    1572         510 :         const char zip_magic[] = "PK\x03\x04";
    1573         510 :         const char gz_magic[] = "\x1f\x8b\x08";
    1574         510 :         const char bz_magic[] = "BZh";
    1575         510 :         char *pos, test = '\0';
    1576         510 :         const int window_size = 1024;
    1577             :         char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */
    1578         510 :         const zend_long readsize = sizeof(buffer) - sizeof(token);
    1579         510 :         const zend_long tokenlen = sizeof(token) - 1;
    1580             :         zend_long halt_offset;
    1581             :         size_t got;
    1582         510 :         php_uint32 compression = PHAR_FILE_COMPRESSED_NONE;
    1583             : 
    1584         510 :         if (error) {
    1585         289 :                 *error = NULL;
    1586             :         }
    1587             : 
    1588         510 :         if (-1 == php_stream_rewind(fp)) {
    1589           0 :                 MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"")
    1590             :         }
    1591             : 
    1592         510 :         buffer[sizeof(buffer)-1] = '\0';
    1593         510 :         memset(buffer, 32, sizeof(token));
    1594         510 :         halt_offset = 0;
    1595             : 
    1596             :         /* Maybe it's better to compile the file instead of just searching,  */
    1597             :         /* but we only want the offset. So we want a .re scanner to find it. */
    1598        1282 :         while(!php_stream_eof(fp)) {
    1599         700 :                 if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) {
    1600           2 :                         MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)")
    1601             :                 }
    1602             : 
    1603         698 :                 if (!test) {
    1604         529 :                         test = '\1';
    1605         529 :                         pos = buffer+tokenlen;
    1606         529 :                         if (!memcmp(pos, gz_magic, 3)) {
    1607          13 :                                 char err = 0;
    1608             :                                 php_stream_filter *filter;
    1609             :                                 php_stream *temp;
    1610             :                                 /* to properly decompress, we have to tell zlib to look for a zlib or gzip header */
    1611             :                                 zval filterparams;
    1612             : 
    1613          13 :                                 if (!PHAR_G(has_zlib)) {
    1614           0 :                                         MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file, enable zlib extension in php.ini")
    1615             :                                 }
    1616          13 :                                 array_init(&filterparams);
    1617             : /* this is defined in zlib's zconf.h */
    1618             : #ifndef MAX_WBITS
    1619             : #define MAX_WBITS 15
    1620             : #endif
    1621          13 :                                 add_assoc_long_ex(&filterparams, "window", sizeof("window") - 1, MAX_WBITS + 32);
    1622             : 
    1623             :                                 /* entire file is gzip-compressed, uncompress to temporary file */
    1624          13 :                                 if (!(temp = php_stream_fopen_tmpfile())) {
    1625           0 :                                         MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"")
    1626             :                                 }
    1627             : 
    1628          13 :                                 php_stream_rewind(fp);
    1629          13 :                                 filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
    1630             : 
    1631          13 :                                 if (!filter) {
    1632           0 :                                         err = 1;
    1633           0 :                                         add_assoc_long_ex(&filterparams, "window", sizeof("window") - 1, MAX_WBITS);
    1634           0 :                                         filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp) TSRMLS_CC);
    1635             :                                         zval_dtor(&filterparams);
    1636             : 
    1637           0 :                                         if (!filter) {
    1638           0 :                                                 php_stream_close(temp);
    1639           0 :                                                 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
    1640             :                                         }
    1641             :                                 } else {
    1642             :                                         zval_dtor(&filterparams);
    1643             :                                 }
    1644             : 
    1645          13 :                                 php_stream_filter_append(&temp->writefilters, filter);
    1646             : 
    1647          13 :                                 if (SUCCESS != php_stream_copy_to_stream_ex(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
    1648           0 :                                         if (err) {
    1649           0 :                                                 php_stream_close(temp);
    1650           0 :                                                 MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
    1651             :                                         }
    1652           0 :                                         php_stream_close(temp);
    1653           0 :                                         MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
    1654             :                                 }
    1655             : 
    1656          13 :                                 php_stream_filter_flush(filter, 1);
    1657          13 :                                 php_stream_filter_remove(filter, 1 TSRMLS_CC);
    1658          13 :                                 php_stream_close(fp);
    1659          13 :                                 fp = temp;
    1660          13 :                                 php_stream_rewind(fp);
    1661          13 :                                 compression = PHAR_FILE_COMPRESSED_GZ;
    1662             : 
    1663             :                                 /* now, start over */
    1664          13 :                                 test = '\0';
    1665          13 :                                 continue;
    1666         516 :                         } else if (!memcmp(pos, bz_magic, 3)) {
    1667             :                                 php_stream_filter *filter;
    1668             :                                 php_stream *temp;
    1669             : 
    1670           8 :                                 if (!PHAR_G(has_bz2)) {
    1671           0 :                                         MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file, enable bz2 extension in php.ini")
    1672             :                                 }
    1673             : 
    1674             :                                 /* entire file is bzip-compressed, uncompress to temporary file */
    1675           8 :                                 if (!(temp = php_stream_fopen_tmpfile())) {
    1676           0 :                                         MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"")
    1677             :                                 }
    1678             : 
    1679           8 :                                 php_stream_rewind(fp);
    1680           8 :                                 filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
    1681             : 
    1682           8 :                                 if (!filter) {
    1683           0 :                                         php_stream_close(temp);
    1684           0 :                                         MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\", filter creation failed")
    1685             :                                 }
    1686             : 
    1687           8 :                                 php_stream_filter_append(&temp->writefilters, filter);
    1688             : 
    1689           8 :                                 if (SUCCESS != php_stream_copy_to_stream_ex(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
    1690           0 :                                         php_stream_close(temp);
    1691           0 :                                         MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file")
    1692             :                                 }
    1693             : 
    1694           8 :                                 php_stream_filter_flush(filter, 1);
    1695           8 :                                 php_stream_filter_remove(filter, 1 TSRMLS_CC);
    1696           8 :                                 php_stream_close(fp);
    1697           8 :                                 fp = temp;
    1698           8 :                                 php_stream_rewind(fp);
    1699           8 :                                 compression = PHAR_FILE_COMPRESSED_BZ2;
    1700             : 
    1701             :                                 /* now, start over */
    1702           8 :                                 test = '\0';
    1703           8 :                                 continue;
    1704             :                         }
    1705             : 
    1706         508 :                         if (!memcmp(pos, zip_magic, 4)) {
    1707          79 :                                 php_stream_seek(fp, 0, SEEK_END);
    1708          79 :                                 return phar_parse_zipfile(fp, fname, fname_len, alias, alias_len, pphar, error TSRMLS_CC);
    1709             :                         }
    1710             : 
    1711         429 :                         if (got > 512) {
    1712         156 :                                 if (phar_is_tar(pos, fname)) {
    1713          72 :                                         php_stream_rewind(fp);
    1714          72 :                                         return phar_parse_tarfile(fp, fname, fname_len, alias, alias_len, pphar, is_data, compression, error TSRMLS_CC);
    1715             :                                 }
    1716             :                         }
    1717             :                 }
    1718             : 
    1719         526 :                 if (got > 0 && (pos = phar_strnstr(buffer, got + sizeof(token), token, sizeof(token)-1)) != NULL) {
    1720         285 :                         halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */
    1721         285 :                         return phar_parse_pharfile(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error TSRMLS_CC);
    1722             :                 }
    1723             : 
    1724         241 :                 halt_offset += got;
    1725         241 :                 memmove(buffer, buffer + window_size, tokenlen); /* move the memory buffer by the size of the window */
    1726             :         }
    1727             : 
    1728          72 :         MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (__HALT_COMPILER(); not found)")
    1729             : }
    1730             : /* }}} */
    1731             : 
    1732             : /*
    1733             :  * given the location of the file extension and the start of the file path,
    1734             :  * determine the end of the portion of the path (i.e. /path/to/file.ext/blah
    1735             :  * grabs "/path/to/file.ext" as does the straight /path/to/file.ext),
    1736             :  * stat it to determine if it exists.
    1737             :  * if so, check to see if it is a directory and fail if so
    1738             :  * if not, check to see if its dirname() exists (i.e. "/path/to") and is a directory
    1739             :  * succeed if we are creating the file, otherwise fail.
    1740             :  */
    1741        1037 : static int phar_analyze_path(const char *fname, const char *ext, int ext_len, int for_create TSRMLS_DC) /* {{{ */
    1742             : {
    1743             :         php_stream_statbuf ssb;
    1744             :         char *realpath;
    1745        1037 :         char *filename = estrndup(fname, (ext - fname) + ext_len);
    1746             : 
    1747        1037 :         if ((realpath = expand_filepath(filename, NULL TSRMLS_CC))) {
    1748             : #ifdef PHP_WIN32
    1749             :                 phar_unixify_path_separators(realpath, strlen(realpath));
    1750             : #endif
    1751        1036 :                 if (zend_hash_str_exists(&(PHAR_GLOBALS->phar_fname_map), realpath, strlen(realpath))) {
    1752           8 :                         efree(realpath);
    1753           8 :                         efree(filename);
    1754           8 :                         return SUCCESS;
    1755             :                 }
    1756             : 
    1757        1028 :                 if (PHAR_G(manifest_cached) && zend_hash_str_exists(&cached_phars, realpath, strlen(realpath))) {
    1758           0 :                         efree(realpath);
    1759           0 :                         efree(filename);
    1760           0 :                         return SUCCESS;
    1761             :                 }
    1762        1028 :                 efree(realpath);
    1763             :         }
    1764             : 
    1765        1029 :         if (SUCCESS == php_stream_stat_path((char *) filename, &ssb)) {
    1766             : 
    1767         381 :                 efree(filename);
    1768             : 
    1769         381 :                 if (ssb.sb.st_mode & S_IFDIR) {
    1770           0 :                         return FAILURE;
    1771             :                 }
    1772             : 
    1773         381 :                 if (for_create == 1) {
    1774           0 :                         return FAILURE;
    1775             :                 }
    1776             : 
    1777         381 :                 return SUCCESS;
    1778             :         } else {
    1779             :                 char *slash;
    1780             : 
    1781         648 :                 if (!for_create) {
    1782         211 :                         efree(filename);
    1783         211 :                         return FAILURE;
    1784             :                 }
    1785             : 
    1786         437 :                 slash = (char *) strrchr(filename, '/');
    1787             : 
    1788         437 :                 if (slash) {
    1789         403 :                         *slash = '\0';
    1790             :                 }
    1791             : 
    1792         437 :                 if (SUCCESS != php_stream_stat_path((char *) filename, &ssb)) {
    1793          34 :                         if (!slash) {
    1794          34 :                                 if (!(realpath = expand_filepath(filename, NULL TSRMLS_CC))) {
    1795           0 :                                         efree(filename);
    1796           0 :                                         return FAILURE;
    1797             :                                 }
    1798             : #ifdef PHP_WIN32
    1799             :                                 phar_unixify_path_separators(realpath, strlen(realpath));
    1800             : #endif
    1801          34 :                                 slash = strstr(realpath, filename) + ((ext - fname) + ext_len);
    1802          34 :                                 *slash = '\0';
    1803          34 :                                 slash = strrchr(realpath, '/');
    1804             : 
    1805          34 :                                 if (slash) {
    1806          34 :                                         *slash = '\0';
    1807             :                                 } else {
    1808           0 :                                         efree(realpath);
    1809           0 :                                         efree(filename);
    1810           0 :                                         return FAILURE;
    1811             :                                 }
    1812             : 
    1813          34 :                                 if (SUCCESS != php_stream_stat_path(realpath, &ssb)) {
    1814           0 :                                         efree(realpath);
    1815           0 :                                         efree(filename);
    1816           0 :                                         return FAILURE;
    1817             :                                 }
    1818             : 
    1819          34 :                                 efree(realpath);
    1820             : 
    1821          34 :                                 if (ssb.sb.st_mode & S_IFDIR) {
    1822          34 :                                         efree(filename);
    1823          34 :                                         return SUCCESS;
    1824             :                                 }
    1825             :                         }
    1826             : 
    1827           0 :                         efree(filename);
    1828           0 :                         return FAILURE;
    1829             :                 }
    1830             : 
    1831         403 :                 efree(filename);
    1832             : 
    1833         403 :                 if (ssb.sb.st_mode & S_IFDIR) {
    1834         402 :                         return SUCCESS;
    1835             :                 }
    1836             : 
    1837           1 :                 return FAILURE;
    1838             :         }
    1839             : }
    1840             : /* }}} */
    1841             : 
    1842             : /* check for ".phar" in extension */
    1843        1060 : static int phar_check_str(const char *fname, const char *ext_str, int ext_len, int executable, int for_create TSRMLS_DC) /* {{{ */
    1844             : {
    1845             :         char test[51];
    1846             :         const char *pos;
    1847             : 
    1848        1060 :         if (ext_len >= 50) {
    1849           0 :                 return FAILURE;
    1850             :         }
    1851             : 
    1852        1060 :         if (executable == 1) {
    1853             :                 /* copy "." as well */
    1854         794 :                 memcpy(test, ext_str - 1, ext_len + 1);
    1855         794 :                 test[ext_len + 1] = '\0';
    1856             :                 /* executable phars must contain ".phar" as a valid extension (phar://.pharmy/oops is invalid) */
    1857             :                 /* (phar://hi/there/.phar/oops is also invalid) */
    1858         794 :                 pos = strstr(test, ".phar");
    1859             : 
    1860        2681 :                 if (pos && (*(pos - 1) != '/')
    1861        1887 :                                 && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) {
    1862         779 :                         return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
    1863             :                 } else {
    1864          15 :                         return FAILURE;
    1865             :                 }
    1866             :         }
    1867             : 
    1868             :         /* data phars need only contain a single non-"." to be valid */
    1869         266 :         if (!executable) {
    1870         151 :                 pos = strstr(ext_str, ".phar");
    1871         603 :                 if (!(pos && (*(pos - 1) != '/')
    1872         452 :                                         && (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) && *(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
    1873         143 :                         return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
    1874             :                 }
    1875             :         } else {
    1876         115 :                 if (*(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
    1877         115 :                         return phar_analyze_path(fname, ext_str, ext_len, for_create TSRMLS_CC);
    1878             :                 }
    1879             :         }
    1880             : 
    1881           8 :         return FAILURE;
    1882             : }
    1883             : /* }}} */
    1884             : 
    1885             : /*
    1886             :  * if executable is 1, only returns SUCCESS if the extension is one of the tar/zip .phar extensions
    1887             :  * if executable is 0, it returns SUCCESS only if the filename does *not* contain ".phar" anywhere, and treats
    1888             :  * the first extension as the filename extension
    1889             :  *
    1890             :  * if an extension is found, it sets ext_str to the location of the file extension in filename,
    1891             :  * and ext_len to the length of the extension.
    1892             :  * for urls like "phar://alias/oops" it instead sets ext_len to -1 and returns FAILURE, which tells
    1893             :  * the calling function to use "alias" as the phar alias
    1894             :  *
    1895             :  * the last parameter should be set to tell the thing to assume that filename is the full path, and only to check the
    1896             :  * extension rules, not to iterate.
    1897             :  */
    1898        3461 : int phar_detect_phar_fname_ext(const char *filename, int filename_len, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete TSRMLS_DC) /* {{{ */
    1899             : {
    1900             :         const char *pos, *slash;
    1901             : 
    1902        3461 :         *ext_str = NULL;
    1903        3461 :         *ext_len = 0;
    1904             : 
    1905        3461 :         if (!filename_len || filename_len == 1) {
    1906          16 :                 return FAILURE;
    1907             :         }
    1908             : 
    1909        3445 :         phar_request_initialize(TSRMLS_C);
    1910             :         /* first check for alias in first segment */
    1911        3445 :         pos = memchr(filename, '/', filename_len);
    1912             : 
    1913        3445 :         if (pos && pos != filename) {
    1914             :                 /* check for url like http:// or phar:// */
    1915          82 :                 if (*(pos - 1) == ':' && (pos - filename) < filename_len - 1 && *(pos + 1) == '/') {
    1916           6 :                         *ext_len = -2;
    1917           6 :                         *ext_str = NULL;
    1918           6 :                         return FAILURE;
    1919             :                 }
    1920          76 :                 if (zend_hash_str_exists(&(PHAR_GLOBALS->phar_alias_map), (char *) filename, pos - filename)) {
    1921          63 :                         *ext_str = pos;
    1922          63 :                         *ext_len = -1;
    1923          63 :                         return FAILURE;
    1924             :                 }
    1925             : 
    1926          13 :                 if (PHAR_G(manifest_cached) && zend_hash_str_exists(&cached_alias, (char *) filename, pos - filename)) {
    1927           0 :                         *ext_str = pos;
    1928           0 :                         *ext_len = -1;
    1929           0 :                         return FAILURE;
    1930             :                 }
    1931             :         }
    1932             : 
    1933        3376 :         if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)) || PHAR_G(manifest_cached)) {
    1934             :                 phar_archive_data *pphar;
    1935             : 
    1936        2589 :                 if (is_complete) {
    1937         826 :                         if (NULL != (pphar = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_fname_map), (char *) filename, filename_len))) {
    1938         245 :                                 *ext_str = filename + (filename_len - pphar->ext_len);
    1939             : woohoo:
    1940        2318 :                                 *ext_len = pphar->ext_len;
    1941             : 
    1942        2318 :                                 if (executable == 2) {
    1943        1894 :                                         return SUCCESS;
    1944             :                                 }
    1945             : 
    1946         424 :                                 if (executable == 1 && !pphar->is_data) {
    1947         351 :                                         return SUCCESS;
    1948             :                                 }
    1949             : 
    1950          73 :                                 if (!executable && pphar->is_data) {
    1951          70 :                                         return SUCCESS;
    1952             :                                 }
    1953             : 
    1954           3 :                                 return FAILURE;
    1955             :                         }
    1956             : 
    1957         172 :                         if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, (char *) filename, filename_len))) {
    1958           4 :                                 *ext_str = filename + (filename_len - pphar->ext_len);
    1959           4 :                                 goto woohoo;
    1960             :                         }
    1961             :                 } else {
    1962             :                         zend_string *str_key;
    1963             :                         zend_ulong unused;
    1964             : 
    1965        5099 :                         for (zend_hash_internal_pointer_reset(&(PHAR_GLOBALS->phar_fname_map));
    1966        2923 :                                 HASH_KEY_NON_EXISTENT != zend_hash_get_current_key_ex(&(PHAR_GLOBALS->phar_fname_map), &str_key, &unused, 0, &PHAR_GLOBALS->phar_fname_map.nInternalPointer);
    1967             :                                 zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map))
    1968         747 :                         ) {
    1969        2806 :                                 if (str_key->len > (uint) filename_len) {
    1970         177 :                                         continue;
    1971             :                                 }
    1972             : 
    1973        8875 :                                 if (!memcmp(filename, str_key->val, str_key->len) && ((uint)filename_len == str_key->len
    1974        6246 :                                         || filename[str_key->len] == '/' || filename[str_key->len] == '\0')) {
    1975        2059 :                                         if (NULL == (pphar = zend_hash_get_current_data_ptr(&(PHAR_GLOBALS->phar_fname_map)))) {
    1976           0 :                                                 break;
    1977             :                                         }
    1978        2059 :                                         *ext_str = filename + (str_key->len - pphar->ext_len);
    1979        2059 :                                         goto woohoo;
    1980             :                                 }
    1981             :                         }
    1982             : 
    1983         117 :                         if (PHAR_G(manifest_cached)) {
    1984          20 :                                 for (zend_hash_internal_pointer_reset(&cached_phars);
    1985          10 :                                         HASH_KEY_NON_EXISTENT != zend_hash_get_current_key_ex(&cached_phars, &str_key, &unused, 0, &cached_phars.nInternalPointer);
    1986             :                                         zend_hash_move_forward(&cached_phars)
    1987           0 :                                 ) {
    1988          10 :                                         if (str_key->len > (uint) filename_len) {
    1989           0 :                                                 continue;
    1990             :                                         }
    1991             : 
    1992          38 :                                         if (!memcmp(filename, str_key->val, str_key->len) && ((uint)filename_len == str_key->len
    1993          28 :                                                 || filename[str_key->len] == '/' || filename[str_key->len] == '\0')) {
    1994          10 :                                                 if (NULL == (pphar = zend_hash_get_current_data_ptr(&cached_phars))) {
    1995           0 :                                                         break;
    1996             :                                                 }
    1997          10 :                                                 *ext_str = filename + (str_key->len - pphar->ext_len);
    1998          10 :                                                 goto woohoo;
    1999             :                                         }
    2000             :                                 }
    2001             :                         }
    2002             :                 }
    2003             :         }
    2004             : 
    2005        1058 :         pos = memchr(filename + 1, '.', filename_len);
    2006             : next_extension:
    2007        1078 :         if (!pos) {
    2008          18 :                 return FAILURE;
    2009             :         }
    2010             : 
    2011        2121 :         while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) {
    2012           1 :                 pos = memchr(pos + 1, '.', filename_len - (pos - filename) + 1);
    2013           1 :                 if (!pos) {
    2014           0 :                         return FAILURE;
    2015             :                 }
    2016             :         }
    2017             : 
    2018        1060 :         slash = memchr(pos, '/', filename_len - (pos - filename));
    2019             : 
    2020        1060 :         if (!slash) {
    2021             :                 /* this is a url like "phar://blah.phar" with no directory */
    2022         957 :                 *ext_str = pos;
    2023         957 :                 *ext_len = strlen(pos);
    2024             : 
    2025             :                 /* file extension must contain "phar" */
    2026         957 :                 switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
    2027             :                         case SUCCESS:
    2028         742 :                                 return SUCCESS;
    2029             :                         case FAILURE:
    2030             :                                 /* we are at the end of the string, so we fail */
    2031         215 :                                 return FAILURE;
    2032             :                 }
    2033             :         }
    2034             : 
    2035             :         /* we've found an extension that ends at a directory separator */
    2036         103 :         *ext_str = pos;
    2037         103 :         *ext_len = slash - pos;
    2038             : 
    2039         103 :         switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create TSRMLS_CC)) {
    2040             :                 case SUCCESS:
    2041          83 :                         return SUCCESS;
    2042             :                 case FAILURE:
    2043             :                         /* look for more extensions */
    2044          20 :                         pos = strchr(pos + 1, '.');
    2045          20 :                         if (pos) {
    2046          15 :                                 *ext_str = NULL;
    2047          15 :                                 *ext_len = 0;
    2048             :                         }
    2049          20 :                         goto next_extension;
    2050             :         }
    2051             : 
    2052           0 :         return FAILURE;
    2053             : }
    2054             : /* }}} */
    2055             : 
    2056        1442 : static int php_check_dots(const char *element, int n) /* {{{ */
    2057             : {
    2058        1460 :         for(n--; n >= 0; --n) {
    2059        1451 :                 if (element[n] != '.') {
    2060        1433 :                         return 1;
    2061             :                 }
    2062             :         }
    2063           9 :         return 0;
    2064             : }
    2065             : /* }}} */
    2066             : 
    2067             : #define IS_DIRECTORY_UP(element, len) \
    2068             :         (len >= 2 && !php_check_dots(element, len))
    2069             : 
    2070             : #define IS_DIRECTORY_CURRENT(element, len) \
    2071             :         (len == 1 && element[0] == '.')
    2072             : 
    2073             : #define IS_BACKSLASH(c) ((c) == '/')
    2074             : 
    2075             : /**
    2076             :  * Remove .. and . references within a phar filename
    2077             :  */
    2078        2139 : char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{ */
    2079             : {
    2080             :         char newpath[MAXPATHLEN];
    2081             :         int newpath_len;
    2082             :         char *ptr;
    2083             :         char *tok;
    2084        2139 :         int ptr_length, path_length = *new_len;
    2085             : 
    2086        2150 :         if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
    2087          11 :                 newpath_len = PHAR_G(cwd_len);
    2088          11 :                 memcpy(newpath, PHAR_G(cwd), newpath_len);
    2089             :         } else {
    2090        2128 :                 newpath[0] = '/';
    2091        2128 :                 newpath_len = 1;
    2092             :         }
    2093             : 
    2094        2139 :         ptr = path;
    2095             : 
    2096        2139 :         if (*ptr == '/') {
    2097        2086 :                 ++ptr;
    2098             :         }
    2099             : 
    2100        2139 :         tok = ptr;
    2101             : 
    2102             :         do {
    2103        2141 :                 ptr = memchr(ptr, '/', path_length - (ptr - path));
    2104        2141 :         } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
    2105             : 
    2106        2139 :         if (!ptr && (path_length - (tok - path))) {
    2107        1061 :                 switch (path_length - (tok - path)) {
    2108             :                         case 1:
    2109         478 :                                 if (*tok == '.') {
    2110           2 :                                         efree(path);
    2111           2 :                                         *new_len = 1;
    2112           2 :                                         return estrndup("/", 1);
    2113             :                                 }
    2114         476 :                                 break;
    2115             :                         case 2:
    2116          16 :                                 if (tok[0] == '.' && tok[1] == '.') {
    2117           0 :                                         efree(path);
    2118           0 :                                         *new_len = 1;
    2119           0 :                                         return estrndup("/", 1);
    2120             :                                 }
    2121             :                 }
    2122        1059 :                 return path;
    2123             :         }
    2124             : 
    2125        2568 :         while (ptr) {
    2126        1061 :                 ptr_length = ptr - tok;
    2127             : last_time:
    2128        1719 :                 if (IS_DIRECTORY_UP(tok, ptr_length)) {
    2129             : #define PREVIOUS newpath[newpath_len - 1]
    2130             : 
    2131          23 :                         while (newpath_len > 1 && !IS_BACKSLASH(PREVIOUS)) {
    2132           5 :                                 newpath_len--;
    2133             :                         }
    2134             : 
    2135           9 :                         if (newpath[0] != '/') {
    2136           0 :                                 newpath[newpath_len] = '\0';
    2137           9 :                         } else if (newpath_len > 1) {
    2138           0 :                                 --newpath_len;
    2139             :                         }
    2140        1701 :                 } else if (!IS_DIRECTORY_CURRENT(tok, ptr_length)) {
    2141        1690 :                         if (newpath_len > 1) {
    2142        1023 :                                 newpath[newpath_len++] = '/';
    2143        1023 :                                 memcpy(newpath + newpath_len, tok, ptr_length+1);
    2144             :                         } else {
    2145         667 :                                 memcpy(newpath + newpath_len, tok, ptr_length+1);
    2146             :                         }
    2147             : 
    2148        1690 :                         newpath_len += ptr_length;
    2149             :                 }
    2150             : 
    2151        1710 :                 if (ptr == path + path_length) {
    2152         649 :                         break;
    2153             :                 }
    2154             : 
    2155        1061 :                 tok = ++ptr;
    2156             : 
    2157             :                 do {
    2158        1062 :                         ptr = memchr(ptr, '/', path_length - (ptr - path));
    2159        1062 :                 } while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
    2160             : 
    2161        1061 :                 if (!ptr && (path_length - (tok - path))) {
    2162         649 :                         ptr_length = path_length - (tok - path);
    2163         649 :                         ptr = path + path_length;
    2164         649 :                         goto last_time;
    2165             :                 }
    2166             :         }
    2167             : 
    2168        1078 :         efree(path);
    2169        1078 :         *new_len = newpath_len;
    2170        1078 :         return estrndup(newpath, newpath_len);
    2171             : }
    2172             : /* }}} */
    2173             : 
    2174             : /**
    2175             :  * Process a phar stream name, ensuring we can handle any of:
    2176             :  * 
    2177             :  * - whatever.phar
    2178             :  * - whatever.phar.gz
    2179             :  * - whatever.phar.bz2
    2180             :  * - whatever.phar.php
    2181             :  *
    2182             :  * Optionally the name might start with 'phar://'
    2183             :  *
    2184             :  * This is used by phar_parse_url()
    2185             :  */
    2186        2578 : int phar_split_fname(const char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create TSRMLS_DC) /* {{{ */
    2187             : {
    2188             :         const char *ext_str;
    2189             : #ifdef PHP_WIN32
    2190             :         char *save;
    2191             : #endif
    2192             :         int ext_len;
    2193             : 
    2194        2578 :         if (!strncasecmp(filename, "phar://", 7)) {
    2195        2128 :                 filename += 7;
    2196        2128 :                 filename_len -= 7;
    2197             :         }
    2198             : 
    2199        2578 :         ext_len = 0;
    2200             : #ifdef PHP_WIN32
    2201             :         save = filename;
    2202             :         filename = estrndup(filename, filename_len);
    2203             :         phar_unixify_path_separators(filename, filename_len);
    2204             : #endif
    2205        2578 :         if (phar_detect_phar_fname_ext(filename, filename_len, &ext_str, &ext_len, executable, for_create, 0 TSRMLS_CC) == FAILURE) {
    2206          97 :                 if (ext_len != -1) {
    2207          34 :                         if (!ext_str) {
    2208             :                                 /* no / detected, restore arch for error message */
    2209             : #ifdef PHP_WIN32
    2210             :                                 *arch = save;
    2211             : #else
    2212          20 :                                 *arch = (char*)filename;
    2213             : #endif
    2214             :                         }
    2215             : 
    2216             : #ifdef PHP_WIN32
    2217             :                         efree(filename);
    2218             : #endif
    2219          34 :                         return FAILURE;
    2220             :                 }
    2221             : 
    2222          63 :                 ext_len = 0;
    2223             :                 /* no extension detected - instead we are dealing with an alias */
    2224             :         }
    2225             : 
    2226        2544 :         *arch_len = ext_str - filename + ext_len;
    2227        2544 :         *arch = estrndup(filename, *arch_len);
    2228             : 
    2229        2544 :         if (ext_str[ext_len]) {
    2230        2086 :                 *entry_len = filename_len - *arch_len;
    2231        2086 :                 *entry = estrndup(ext_str+ext_len, *entry_len);
    2232             : #ifdef PHP_WIN32
    2233             :                 phar_unixify_path_separators(*entry, *entry_len);
    2234             : #endif
    2235        2086 :                 *entry = phar_fix_filepath(*entry, entry_len, 0 TSRMLS_CC);
    2236             :         } else {
    2237         458 :                 *entry_len = 1;
    2238         458 :                 *entry = estrndup("/", 1);
    2239             :         }
    2240             : 
    2241             : #ifdef PHP_WIN32
    2242             :         efree(filename);
    2243             : #endif
    2244             : 
    2245        2544 :         return SUCCESS;
    2246             : }
    2247             : /* }}} */
    2248             : 
    2249             : /**
    2250             :  * Invoked when a user calls Phar::mapPhar() from within an executing .phar
    2251             :  * to set up its manifest directly
    2252             :  */
    2253         134 : int phar_open_executed_filename(char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
    2254             : {
    2255             :         char *fname;
    2256             :         php_stream *fp;
    2257             :         int fname_len;
    2258         134 :         char *actual = NULL;
    2259             :         int ret;
    2260             : 
    2261         134 :         if (error) {
    2262         134 :                 *error = NULL;
    2263             :         }
    2264             : 
    2265         134 :         fname = (char*)zend_get_executed_filename(TSRMLS_C);
    2266         134 :         fname_len = strlen(fname);
    2267             : 
    2268         134 :         if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0 TSRMLS_CC) == SUCCESS) {
    2269          61 :                 return SUCCESS;
    2270             :         }
    2271             : 
    2272          73 :         if (!strcmp(fname, "[no active file]")) {
    2273           0 :                 if (error) {
    2274           0 :                         spprintf(error, 0, "cannot initialize a phar outside of PHP execution");
    2275             :                 }
    2276           0 :                 return FAILURE;
    2277             :         }
    2278             : 
    2279          73 :         if (0 == zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1 TSRMLS_CC)) {
    2280           1 :                 if (error) {
    2281           1 :                         spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar");
    2282             :                 }
    2283           1 :                 return FAILURE;
    2284             :         }
    2285             : 
    2286             : 
    2287             : #if PHP_API_VERSION < 20100412
    2288             :         if (PG(safe_mode) && (!php_checkuid(fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
    2289             :                 return FAILURE;
    2290             :         }
    2291             : #endif
    2292             : 
    2293          72 :         if (php_check_open_basedir(fname TSRMLS_CC)) {
    2294           0 :                 return FAILURE;
    2295             :         }
    2296             : 
    2297          72 :         fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, &actual);
    2298             : 
    2299          72 :         if (!fp) {
    2300           0 :                 if (error) {
    2301           0 :                         spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
    2302             :                 }
    2303           0 :                 if (actual) {
    2304           0 :                         efree(actual);
    2305             :                 }
    2306           0 :                 return FAILURE;
    2307             :         }
    2308             : 
    2309          72 :         if (actual) {
    2310          72 :                 fname = actual;
    2311          72 :                 fname_len = strlen(actual);
    2312             :         }
    2313             : 
    2314          72 :         ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, 0, error TSRMLS_CC);
    2315             : 
    2316          72 :         if (actual) {
    2317          72 :                 efree(actual);
    2318             :         }
    2319             : 
    2320          72 :         return ret;
    2321             : }
    2322             : /* }}} */
    2323             : 
    2324             : /**
    2325             :  * Validate the CRC32 of a file opened from within the phar
    2326             :  */
    2327        1243 : int phar_postprocess_file(phar_entry_data *idata, php_uint32 crc32, char **error, int process_zip TSRMLS_DC) /* {{{ */
    2328             : {
    2329        1243 :         php_uint32 crc = ~0;
    2330        1243 :         int len = idata->internal_file->uncompressed_filesize;
    2331        1243 :         php_stream *fp = idata->fp;
    2332        1243 :         phar_entry_info *entry = idata->internal_file;
    2333             : 
    2334        1243 :         if (error) {
    2335        1243 :                 *error = NULL;
    2336             :         }
    2337             : 
    2338        1243 :         if (entry->is_zip && process_zip > 0) {
    2339             :                 /* verify local file header */
    2340             :                 phar_zip_file_header local;
    2341             :                 phar_zip_data_desc desc;
    2342             : 
    2343         175 :                 if (SUCCESS != phar_open_archive_fp(idata->phar TSRMLS_CC)) {
    2344           0 :                         spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", idata->phar->fname, entry->filename);
    2345           0 :                         return FAILURE;
    2346             :                 }
    2347         175 :                 php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC), entry->header_offset, SEEK_SET);
    2348             : 
    2349         175 :                 if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC), (char *) &local, sizeof(local))) {
    2350             : 
    2351           0 :                         spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", idata->phar->fname, entry->filename);
    2352           0 :                         return FAILURE;
    2353             :                 }
    2354             : 
    2355             :                 /* check for data descriptor */
    2356         175 :                 if (((PHAR_ZIP_16(local.flags)) & 0x8) == 0x8) {
    2357           1 :                         php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC),
    2358             :                                         entry->header_offset + sizeof(local) +
    2359             :                                         PHAR_ZIP_16(local.filename_len) +
    2360             :                                         PHAR_ZIP_16(local.extra_len) +
    2361             :                                         entry->compressed_filesize, SEEK_SET);
    2362           1 :                         if (sizeof(desc) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC),
    2363             :                                                             (char *) &desc, sizeof(desc))) {
    2364           0 :                                 spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local data descriptor for file \"%s\")", idata->phar->fname, entry->filename);
    2365           0 :                                 return FAILURE;
    2366             :                         }
    2367           2 :                         if (desc.signature[0] == 'P' && desc.signature[1] == 'K') {
    2368           1 :                                 memcpy(&(local.crc32), &(desc.crc32), 12);
    2369             :                         } else {
    2370             :                                 /* old data descriptors have no signature */
    2371           0 :                                 memcpy(&(local.crc32), &desc, 12);
    2372             :                         }
    2373             :                 }
    2374             :                 /* verify local header */
    2375         175 :                 if (entry->filename_len != PHAR_ZIP_16(local.filename_len) || entry->crc32 != PHAR_ZIP_32(local.crc32) || entry->uncompressed_filesize != PHAR_ZIP_32(local.uncompsize) || entry->compressed_filesize != PHAR_ZIP_32(local.compsize)) {
    2376           0 :                         spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local header of file \"%s\" does not match central directory)", idata->phar->fname, entry->filename);
    2377           0 :                         return FAILURE;
    2378             :                 }
    2379             : 
    2380             :                 /* construct actual offset to file start - local extra_len can be different from central extra_len */
    2381         175 :                 entry->offset = entry->offset_abs =
    2382         175 :                         sizeof(local) + entry->header_offset + PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len);
    2383             : 
    2384         175 :                 if (idata->zero && idata->zero != entry->offset_abs) {
    2385           2 :                         idata->zero = entry->offset_abs;
    2386             :                 }
    2387             :         }
    2388             : 
    2389        1243 :         if (process_zip == 1) {
    2390        1053 :                 return SUCCESS;
    2391             :         }
    2392             : 
    2393         190 :         php_stream_seek(fp, idata->zero, SEEK_SET);
    2394             : 
    2395       17992 :         while (len--) {
    2396       17612 :                 CRC32(crc, php_stream_getc(fp));
    2397             :         }
    2398             : 
    2399         190 :         php_stream_seek(fp, idata->zero, SEEK_SET);
    2400             : 
    2401         190 :         if (~crc == crc32) {
    2402         188 :                 entry->is_crc_checked = 1;
    2403         188 :                 return SUCCESS;
    2404             :         } else {
    2405           2 :                 spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
    2406           2 :                 return FAILURE;
    2407             :         }
    2408             : }
    2409             : /* }}} */
    2410             : 
    2411      127669 : static inline void phar_set_32(char *buffer, int var) /* {{{ */
    2412             : {
    2413             : #ifdef WORDS_BIGENDIAN
    2414             :         *((buffer) + 3) = (unsigned char) (((var) >> 24) & 0xFF);
    2415             :         *((buffer) + 2) = (unsigned char) (((var) >> 16) & 0xFF);
    2416             :         *((buffer) + 1) = (unsigned char) (((var) >> 8) & 0xFF);
    2417             :         *((buffer) + 0) = (unsigned char) ((var) & 0xFF);
    2418             : #else
    2419      127669 :          memcpy(buffer, &var, sizeof(var));
    2420             : #endif
    2421      127669 : } /* }}} */
    2422             : 
    2423       14389 : static int phar_flush_clean_deleted_apply(zval *zv TSRMLS_DC) /* {{{ */
    2424             : {
    2425       14389 :         phar_entry_info *entry = (phar_entry_info *)Z_PTR_P(zv);
    2426             : 
    2427       14389 :         if (entry->fp_refcount <= 0 && entry->is_deleted) {
    2428          10 :                 return ZEND_HASH_APPLY_REMOVE;
    2429             :         } else {
    2430       14379 :                 return ZEND_HASH_APPLY_KEEP;
    2431             :         }
    2432             : }
    2433             : /* }}} */
    2434             : 
    2435             : #include "stub.h"
    2436             : 
    2437          96 : char *phar_create_default_stub(const char *index_php, const char *web_index, size_t *len, char **error TSRMLS_DC) /* {{{ */
    2438             : {
    2439          96 :         char *stub = NULL;
    2440             :         int index_len, web_len;
    2441             :         size_t dummy;
    2442             : 
    2443          96 :         if (!len) {
    2444           0 :                 len = &dummy;
    2445             :         }
    2446             : 
    2447          96 :         if (error) {
    2448          16 :                 *error = NULL;
    2449             :         }
    2450             : 
    2451          96 :         if (!index_php) {
    2452          86 :                 index_php = "index.php";
    2453             :         }
    2454             : 
    2455          96 :         if (!web_index) {
    2456          92 :                 web_index = "index.php";
    2457             :         }
    2458             : 
    2459          96 :         index_len = strlen(index_php);
    2460          96 :         web_len = strlen(web_index);
    2461             : 
    2462          96 :         if (index_len > 400) {
    2463             :                 /* ridiculous size not allowed for index.php startup filename */
    2464           2 :                 if (error) {
    2465           2 :                         spprintf(error, 0, "Illegal filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", index_len);
    2466           2 :                         return NULL;
    2467             :                 }
    2468             :         }
    2469             : 
    2470          94 :         if (web_len > 400) {
    2471             :                 /* ridiculous size not allowed for index.php startup filename */
    2472           1 :                 if (error) {
    2473           1 :                         spprintf(error, 0, "Illegal web filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", web_len);
    2474           1 :                         return NULL;
    2475             :                 }
    2476             :         }
    2477             : 
    2478          93 :         phar_get_stub(index_php, web_index, len, &stub, index_len+1, web_len+1 TSRMLS_CC);
    2479          93 :         return stub;
    2480             : }
    2481             : /* }}} */
    2482             : 
    2483             : /**
    2484             :  * Save phar contents to disk
    2485             :  *
    2486             :  * user_stub contains either a string, or a resource pointer, if len is a negative length.
    2487             :  * user_stub and len should be both 0 if the default or existing stub should be used
    2488             :  */
    2489        4919 : int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int convert, char **error TSRMLS_DC) /* {{{ */
    2490             : {
    2491        4919 :         char halt_stub[] = "__HALT_COMPILER();";
    2492             :         char *newstub, *tmp;
    2493             :         phar_entry_info *entry, *newentry;
    2494        4919 :         int halt_offset, restore_alias_len, global_flags = 0, closeoldfile;
    2495        4919 :         char *pos, has_dirs = 0;
    2496             :         char manifest[18], entry_buffer[24];
    2497             :         zend_off_t manifest_ftell;
    2498             :         zend_long offset;
    2499             :         size_t wrote;
    2500             :         php_uint32 manifest_len, mytime, loc, new_manifest_count;
    2501             :         php_uint32 newcrc32;
    2502             :         php_stream *file, *oldfile, *newfile, *stubfile;
    2503             :         php_stream_filter *filter;
    2504             :         php_serialize_data_t metadata_hash;
    2505        4919 :         smart_str main_metadata_str = {0};
    2506        4919 :         int free_user_stub, free_fp = 1, free_ufp = 1;
    2507        4919 :         int manifest_hack = 0;
    2508             : 
    2509        4919 :         if (phar->is_persistent) {
    2510           0 :                 if (error) {
    2511           0 :                         spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
    2512             :                 }
    2513           0 :                 return EOF;
    2514             :         }
    2515             : 
    2516        4919 :         if (error) {
    2517        4919 :                 *error = NULL;
    2518             :         }
    2519             : 
    2520        4919 :         if (!zend_hash_num_elements(&phar->manifest) && !user_stub) {
    2521          14 :                 return EOF;
    2522             :         }
    2523             : 
    2524        4905 :         zend_hash_clean(&phar->virtual_dirs);
    2525             : 
    2526        4905 :         if (phar->is_zip) {
    2527         203 :                 return phar_zip_flush(phar, user_stub, len, convert, error TSRMLS_CC);
    2528             :         }
    2529             : 
    2530        4702 :         if (phar->is_tar) {
    2531         193 :                 return phar_tar_flush(phar, user_stub, len, convert, error TSRMLS_CC);
    2532             :         }
    2533             : 
    2534        4509 :         if (PHAR_G(readonly)) {
    2535           0 :                 return EOF;
    2536             :         }
    2537             : 
    2538        8931 :         if (phar->fp && !phar->is_brandnew) {
    2539        4422 :                 oldfile = phar->fp;
    2540        4422 :                 closeoldfile = 0;
    2541        4422 :                 php_stream_rewind(oldfile);
    2542             :         } else {
    2543          87 :                 oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
    2544          87 :                 closeoldfile = oldfile != NULL;
    2545             :         }
    2546        4509 :         newfile = php_stream_fopen_tmpfile();
    2547        4509 :         if (!newfile) {
    2548           0 :                 if (error) {
    2549           0 :                         spprintf(error, 0, "unable to create temporary file");
    2550             :                 }
    2551           0 :                 if (closeoldfile) {
    2552           0 :                         php_stream_close(oldfile);
    2553             :                 }
    2554           0 :                 return EOF;
    2555             :         }
    2556             : 
    2557        4509 :         if (user_stub) {
    2558             :                 zend_string *suser_stub;
    2559          29 :                 if (len < 0) {
    2560             :                         /* resource passed in */
    2561           4 :                         if (!(php_stream_from_zval_no_verify(stubfile, (zval *)user_stub))) {
    2562           0 :                                 if (closeoldfile) {
    2563           0 :                                         php_stream_close(oldfile);
    2564             :                                 }
    2565           0 :                                 php_stream_close(newfile);
    2566           0 :                                 if (error) {
    2567           0 :                                         spprintf(error, 0, "unable to access resource to copy stub to new phar \"%s\"", phar->fname);
    2568             :                                 }
    2569           0 :                                 return EOF;
    2570             :                         }
    2571           4 :                         if (len == -1) {
    2572           3 :                                 len = PHP_STREAM_COPY_ALL;
    2573             :                         } else {
    2574           1 :                                 len = -len;
    2575             :                         }
    2576           4 :                         user_stub = 0;
    2577             : 
    2578           4 :                         if (!(suser_stub = php_stream_copy_to_mem(stubfile, len, 0))) {
    2579           0 :                                 if (closeoldfile) {
    2580           0 :                                         php_stream_close(oldfile);
    2581             :                                 }
    2582           0 :                                 php_stream_close(newfile);
    2583           0 :                                 if (error) {
    2584           0 :                                         spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", phar->fname);
    2585             :                                 }
    2586           0 :                                 return EOF;
    2587             :                         }
    2588           4 :                         free_user_stub = 1;
    2589           4 :                         user_stub = suser_stub->val;
    2590           4 :                         len = suser_stub->len;
    2591             :                 } else {
    2592          25 :                         free_user_stub = 0;
    2593             :                 }
    2594          29 :                 tmp = estrndup(user_stub, len);
    2595          29 :                 if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) {
    2596           1 :                         efree(tmp);
    2597           1 :                         if (closeoldfile) {
    2598           0 :                                 php_stream_close(oldfile);
    2599             :                         }
    2600           1 :                         php_stream_close(newfile);
    2601           1 :                         if (error) {
    2602           1 :                                 spprintf(error, 0, "illegal stub for phar \"%s\"", phar->fname);
    2603             :                         }
    2604           1 :                         if (free_user_stub) {
    2605             :                                 zend_string_free(suser_stub);
    2606             :                         }
    2607           1 :                         return EOF;
    2608             :                 }
    2609          28 :                 pos = user_stub + (pos - tmp);
    2610          28 :                 efree(tmp);
    2611          28 :                 len = pos - user_stub + 18;
    2612          56 :                 if ((size_t)len != php_stream_write(newfile, user_stub, len)
    2613          56 :                 ||                        5 != php_stream_write(newfile, " ?>\r\n", 5)) {
    2614           0 :                         if (closeoldfile) {
    2615           0 :                                 php_stream_close(oldfile);
    2616             :                         }
    2617           0 :                         php_stream_close(newfile);
    2618           0 :                         if (error) {
    2619           0 :                                 spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname);
    2620             :                         }
    2621           0 :                         if (free_user_stub) {
    2622             :                                 zend_string_free(suser_stub);
    2623             :                         }
    2624           0 :                         return EOF;
    2625             :                 }
    2626          28 :                 phar->halt_offset = len + 5;
    2627          28 :                 if (free_user_stub) {
    2628             :                         zend_string_free(suser_stub);
    2629             :                 }
    2630             :         } else {
    2631             :                 size_t written;
    2632             : 
    2633        8880 :                 if (!user_stub && phar->halt_offset && oldfile && !phar->is_brandnew) {
    2634        4400 :                         php_stream_copy_to_stream_ex(oldfile, newfile, phar->halt_offset, &written);
    2635        4400 :                         newstub = NULL;
    2636             :                 } else {
    2637             :                         /* this is either a brand new phar or a default stub overwrite */
    2638          80 :                         newstub = phar_create_default_stub(NULL, NULL, &(phar->halt_offset), NULL TSRMLS_CC);
    2639          80 :                         written = php_stream_write(newfile, newstub, phar->halt_offset);
    2640             :                 }
    2641        4480 :                 if (phar->halt_offset != written) {
    2642           0 :                         if (closeoldfile) {
    2643           0 :                                 php_stream_close(oldfile);
    2644             :                         }
    2645           0 :                         php_stream_close(newfile);
    2646           0 :                         if (error) {
    2647           0 :                                 if (newstub) {
    2648           0 :                                         spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname);
    2649             :                                 } else {
    2650           0 :                                         spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname);
    2651             :                                 }
    2652             :                         }
    2653           0 :                         if (newstub) {
    2654           0 :                                 efree(newstub);
    2655             :                         }
    2656           0 :                         return EOF;
    2657             :                 }
    2658        4480 :                 if (newstub) {
    2659          80 :                         efree(newstub);
    2660             :                 }
    2661             :         }
    2662        4508 :         manifest_ftell = php_stream_tell(newfile);
    2663        4508 :         halt_offset = manifest_ftell;
    2664             : 
    2665             :         /* Check whether we can get rid of some of the deleted entries which are
    2666             :          * unused. However some might still be in use so even after this clean-up
    2667             :          * we need to skip entries marked is_deleted. */
    2668        4508 :         zend_hash_apply(&phar->manifest, phar_flush_clean_deleted_apply TSRMLS_CC);
    2669             : 
    2670             :         /* compress as necessary, calculate crcs, serialize meta-data, manifest size, and file sizes */
    2671        4508 :         main_metadata_str.s = NULL;
    2672        9016 :         if (Z_TYPE(phar->metadata) != IS_UNDEF) {
    2673          13 :                 PHP_VAR_SERIALIZE_INIT(metadata_hash);
    2674          13 :                 php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
    2675          13 :                 PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
    2676             :         }
    2677        4508 :         new_manifest_count = 0;
    2678        4508 :         offset = 0;
    2679       23395 :         for (zend_hash_internal_pointer_reset(&phar->manifest);
    2680       18887 :                 zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
    2681       14379 :                 zend_hash_move_forward(&phar->manifest)) {
    2682       28758 :                 if ((entry = zend_hash_get_current_data_ptr(&phar->manifest)) == NULL) {
    2683           0 :                         continue;
    2684             :                 }
    2685       14379 :                 if (entry->cfp) {
    2686             :                         /* did we forget to get rid of cfp last time? */
    2687           0 :                         php_stream_close(entry->cfp);
    2688           0 :                         entry->cfp = 0;
    2689             :                 }
    2690       14379 :                 if (entry->is_deleted || entry->is_mounted) {
    2691             :                         /* remove this from the new phar */
    2692           5 :                         continue;
    2693             :                 }
    2694       14374 :                 if (!entry->is_modified && entry->fp_refcount) {
    2695             :                         /* open file pointers refer to this fp, do not free the stream */
    2696           2 :                         switch (entry->fp_type) {
    2697             :                                 case PHAR_FP:
    2698           2 :                                         free_fp = 0;
    2699           2 :                                         break;
    2700             :                                 case PHAR_UFP:
    2701           0 :                                         free_ufp = 0;
    2702             :                                 default:
    2703             :                                         break;
    2704             :                         }
    2705             :                 }
    2706             :                 /* after excluding deleted files, calculate manifest size in bytes and number of entries */
    2707       14374 :                 ++new_manifest_count;
    2708       14374 :                 phar_add_virtual_dirs(phar, entry->filename, entry->filename_len TSRMLS_CC);
    2709             : 
    2710       14374 :                 if (entry->is_dir) {
    2711             :                         /* we use this to calculate API version, 1.1.1 is used for phars with directories */
    2712          27 :                         has_dirs = 1;
    2713             :                 }
    2714       28748 :                 if (Z_TYPE(entry->metadata) != IS_UNDEF) {
    2715          78 :                         if (entry->metadata_str.s) {
    2716          53 :                                 smart_str_free(&entry->metadata_str);
    2717             :                         }
    2718          78 :                         entry->metadata_str.s = NULL;
    2719          78 :                         PHP_VAR_SERIALIZE_INIT(metadata_hash);
    2720          78 :                         php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC);
    2721          78 :                         PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
    2722             :                 } else {
    2723       14296 :                         if (entry->metadata_str.s) {
    2724           2 :                                 smart_str_free(&entry->metadata_str);
    2725             :                         }
    2726       14296 :                         entry->metadata_str.s = NULL;
    2727             :                 }
    2728             : 
    2729             :                 /* 32 bits for filename length, length of filename, manifest + metadata, and add 1 for trailing / if a directory */
    2730       14374 :                 offset += 4 + entry->filename_len + sizeof(entry_buffer) + (entry->metadata_str.s ? entry->metadata_str.s->len : 0) + (entry->is_dir ? 1 : 0);
    2731             : 
    2732             :                 /* compress and rehash as necessary */
    2733       14374 :                 if ((oldfile && !entry->is_modified) || entry->is_dir) {
    2734        6848 :                         if (entry->fp_type == PHAR_UFP) {
    2735             :                                 /* reset so we can copy the compressed data over */
    2736           1 :                                 entry->fp_type = PHAR_FP;
    2737             :                         }
    2738        6848 :                         continue;
    2739             :                 }
    2740        7526 :                 if (!phar_get_efp(entry, 0 TSRMLS_CC)) {
    2741             :                         /* re-open internal file pointer just-in-time */
    2742           1 :                         newentry = phar_open_jit(phar, entry, error TSRMLS_CC);
    2743           1 :                         if (!newentry) {
    2744             :                                 /* major problem re-opening, so we ignore this file and the error */
    2745           1 :                                 efree(*error);
    2746           1 :                                 *error = NULL;
    2747           1 :                                 continue;
    2748             :                         }
    2749           0 :                         entry = newentry;
    2750             :                 }
    2751        7525 :                 file = phar_get_efp(entry, 0 TSRMLS_CC);
    2752        7525 :                 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
    2753           0 :                         if (closeoldfile) {
    2754           0 :                                 php_stream_close(oldfile);
    2755             :                         }
    2756           0 :                         php_stream_close(newfile);
    2757           0 :                         if (error) {
    2758           0 :                                 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
    2759             :                         }
    2760           0 :                         return EOF;
    2761             :                 }
    2762        7525 :                 newcrc32 = ~0;
    2763        7525 :                 mytime = entry->uncompressed_filesize;
    2764       98523 :                 for (loc = 0;loc < mytime; ++loc) {
    2765       90998 :                         CRC32(newcrc32, php_stream_getc(file));
    2766             :                 }
    2767        7525 :                 entry->crc32 = ~newcrc32;
    2768        7525 :                 entry->is_crc_checked = 1;
    2769        7525 :                 if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
    2770             :                         /* not compressed */
    2771        7494 :                         entry->compressed_filesize = entry->uncompressed_filesize;
    2772        7494 :                         continue;
    2773             :                 }
    2774          31 :                 filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
    2775          31 :                 if (!filter) {
    2776           0 :                         if (closeoldfile) {
    2777           0 :                                 php_stream_close(oldfile);
    2778             :                         }
    2779           0 :                         php_stream_close(newfile);
    2780           0 :                         if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
    2781           0 :                                 if (error) {
    2782           0 :                                         spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
    2783             :                                 }
    2784             :                         } else {
    2785           0 :                                 if (error) {
    2786           0 :                                         spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
    2787             :                                 }
    2788             :                         }
    2789           0 :                         return EOF;
    2790             :                 }
    2791             : 
    2792             :                 /* create new file that holds the compressed version */
    2793             :                 /* work around inability to specify freedom in write and strictness
    2794             :                 in read count */
    2795          31 :                 entry->cfp = php_stream_fopen_tmpfile();
    2796          31 :                 if (!entry->cfp) {
    2797           0 :                         if (error) {
    2798           0 :                                 spprintf(error, 0, "unable to create temporary file");
    2799             :                         }
    2800           0 :                         if (closeoldfile) {
    2801           0 :                                 php_stream_close(oldfile);
    2802             :                         }
    2803           0 :                         php_stream_close(newfile);
    2804           0 :                         return EOF;
    2805             :                 }
    2806          31 :                 php_stream_flush(file);
    2807          31 :                 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
    2808           0 :                         if (closeoldfile) {
    2809           0 :                                 php_stream_close(oldfile);
    2810             :                         }
    2811           0 :                         php_stream_close(newfile);
    2812           0 :                         if (error) {
    2813           0 :                                 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
    2814             :                         }
    2815           0 :                         return EOF;
    2816             :                 }
    2817          31 :                 php_stream_filter_append((&entry->cfp->writefilters), filter);
    2818          31 :                 if (SUCCESS != php_stream_copy_to_stream_ex(file, entry->cfp, entry->uncompressed_filesize, NULL)) {
    2819           0 :                         if (closeoldfile) {
    2820           0 :                                 php_stream_close(oldfile);
    2821             :                         }
    2822           0 :                         php_stream_close(newfile);
    2823           0 :                         if (error) {
    2824           0 :                                 spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
    2825             :                         }
    2826           0 :                         return EOF;
    2827             :                 }
    2828          31 :                 php_stream_filter_flush(filter, 1);
    2829          31 :                 php_stream_flush(entry->cfp);
    2830          31 :                 php_stream_filter_remove(filter, 1 TSRMLS_CC);
    2831          31 :                 php_stream_seek(entry->cfp, 0, SEEK_END);
    2832          31 :                 entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp);
    2833             :                 /* generate crc on compressed file */
    2834          31 :                 php_stream_rewind(entry->cfp);
    2835          31 :                 entry->old_flags = entry->flags;
    2836          31 :                 entry->is_modified = 1;
    2837          31 :                 global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK);
    2838             :         }
    2839        4508 :         global_flags |= PHAR_HDR_SIGNATURE;
    2840             : 
    2841             :         /* write out manifest pre-header */
    2842             :         /*  4: manifest length
    2843             :          *  4: manifest entry count
    2844             :          *  2: phar version
    2845             :          *  4: phar global flags
    2846             :          *  4: alias length
    2847             :          *  ?: the alias itself
    2848             :          *  4: phar metadata length
    2849             :          *  ?: phar metadata
    2850             :          */
    2851        4508 :         restore_alias_len = phar->alias_len;
    2852        4508 :         if (phar->is_temporary_alias) {
    2853         304 :                 phar->alias_len = 0;
    2854             :         }
    2855             : 
    2856        4508 :         manifest_len = offset + phar->alias_len + sizeof(manifest) + (main_metadata_str.s ? main_metadata_str.s->len : 0);
    2857        4508 :         phar_set_32(manifest, manifest_len);
    2858             :         /* Hack - see bug #65028, add padding byte to the end of the manifest */
    2859        4508 :         if(manifest[0] == '\r' || manifest[0] == '\n') {
    2860           3 :                 manifest_len++;
    2861           3 :                 phar_set_32(manifest, manifest_len);
    2862           3 :                 manifest_hack = 1;
    2863             :         }
    2864        4508 :         phar_set_32(manifest+4, new_manifest_count);
    2865        4508 :         if (has_dirs) {
    2866          26 :                 *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
    2867          26 :                 *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
    2868             :         } else {
    2869        4482 :                 *(manifest + 8) = (unsigned char) (((PHAR_API_VERSION_NODIR) >> 8) & 0xFF);
    2870        4482 :                 *(manifest + 9) = (unsigned char) (((PHAR_API_VERSION_NODIR) & 0xF0));
    2871             :         }
    2872        4508 :         phar_set_32(manifest+10, global_flags);
    2873        4508 :         phar_set_32(manifest+14, phar->alias_len);
    2874             : 
    2875             :         /* write the manifest header */
    2876        9016 :         if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest))
    2877        9016 :         || (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) {
    2878             : 
    2879           0 :                 if (closeoldfile) {
    2880           0 :                         php_stream_close(oldfile);
    2881             :                 }
    2882             : 
    2883           0 :                 php_stream_close(newfile);
    2884           0 :                 phar->alias_len = restore_alias_len;
    2885             : 
    2886           0 :                 if (error) {
    2887           0 :                         spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
    2888             :                 }
    2889             : 
    2890           0 :                 return EOF;
    2891             :         }
    2892             : 
    2893        4508 :         phar->alias_len = restore_alias_len;
    2894             : 
    2895        4508 :         phar_set_32(manifest, main_metadata_str.s ? main_metadata_str.s->len : 0);
    2896        4521 :         if (4 != php_stream_write(newfile, manifest, 4) || ((main_metadata_str.s ? main_metadata_str.s->len : 0)
    2897          13 :         && main_metadata_str.s->len != php_stream_write(newfile, main_metadata_str.s->val, main_metadata_str.s->len))) {
    2898             :                 smart_str_free(&main_metadata_str);
    2899             : 
    2900           0 :                 if (closeoldfile) {
    2901           0 :                         php_stream_close(oldfile);
    2902             :                 }
    2903             : 
    2904           0 :                 php_stream_close(newfile);
    2905           0 :                 phar->alias_len = restore_alias_len;
    2906             : 
    2907           0 :                 if (error) {
    2908           0 :                         spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
    2909             :                 }
    2910             : 
    2911           0 :                 return EOF;
    2912             :         }
    2913             :         smart_str_free(&main_metadata_str);
    2914             : 
    2915             :         /* re-calculate the manifest location to simplify later code */
    2916        4508 :         manifest_ftell = php_stream_tell(newfile);
    2917             : 
    2918             :         /* now write the manifest */
    2919       23395 :         for (zend_hash_internal_pointer_reset(&phar->manifest);
    2920       18887 :                 zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
    2921       14379 :                 zend_hash_move_forward(&phar->manifest)) {
    2922             : 
    2923       28758 :                 if ((entry = zend_hash_get_current_data_ptr(&phar->manifest)) == NULL) {
    2924           0 :                         continue;
    2925             :                 }
    2926             : 
    2927       14379 :                 if (entry->is_deleted || entry->is_mounted) {
    2928             :                         /* remove this from the new phar if deleted, ignore if mounted */
    2929           5 :                         continue;
    2930             :                 }
    2931             : 
    2932       14374 :                 if (entry->is_dir) {
    2933             :                         /* add 1 for trailing slash */
    2934          27 :                         phar_set_32(entry_buffer, entry->filename_len + 1);
    2935             :                 } else {
    2936       14347 :                         phar_set_32(entry_buffer, entry->filename_len);
    2937             :                 }
    2938             : 
    2939       43149 :                 if (4 != php_stream_write(newfile, entry_buffer, 4)
    2940       43122 :                 || entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len)
    2941       57523 :                 || (entry->is_dir && 1 != php_stream_write(newfile, "/", 1))) {
    2942           0 :                         if (closeoldfile) {
    2943           0 :                                 php_stream_close(oldfile);
    2944             :                         }
    2945           0 :                         php_stream_close(newfile);
    2946           0 :                         if (error) {
    2947           0 :                                 if (entry->is_dir) {
    2948           0 :                                         spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
    2949             :                                 } else {
    2950           0 :                                         spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
    2951             :                                 }
    2952             :                         }
    2953           0 :                         return EOF;
    2954             :                 }
    2955             : 
    2956             :                 /* set the manifest meta-data:
    2957             :                         4: uncompressed filesize
    2958             :                         4: creation timestamp
    2959             :                         4: compressed filesize
    2960             :                         4: crc32
    2961             :                         4: flags
    2962             :                         4: metadata-len
    2963             :                         +: metadata
    2964             :                 */
    2965       14374 :                 mytime = time(NULL);
    2966       14374 :                 phar_set_32(entry_buffer, entry->uncompressed_filesize);
    2967       14374 :                 phar_set_32(entry_buffer+4, mytime);
    2968       14374 :                 phar_set_32(entry_buffer+8, entry->compressed_filesize);
    2969       14374 :                 phar_set_32(entry_buffer+12, entry->crc32);
    2970       14374 :                 phar_set_32(entry_buffer+16, entry->flags);
    2971       14374 :                 phar_set_32(entry_buffer+20, entry->metadata_str.s ? entry->metadata_str.s->len : 0);
    2972             : 
    2973       28826 :                 if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer))
    2974       28748 :                 || (entry->metadata_str.s &&
    2975          78 :                     entry->metadata_str.s->len != php_stream_write(newfile, entry->metadata_str.s->val, entry->metadata_str.s->len))) {
    2976           0 :                         if (closeoldfile) {
    2977           0 :                                 php_stream_close(oldfile);
    2978             :                         }
    2979             : 
    2980           0 :                         php_stream_close(newfile);
    2981             : 
    2982           0 :                         if (error) {
    2983           0 :                                 spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
    2984             :                         }
    2985             : 
    2986           0 :                         return EOF;
    2987             :                 }
    2988             :         }
    2989             :         /* Hack - see bug #65028, add padding byte to the end of the manifest */
    2990        4508 :         if(manifest_hack) {
    2991           3 :                 if(1 != php_stream_write(newfile, manifest, 1)) {
    2992           0 :                         if (closeoldfile) {
    2993           0 :                                 php_stream_close(oldfile);
    2994             :                         }
    2995             : 
    2996           0 :                         php_stream_close(newfile);
    2997             : 
    2998           0 :                         if (error) {
    2999           0 :                                 spprintf(error, 0, "unable to write manifest padding byte");
    3000             :                         }
    3001             : 
    3002           0 :                         return EOF;
    3003             :                 }
    3004             :         }
    3005             : 
    3006             :         /* now copy the actual file data to the new phar */
    3007        4508 :         offset = php_stream_tell(newfile);
    3008       23393 :         for (zend_hash_internal_pointer_reset(&phar->manifest);
    3009       18885 :                 zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
    3010       14377 :                 zend_hash_move_forward(&phar->manifest)) {
    3011             : 
    3012       28756 :                 if ((entry = zend_hash_get_current_data_ptr(&phar->manifest)) == NULL) {
    3013           0 :                         continue;
    3014             :                 }
    3015             : 
    3016       14378 :                 if (entry->is_deleted || entry->is_dir || entry->is_mounted) {
    3017          32 :                         continue;
    3018             :                 }
    3019             : 
    3020       14346 :                 if (entry->cfp) {
    3021          31 :                         file = entry->cfp;
    3022          31 :                         php_stream_rewind(file);
    3023             :                 } else {
    3024       14315 :                         file = phar_get_efp(entry, 0 TSRMLS_CC);
    3025       14315 :                         if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
    3026           1 :                                 if (closeoldfile) {
    3027           0 :                                         php_stream_close(oldfile);
    3028             :                                 }
    3029           1 :                                 php_stream_close(newfile);
    3030           1 :                                 if (error) {
    3031           1 :                                         spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
    3032             :                                 }
    3033           1 :                                 return EOF;
    3034             :                         }
    3035             :                 }
    3036             : 
    3037       14345 :                 if (!file) {
    3038           0 :                         if (closeoldfile) {
    3039           0 :                                 php_stream_close(oldfile);
    3040             :                         }
    3041           0 :                         php_stream_close(newfile);
    3042           0 :                         if (error) {
    3043           0 :                                 spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
    3044             :                         }
    3045           0 :                         return EOF;
    3046             :                 }
    3047             : 
    3048             :                 /* this will have changed for all files that have either changed compression or been modified */
    3049       14345 :                 entry->offset = entry->offset_abs = offset;
    3050       14345 :                 offset += entry->compressed_filesize;
    3051       14345 :                 if (php_stream_copy_to_stream_ex(file, newfile, entry->compressed_filesize, &wrote) == FAILURE) {
    3052           0 :                         if (closeoldfile) {
    3053           0 :                                 php_stream_close(oldfile);
    3054             :                         }
    3055             : 
    3056           0 :                         php_stream_close(newfile);
    3057             : 
    3058           0 :                         if (error) {
    3059           0 :                                 spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
    3060             :                         }
    3061             : 
    3062           0 :                         return EOF;
    3063             :                 }
    3064             : 
    3065       14345 :                 entry->is_modified = 0;
    3066             : 
    3067       14345 :                 if (entry->cfp) {
    3068          31 :                         php_stream_close(entry->cfp);
    3069          31 :                         entry->cfp = NULL;
    3070             :                 }
    3071             : 
    3072       14345 :                 if (entry->fp_type == PHAR_MOD) {
    3073             :                         /* this fp is in use by a phar_entry_data returned by phar_get_entry_data, it will be closed when the phar_entry_data is phar_entry_delref'ed */
    3074        4342 :                         if (entry->fp_refcount == 0 && entry->fp != phar->fp && entry->fp != phar->ufp) {
    3075        4306 :                                 php_stream_close(entry->fp);
    3076             :                         }
    3077             : 
    3078        4342 :                         entry->fp = NULL;
    3079        4342 :                         entry->fp_type = PHAR_FP;
    3080       10003 :                 } else if (entry->fp_type == PHAR_UFP) {
    3081        3092 :                         entry->fp_type = PHAR_FP;
    3082             :                 }
    3083             :         }
    3084             : 
    3085             :         /* append signature */
    3086        4507 :         if (global_flags & PHAR_HDR_SIGNATURE) {
    3087             :                 char sig_buf[4];
    3088             : 
    3089        4507 :                 php_stream_rewind(newfile);
    3090             : 
    3091        4507 :                 if (phar->signature) {
    3092        4390 :                         efree(phar->signature);
    3093        4390 :                         phar->signature = NULL;
    3094             :                 }
    3095             : 
    3096        4507 :                 switch(phar->sig_flags) {
    3097             : #ifndef PHAR_HASH_OK
    3098             :                         case PHAR_SIG_SHA512:
    3099             :                         case PHAR_SIG_SHA256:
    3100             :                                 if (closeoldfile) {
    3101             :                                         php_stream_close(oldfile);
    3102             :                                 }
    3103             :                                 php_stream_close(newfile);
    3104             :                                 if (error) {
    3105             :                                         spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
    3106             :                                 }
    3107             :                                 return EOF;
    3108             : #endif
    3109             :                         default: {
    3110        4507 :                                 char *digest = NULL;
    3111             :                                 int digest_len;
    3112             : 
    3113        4507 :                                 if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, error TSRMLS_CC)) {
    3114           0 :                                         if (error) {
    3115           0 :                                                 char *save = *error;
    3116           0 :                                                 spprintf(error, 0, "phar error: unable to write signature: %s", save);
    3117           0 :                                                 efree(save);
    3118             :                                         }
    3119           0 :                                         if (digest) {
    3120           0 :                                                 efree(digest);
    3121             :                                         }
    3122           0 :                                         if (closeoldfile) {
    3123           0 :                                                 php_stream_close(oldfile);
    3124             :                                         }
    3125           0 :                                         php_stream_close(newfile);
    3126           0 :                                         return EOF;
    3127             :                                 }
    3128             : 
    3129        4507 :                                 php_stream_write(newfile, digest, digest_len);
    3130        4507 :                                 efree(digest);
    3131        4507 :                                 if (phar->sig_flags == PHAR_SIG_OPENSSL) {
    3132           1 :                                         phar_set_32(sig_buf, digest_len);
    3133           1 :                                         php_stream_write(newfile, sig_buf, 4);
    3134             :                                 }
    3135             :                                 break;
    3136             :                         }
    3137             :                 }
    3138        4507 :                 phar_set_32(sig_buf, phar->sig_flags);
    3139        4507 :                 php_stream_write(newfile, sig_buf, 4);
    3140        4507 :                 php_stream_write(newfile, "GBMB", 4);
    3141             :         }
    3142             : 
    3143             :         /* finally, close the temp file, rename the original phar,
    3144             :            move the temp to the old phar, unlink the old phar, and reload it into memory
    3145             :         */
    3146        4507 :         if (phar->fp && free_fp) {
    3147        4432 :                 php_stream_close(phar->fp);
    3148             :         }
    3149             : 
    3150        4507 :         if (phar->ufp) {
    3151          17 :                 if (free_ufp) {
    3152          17 :                         php_stream_close(phar->ufp);
    3153             :                 }
    3154          17 :                 phar->ufp = NULL;
    3155             :         }
    3156             : 
    3157        4507 :         if (closeoldfile) {
    3158          15 :                 php_stream_close(oldfile);
    3159             :         }
    3160             : 
    3161        4507 :         phar->internal_file_start = halt_offset + manifest_len + 4;
    3162        4507 :         phar->halt_offset = halt_offset;
    3163        4507 :         phar->is_brandnew = 0;
    3164             : 
    3165        4507 :         php_stream_rewind(newfile);
    3166             : 
    3167        4507 :         if (phar->donotflush) {
    3168             :                 /* deferred flush */
    3169          12 :                 phar->fp = newfile;
    3170             :         } else {
    3171        4495 :                 phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
    3172        4495 :                 if (!phar->fp) {
    3173           0 :                         phar->fp = newfile;
    3174           0 :                         if (error) {
    3175           0 :                                 spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
    3176             :                         }
    3177           0 :                         return EOF;
    3178             :                 }
    3179             : 
    3180        4495 :                 if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
    3181             :                         /* to properly compress, we have to tell zlib to add a zlib header */
    3182             :                         zval filterparams;
    3183             : 
    3184           5 :                         array_init(&filterparams);
    3185           5 :                         add_assoc_long(&filterparams, "window", MAX_WBITS+16);
    3186           5 :                         filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp) TSRMLS_CC);
    3187             :                         zval_dtor(&filterparams);
    3188             : 
    3189           5 :                         if (!filter) {
    3190           0 :                                 if (error) {
    3191           0 :                                         spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname);
    3192             :                                 }
    3193           0 :                                 return EOF;
    3194             :                         }
    3195             : 
    3196           5 :                         php_stream_filter_append(&phar->fp->writefilters, filter);
    3197           5 :                         php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
    3198           5 :                         php_stream_filter_flush(filter, 1);
    3199           5 :                         php_stream_filter_remove(filter, 1 TSRMLS_CC);
    3200           5 :                         php_stream_close(phar->fp);
    3201             :                         /* use the temp stream as our base */
    3202           5 :                         phar->fp = newfile;
    3203        4490 :                 } else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
    3204           3 :                         filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp) TSRMLS_CC);
    3205           3 :                         php_stream_filter_append(&phar->fp->writefilters, filter);
    3206           3 :                         php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
    3207           3 :                         php_stream_filter_flush(filter, 1);
    3208           3 :                         php_stream_filter_remove(filter, 1 TSRMLS_CC);
    3209           3 :                         php_stream_close(phar->fp);
    3210             :                         /* use the temp stream as our base */
    3211           3 :                         phar->fp = newfile;
    3212             :                 } else {
    3213        4487 :                         php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
    3214             :                         /* we could also reopen the file in "rb" mode but there is no need for that */
    3215        4487 :                         php_stream_close(newfile);
    3216             :                 }
    3217             :         }
    3218             : 
    3219        4507 :         if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) {
    3220           0 :                 if (error) {
    3221           0 :                         spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname);
    3222             :                 }
    3223           0 :                 return EOF;
    3224             :         }
    3225             : 
    3226        4507 :         return EOF;
    3227             : }
    3228             : /* }}} */
    3229             : 
    3230             : #ifdef COMPILE_DL_PHAR
    3231             : ZEND_GET_MODULE(phar)
    3232             : #endif
    3233             : 
    3234             : /* {{{ phar_functions[]
    3235             :  *
    3236             :  * Every user visible function must have an entry in phar_functions[].
    3237             :  */
    3238             : zend_function_entry phar_functions[] = {
    3239             :         PHP_FE_END
    3240             : };
    3241             : /* }}}*/
    3242             : 
    3243           4 : static size_t phar_zend_stream_reader(void *handle, char *buf, size_t len TSRMLS_DC) /* {{{ */
    3244             : {
    3245           4 :         return php_stream_read(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC), buf, len);
    3246             : }
    3247             : /* }}} */
    3248             : 
    3249           2 : static size_t phar_zend_stream_fsizer(void *handle TSRMLS_DC) /* {{{ */
    3250             : {
    3251           2 :         return ((phar_archive_data*)handle)->halt_offset + 32;
    3252             : } /* }}} */
    3253             : 
    3254             : zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
    3255             : #define phar_orig_zend_open zend_stream_open_function
    3256             : 
    3257       15428 : static char *phar_resolve_path(const char *filename, int filename_len TSRMLS_DC)
    3258             : {
    3259       15428 :         return phar_find_in_include_path((char *) filename, filename_len, NULL TSRMLS_CC);
    3260             : }
    3261             : 
    3262       28613 : static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) /* {{{ */
    3263             : {
    3264             :         zend_op_array *res;
    3265       28613 :         char *name = NULL;
    3266             :         int failed;
    3267             :         phar_archive_data *phar;
    3268             : 
    3269       28613 :         if (!file_handle || !file_handle->filename) {
    3270           0 :                 return phar_orig_compile_file(file_handle, type TSRMLS_CC);
    3271             :         }
    3272       28613 :         if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, "://")) {
    3273         178 :                 if (SUCCESS == phar_open_from_filename((char*)file_handle->filename, strlen(file_handle->filename), NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
    3274         157 :                         if (phar->is_zip || phar->is_tar) {
    3275          53 :                                 zend_file_handle f = *file_handle;
    3276             : 
    3277             :                                 /* zip or tar-based phar */
    3278          53 :                                 spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php");
    3279          53 :                                 if (SUCCESS == phar_orig_zend_open((const char *)name, file_handle TSRMLS_CC)) {
    3280          52 :                                         efree(name);
    3281          52 :                                         name = NULL;
    3282          52 :                                         file_handle->filename = f.filename;
    3283          52 :                                         if (file_handle->opened_path) {
    3284          52 :                                                 efree(file_handle->opened_path);
    3285             :                                         }
    3286          52 :                                         file_handle->opened_path = f.opened_path;
    3287          52 :                                         file_handle->free_filename = f.free_filename;
    3288             :                                 } else {
    3289           1 :                                         *file_handle = f;
    3290             :                                 }
    3291          51 :                         } else if (phar->flags & PHAR_FILE_COMPRESSION_MASK) {
    3292             :                                 /* compressed phar */
    3293           2 :                                 file_handle->type = ZEND_HANDLE_STREAM;
    3294             :                                 /* we do our own reading directly from the phar, don't change the next line */
    3295           2 :                                 file_handle->handle.stream.handle  = phar;
    3296           2 :                                 file_handle->handle.stream.reader  = phar_zend_stream_reader;
    3297           2 :                                 file_handle->handle.stream.closer  = NULL;
    3298           2 :                                 file_handle->handle.stream.fsizer  = phar_zend_stream_fsizer;
    3299           2 :                                 file_handle->handle.stream.isatty  = 0;
    3300           4 :                                 phar->is_persistent ?
    3301           0 :                                         php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
    3302           2 :                                         php_stream_rewind(phar->fp);
    3303           2 :                                 memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
    3304             :                         }
    3305             :                 }
    3306             :         }
    3307             : 
    3308       28613 :         zend_try {
    3309       28613 :                 failed = 0;
    3310       28613 :                 CG(zend_lineno) = 0;
    3311       28613 :                 res = phar_orig_compile_file(file_handle, type TSRMLS_CC);
    3312         224 :         } zend_catch {
    3313         224 :                 failed = 1;
    3314         224 :                 res = NULL;
    3315       28613 :         } zend_end_try();
    3316             : 
    3317       28613 :         if (name) {
    3318           1 :                 efree(name);
    3319             :         }
    3320             : 
    3321       28613 :         if (failed) {
    3322         224 :                 zend_bailout();
    3323             :         }
    3324             : 
    3325       28389 :         return res;
    3326             : }
    3327             : /* }}} */
    3328             : 
    3329             : typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int TSRMLS_DC);
    3330             : typedef zend_compile_t* (compile_hook)(zend_compile_t *ptr);
    3331             : 
    3332      821640 : static void mime_type_dtor(zval *zv)
    3333             : {
    3334      821640 :         free(Z_PTR_P(zv));
    3335      821640 : }
    3336             : 
    3337       20507 : PHP_GINIT_FUNCTION(phar) /* {{{ */
    3338             : {
    3339             :         phar_mime_type mime;
    3340             : 
    3341       20507 :         memset(phar_globals, 0, sizeof(zend_phar_globals));
    3342       20507 :         phar_globals->readonly = 1;
    3343             : 
    3344       20507 :         zend_hash_init(&phar_globals->mime_types, 0, NULL, mime_type_dtor, 1);
    3345             : 
    3346             : #define PHAR_SET_MIME(mimetype, ret, fileext) \
    3347             :                 mime.mime = mimetype; \
    3348             :                 mime.len = sizeof((mimetype))+1; \
    3349             :                 mime.type = ret; \
    3350             :                 zend_hash_str_add_mem(&phar_globals->mime_types, fileext, sizeof(fileext)-1, (void *)&mime, sizeof(phar_mime_type)); \
    3351             : 
    3352       20507 :         PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
    3353       20507 :         PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c")
    3354       20507 :         PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc")
    3355       20507 :         PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp")
    3356       20507 :         PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++")
    3357       20507 :         PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd")
    3358       20507 :         PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h")
    3359       20507 :         PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log")
    3360       20507 :         PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng")
    3361       20507 :         PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt")
    3362       20507 :         PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd")
    3363       20507 :         PHAR_SET_MIME("", PHAR_MIME_PHP, "php")
    3364       20507 :         PHAR_SET_MIME("", PHAR_MIME_PHP, "inc")
    3365       20507 :         PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
    3366       20507 :         PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
    3367       20507 :         PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
    3368       20507 :         PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
    3369       20507 :         PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm")
    3370       20507 :         PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html")
    3371       20507 :         PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls")
    3372       20507 :         PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
    3373       20507 :         PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe")
    3374       20507 :         PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg")
    3375       20507 :         PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg")
    3376       20507 :         PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
    3377       20507 :         PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi")
    3378       20507 :         PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid")
    3379       20507 :         PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
    3380       20507 :         PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
    3381       20507 :         PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
    3382       20507 :         PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg")
    3383       20507 :         PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpeg")
    3384       20507 :         PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
    3385       20507 :         PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
    3386       20507 :         PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
    3387       20507 :         PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif")
    3388       20507 :         PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tiff")
    3389       20507 :         PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
    3390       20507 :         PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
    3391       20507 :         PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
    3392             : 
    3393       20507 :         phar_restore_orig_functions(TSRMLS_C);
    3394       20507 : }
    3395             : /* }}} */
    3396             : 
    3397       20541 : PHP_GSHUTDOWN_FUNCTION(phar) /* {{{ */
    3398             : {
    3399       20541 :         zend_hash_destroy(&phar_globals->mime_types);
    3400       20541 : }
    3401             : /* }}} */
    3402             : 
    3403       20507 : PHP_MINIT_FUNCTION(phar) /* {{{ */
    3404             : {
    3405       20507 :         REGISTER_INI_ENTRIES();
    3406             : 
    3407       20507 :         phar_orig_compile_file = zend_compile_file;
    3408       20507 :         zend_compile_file = phar_compile_file;
    3409             : 
    3410       20507 :         phar_save_resolve_path = zend_resolve_path;
    3411       20507 :         zend_resolve_path = phar_resolve_path;
    3412             : 
    3413       20507 :         phar_object_init(TSRMLS_C);
    3414             : 
    3415       20507 :         phar_intercept_functions_init(TSRMLS_C);
    3416       20507 :         phar_save_orig_functions(TSRMLS_C);
    3417             : 
    3418       20507 :         return php_register_url_stream_wrapper("phar", &php_stream_phar_wrapper TSRMLS_CC);
    3419             : }
    3420             : /* }}} */
    3421             : 
    3422       20541 : PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */
    3423             : {
    3424       20541 :         php_unregister_url_stream_wrapper("phar" TSRMLS_CC);
    3425             : 
    3426       20541 :         phar_intercept_functions_shutdown(TSRMLS_C);
    3427             : 
    3428       20541 :         if (zend_compile_file == phar_compile_file) {
    3429       20541 :                 zend_compile_file = phar_orig_compile_file;
    3430             :         }
    3431             : 
    3432       20541 :         if (PHAR_G(manifest_cached)) {
    3433           3 :                 zend_hash_destroy(&(cached_phars));
    3434           3 :                 zend_hash_destroy(&(cached_alias));
    3435             :         }
    3436             : 
    3437       20541 :         return SUCCESS;
    3438             : }
    3439             : /* }}} */
    3440             : 
    3441       25700 : void phar_request_initialize(TSRMLS_D) /* {{{ */
    3442             : {
    3443       25700 :         if (!PHAR_GLOBALS->request_init)
    3444             :         {
    3445         553 :                 PHAR_G(last_phar) = NULL;
    3446         553 :                 PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
    3447         553 :                 PHAR_G(has_bz2) = zend_hash_str_exists(&module_registry, "bz2", sizeof("bz2")-1);
    3448         553 :                 PHAR_G(has_zlib) = zend_hash_str_exists(&module_registry, "zlib", sizeof("zlib")-1);
    3449         553 :                 PHAR_GLOBALS->request_init = 1;
    3450         553 :                 PHAR_GLOBALS->request_ends = 0;
    3451         553 :                 PHAR_GLOBALS->request_done = 0;
    3452         553 :                 zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), 5, zend_get_hash_value, destroy_phar_data,  0);
    3453         553 :                 zend_hash_init(&(PHAR_GLOBALS->phar_persist_map), 5, zend_get_hash_value, NULL,  0);
    3454         553 :                 zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), 5, zend_get_hash_value, NULL, 0);
    3455             : 
    3456         553 :                 if (PHAR_G(manifest_cached)) {
    3457             :                         phar_archive_data *pphar;
    3458           3 :                         phar_entry_fp *stuff = (phar_entry_fp *) ecalloc(zend_hash_num_elements(&cached_phars), sizeof(phar_entry_fp));
    3459             : 
    3460           9 :                         for (zend_hash_internal_pointer_reset(&cached_phars);
    3461             :                         (pphar = zend_hash_get_current_data_ptr(&cached_phars)) != NULL;
    3462           3 :                         zend_hash_move_forward(&cached_phars)) {
    3463           3 :                                 stuff[pphar->phar_pos].manifest = (phar_entry_fp_info *) ecalloc( zend_hash_num_elements(&(pphar->manifest)), sizeof(phar_entry_fp_info));
    3464             :                         }
    3465             : 
    3466           3 :                         PHAR_GLOBALS->cached_fp = stuff;
    3467             :                 }
    3468             : 
    3469         553 :                 PHAR_GLOBALS->phar_SERVER_mung_list = 0;
    3470         553 :                 PHAR_G(cwd) = NULL;
    3471         553 :                 PHAR_G(cwd_len) = 0;
    3472         553 :                 PHAR_G(cwd_init) = 0;
    3473             :         }
    3474       25700 : }
    3475             : /* }}} */
    3476             : 
    3477       20500 : PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
    3478             : {
    3479             :         int i;
    3480             : 
    3481       20500 :         PHAR_GLOBALS->request_ends = 1;
    3482             : 
    3483       20500 :         if (PHAR_GLOBALS->request_init)
    3484             :         {
    3485         553 :                 phar_release_functions(TSRMLS_C);
    3486         553 :                 zend_hash_destroy(&(PHAR_GLOBALS->phar_alias_map));
    3487         553 :                 PHAR_GLOBALS->phar_alias_map.arHash = NULL;
    3488         553 :                 zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
    3489         553 :                 PHAR_GLOBALS->phar_fname_map.arHash = NULL;
    3490         553 :                 zend_hash_destroy(&(PHAR_GLOBALS->phar_persist_map));
    3491         553 :                 PHAR_GLOBALS->phar_persist_map.arHash = NULL;
    3492         553 :                 PHAR_GLOBALS->phar_SERVER_mung_list = 0;
    3493             : 
    3494         553 :                 if (PHAR_GLOBALS->cached_fp) {
    3495           6 :                         for (i = 0; i < zend_hash_num_elements(&cached_phars); ++i) {
    3496           3 :                                 if (PHAR_GLOBALS->cached_fp[i].fp) {
    3497           1 :                                         php_stream_close(PHAR_GLOBALS->cached_fp[i].fp);
    3498             :                                 }
    3499           3 :                                 if (PHAR_GLOBALS->cached_fp[i].ufp) {
    3500           0 :                                         php_stream_close(PHAR_GLOBALS->cached_fp[i].ufp);
    3501             :                                 }
    3502           3 :                                 efree(PHAR_GLOBALS->cached_fp[i].manifest);
    3503             :                         }
    3504           3 :                         efree(PHAR_GLOBALS->cached_fp);
    3505           3 :                         PHAR_GLOBALS->cached_fp = 0;
    3506             :                 }
    3507             : 
    3508         553 :                 PHAR_GLOBALS->request_init = 0;
    3509             : 
    3510         553 :                 if (PHAR_G(cwd)) {
    3511          26 :                         efree(PHAR_G(cwd));
    3512             :                 }
    3513             : 
    3514         553 :                 PHAR_G(cwd) = NULL;
    3515         553 :                 PHAR_G(cwd_len) = 0;
    3516         553 :                 PHAR_G(cwd_init) = 0;
    3517             :         }
    3518             : 
    3519       20500 :         PHAR_GLOBALS->request_done = 1;
    3520       20500 :         return SUCCESS;
    3521             : }
    3522             : /* }}} */
    3523             : 
    3524         143 : PHP_MINFO_FUNCTION(phar) /* {{{ */
    3525             : {
    3526         143 :         phar_request_initialize(TSRMLS_C);
    3527         143 :         php_info_print_table_start();
    3528         143 :         php_info_print_table_header(2, "Phar: PHP Archive support", "enabled");
    3529         143 :         php_info_print_table_row(2, "Phar EXT version", PHP_PHAR_VERSION);
    3530         143 :         php_info_print_table_row(2, "Phar API version", PHP_PHAR_API_VERSION);
    3531         143 :         php_info_print_table_row(2, "SVN revision", "$Id: 0903f6c952f364820a926dbbc5fd070f9ad1920f $");
    3532         143 :         php_info_print_table_row(2, "Phar-based phar archives", "enabled");
    3533         143 :         php_info_print_table_row(2, "Tar-based phar archives", "enabled");
    3534         143 :         php_info_print_table_row(2, "ZIP-based phar archives", "enabled");
    3535             : 
    3536         143 :         if (PHAR_G(has_zlib)) {
    3537         143 :                 php_info_print_table_row(2, "gzip compression", "enabled");
    3538             :         } else {
    3539           0 :                 php_info_print_table_row(2, "gzip compression", "disabled (install ext/zlib)");
    3540             :         }
    3541             : 
    3542         143 :         if (PHAR_G(has_bz2)) {
    3543         143 :                 php_info_print_table_row(2, "bzip2 compression", "enabled");
    3544             :         } else {
    3545           0 :                 php_info_print_table_row(2, "bzip2 compression", "disabled (install pecl/bz2)");
    3546             :         }
    3547             : #ifdef PHAR_HAVE_OPENSSL
    3548         143 :         php_info_print_table_row(2, "Native OpenSSL support", "enabled");
    3549             : #else
    3550             :         if (zend_hash_str_exists(&module_registry, "openssl", sizeof("openssl")-1)) {
    3551             :                 php_info_print_table_row(2, "OpenSSL support", "enabled");
    3552             :         } else {
    3553             :                 php_info_print_table_row(2, "OpenSSL support", "disabled (install ext/openssl)");
    3554             :         }
    3555             : #endif
    3556         143 :         php_info_print_table_end();
    3557             : 
    3558         143 :         php_info_print_box_start(0);
    3559         143 :         PUTS("Phar based on pear/PHP_Archive, original concept by Davey Shafik.");
    3560         143 :         PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
    3561         143 :         PUTS("Phar fully realized by Gregory Beaver and Marcus Boerger.");
    3562         143 :         PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
    3563         143 :         PUTS("Portions of tar implementation Copyright (c) 2003-2009 Tim Kientzle.");
    3564         143 :         php_info_print_box_end();
    3565             : 
    3566         143 :         DISPLAY_INI_ENTRIES();
    3567         143 : }
    3568             : /* }}} */
    3569             : 
    3570             : /* {{{ phar_module_entry
    3571             :  */
    3572             : static const zend_module_dep phar_deps[] = {
    3573             :         ZEND_MOD_OPTIONAL("apc")
    3574             :         ZEND_MOD_OPTIONAL("bz2")
    3575             :         ZEND_MOD_OPTIONAL("openssl")
    3576             :         ZEND_MOD_OPTIONAL("zlib")
    3577             :         ZEND_MOD_OPTIONAL("standard")
    3578             : #if defined(HAVE_HASH) && !defined(COMPILE_DL_HASH)
    3579             :         ZEND_MOD_REQUIRED("hash")
    3580             : #endif
    3581             : #if HAVE_SPL
    3582             :         ZEND_MOD_REQUIRED("spl")
    3583             : #endif
    3584             :         ZEND_MOD_END
    3585             : };
    3586             : 
    3587             : zend_module_entry phar_module_entry = {
    3588             :         STANDARD_MODULE_HEADER_EX, NULL,
    3589             :         phar_deps,
    3590             :         "Phar",
    3591             :         phar_functions,
    3592             :         PHP_MINIT(phar),
    3593             :         PHP_MSHUTDOWN(phar),
    3594             :         NULL,
    3595             :         PHP_RSHUTDOWN(phar),
    3596             :         PHP_MINFO(phar),
    3597             :         PHP_PHAR_VERSION,
    3598             :         PHP_MODULE_GLOBALS(phar),   /* globals descriptor */
    3599             :         PHP_GINIT(phar),            /* globals ctor */
    3600             :         PHP_GSHUTDOWN(phar),        /* globals dtor */
    3601             :         NULL,                       /* post deactivate */
    3602             :         STANDARD_MODULE_PROPERTIES_EX
    3603             : };
    3604             : /* }}} */
    3605             : 
    3606             : /*
    3607             :  * Local variables:
    3608             :  * tab-width: 4
    3609             :  * c-basic-offset: 4
    3610             :  * End:
    3611             :  * vim600: noet sw=4 ts=4 fdm=marker
    3612             :  * vim<600: noet sw=4 ts=4
    3613             :  */

Generated by: LCOV version 1.10

Generated at Sat, 22 Nov 2014 23:01:21 +0000 (3 days ago)

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