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: 1404 1792 78.3 %
Date: 2016-06-25 Functions: 46 46 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 25 Jun 2016 07:09:02 +0000 (2 days ago)

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