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: 1396 1790 78.0 %
Date: 2014-07-21 Functions: 44 44 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Tue, 22 Jul 2014 01:33:16 +0000 (4 days ago)

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