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

Generated by: LCOV version 1.10

Generated at Sat, 23 May 2015 19:26:35 +0000 (2 days ago)

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