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

LCOV - code coverage report
Current view: top level - ext/phar - util.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 739 975 75.8 %
Date: 2014-10-14 Functions: 28 29 96.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | phar php single-file executable PHP extension                        |
       4             :   | utility functions                                                    |
       5             :   +----------------------------------------------------------------------+
       6             :   | Copyright (c) 2005-2014 The PHP Group                                |
       7             :   +----------------------------------------------------------------------+
       8             :   | This source file is subject to version 3.01 of the PHP license,      |
       9             :   | that is bundled with this package in the file LICENSE, and is        |
      10             :   | available through the world-wide-web at the following url:           |
      11             :   | http://www.php.net/license/3_01.txt.                                 |
      12             :   | If you did not receive a copy of the PHP license and are unable to   |
      13             :   | obtain it through the world-wide-web, please send a note to          |
      14             :   | license@php.net so we can mail you a copy immediately.               |
      15             :   +----------------------------------------------------------------------+
      16             :   | Authors: Gregory Beaver <cellog@php.net>                             |
      17             :   |          Marcus Boerger <helly@php.net>                              |
      18             :   +----------------------------------------------------------------------+
      19             : */
      20             : 
      21             : /* $Id$ */
      22             : 
      23             : #include "phar_internal.h"
      24             : #ifdef PHAR_HASH_OK
      25             : #include "ext/hash/php_hash_sha.h"
      26             : #endif
      27             : 
      28             : #ifdef PHAR_HAVE_OPENSSL
      29             : /* OpenSSL includes */
      30             : #include <openssl/evp.h>
      31             : #include <openssl/x509.h>
      32             : #include <openssl/x509v3.h>
      33             : #include <openssl/crypto.h>
      34             : #include <openssl/pem.h>
      35             : #include <openssl/err.h>
      36             : #include <openssl/conf.h>
      37             : #include <openssl/rand.h>
      38             : #include <openssl/ssl.h>
      39             : #include <openssl/pkcs12.h>
      40             : #else
      41             : static int phar_call_openssl_signverify(int is_sign, php_stream *fp, zend_off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC);
      42             : #endif
      43             : 
      44             : /* for links to relative location, prepend cwd of the entry */
      45          31 : static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC) /* {{{ */
      46             : {
      47          31 :         char *p, *ret = NULL;
      48          31 :         if (!entry->link) {
      49           0 :                 return NULL;
      50             :         }
      51          31 :         if (entry->link[0] == '/') {
      52           1 :                 return estrdup(entry->link + 1);
      53             :         }
      54          30 :         p = strrchr(entry->filename, '/');
      55          30 :         if (p) {
      56           3 :                 *p = '\0';
      57           3 :                 spprintf(&ret, 0, "%s/%s", entry->filename, entry->link);
      58           3 :                 return ret;
      59             :         }
      60          27 :         return entry->link;
      61             : }
      62             : /* }}} */
      63             : 
      64        7972 : phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC) /* {{{ */
      65             : {
      66             :         phar_entry_info *link_entry;
      67             :         char *link;
      68             : 
      69        7972 :         if (!entry->link) {
      70        7941 :                 return entry;
      71             :         }
      72             : 
      73          31 :         link = phar_get_link_location(entry TSRMLS_CC);
      74          65 :         if (NULL != (link_entry = zend_hash_str_find_ptr(&(entry->phar->manifest), entry->link, strlen(entry->link))) ||
      75           3 :                 NULL != (link_entry = zend_hash_str_find_ptr(&(entry->phar->manifest), link, strlen(link)))) {
      76          31 :                 if (link != entry->link) {
      77           4 :                         efree(link);
      78             :                 }
      79          31 :                 return phar_get_link_source(link_entry TSRMLS_CC);
      80             :         } else {
      81           0 :                 if (link != entry->link) {
      82           0 :                         efree(link);
      83             :                 }
      84           0 :                 return NULL;
      85             :         }
      86             : }
      87             : /* }}} */
      88             : 
      89             : /* retrieve a phar_entry_info's current file pointer for reading contents */
      90       59775 : php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) /* {{{ */
      91             : {
      92       59775 :         if (follow_links && entry->link) {
      93           3 :                 phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
      94             : 
      95           3 :                 if (link_entry && link_entry != entry) {
      96           3 :                         return phar_get_efp(link_entry, 1 TSRMLS_CC);
      97             :                 }
      98             :         }
      99             : 
     100       59772 :         if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) {
     101       16019 :                 if (!phar_get_entrypfp(entry TSRMLS_CC)) {
     102             :                         /* re-open just in time for cases where our refcount reached 0 on the phar archive */
     103          22 :                         phar_open_archive_fp(entry->phar TSRMLS_CC);
     104             :                 }
     105       16019 :                 return phar_get_entrypfp(entry TSRMLS_CC);
     106       43753 :         } else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) {
     107       15638 :                 return phar_get_entrypufp(entry TSRMLS_CC);
     108       28115 :         } else if (entry->fp_type == PHAR_MOD) {
     109       28104 :                 return entry->fp;
     110             :         } else {
     111             :                 /* temporary manifest entry */
     112          11 :                 if (!entry->fp) {
     113           0 :                         entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
     114             :                 }
     115          11 :                 return entry->fp;
     116             :         }
     117             : }
     118             : /* }}} */
     119             : 
     120       23820 : int phar_seek_efp(phar_entry_info *entry, zend_off_t offset, int whence, zend_off_t position, int follow_links TSRMLS_DC) /* {{{ */
     121             : {
     122       23820 :         php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
     123             :         zend_off_t temp, eoffset;
     124             : 
     125       23820 :         if (!fp) {
     126           1 :                 return -1;
     127             :         }
     128             : 
     129       23819 :         if (follow_links) {
     130             :                 phar_entry_info *t;
     131        7717 :                 t = phar_get_link_source(entry TSRMLS_CC);
     132        7717 :                 if (t) {
     133        7717 :                         entry = t;
     134             :                 }
     135             :         }
     136             : 
     137       23819 :         if (entry->is_dir) {
     138          18 :                 return 0;
     139             :         }
     140             : 
     141       23801 :         eoffset = phar_get_fp_offset(entry TSRMLS_CC);
     142             : 
     143       23801 :         switch (whence) {
     144             :                 case SEEK_END:
     145           0 :                         temp = eoffset + entry->uncompressed_filesize + offset;
     146           0 :                         break;
     147             :                 case SEEK_CUR:
     148           0 :                         temp = eoffset + position + offset;
     149           0 :                         break;
     150             :                 case SEEK_SET:
     151       23801 :                         temp = eoffset + offset;
     152       23801 :                         break;
     153             :                 default:
     154           0 :                         temp = 0;
     155             :         }
     156             : 
     157       23801 :         if (temp > eoffset + (zend_off_t) entry->uncompressed_filesize) {
     158           0 :                 return -1;
     159             :         }
     160             : 
     161       23801 :         if (temp < eoffset) {
     162           0 :                 return -1;
     163             :         }
     164             : 
     165       23801 :         return php_stream_seek(fp, temp, SEEK_SET);
     166             : }
     167             : /* }}} */
     168             : 
     169             : /* mount an absolute path or uri to a path internal to the phar archive */
     170          23 : int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC) /* {{{ */
     171             : {
     172          23 :         phar_entry_info entry = {0};
     173             :         php_stream_statbuf ssb;
     174             :         int is_phar;
     175             :         const char *err;
     176             : 
     177          23 :         if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) {
     178           0 :                 return FAILURE;
     179             :         }
     180             : 
     181          23 :         if (path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
     182             :                 /* no creating magic phar files by mounting them */
     183           1 :                 return FAILURE;
     184             :         }
     185             : 
     186          22 :         is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7));
     187             : 
     188          22 :         entry.phar = phar;
     189          22 :         entry.filename = estrndup(path, path_len);
     190             : #ifdef PHP_WIN32
     191             :         phar_unixify_path_separators(entry.filename, path_len);
     192             : #endif
     193          22 :         entry.filename_len = path_len;
     194          22 :         if (is_phar) {
     195           4 :                 entry.tmp = estrndup(filename, filename_len);
     196             :         } else {
     197          18 :                 entry.tmp = expand_filepath(filename, NULL TSRMLS_CC);
     198          18 :                 if (!entry.tmp) {
     199           0 :                         entry.tmp = estrndup(filename, filename_len);
     200             :                 }
     201             :         }
     202             : #if PHP_API_VERSION < 20100412
     203             :         if (PG(safe_mode) && !is_phar && (!php_checkuid(entry.tmp, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
     204             :                 efree(entry.tmp);
     205             :                 efree(entry.filename);
     206             :                 return FAILURE;
     207             :         }
     208             : #endif
     209          22 :         filename = entry.tmp;
     210             : 
     211             :         /* only check openbasedir for files, not for phar streams */
     212          22 :         if (!is_phar && php_check_open_basedir(filename TSRMLS_CC)) {
     213           0 :                 efree(entry.tmp);
     214           0 :                 efree(entry.filename);
     215           0 :                 return FAILURE;
     216             :         }
     217             : 
     218          22 :         entry.is_mounted = 1;
     219          22 :         entry.is_crc_checked = 1;
     220          22 :         entry.fp_type = PHAR_TMP;
     221             : 
     222          22 :         if (SUCCESS != php_stream_stat_path(filename, &ssb)) {
     223           3 :                 efree(entry.tmp);
     224           3 :                 efree(entry.filename);
     225           3 :                 return FAILURE;
     226             :         }
     227             : 
     228          19 :         if (ssb.sb.st_mode & S_IFDIR) {
     229           5 :                 entry.is_dir = 1;
     230          10 :                 if (NULL == zend_hash_str_add_ptr(&phar->mounted_dirs, entry.filename, path_len, entry.filename)) {
     231             :                         /* directory already mounted */
     232           1 :                         efree(entry.tmp);
     233           1 :                         efree(entry.filename);
     234           1 :                         return FAILURE;
     235             :                 }
     236             :         } else {
     237          14 :                 entry.is_dir = 0;
     238          14 :                 entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
     239             :         }
     240             : 
     241          18 :         entry.flags = ssb.sb.st_mode;
     242             : 
     243          36 :         if (NULL != zend_hash_str_add_mem(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info))) {
     244          15 :                 return SUCCESS;
     245             :         }
     246             : 
     247           3 :         efree(entry.tmp);
     248           3 :         efree(entry.filename);
     249           3 :         return FAILURE;
     250             : }
     251             : /* }}} */
     252             : 
     253       15332 : char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */
     254             : {
     255             :         char *path, *fname, *arch, *entry, *ret, *test;
     256             :         int arch_len, entry_len, fname_len, ret_len;
     257             :         phar_archive_data *phar;
     258             : 
     259       15332 :         if (pphar) {
     260           0 :                 *pphar = NULL;
     261             :         } else {
     262       15332 :                 pphar = &phar;
     263             :         }
     264             : 
     265       15332 :         if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
     266       15310 :                 return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
     267             :         }
     268             : 
     269          22 :         fname = (char*)zend_get_executed_filename(TSRMLS_C);
     270          22 :         fname_len = strlen(fname);
     271             : 
     272          22 :         if (PHAR_G(last_phar) && !memcmp(fname, "phar://", 7) && fname_len - 7 >= PHAR_G(last_phar_name_len) && !memcmp(fname + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) {
     273           1 :                 arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
     274           1 :                 arch_len = PHAR_G(last_phar_name_len);
     275           1 :                 phar = PHAR_G(last_phar);
     276           1 :                 goto splitted;
     277             :         }
     278             : 
     279          21 :         if (fname_len < 7 || memcmp(fname, "phar://", 7) || SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
     280          14 :                 return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
     281             :         }
     282             : 
     283           7 :         efree(entry);
     284             : 
     285           7 :         if (*filename == '.') {
     286             :                 int try_len;
     287             : 
     288           4 :                 if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
     289           0 :                         efree(arch);
     290           0 :                         return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
     291             :                 }
     292             : splitted:
     293           5 :                 if (pphar) {
     294           5 :                         *pphar = phar;
     295             :                 }
     296             : 
     297           5 :                 try_len = filename_len;
     298           5 :                 test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
     299             : 
     300           5 :                 if (*test == '/') {
     301           2 :                         if (zend_hash_str_exists(&(phar->manifest), test + 1, try_len - 1)) {
     302           2 :                                 spprintf(&ret, 0, "phar://%s%s", arch, test);
     303           2 :                                 efree(arch);
     304           2 :                                 efree(test);
     305           2 :                                 return ret;
     306             :                         }
     307             :                 } else {
     308           3 :                         if (zend_hash_str_exists(&(phar->manifest), test, try_len)) {
     309           2 :                                 spprintf(&ret, 0, "phar://%s/%s", arch, test);
     310           2 :                                 efree(arch);
     311           2 :                                 efree(test);
     312           2 :                                 return ret;
     313             :                         }
     314             :                 }
     315           1 :                 efree(test);
     316             :         }
     317             : 
     318           4 :         spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
     319           4 :         efree(arch);
     320           4 :         ret = php_resolve_path(filename, filename_len, path TSRMLS_CC);
     321           4 :         efree(path);
     322             : 
     323           4 :         if (ret && strlen(ret) > 8 && !strncmp(ret, "phar://", 7)) {
     324           2 :                 ret_len = strlen(ret);
     325             :                 /* found phar:// */
     326             : 
     327           2 :                 if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
     328           0 :                         return ret;
     329             :                 }
     330             : 
     331           4 :                 *pphar = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len);
     332             : 
     333           2 :                 if (!*pphar && PHAR_G(manifest_cached)) {
     334           0 :                         *pphar = zend_hash_str_find_ptr(&cached_phars, arch, arch_len);
     335             :                 }
     336             : 
     337           2 :                 efree(arch);
     338           2 :                 efree(entry);
     339             :         }
     340             : 
     341           4 :         return ret;
     342             : }
     343             : /* }}} */
     344             : 
     345             : /**
     346             :  * Retrieve a copy of the file information on a single file within a phar, or null.
     347             :  * This also transfers the open file pointer, if any, to the entry.
     348             :  *
     349             :  * If the file does not already exist, this will fail.  Pre-existing files can be
     350             :  * appended, truncated, or read.  For read, if the entry is marked unmodified, it is
     351             :  * assumed that the file pointer, if present, is opened for reading
     352             :  */
     353        8210 : int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, const char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */
     354             : {
     355             :         phar_archive_data *phar;
     356             :         phar_entry_info *entry;
     357        8210 :         int for_write  = mode[0] != 'r' || mode[1] == '+';
     358        8210 :         int for_append = mode[0] == 'a';
     359        8210 :         int for_create = mode[0] != 'r';
     360        8210 :         int for_trunc  = mode[0] == 'w';
     361             : 
     362        8210 :         if (!ret) {
     363           0 :                 return FAILURE;
     364             :         }
     365             : 
     366        8210 :         *ret = NULL;
     367             : 
     368        8210 :         if (error) {
     369        8210 :                 *error = NULL;
     370             :         }
     371             : 
     372        8210 :         if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
     373           0 :                 return FAILURE;
     374             :         }
     375             : 
     376        8210 :         if (for_write && PHAR_G(readonly) && !phar->is_data) {
     377           0 :                 if (error) {
     378           0 :                         spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname);
     379             :                 }
     380           0 :                 return FAILURE;
     381             :         }
     382             : 
     383        8210 :         if (!path_len) {
     384           4 :                 if (error) {
     385           4 :                         spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname);
     386             :                 }
     387           4 :                 return FAILURE;
     388             :         }
     389             : really_get_entry:
     390        8207 :         if (allow_dir) {
     391          18 :                 if ((entry = phar_get_entry_info_dir(phar, path, path_len, allow_dir, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) {
     392          16 :                         if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
     393          16 :                                 return SUCCESS;
     394             :                         }
     395           0 :                         return FAILURE;
     396             :                 }
     397             :         } else {
     398        8189 :                 if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) {
     399        3540 :                         if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
     400        3516 :                                 return SUCCESS;
     401             :                         }
     402          24 :                         return FAILURE;
     403             :                 }
     404             :         }
     405             : 
     406        4651 :         if (for_write && phar->is_persistent) {
     407           1 :                 if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
     408           0 :                         if (error) {
     409           0 :                                 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname);
     410             :                         }
     411           0 :                         return FAILURE;
     412             :                 } else {
     413           1 :                         goto really_get_entry;
     414             :                 }
     415             :         }
     416             : 
     417        4650 :         if (entry->is_modified && !for_write) {
     418           0 :                 if (error) {
     419           0 :                         spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname);
     420             :                 }
     421           0 :                 return FAILURE;
     422             :         }
     423             : 
     424        4650 :         if (entry->fp_refcount && for_write) {
     425           1 :                 if (error) {
     426           1 :                         spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname);
     427             :                 }
     428           1 :                 return FAILURE;
     429             :         }
     430             : 
     431        4649 :         if (entry->is_deleted) {
     432           0 :                 if (!for_create) {
     433           0 :                         return FAILURE;
     434             :                 }
     435           0 :                 entry->is_deleted = 0;
     436             :         }
     437             : 
     438        4649 :         if (entry->is_dir) {
     439           2 :                 *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
     440           2 :                 (*ret)->position = 0;
     441           2 :                 (*ret)->fp = NULL;
     442           2 :                 (*ret)->phar = phar;
     443           2 :                 (*ret)->for_write = for_write;
     444           2 :                 (*ret)->internal_file = entry;
     445           2 :                 (*ret)->is_zip = entry->is_zip;
     446           2 :                 (*ret)->is_tar = entry->is_tar;
     447             : 
     448           2 :                 if (!phar->is_persistent) {
     449           2 :                         ++(entry->phar->refcount);
     450           2 :                         ++(entry->fp_refcount);
     451             :                 }
     452             : 
     453           2 :                 return SUCCESS;
     454             :         }
     455             : 
     456        4647 :         if (entry->fp_type == PHAR_MOD) {
     457           0 :                 if (for_trunc) {
     458           0 :                         if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
     459           0 :                                 return FAILURE;
     460             :                         }
     461           0 :                 } else if (for_append) {
     462           0 :                         phar_seek_efp(entry, 0, SEEK_END, 0, 0 TSRMLS_CC);
     463             :                 }
     464             :         } else {
     465        4647 :                 if (for_write) {
     466        4124 :                         if (entry->link) {
     467           1 :                                 efree(entry->link);
     468           1 :                                 entry->link = NULL;
     469           1 :                                 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
     470             :                         }
     471             : 
     472        4124 :                         if (for_trunc) {
     473        4123 :                                 if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
     474           0 :                                         return FAILURE;
     475             :                                 }
     476             :                         } else {
     477           1 :                                 if (FAILURE == phar_separate_entry_fp(entry, error TSRMLS_CC)) {
     478           0 :                                         return FAILURE;
     479             :                                 }
     480             :                         }
     481             :                 } else {
     482         523 :                         if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
     483           4 :                                 return FAILURE;
     484             :                         }
     485             :                 }
     486             :         }
     487             : 
     488        4643 :         *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
     489        4643 :         (*ret)->position = 0;
     490        4643 :         (*ret)->phar = phar;
     491        4643 :         (*ret)->for_write = for_write;
     492        4643 :         (*ret)->internal_file = entry;
     493        4643 :         (*ret)->is_zip = entry->is_zip;
     494        4643 :         (*ret)->is_tar = entry->is_tar;
     495        4643 :         (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
     496        4643 :         if (entry->link) {
     497           3 :                 (*ret)->zero = phar_get_fp_offset(phar_get_link_source(entry TSRMLS_CC) TSRMLS_CC);
     498             :         } else {
     499        4640 :                 (*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC);
     500             :         }
     501             : 
     502        4643 :         if (!phar->is_persistent) {
     503        4643 :                 ++(entry->fp_refcount);
     504        4643 :                 ++(entry->phar->refcount);
     505             :         }
     506             : 
     507        4643 :         return SUCCESS;
     508             : }
     509             : /* }}} */
     510             : 
     511             : /**
     512             :  * Create a new dummy file slot within a writeable phar for a newly created file
     513             :  */
     514        7663 : phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, const char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */
     515             : {
     516             :         phar_archive_data *phar;
     517             :         phar_entry_info *entry, etemp;
     518             :         phar_entry_data *ret;
     519             :         const char *pcr_error;
     520             :         char is_dir;
     521             : 
     522             : #ifdef PHP_WIN32
     523             :         phar_unixify_path_separators(path, path_len);
     524             : #endif
     525             : 
     526        7663 :         is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0;
     527             : 
     528        7663 :         if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
     529           0 :                 return NULL;
     530             :         }
     531             : 
     532        7663 :         if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error, security TSRMLS_CC)) {
     533           5 :                 return NULL;
     534        7658 :         } else if (ret) {
     535        4126 :                 return ret;
     536             :         }
     537             : 
     538        3532 :         if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
     539           8 :                 if (error) {
     540           8 :                         spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
     541             :                 }
     542           8 :                 return NULL;
     543             :         }
     544             : 
     545        3524 :         if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
     546           0 :                 if (error) {
     547           0 :                         spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname);
     548             :                 }
     549           0 :                 return NULL;
     550             :         }
     551             : 
     552             :         /* create a new phar data holder */
     553        3524 :         ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
     554             : 
     555             :         /* create an entry, this is a new file */
     556        3524 :         memset(&etemp, 0, sizeof(phar_entry_info));
     557        3524 :         etemp.filename_len = path_len;
     558        3524 :         etemp.fp_type = PHAR_MOD;
     559        3524 :         etemp.fp = php_stream_fopen_tmpfile();
     560             : 
     561        3524 :         if (!etemp.fp) {
     562           0 :                 if (error) {
     563           0 :                         spprintf(error, 0, "phar error: unable to create temporary file");
     564             :                 }
     565           0 :                 efree(ret);
     566           0 :                 return NULL;
     567             :         }
     568             : 
     569        3524 :         etemp.fp_refcount = 1;
     570             : 
     571        3524 :         if (allow_dir == 2) {
     572          16 :                 etemp.is_dir = 1;
     573          16 :                 etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_DIR;
     574             :         } else {
     575        3508 :                 etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
     576             :         }
     577        3524 :         if (is_dir) {
     578           2 :                 etemp.filename_len--; /* strip trailing / */
     579           2 :                 path_len--;
     580             :         }
     581             : 
     582        3524 :         phar_add_virtual_dirs(phar, path, path_len TSRMLS_CC);
     583        3524 :         etemp.is_modified = 1;
     584        3524 :         etemp.timestamp = time(0);
     585        3524 :         etemp.is_crc_checked = 1;
     586        3524 :         etemp.phar = phar;
     587        3524 :         etemp.filename = estrndup(path, path_len);
     588        3524 :         etemp.is_zip = phar->is_zip;
     589             : 
     590        3524 :         if (phar->is_tar) {
     591         100 :                 etemp.is_tar = phar->is_tar;
     592         100 :                 etemp.tar_type = etemp.is_dir ? TAR_DIR : TAR_FILE;
     593             :         }
     594             : 
     595        7048 :         if (NULL == (entry = zend_hash_str_add_mem(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info)))) {
     596           0 :                 php_stream_close(etemp.fp);
     597           0 :                 if (error) {
     598           0 :                         spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname);
     599             :                 }
     600           0 :                 efree(ret);
     601           0 :                 efree(etemp.filename);
     602           0 :                 return NULL;
     603             :         }
     604             : 
     605        3524 :         if (!entry) {
     606           0 :                 php_stream_close(etemp.fp);
     607           0 :                 efree(etemp.filename);
     608           0 :                 efree(ret);
     609           0 :                 return NULL;
     610             :         }
     611             : 
     612        3524 :         ++(phar->refcount);
     613        3524 :         ret->phar = phar;
     614        3524 :         ret->fp = entry->fp;
     615        3524 :         ret->position = ret->zero = 0;
     616        3524 :         ret->for_write = 1;
     617        3524 :         ret->is_zip = entry->is_zip;
     618        3524 :         ret->is_tar = entry->is_tar;
     619        3524 :         ret->internal_file = entry;
     620             : 
     621        3524 :         return ret;
     622             : }
     623             : /* }}} */
     624             : 
     625             : /* initialize a phar_archive_data's read-only fp for existing phar data */
     626         346 : int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) /* {{{ */
     627             : {
     628         346 :         if (phar_get_pharfp(phar TSRMLS_CC)) {
     629         177 :                 return SUCCESS;
     630             :         }
     631             : 
     632         169 :         if (php_check_open_basedir(phar->fname TSRMLS_CC)) {
     633           0 :                 return FAILURE;
     634             :         }
     635             : 
     636         169 :         phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC);
     637             : 
     638         169 :         if (!phar_get_pharfp(phar TSRMLS_CC)) {
     639           4 :                 return FAILURE;
     640             :         }
     641             : 
     642         165 :         return SUCCESS;
     643             : }
     644             : /* }}} */
     645             : 
     646             : /* copy file data from an existing to a new phar_entry_info that is not in the manifest */
     647           6 : int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC) /* {{{ */
     648             : {
     649             :         phar_entry_info *link;
     650             : 
     651           6 :         if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) {
     652           0 :                 return FAILURE;
     653             :         }
     654             : 
     655           6 :         if (dest->link) {
     656           0 :                 efree(dest->link);
     657           0 :                 dest->link = NULL;
     658           0 :                 dest->tar_type = (dest->is_tar ? TAR_FILE : '\0');
     659             :         }
     660             : 
     661           6 :         dest->fp_type = PHAR_MOD;
     662           6 :         dest->offset = 0;
     663           6 :         dest->is_modified = 1;
     664           6 :         dest->fp = php_stream_fopen_tmpfile();
     665           6 :         if (dest->fp == NULL) {
     666           0 :                 spprintf(error, 0, "phar error: unable to create temporary file");
     667           0 :                 return EOF;
     668             :         }
     669           6 :         phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC);
     670           6 :         link = phar_get_link_source(source TSRMLS_CC);
     671             : 
     672           6 :         if (!link) {
     673           0 :                 link = source;
     674             :         }
     675             : 
     676           6 :         if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize, NULL)) {
     677           0 :                 php_stream_close(dest->fp);
     678           0 :                 dest->fp_type = PHAR_FP;
     679           0 :                 if (error) {
     680           0 :                         spprintf(error, 4096, "phar error: unable to copy contents of file \"%s\" to \"%s\" in phar archive \"%s\"", source->filename, dest->filename, source->phar->fname);
     681             :                 }
     682           0 :                 return FAILURE;
     683             :         }
     684             : 
     685           6 :         return SUCCESS;
     686             : }
     687             : /* }}} */
     688             : 
     689             : /* open and decompress a compressed phar entry
     690             :  */
     691        2430 : int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) /* {{{ */
     692             : {
     693             :         php_stream_filter *filter;
     694        2430 :         phar_archive_data *phar = entry->phar;
     695             :         char *filtername;
     696             :         zend_off_t loc;
     697             :         php_stream *ufp;
     698             :         phar_entry_data dummy;
     699             : 
     700        2430 :         if (follow_links && entry->link) {
     701           3 :                 phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
     702           3 :                 if (link_entry && link_entry != entry) {
     703           3 :                         return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC);
     704             :                 }
     705             :         }
     706             : 
     707        2427 :         if (entry->is_modified) {
     708        1362 :                 return SUCCESS;
     709             :         }
     710             : 
     711        1065 :         if (entry->fp_type == PHAR_TMP) {
     712           9 :                 if (!entry->fp) {
     713           8 :                         entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
     714             :                 }
     715           9 :                 return SUCCESS;
     716             :         }
     717             : 
     718        1056 :         if (entry->fp_type != PHAR_FP) {
     719             :                 /* either newly created or already modified */
     720           2 :                 return SUCCESS;
     721             :         }
     722             : 
     723        1054 :         if (!phar_get_pharfp(phar TSRMLS_CC)) {
     724         147 :                 if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) {
     725           1 :                         spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
     726           1 :                         return FAILURE;
     727             :                 }
     728             :         }
     729             : 
     730        1053 :         if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
     731        1012 :                 dummy.internal_file = entry;
     732        1012 :                 dummy.phar = phar;
     733        1012 :                 dummy.zero = entry->offset;
     734        1012 :                 dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
     735        1012 :                 if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
     736           0 :                         return FAILURE;
     737             :                 }
     738        1012 :                 return SUCCESS;
     739             :         }
     740             : 
     741          41 :         if (!phar_get_entrypufp(entry TSRMLS_CC)) {
     742          24 :                 phar_set_entrypufp(entry, php_stream_fopen_tmpfile() TSRMLS_CC);
     743          24 :                 if (!phar_get_entrypufp(entry TSRMLS_CC)) {
     744           0 :                         spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
     745           0 :                         return FAILURE;
     746             :                 }
     747             :         }
     748             : 
     749          41 :         dummy.internal_file = entry;
     750          41 :         dummy.phar = phar;
     751          41 :         dummy.zero = entry->offset;
     752          41 :         dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
     753          41 :         if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
     754           0 :                 return FAILURE;
     755             :         }
     756             : 
     757          41 :         ufp = phar_get_entrypufp(entry TSRMLS_CC);
     758             : 
     759          41 :         if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
     760          41 :                 filter = php_stream_filter_create(filtername, NULL, 0 TSRMLS_CC);
     761             :         } else {
     762           0 :                 filter = NULL;
     763             :         }
     764             : 
     765          41 :         if (!filter) {
     766           0 :                 spprintf(error, 4096, "phar error: unable to read phar \"%s\" (cannot create %s filter while decompressing file \"%s\")", phar->fname, phar_decompress_filter(entry, 1), entry->filename);
     767           0 :                 return FAILURE;
     768             :         }
     769             : 
     770             :         /* now we can safely use proper decompression */
     771             :         /* save the new offset location within ufp */
     772          41 :         php_stream_seek(ufp, 0, SEEK_END);
     773          41 :         loc = php_stream_tell(ufp);
     774          41 :         php_stream_filter_append(&ufp->writefilters, filter);
     775          41 :         php_stream_seek(phar_get_entrypfp(entry TSRMLS_CC), phar_get_fp_offset(entry TSRMLS_CC), SEEK_SET);
     776             : 
     777          41 :         if (entry->uncompressed_filesize) {
     778          40 :                 if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_entrypfp(entry TSRMLS_CC), ufp, entry->compressed_filesize, NULL)) {
     779           0 :                         spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
     780           0 :                         php_stream_filter_remove(filter, 1 TSRMLS_CC);
     781           0 :                         return FAILURE;
     782             :                 }
     783             :         }
     784             : 
     785          41 :         php_stream_filter_flush(filter, 1);
     786          41 :         php_stream_flush(ufp);
     787          41 :         php_stream_filter_remove(filter, 1 TSRMLS_CC);
     788             : 
     789          41 :         if (php_stream_tell(ufp) - loc != (zend_off_t) entry->uncompressed_filesize) {
     790           4 :                 spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
     791           4 :                 return FAILURE;
     792             :         }
     793             : 
     794          37 :         entry->old_flags = entry->flags;
     795             : 
     796             :         /* this is now the new location of the file contents within this fp */
     797          37 :         phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
     798          37 :         dummy.zero = entry->offset;
     799          37 :         dummy.fp = ufp;
     800          37 :         if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0 TSRMLS_CC)) {
     801           0 :                 return FAILURE;
     802             :         }
     803          37 :         return SUCCESS;
     804             : }
     805             : /* }}} */
     806             : 
     807        4123 : int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
     808             : {
     809        4123 :         if (entry->fp_type == PHAR_MOD) {
     810             :                 /* already newly created, truncate */
     811           0 :                 php_stream_truncate_set_size(entry->fp, 0);
     812             : 
     813           0 :                 entry->old_flags = entry->flags;
     814           0 :                 entry->is_modified = 1;
     815           0 :                 phar->is_modified = 1;
     816             :                 /* reset file size */
     817           0 :                 entry->uncompressed_filesize = 0;
     818           0 :                 entry->compressed_filesize = 0;
     819           0 :                 entry->crc32 = 0;
     820           0 :                 entry->flags = PHAR_ENT_PERM_DEF_FILE;
     821           0 :                 entry->fp_type = PHAR_MOD;
     822           0 :                 entry->offset = 0;
     823           0 :                 return SUCCESS;
     824             :         }
     825             : 
     826        4123 :         if (error) {
     827        4123 :                 *error = NULL;
     828             :         }
     829             : 
     830             :         /* open a new temp file for writing */
     831        4123 :         if (entry->link) {
     832           0 :                 efree(entry->link);
     833           0 :                 entry->link = NULL;
     834           0 :                 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
     835             :         }
     836             : 
     837        4123 :         entry->fp = php_stream_fopen_tmpfile();
     838             : 
     839        4123 :         if (!entry->fp) {
     840           0 :                 if (error) {
     841           0 :                         spprintf(error, 0, "phar error: unable to create temporary file");
     842             :                 }
     843           0 :                 return FAILURE;
     844             :         }
     845             : 
     846        4123 :         entry->old_flags = entry->flags;
     847        4123 :         entry->is_modified = 1;
     848        4123 :         phar->is_modified = 1;
     849             :         /* reset file size */
     850        4123 :         entry->uncompressed_filesize = 0;
     851        4123 :         entry->compressed_filesize = 0;
     852        4123 :         entry->crc32 = 0;
     853        4123 :         entry->flags = PHAR_ENT_PERM_DEF_FILE;
     854        4123 :         entry->fp_type = PHAR_MOD;
     855        4123 :         entry->offset = 0;
     856        4123 :         return SUCCESS;
     857             : }
     858             : /* }}} */
     859             : 
     860           1 : int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
     861             : {
     862             :         php_stream *fp;
     863             :         phar_entry_info *link;
     864             : 
     865           1 :         if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
     866           0 :                 return FAILURE;
     867             :         }
     868             : 
     869           1 :         if (entry->fp_type == PHAR_MOD) {
     870           0 :                 return SUCCESS;
     871             :         }
     872             : 
     873           1 :         fp = php_stream_fopen_tmpfile();
     874           1 :         if (fp == NULL) {
     875           0 :                 spprintf(error, 0, "phar error: unable to create temporary file");
     876           0 :                 return FAILURE;
     877             :         }
     878           1 :         phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
     879           1 :         link = phar_get_link_source(entry TSRMLS_CC);
     880             : 
     881           1 :         if (!link) {
     882           0 :                 link = entry;
     883             :         }
     884             : 
     885           1 :         if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize, NULL)) {
     886           0 :                 if (error) {
     887           0 :                         spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
     888             :                 }
     889           0 :                 return FAILURE;
     890             :         }
     891             : 
     892           1 :         if (entry->link) {
     893           0 :                 efree(entry->link);
     894           0 :                 entry->link = NULL;
     895           0 :                 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
     896             :         }
     897             : 
     898           1 :         entry->offset = 0;
     899           1 :         entry->fp = fp;
     900           1 :         entry->fp_type = PHAR_MOD;
     901           1 :         entry->is_modified = 1;
     902           1 :         return SUCCESS;
     903             : }
     904             : /* }}} */
     905             : 
     906             : /**
     907             :  * helper function to open an internal file's fp just-in-time
     908             :  */
     909           1 : phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
     910             : {
     911           1 :         if (error) {
     912           1 :                 *error = NULL;
     913             :         }
     914             :         /* seek to start of internal file and read it */
     915           1 :         if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
     916           1 :                 return NULL;
     917             :         }
     918           0 :         if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
     919           0 :                 spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname);
     920           0 :                 return NULL;
     921             :         }
     922           0 :         return entry;
     923             : }
     924             : /* }}} */
     925             : 
     926           0 : PHP_PHAR_API int phar_resolve_alias(char *alias, int alias_len, char **filename, int *filename_len TSRMLS_DC) /* {{{ */ {
     927             :         phar_archive_data *fd_ptr;
     928           0 :         if (PHAR_GLOBALS->phar_alias_map.arHash
     929           0 :                         && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len))) {
     930           0 :                 *filename = fd_ptr->fname;
     931           0 :                 *filename_len = fd_ptr->fname_len;
     932           0 :                 return SUCCESS;
     933             :         }
     934           0 :         return FAILURE;
     935             : }
     936             : /* }}} */
     937             : 
     938          16 : int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
     939             : {
     940          16 :         if (phar->refcount || phar->is_persistent) {
     941          13 :                 return FAILURE;
     942             :         }
     943             : 
     944             :         /* this archive has no open references, so emit an E_STRICT and remove it */
     945           3 :         if (zend_hash_str_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
     946           0 :                 return FAILURE;
     947             :         }
     948             : 
     949             :         /* invalidate phar cache */
     950           3 :         PHAR_G(last_phar) = NULL;
     951           3 :         PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
     952             : 
     953           3 :         return SUCCESS;
     954             : }
     955             : /* }}} */
     956             : 
     957             : /**
     958             :  * Looks up a phar archive in the filename map, connecting it to the alias
     959             :  * (if any) or returns null
     960             :  */
     961       20027 : int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
     962             : {
     963             :         phar_archive_data *fd, *fd_ptr;
     964             :         char *my_realpath, *save;
     965             :         int save_len;
     966             : 
     967       20027 :         phar_request_initialize(TSRMLS_C);
     968             : 
     969       20027 :         if (error) {
     970       19444 :                 *error = NULL;
     971             :         }
     972             : 
     973       20027 :         *archive = NULL;
     974             : 
     975       20027 :         if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
     976       18331 :                 *archive = PHAR_G(last_phar);
     977       18331 :                 if (alias && alias_len) {
     978             : 
     979         175 :                         if (!PHAR_G(last_phar)->is_temporary_alias && (alias_len != PHAR_G(last_phar)->alias_len || memcmp(PHAR_G(last_phar)->alias, alias, alias_len))) {
     980           3 :                                 if (error) {
     981           3 :                                         spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
     982             :                                 }
     983           3 :                                 *archive = NULL;
     984           3 :                                 return FAILURE;
     985             :                         }
     986             : 
     987         344 :                         if (PHAR_G(last_phar)->alias_len && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len))) {
     988         135 :                                 zend_hash_str_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
     989             :                         }
     990             : 
     991         172 :                         zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, *archive);
     992         172 :                         PHAR_G(last_alias) = alias;
     993         172 :                         PHAR_G(last_alias_len) = alias_len;
     994             :                 }
     995             : 
     996       18328 :                 return SUCCESS;
     997             :         }
     998             : 
     999        1696 :         if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
    1000           3 :                 fd = PHAR_G(last_phar);
    1001           3 :                 fd_ptr = fd;
    1002           3 :                 goto alias_success;
    1003             :         }
    1004             : 
    1005        1693 :         if (alias && alias_len) {
    1006         254 :                 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len))) {
    1007             : alias_success:
    1008          21 :                         if (fname && (fname_len != fd_ptr->fname_len || strncmp(fname, fd_ptr->fname, fname_len))) {
    1009           5 :                                 if (error) {
    1010           5 :                                         spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, fd_ptr->fname, fname);
    1011             :                                 }
    1012           5 :                                 if (SUCCESS == phar_free_alias(fd_ptr, alias, alias_len TSRMLS_CC)) {
    1013           0 :                                         if (error) {
    1014           0 :                                                 efree(*error);
    1015           0 :                                                 *error = NULL;
    1016             :                                         }
    1017             :                                 }
    1018           5 :                                 return FAILURE;
    1019             :                         }
    1020             : 
    1021          16 :                         *archive = fd_ptr;
    1022          16 :                         fd = fd_ptr;
    1023          16 :                         PHAR_G(last_phar) = fd;
    1024          16 :                         PHAR_G(last_phar_name) = fd->fname;
    1025          16 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1026          16 :                         PHAR_G(last_alias) = alias;
    1027          16 :                         PHAR_G(last_alias_len) = alias_len;
    1028             : 
    1029          16 :                         return SUCCESS;
    1030             :                 }
    1031             : 
    1032         109 :                 if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_alias, alias, alias_len))) {
    1033           0 :                         goto alias_success;
    1034             :                 }
    1035             :         }
    1036             : 
    1037        1675 :         my_realpath = NULL;
    1038        1675 :         save = fname;
    1039        1675 :         save_len = fname_len;
    1040             : 
    1041        1675 :         if (fname && fname_len) {
    1042        3350 :                 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len))) {
    1043         772 :                         *archive = fd_ptr;
    1044         772 :                         fd = fd_ptr;
    1045             : 
    1046         772 :                         if (alias && alias_len) {
    1047          43 :                                 if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
    1048           0 :                                         if (error) {
    1049           0 :                                                 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, fd_ptr->fname, fname);
    1050             :                                         }
    1051           0 :                                         return FAILURE;
    1052             :                                 }
    1053             : 
    1054          86 :                                 if (fd->alias_len && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len))) {
    1055           1 :                                         zend_hash_str_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
    1056             :                                 }
    1057             : 
    1058          43 :                                 zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, fd);
    1059             :                         }
    1060             : 
    1061         772 :                         PHAR_G(last_phar) = fd;
    1062         772 :                         PHAR_G(last_phar_name) = fd->fname;
    1063         772 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1064         772 :                         PHAR_G(last_alias) = fd->alias;
    1065         772 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1066             : 
    1067         772 :                         return SUCCESS;
    1068             :                 }
    1069             : 
    1070        1028 :                 if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_phars, fname, fname_len))) {
    1071           3 :                         *archive = fd_ptr;
    1072           3 :                         fd = fd_ptr;
    1073             : 
    1074             :                         /* this could be problematic - alias should never be different from manifest alias
    1075             :                            for cached phars */
    1076           3 :                         if (!fd->is_temporary_alias && alias && alias_len) {
    1077           0 :                                 if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
    1078           0 :                                         if (error) {
    1079           0 :                                                 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, fd_ptr->fname, fname);
    1080             :                                         }
    1081           0 :                                         return FAILURE;
    1082             :                                 }
    1083             :                         }
    1084             : 
    1085           3 :                         PHAR_G(last_phar) = fd;
    1086           3 :                         PHAR_G(last_phar_name) = fd->fname;
    1087           3 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1088           3 :                         PHAR_G(last_alias) = fd->alias;
    1089           3 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1090             : 
    1091           3 :                         return SUCCESS;
    1092             :                 }
    1093             : 
    1094        1800 :                 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_alias_map), save, save_len))) {
    1095         128 :                         fd = *archive = fd_ptr;
    1096             : 
    1097         128 :                         PHAR_G(last_phar) = fd;
    1098         128 :                         PHAR_G(last_phar_name) = fd->fname;
    1099         128 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1100         128 :                         PHAR_G(last_alias) = fd->alias;
    1101         128 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1102             : 
    1103         128 :                         return SUCCESS;
    1104             :                 }
    1105             : 
    1106         894 :                 if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_alias, save, save_len))) {
    1107           0 :                         fd = *archive = fd_ptr;
    1108             : 
    1109           0 :                         PHAR_G(last_phar) = fd;
    1110           0 :                         PHAR_G(last_phar_name) = fd->fname;
    1111           0 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1112           0 :                         PHAR_G(last_alias) = fd->alias;
    1113           0 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1114             : 
    1115           0 :                         return SUCCESS;
    1116             :                 }
    1117             : 
    1118             :                 /* not found, try converting \ to / */
    1119         772 :                 my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
    1120             : 
    1121         772 :                 if (my_realpath) {
    1122         772 :                         fname_len = strlen(my_realpath);
    1123         772 :                         fname = my_realpath;
    1124             :                 } else {
    1125           0 :                         return FAILURE;
    1126             :                 }
    1127             : #ifdef PHP_WIN32
    1128             :                 phar_unixify_path_separators(fname, fname_len);
    1129             : #endif
    1130             : 
    1131        1544 :                 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len))) {
    1132             : realpath_success:
    1133          15 :                         *archive = fd_ptr;
    1134          15 :                         fd = fd_ptr;
    1135             : 
    1136          15 :                         if (alias && alias_len) {
    1137           0 :                                 zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, fd);
    1138             :                         }
    1139             : 
    1140          15 :                         efree(my_realpath);
    1141             : 
    1142          15 :                         PHAR_G(last_phar) = fd;
    1143          15 :                         PHAR_G(last_phar_name) = fd->fname;
    1144          15 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1145          15 :                         PHAR_G(last_alias) = fd->alias;
    1146          15 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1147             : 
    1148          15 :                         return SUCCESS;
    1149             :                 }
    1150             : 
    1151         879 :                 if (PHAR_G(manifest_cached) && NULL != (fd_ptr = zend_hash_str_find_ptr(&cached_phars, fname, fname_len))) {
    1152           0 :                         goto realpath_success;
    1153             :                 }
    1154             : 
    1155         757 :                 efree(my_realpath);
    1156             :         }
    1157             : 
    1158         757 :         return FAILURE;
    1159             : }
    1160             : /* }}} */
    1161             : 
    1162             : /**
    1163             :  * Determine which stream compression filter (if any) we need to read this file
    1164             :  */
    1165          49 : char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
    1166             : {
    1167          49 :         switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
    1168             :         case PHAR_ENT_COMPRESSED_GZ:
    1169          33 :                 return "zlib.deflate";
    1170             :         case PHAR_ENT_COMPRESSED_BZ2:
    1171          16 :                 return "bzip2.compress";
    1172             :         default:
    1173           0 :                 return return_unknown ? "unknown" : NULL;
    1174             :         }
    1175             : }
    1176             : /* }}} */
    1177             : 
    1178             : /**
    1179             :  * Determine which stream decompression filter (if any) we need to read this file
    1180             :  */
    1181          41 : char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
    1182             : {
    1183             :         php_uint32 flags;
    1184             : 
    1185          41 :         if (entry->is_modified) {
    1186           0 :                 flags = entry->old_flags;
    1187             :         } else {
    1188          41 :                 flags = entry->flags;
    1189             :         }
    1190             : 
    1191          41 :         switch (flags & PHAR_ENT_COMPRESSION_MASK) {
    1192             :                 case PHAR_ENT_COMPRESSED_GZ:
    1193          28 :                         return "zlib.inflate";
    1194             :                 case PHAR_ENT_COMPRESSED_BZ2:
    1195          13 :                         return "bzip2.decompress";
    1196             :                 default:
    1197           0 :                         return return_unknown ? "unknown" : NULL;
    1198             :         }
    1199             : }
    1200             : /* }}} */
    1201             : 
    1202             : /**
    1203             :  * retrieve information on a file contained within a phar, or null if it ain't there
    1204             :  */
    1205        8276 : phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */
    1206             : {
    1207        8276 :         return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC);
    1208             : }
    1209             : /* }}} */
    1210             : /**
    1211             :  * retrieve information on a file or directory contained within a phar, or null if none found
    1212             :  * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only
    1213             :  * valid pre-existing empty directory entries
    1214             :  */
    1215        9056 : phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error, int security TSRMLS_DC) /* {{{ */
    1216             : {
    1217             :         const char *pcr_error;
    1218             :         phar_entry_info *entry;
    1219             :         int is_dir;
    1220             : 
    1221             : #ifdef PHP_WIN32
    1222             :         phar_unixify_path_separators(path, path_len);
    1223             : #endif
    1224             : 
    1225        9056 :         is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0;
    1226             : 
    1227        9056 :         if (error) {
    1228        1324 :                 *error = NULL;
    1229             :         }
    1230             : 
    1231        9056 :         if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
    1232           0 :                 if (error) {
    1233           0 :                         spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it");
    1234             :                 }
    1235           0 :                 return NULL;
    1236             :         }
    1237             : 
    1238        9056 :         if (!path_len && !dir) {
    1239           2 :                 if (error) {
    1240           2 :                         spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
    1241             :                 }
    1242           2 :                 return NULL;
    1243             :         }
    1244             : 
    1245        9054 :         if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
    1246           8 :                 if (error) {
    1247           0 :                         spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
    1248             :                 }
    1249           8 :                 return NULL;
    1250             :         }
    1251             : 
    1252        9046 :         if (!phar->manifest.arHash) {
    1253           0 :                 return NULL;
    1254             :         }
    1255             : 
    1256        9046 :         if (is_dir) {
    1257           5 :                 if (!path_len || path_len == 1) {
    1258           0 :                         return NULL;
    1259             :                 }
    1260           5 :                 path_len--;
    1261             :         }
    1262             : 
    1263       18092 :         if (NULL != (entry = zend_hash_str_find_ptr(&phar->manifest, path, path_len))) {
    1264        5445 :                 if (entry->is_deleted) {
    1265             :                         /* entry is deleted, but has not been flushed to disk yet */
    1266           0 :                         return NULL;
    1267             :                 }
    1268        5445 :                 if (entry->is_dir && !dir) {
    1269           1 :                         if (error) {
    1270           1 :                                 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
    1271             :                         }
    1272           1 :                         return NULL;
    1273             :                 }
    1274        5444 :                 if (!entry->is_dir && dir == 2) {
    1275             :                         /* user requested a directory, we must return one */
    1276           3 :                         if (error) {
    1277           3 :                                 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
    1278             :                         }
    1279           3 :                         return NULL;
    1280             :                 }
    1281        5441 :                 return entry;
    1282             :         }
    1283             : 
    1284        3601 :         if (dir) {
    1285          53 :                 if (zend_hash_str_exists(&phar->virtual_dirs, path, path_len)) {
    1286             :                         /* a file or directory exists in a sub-directory of this path */
    1287          20 :                         entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
    1288             :                         /* this next line tells PharFileInfo->__destruct() to efree the filename */
    1289          20 :                         entry->is_temp_dir = entry->is_dir = 1;
    1290          20 :                         entry->filename = (char *) estrndup(path, path_len + 1);
    1291          20 :                         entry->filename_len = path_len;
    1292          20 :                         entry->phar = phar;
    1293          20 :                         return entry;
    1294             :                 }
    1295             :         }
    1296             : 
    1297        3581 :         if (phar->mounted_dirs.arHash && zend_hash_num_elements(&phar->mounted_dirs)) {
    1298             :                 zend_string *str_key;
    1299             : 
    1300           6 :                 ZEND_HASH_FOREACH_STR_KEY(&phar->mounted_dirs, str_key) {
    1301           3 :                         if ((int)str_key->len >= path_len || strncmp(str_key->val, path, str_key->len)) {
    1302           0 :                                 continue;
    1303             :                         } else {
    1304             :                                 char *test;
    1305             :                                 int test_len;
    1306             :                                 php_stream_statbuf ssb;
    1307             : 
    1308           6 :                                 if (NULL == (entry = zend_hash_find_ptr(&phar->manifest, str_key))) {
    1309           0 :                                         if (error) {
    1310           0 :                                                 spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key->val);
    1311             :                                         }
    1312           0 :                                         return NULL;
    1313             :                                 }
    1314             : 
    1315           3 :                                 if (!entry->tmp || !entry->is_mounted) {
    1316           0 :                                         if (error) {
    1317           0 :                                                 spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key->val);
    1318             :                                         }
    1319           0 :                                         return NULL;
    1320             :                                 }
    1321             : 
    1322           3 :                                 test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + str_key->len);
    1323             : 
    1324           3 :                                 if (SUCCESS != php_stream_stat_path(test, &ssb)) {
    1325           0 :                                         efree(test);
    1326           0 :                                         return NULL;
    1327             :                                 }
    1328             : 
    1329           3 :                                 if (ssb.sb.st_mode & S_IFDIR && !dir) {
    1330           1 :                                         efree(test);
    1331           1 :                                         if (error) {
    1332           1 :                                                 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
    1333             :                                         }
    1334           1 :                                         return NULL;
    1335             :                                 }
    1336             : 
    1337           2 :                                 if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
    1338           0 :                                         efree(test);
    1339             :                                         /* user requested a directory, we must return one */
    1340           0 :                                         if (error) {
    1341           0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
    1342             :                                         }
    1343           0 :                                         return NULL;
    1344             :                                 }
    1345             : 
    1346             :                                 /* mount the file just in time */
    1347           2 :                                 if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
    1348           0 :                                         efree(test);
    1349           0 :                                         if (error) {
    1350           0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
    1351             :                                         }
    1352           0 :                                         return NULL;
    1353             :                                 }
    1354             : 
    1355           2 :                                 efree(test);
    1356             : 
    1357           4 :                                 if (NULL == (entry = zend_hash_str_find_ptr(&phar->manifest, path, path_len))) {
    1358           0 :                                         if (error) {
    1359           0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
    1360             :                                         }
    1361           0 :                                         return NULL;
    1362             :                                 }
    1363           2 :                                 return entry;
    1364             :                         }
    1365             :                 } ZEND_HASH_FOREACH_END();
    1366             :         }
    1367             : 
    1368        3578 :         return NULL;
    1369             : }
    1370             : /* }}} */
    1371             : 
    1372             : static const char hexChars[] = "0123456789ABCDEF";
    1373             : 
    1374        5109 : static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
    1375             : {
    1376        5109 :         int pos = -1;
    1377        5109 :         size_t len = 0;
    1378             : 
    1379        5109 :         *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
    1380             : 
    1381      108317 :         for (; len < digest_len; ++len) {
    1382      103208 :                 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
    1383      103208 :                 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
    1384             :         }
    1385        5109 :         (*signature)[++pos] = '\0';
    1386        5109 :         return pos;
    1387             : }
    1388             : /* }}} */
    1389             : 
    1390             : #ifndef PHAR_HAVE_OPENSSL
    1391             : static int phar_call_openssl_signverify(int is_sign, php_stream *fp, zend_off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC) /* {{{ */
    1392             : {
    1393             :         zend_fcall_info fci;
    1394             :         zend_fcall_info_cache fcc;
    1395             :         zval retval, zp[3], openssl;
    1396             :         zend_string *str;
    1397             : 
    1398             :         ZVAL_STRINGL(&openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1);
    1399             :         ZVAL_STRINGL(&zp[1], *signature, *signature_len);
    1400             :         ZVAL_STRINGL(&zp[2], key, key_len);
    1401             :         php_stream_rewind(fp);
    1402             :         str = php_stream_copy_to_mem(fp, (size_t) end, 0);
    1403             :         if (str) {
    1404             :                 ZVAL_STR(&zp[0], str);
    1405             :         } else {
    1406             :                 ZVAL_EMPTY_STRING(&zp[0]);
    1407             :         }
    1408             : 
    1409             :         if (end != Z_STRLEN(zp[0])) {
    1410             :                 zval_dtor(&zp[0]);
    1411             :                 zval_dtor(&zp[1]);
    1412             :                 zval_dtor(&zp[2]);
    1413             :                 zval_dtor(&openssl);
    1414             :                 return FAILURE;
    1415             :         }
    1416             : 
    1417             :         if (FAILURE == zend_fcall_info_init(&openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
    1418             :                 zval_dtor(&zp[0]);
    1419             :                 zval_dtor(&zp[1]);
    1420             :                 zval_dtor(&zp[2]);
    1421             :                 zval_dtor(&openssl);
    1422             :                 return FAILURE;
    1423             :         }
    1424             : 
    1425             :         fci.param_count = 3;
    1426             :         fci.params = zp;
    1427             :         Z_ADDREF(zp[0]);
    1428             :         if (is_sign) {
    1429             :                 ZVAL_NEW_REF(&zp[1], &zp[1]);
    1430             :         } else {
    1431             :                 Z_ADDREF(zp[1]);
    1432             :         }
    1433             :         Z_ADDREF(zp[2]);
    1434             : 
    1435             :         fci.retval = &retval;
    1436             : 
    1437             :         if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
    1438             :                 zval_dtor(&zp[0]);
    1439             :                 zval_dtor(&zp[1]);
    1440             :                 zval_dtor(&zp[2]);
    1441             :                 zval_dtor(&openssl);
    1442             :                 return FAILURE;
    1443             :         }
    1444             : 
    1445             :         zval_dtor(&openssl);
    1446             :         Z_DELREF(zp[0]);
    1447             : 
    1448             :         if (is_sign) {
    1449             :                 ZVAL_UNREF(&zp[1]);
    1450             :         } else {
    1451             :                 Z_DELREF(zp[1]);
    1452             :         }
    1453             :         Z_DELREF(zp[2]);
    1454             : 
    1455             :         zval_dtor(&zp[0]);
    1456             :         zval_dtor(&zp[2]);
    1457             : 
    1458             :         switch (Z_TYPE(retval)) {
    1459             :                 default:
    1460             :                 case IS_LONG:
    1461             :                         zval_dtor(&zp[1]);
    1462             :                         if (1 == Z_LVAL(retval)) {
    1463             :                                 return SUCCESS;
    1464             :                         }
    1465             :                         return FAILURE;
    1466             :                 case IS_TRUE:
    1467             :                         *signature = estrndup(Z_STRVAL(zp[1]), Z_STRLEN(zp[1]));
    1468             :                         *signature_len = Z_STRLEN(zp[1]);
    1469             :                         zval_dtor(&zp[1]);
    1470             :                         return SUCCESS;
    1471             :                 case IS_FALSE:
    1472             :                         zval_dtor(&zp[1]);
    1473             :                         return FAILURE;
    1474             :         }
    1475             : }
    1476             : /* }}} */
    1477             : #endif /* #ifndef PHAR_HAVE_OPENSSL */
    1478             : 
    1479         233 : int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_type, char *sig, int sig_len, char *fname, char **signature, int *signature_len, char **error TSRMLS_DC) /* {{{ */
    1480             : {
    1481             :         int read_size, len;
    1482             :         zend_off_t read_len;
    1483             :         unsigned char buf[1024];
    1484             : 
    1485         233 :         php_stream_rewind(fp);
    1486             : 
    1487         233 :         switch (sig_type) {
    1488             :                 case PHAR_SIG_OPENSSL: {
    1489             : #ifdef PHAR_HAVE_OPENSSL
    1490             :                         BIO *in;
    1491             :                         EVP_PKEY *key;
    1492           3 :                         EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
    1493             :                         EVP_MD_CTX md_ctx;
    1494             : #else
    1495             :                         int tempsig;
    1496             : #endif
    1497           3 :                         zend_string *pubkey = NULL;
    1498             :                         char *pfile;
    1499             :                         php_stream *pfp;
    1500             : #ifndef PHAR_HAVE_OPENSSL
    1501             :                         if (!zend_hash_str_exists(&module_registry, "openssl", sizeof("openssl")-1)) {
    1502             :                                 if (error) {
    1503             :                                         spprintf(error, 0, "openssl not loaded");
    1504             :                                 }
    1505             :                                 return FAILURE;
    1506             :                         }
    1507             : #endif
    1508             :                         /* use __FILE__ . '.pubkey' for public key file */
    1509           3 :                         spprintf(&pfile, 0, "%s.pubkey", fname);
    1510           3 :                         pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
    1511           3 :                         efree(pfile);
    1512             : 
    1513           3 :                         if (!pfp || !(pubkey = php_stream_copy_to_mem(pfp, PHP_STREAM_COPY_ALL, 0)) || !pubkey->len) {
    1514           0 :                                 if (pfp) {
    1515           0 :                                         php_stream_close(pfp);
    1516             :                                 }
    1517           0 :                                 if (error) {
    1518           0 :                                         spprintf(error, 0, "openssl public key could not be read");
    1519             :                                 }
    1520           0 :                                 return FAILURE;
    1521             :                         }
    1522             : 
    1523           3 :                         php_stream_close(pfp);
    1524             : #ifndef PHAR_HAVE_OPENSSL
    1525             :                         tempsig = sig_len;
    1526             : 
    1527             :                         if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey ? pubkey->val : NULL, pubkey ? pubkey->len : 0, &sig, &tempsig TSRMLS_CC)) {
    1528             :                                 if (pubkey) {
    1529             :                                         zend_string_release(pubkey);
    1530             :                                 }
    1531             : 
    1532             :                                 if (error) {
    1533             :                                         spprintf(error, 0, "openssl signature could not be verified");
    1534             :                                 }
    1535             : 
    1536             :                                 return FAILURE;
    1537             :                         }
    1538             : 
    1539             :                         if (pubkey) {
    1540             :                                 zend_string_release(pubkey);
    1541             :                         }
    1542             : 
    1543             :                         sig_len = tempsig;
    1544             : #else
    1545           3 :                         in = BIO_new_mem_buf(pubkey ? pubkey->val : NULL, pubkey ? pubkey->len : 0);
    1546             : 
    1547           3 :                         if (NULL == in) {
    1548             :                                 zend_string_release(pubkey);
    1549           0 :                                 if (error) {
    1550           0 :                                         spprintf(error, 0, "openssl signature could not be processed");
    1551             :                                 }
    1552           0 :                                 return FAILURE;
    1553             :                         }
    1554             : 
    1555           3 :                         key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
    1556           3 :                         BIO_free(in);
    1557             :                         zend_string_release(pubkey);
    1558             : 
    1559           3 :                         if (NULL == key) {
    1560           0 :                                 if (error) {
    1561           0 :                                         spprintf(error, 0, "openssl signature could not be processed");
    1562             :                                 }
    1563           0 :                                 return FAILURE;
    1564             :                         }
    1565             : 
    1566           3 :                         EVP_VerifyInit(&md_ctx, mdtype);
    1567           3 :                         read_len = end_of_phar;
    1568             : 
    1569           3 :                         if (read_len > sizeof(buf)) {
    1570           2 :                                 read_size = sizeof(buf);
    1571             :                         } else {
    1572           1 :                                 read_size = (int)read_len;
    1573             :                         }
    1574             : 
    1575           3 :                         php_stream_seek(fp, 0, SEEK_SET);
    1576             : 
    1577          22 :                         while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1578          16 :                                 EVP_VerifyUpdate (&md_ctx, buf, len);
    1579          16 :                                 read_len -= (zend_off_t)len;
    1580             : 
    1581          16 :                                 if (read_len < read_size) {
    1582           5 :                                         read_size = (int)read_len;
    1583             :                                 }
    1584             :                         }
    1585             : 
    1586           3 :                         if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
    1587             :                                 /* 1: signature verified, 0: signature does not match, -1: failed signature operation */
    1588           0 :                                 EVP_MD_CTX_cleanup(&md_ctx);
    1589             : 
    1590           0 :                                 if (error) {
    1591           0 :                                         spprintf(error, 0, "broken openssl signature");
    1592             :                                 }
    1593             : 
    1594           0 :                                 return FAILURE;
    1595             :                         }
    1596             : 
    1597           3 :                         EVP_MD_CTX_cleanup(&md_ctx);
    1598             : #endif
    1599             : 
    1600           3 :                         *signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
    1601             :                 }
    1602           3 :                 break;
    1603             : #ifdef PHAR_HASH_OK
    1604             :                 case PHAR_SIG_SHA512: {
    1605             :                         unsigned char digest[64];
    1606             :                         PHP_SHA512_CTX context;
    1607             : 
    1608           2 :                         PHP_SHA512Init(&context);
    1609           2 :                         read_len = end_of_phar;
    1610             : 
    1611           2 :                         if (read_len > sizeof(buf)) {
    1612           0 :                                 read_size = sizeof(buf);
    1613             :                         } else {
    1614           2 :                                 read_size = (int)read_len;
    1615             :                         }
    1616             : 
    1617           6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1618           2 :                                 PHP_SHA512Update(&context, buf, len);
    1619           2 :                                 read_len -= (zend_off_t)len;
    1620           2 :                                 if (read_len < read_size) {
    1621           2 :                                         read_size = (int)read_len;
    1622             :                                 }
    1623             :                         }
    1624             : 
    1625           2 :                         PHP_SHA512Final(digest, &context);
    1626             : 
    1627           2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1628           0 :                                 if (error) {
    1629           0 :                                         spprintf(error, 0, "broken signature");
    1630             :                                 }
    1631           0 :                                 return FAILURE;
    1632             :                         }
    1633             : 
    1634           2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1635           2 :                         break;
    1636             :                 }
    1637             :                 case PHAR_SIG_SHA256: {
    1638             :                         unsigned char digest[32];
    1639             :                         PHP_SHA256_CTX context;
    1640             : 
    1641           2 :                         PHP_SHA256Init(&context);
    1642           2 :                         read_len = end_of_phar;
    1643             : 
    1644           2 :                         if (read_len > sizeof(buf)) {
    1645           0 :                                 read_size = sizeof(buf);
    1646             :                         } else {
    1647           2 :                                 read_size = (int)read_len;
    1648             :                         }
    1649             : 
    1650           6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1651           2 :                                 PHP_SHA256Update(&context, buf, len);
    1652           2 :                                 read_len -= (zend_off_t)len;
    1653           2 :                                 if (read_len < read_size) {
    1654           2 :                                         read_size = (int)read_len;
    1655             :                                 }
    1656             :                         }
    1657             : 
    1658           2 :                         PHP_SHA256Final(digest, &context);
    1659             : 
    1660           2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1661           0 :                                 if (error) {
    1662           0 :                                         spprintf(error, 0, "broken signature");
    1663             :                                 }
    1664           0 :                                 return FAILURE;
    1665             :                         }
    1666             : 
    1667           2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1668           2 :                         break;
    1669             :                 }
    1670             : #else
    1671             :                 case PHAR_SIG_SHA512:
    1672             :                 case PHAR_SIG_SHA256:
    1673             :                         if (error) {
    1674             :                                 spprintf(error, 0, "unsupported signature");
    1675             :                         }
    1676             :                         return FAILURE;
    1677             : #endif
    1678             :                 case PHAR_SIG_SHA1: {
    1679             :                         unsigned char digest[20];
    1680             :                         PHP_SHA1_CTX  context;
    1681             : 
    1682         224 :                         PHP_SHA1Init(&context);
    1683         224 :                         read_len = end_of_phar;
    1684             : 
    1685         224 :                         if (read_len > sizeof(buf)) {
    1686          97 :                                 read_size = sizeof(buf);
    1687             :                         } else {
    1688         127 :                                 read_size = (int)read_len;
    1689             :                         }
    1690             : 
    1691        1656 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1692        1208 :                                 PHP_SHA1Update(&context, buf, len);
    1693        1208 :                                 read_len -= (zend_off_t)len;
    1694        1208 :                                 if (read_len < read_size) {
    1695         288 :                                         read_size = (int)read_len;
    1696             :                                 }
    1697             :                         }
    1698             : 
    1699         224 :                         PHP_SHA1Final(digest, &context);
    1700             : 
    1701         224 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1702           0 :                                 if (error) {
    1703           0 :                                         spprintf(error, 0, "broken signature");
    1704             :                                 }
    1705           0 :                                 return FAILURE;
    1706             :                         }
    1707             : 
    1708         224 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1709         224 :                         break;
    1710             :                 }
    1711             :                 case PHAR_SIG_MD5: {
    1712             :                         unsigned char digest[16];
    1713             :                         PHP_MD5_CTX   context;
    1714             : 
    1715           2 :                         PHP_MD5Init(&context);
    1716           2 :                         read_len = end_of_phar;
    1717             : 
    1718           2 :                         if (read_len > sizeof(buf)) {
    1719           0 :                                 read_size = sizeof(buf);
    1720             :                         } else {
    1721           2 :                                 read_size = (int)read_len;
    1722             :                         }
    1723             : 
    1724           6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1725           2 :                                 PHP_MD5Update(&context, buf, len);
    1726           2 :                                 read_len -= (zend_off_t)len;
    1727           2 :                                 if (read_len < read_size) {
    1728           2 :                                         read_size = (int)read_len;
    1729             :                                 }
    1730             :                         }
    1731             : 
    1732           2 :                         PHP_MD5Final(digest, &context);
    1733             : 
    1734           2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1735           0 :                                 if (error) {
    1736           0 :                                         spprintf(error, 0, "broken signature");
    1737             :                                 }
    1738           0 :                                 return FAILURE;
    1739             :                         }
    1740             : 
    1741           2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1742           2 :                         break;
    1743             :                 }
    1744             :                 default:
    1745           0 :                         if (error) {
    1746           0 :                                 spprintf(error, 0, "broken or unsupported signature");
    1747             :                         }
    1748           0 :                         return FAILURE;
    1749             :         }
    1750         233 :         return SUCCESS;
    1751             : }
    1752             : /* }}} */
    1753             : 
    1754        4876 : int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
    1755             : {
    1756             :         unsigned char buf[1024];
    1757             :         int sig_len;
    1758             : 
    1759        4876 :         php_stream_rewind(fp);
    1760             : 
    1761        4876 :         if (phar->signature) {
    1762         272 :                 efree(phar->signature);
    1763         272 :                 phar->signature = NULL;
    1764             :         }
    1765             : 
    1766        4876 :         switch(phar->sig_flags) {
    1767             : #ifdef PHAR_HASH_OK
    1768             :                 case PHAR_SIG_SHA512: {
    1769             :                         unsigned char digest[64];
    1770             :                         PHP_SHA512_CTX context;
    1771             : 
    1772           3 :                         PHP_SHA512Init(&context);
    1773             : 
    1774          16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    1775          10 :                                 PHP_SHA512Update(&context, buf, sig_len);
    1776             :                         }
    1777             : 
    1778           3 :                         PHP_SHA512Final(digest, &context);
    1779           3 :                         *signature = estrndup((char *) digest, 64);
    1780           3 :                         *signature_length = 64;
    1781           3 :                         break;
    1782             :                 }
    1783             :                 case PHAR_SIG_SHA256: {
    1784             :                         unsigned char digest[32];
    1785             :                         PHP_SHA256_CTX  context;
    1786             : 
    1787           3 :                         PHP_SHA256Init(&context);
    1788             : 
    1789          16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    1790          10 :                                 PHP_SHA256Update(&context, buf, sig_len);
    1791             :                         }
    1792             : 
    1793           3 :                         PHP_SHA256Final(digest, &context);
    1794           3 :                         *signature = estrndup((char *) digest, 32);
    1795           3 :                         *signature_length = 32;
    1796           3 :                         break;
    1797             :                 }
    1798             : #else
    1799             :                 case PHAR_SIG_SHA512:
    1800             :                 case PHAR_SIG_SHA256:
    1801             :                         if (error) {
    1802             :                                 spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
    1803             :                         }
    1804             : 
    1805             :                         return FAILURE;
    1806             : #endif
    1807             :                 case PHAR_SIG_OPENSSL: {
    1808             :                         int siglen;
    1809             :                         unsigned char *sigbuf;
    1810             : #ifdef PHAR_HAVE_OPENSSL
    1811             :                         BIO *in;
    1812             :                         EVP_PKEY *key;
    1813             :                         EVP_MD_CTX *md_ctx;
    1814             : 
    1815           3 :                         in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
    1816             : 
    1817           3 :                         if (in == NULL) {
    1818           0 :                                 if (error) {
    1819           0 :                                         spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
    1820             :                                 }
    1821           0 :                                 return FAILURE;
    1822             :                         }
    1823             : 
    1824           3 :                         key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
    1825           3 :                         BIO_free(in);
    1826             : 
    1827           3 :                         if (!key) {
    1828           0 :                                 if (error) {
    1829           0 :                                         spprintf(error, 0, "unable to process private key");
    1830             :                                 }
    1831           0 :                                 return FAILURE;
    1832             :                         }
    1833             : 
    1834           3 :                         md_ctx = EVP_MD_CTX_create();
    1835             : 
    1836           3 :                         siglen = EVP_PKEY_size(key);
    1837           3 :                         sigbuf = emalloc(siglen + 1);
    1838             : 
    1839           3 :                         if (!EVP_SignInit(md_ctx, EVP_sha1())) {
    1840           0 :                                 efree(sigbuf);
    1841           0 :                                 if (error) {
    1842           0 :                                         spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname);
    1843             :                                 }
    1844           0 :                                 return FAILURE;
    1845             :                         }
    1846             : 
    1847          16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    1848          10 :                                 if (!EVP_SignUpdate(md_ctx, buf, sig_len)) {
    1849           0 :                                         efree(sigbuf);
    1850           0 :                                         if (error) {
    1851           0 :                                                 spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname);
    1852             :                                         }
    1853           0 :                                         return FAILURE;
    1854             :                                 }
    1855             :                         }
    1856             : 
    1857           3 :                         if (!EVP_SignFinal (md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
    1858           0 :                                 efree(sigbuf);
    1859           0 :                                 if (error) {
    1860           0 :                                         spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
    1861             :                                 }
    1862           0 :                                 return FAILURE;
    1863             :                         }
    1864             : 
    1865           3 :                         sigbuf[siglen] = '\0';
    1866           3 :                         EVP_MD_CTX_destroy(md_ctx);
    1867             : #else
    1868             :                         sigbuf = NULL;
    1869             :                         siglen = 0;
    1870             :                         php_stream_seek(fp, 0, SEEK_END);
    1871             : 
    1872             :                         if (FAILURE == phar_call_openssl_signverify(1, fp, php_stream_tell(fp), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen TSRMLS_CC)) {
    1873             :                                 if (error) {
    1874             :                                         spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
    1875             :                                 }
    1876             :                                 return FAILURE;
    1877             :                         }
    1878             : #endif
    1879           3 :                         *signature = (char *) sigbuf;
    1880           3 :                         *signature_length = siglen;
    1881             :                 }
    1882           3 :                 break;
    1883             :                 default:
    1884         169 :                         phar->sig_flags = PHAR_SIG_SHA1;
    1885             :                 case PHAR_SIG_SHA1: {
    1886             :                         unsigned char digest[20];
    1887             :                         PHP_SHA1_CTX  context;
    1888             : 
    1889        4862 :                         PHP_SHA1Init(&context);
    1890             : 
    1891       42593 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    1892       32869 :                                 PHP_SHA1Update(&context, buf, sig_len);
    1893             :                         }
    1894             : 
    1895        4862 :                         PHP_SHA1Final(digest, &context);
    1896        4862 :                         *signature = estrndup((char *) digest, 20);
    1897        4862 :                         *signature_length = 20;
    1898        4862 :                         break;
    1899             :                 }
    1900             :                 case PHAR_SIG_MD5: {
    1901             :                         unsigned char digest[16];
    1902             :                         PHP_MD5_CTX   context;
    1903             : 
    1904           5 :                         PHP_MD5Init(&context);
    1905             : 
    1906          22 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    1907          12 :                                 PHP_MD5Update(&context, buf, sig_len);
    1908             :                         }
    1909             : 
    1910           5 :                         PHP_MD5Final(digest, &context);
    1911           5 :                         *signature = estrndup((char *) digest, 16);
    1912           5 :                         *signature_length = 16;
    1913             :                         break;
    1914             :                 }
    1915             :         }
    1916             : 
    1917        4876 :         phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
    1918        4876 :         return SUCCESS;
    1919             : }
    1920             : /* }}} */
    1921             : 
    1922       21166 : void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
    1923             : {
    1924             :         const char *s;
    1925             : 
    1926      119956 :         while ((s = zend_memrchr(filename, '/', filename_len))) {
    1927       35272 :                 filename_len = s - filename;
    1928       35272 :                 if (NULL == zend_hash_str_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
    1929        7043 :                         break;
    1930             :                 }
    1931             :         }
    1932       21166 : }
    1933             : /* }}} */
    1934             : 
    1935           4 : static int phar_update_cached_entry(zval *data, void *argument TSRMLS_DC) /* {{{ */
    1936             : {
    1937           4 :         phar_entry_info *entry = (phar_entry_info *)Z_PTR_P(data);
    1938             : 
    1939           4 :         entry->phar = (phar_archive_data *)argument;
    1940             : 
    1941           4 :         if (entry->link) {
    1942           0 :                 entry->link = estrdup(entry->link);
    1943             :         }
    1944             : 
    1945           4 :         if (entry->tmp) {
    1946           0 :                 entry->tmp = estrdup(entry->tmp);
    1947             :         }
    1948             : 
    1949           4 :         entry->metadata_str.s = NULL;
    1950           4 :         entry->filename = estrndup(entry->filename, entry->filename_len);
    1951           4 :         entry->is_persistent = 0;
    1952             : 
    1953           8 :         if (Z_TYPE(entry->metadata) != IS_UNDEF) {
    1954           3 :                 if (entry->metadata_len) {
    1955           3 :                         char *buf = estrndup((char *) Z_PTR(entry->metadata), entry->metadata_len);
    1956             :                         /* assume success, we would have failed before */
    1957           3 :                         phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len TSRMLS_CC);
    1958           3 :                         efree(buf);
    1959             :                 } else {
    1960           0 :                         zval_copy_ctor(&entry->metadata);
    1961           0 :                         entry->metadata_str.s = NULL;
    1962             :                 }
    1963             :         }
    1964           4 :         return ZEND_HASH_APPLY_KEEP;
    1965             : }
    1966             : /* }}} */
    1967             : 
    1968           4 : static void phar_manifest_copy_ctor(zval *zv) /* {{{ */
    1969             : {
    1970           4 :         phar_entry_info *info = emalloc(sizeof(phar_entry_info));
    1971           4 :         memcpy(info, Z_PTR_P(zv), sizeof(phar_entry_info));
    1972           4 :         Z_PTR_P(zv) = info;
    1973           4 : }
    1974             : /* }}} */
    1975             : 
    1976           3 : static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
    1977             : {
    1978             :         phar_archive_data *phar;
    1979             :         HashTable newmanifest;
    1980             :         char *fname;
    1981             :         phar_archive_object *objphar;
    1982             : 
    1983           3 :         phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
    1984           3 :         *phar = **pphar;
    1985           3 :         phar->is_persistent = 0;
    1986           3 :         fname = phar->fname;
    1987           3 :         phar->fname = estrndup(phar->fname, phar->fname_len);
    1988           3 :         phar->ext = phar->fname + (phar->ext - fname);
    1989             : 
    1990           3 :         if (phar->alias) {
    1991           3 :                 phar->alias = estrndup(phar->alias, phar->alias_len);
    1992             :         }
    1993             : 
    1994           3 :         if (phar->signature) {
    1995           3 :                 phar->signature = estrdup(phar->signature);
    1996             :         }
    1997             : 
    1998           6 :         if (Z_TYPE(phar->metadata) != IS_UNDEF) {
    1999             :                 /* assume success, we would have failed before */
    2000           3 :                 if (phar->metadata_len) {
    2001           3 :                         char *buf = estrndup((char *) Z_PTR(phar->metadata), phar->metadata_len);
    2002           3 :                         phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC);
    2003           3 :                         efree(buf);
    2004             :                 } else {
    2005           0 :                         zval_copy_ctor(&phar->metadata);
    2006             :                 }
    2007             :         }
    2008             : 
    2009           3 :         zend_hash_init(&newmanifest, sizeof(phar_entry_info),
    2010             :                 zend_get_hash_value, destroy_phar_manifest_entry, 0);
    2011           3 :         zend_hash_copy(&newmanifest, &(*pphar)->manifest, phar_manifest_copy_ctor);
    2012           3 :         zend_hash_apply_with_argument(&newmanifest, phar_update_cached_entry, (void *)phar TSRMLS_CC);
    2013           3 :         phar->manifest = newmanifest;
    2014           3 :         zend_hash_init(&phar->mounted_dirs, sizeof(char *),
    2015             :                 zend_get_hash_value, NULL, 0);
    2016           3 :         zend_hash_init(&phar->virtual_dirs, sizeof(char *),
    2017             :                 zend_get_hash_value, NULL, 0);
    2018           3 :         zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL);
    2019           3 :         *pphar = phar;
    2020             : 
    2021             :         /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
    2022           7 :         ZEND_HASH_FOREACH_PTR(&PHAR_GLOBALS->phar_persist_map, objphar) {
    2023           2 :                 if (objphar->archive->fname_len == phar->fname_len && !memcmp(objphar->archive->fname, phar->fname, phar->fname_len)) {
    2024           2 :                         objphar->archive = phar;
    2025             :                 }
    2026             :         } ZEND_HASH_FOREACH_END();
    2027           3 : }
    2028             : /* }}} */
    2029             : 
    2030           3 : int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
    2031             : {
    2032             :         zval zv, *pzv;
    2033             :         phar_archive_data *newpphar;
    2034             : 
    2035           3 :         ZVAL_PTR(&zv, *pphar);
    2036           3 :         if (NULL == (pzv = zend_hash_str_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, &zv))) {
    2037           0 :                 return FAILURE;
    2038             :         }
    2039             : 
    2040           3 :         phar_copy_cached_phar((phar_archive_data **)&Z_PTR_P(pzv) TSRMLS_CC);
    2041           3 :         newpphar = Z_PTR_P(pzv);
    2042             :         /* invalidate phar cache */
    2043           3 :         PHAR_G(last_phar) = NULL;
    2044           3 :         PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
    2045             : 
    2046           6 :         if (newpphar->alias_len && NULL == zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_alias_map), newpphar->alias, newpphar->alias_len, newpphar)) {
    2047           0 :                 zend_hash_str_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
    2048           0 :                 return FAILURE;
    2049             :         }
    2050             : 
    2051           3 :         *pphar = newpphar;
    2052           3 :         return SUCCESS;
    2053             : }
    2054             : /* }}} */
    2055             : 
    2056             : /*
    2057             :  * Local variables:
    2058             :  * tab-width: 4
    2059             :  * c-basic-offset: 4
    2060             :  * End:
    2061             :  * vim600: noet sw=4 ts=4 fdm=marker
    2062             :  * vim<600: noet sw=4 ts=4
    2063             :  */

Generated by: LCOV version 1.10

Generated at Tue, 14 Oct 2014 07:25:47 +0000 (7 days ago)

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