root/ext/phar/phar.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_DECLARE_MODULE_GLOBALS
  2. ZEND_INI_MH
  3. phar_split_cache_list
  4. ZEND_INI_MH
  5. PHP_INI_BEGIN
  6. phar_archive_delref
  7. destroy_phar_data_only
  8. phar_unalias_apply
  9. phar_tmpclose_apply
  10. destroy_phar_data
  11. destroy_phar_manifest_entry_int
  12. destroy_phar_manifest_entry
  13. phar_entry_delref
  14. phar_entry_remove
  15. phar_open_parsed_phar
  16. phar_parse_metadata
  17. phar_parse_pharfile
  18. phar_open_or_create_filename
  19. phar_create_or_parse_filename
  20. phar_open_from_filename
  21. phar_strnstr
  22. phar_open_from_fp
  23. phar_analyze_path
  24. phar_check_str
  25. phar_detect_phar_fname_ext
  26. php_check_dots
  27. phar_fix_filepath
  28. phar_split_fname
  29. phar_open_executed_filename
  30. phar_postprocess_file
  31. phar_set_32
  32. phar_flush_clean_deleted_apply
  33. phar_create_default_stub
  34. phar_flush
  35. phar_zend_stream_reader
  36. phar_zend_stream_fsizer
  37. phar_resolve_path
  38. phar_compile_file
  39. mime_type_dtor
  40. PHP_GINIT_FUNCTION
  41. PHP_GSHUTDOWN_FUNCTION
  42. PHP_MINIT_FUNCTION
  43. PHP_MSHUTDOWN_FUNCTION
  44. phar_request_initialize
  45. PHP_RSHUTDOWN_FUNCTION
  46. PHP_MINFO_FUNCTION

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

/* [<][>][^][v][top][bottom][index][help] */