PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - phar - phar.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 1774
Code covered: 77.8 % Executed lines: 1381
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:07 +0000 (3 days ago)

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