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: 743 990 75.1 %
Date: 2014-07-21 Functions: 27 28 96.4 %
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, 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        7974 : 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        7974 :         if (!entry->link) {
      70        7943 :                 return entry;
      71             :         }
      72             : 
      73          31 :         link = phar_get_link_location(entry TSRMLS_CC);
      74          34 :         if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) ||
      75           3 :                 SUCCESS == zend_hash_find(&(entry->phar->manifest), link, strlen(link), (void **)&link_entry)) {
      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       59789 : php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) /* {{{ */
      91             : {
      92       59789 :         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       59786 :         if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) {
     101       16023 :                 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       16023 :                 return phar_get_entrypfp(entry TSRMLS_CC);
     106       43763 :         } else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) {
     107       15638 :                 return phar_get_entrypufp(entry TSRMLS_CC);
     108       28125 :         } else if (entry->fp_type == PHAR_MOD) {
     109       28114 :                 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       23824 : int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC) /* {{{ */
     121             : {
     122       23824 :         php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
     123             :         off_t temp, eoffset;
     124             : 
     125       23824 :         if (!fp) {
     126           1 :                 return -1;
     127             :         }
     128             : 
     129       23823 :         if (follow_links) {
     130             :                 phar_entry_info *t;
     131        7719 :                 t = phar_get_link_source(entry TSRMLS_CC);
     132        7719 :                 if (t) {
     133        7719 :                         entry = t;
     134             :                 }
     135             :         }
     136             : 
     137       23823 :         if (entry->is_dir) {
     138          18 :                 return 0;
     139             :         }
     140             : 
     141       23805 :         eoffset = phar_get_fp_offset(entry TSRMLS_CC);
     142             : 
     143       23805 :         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       23805 :                         temp = eoffset + offset;
     152       23805 :                         break;
     153             :                 default:
     154           0 :                         temp = 0;
     155             :         }
     156             : 
     157       23805 :         if (temp > eoffset + (off_t) entry->uncompressed_filesize) {
     158           0 :                 return -1;
     159             :         }
     160             : 
     161       23805 :         if (temp < eoffset) {
     162           0 :                 return -1;
     163             :         }
     164             : 
     165       23805 :         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           5 :                 if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) {
     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          18 :         if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
     244          15 :                 return SUCCESS;
     245             :         }
     246             : 
     247           3 :         efree(entry.tmp);
     248           3 :         efree(entry.filename);
     249           3 :         return FAILURE;
     250             : }
     251             : /* }}} */
     252             : 
     253       17302 : 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       17302 :         if (pphar) {
     260           0 :                 *pphar = NULL;
     261             :         } else {
     262       17302 :                 pphar = &phar;
     263             :         }
     264             : 
     265       17302 :         if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
     266       17279 :                 return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
     267             :         }
     268             : 
     269          23 :         fname = (char*)zend_get_executed_filename(TSRMLS_C);
     270          23 :         fname_len = strlen(fname);
     271             : 
     272          23 :         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           2 :                 arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
     274           2 :                 arch_len = PHAR_G(last_phar_name_len);
     275           2 :                 phar = PHAR_G(last_phar);
     276           2 :                 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           6 :                 if (pphar) {
     294           6 :                         *pphar = phar;
     295             :                 }
     296             : 
     297           6 :                 try_len = filename_len;
     298           6 :                 test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
     299             : 
     300           6 :                 if (*test == '/') {
     301           2 :                         if (zend_hash_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           4 :                         if (zend_hash_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           2 :                 efree(test);
     316             :         }
     317             : 
     318           5 :         spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
     319           5 :         efree(arch);
     320           5 :         ret = php_resolve_path(filename, filename_len, path TSRMLS_CC);
     321           5 :         efree(path);
     322             : 
     323           5 :         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           2 :                 zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
     332             : 
     333           2 :                 if (!pphar && PHAR_G(manifest_cached)) {
     334           0 :                         zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
     335             :                 }
     336             : 
     337           2 :                 efree(arch);
     338           2 :                 efree(entry);
     339             :         }
     340             : 
     341           5 :         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        8218 : 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        8218 :         int for_write  = mode[0] != 'r' || mode[1] == '+';
     358        8218 :         int for_append = mode[0] == 'a';
     359        8218 :         int for_create = mode[0] != 'r';
     360        8218 :         int for_trunc  = mode[0] == 'w';
     361             : 
     362        8218 :         if (!ret) {
     363           0 :                 return FAILURE;
     364             :         }
     365             : 
     366        8218 :         *ret = NULL;
     367             : 
     368        8218 :         if (error) {
     369        8218 :                 *error = NULL;
     370             :         }
     371             : 
     372        8218 :         if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
     373           0 :                 return FAILURE;
     374             :         }
     375             : 
     376        8218 :         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        8218 :         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        8215 :         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        8197 :                 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        3544 :                         if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
     400        3518 :                                 return SUCCESS;
     401             :                         }
     402          26 :                         return FAILURE;
     403             :                 }
     404             :         }
     405             : 
     406        4655 :         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        4654 :         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        4654 :         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        4653 :         if (entry->is_deleted) {
     432           0 :                 if (!for_create) {
     433           0 :                         return FAILURE;
     434             :                 }
     435           0 :                 entry->is_deleted = 0;
     436             :         }
     437             : 
     438        4653 :         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        4651 :         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        4651 :                 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         527 :                         if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
     483           4 :                                 return FAILURE;
     484             :                         }
     485             :                 }
     486             :         }
     487             : 
     488        4647 :         *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
     489        4647 :         (*ret)->position = 0;
     490        4647 :         (*ret)->phar = phar;
     491        4647 :         (*ret)->for_write = for_write;
     492        4647 :         (*ret)->internal_file = entry;
     493        4647 :         (*ret)->is_zip = entry->is_zip;
     494        4647 :         (*ret)->is_tar = entry->is_tar;
     495        4647 :         (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
     496        4647 :         if (entry->link) {
     497           3 :                 (*ret)->zero = phar_get_fp_offset(phar_get_link_source(entry TSRMLS_CC) TSRMLS_CC);
     498             :         } else {
     499        4644 :                 (*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC);
     500             :         }
     501             : 
     502        4647 :         if (!phar->is_persistent) {
     503        4647 :                 ++(entry->fp_refcount);
     504        4647 :                 ++(entry->phar->refcount);
     505             :         }
     506             : 
     507        4647 :         return SUCCESS;
     508             : }
     509             : /* }}} */
     510             : 
     511             : /**
     512             :  * Create a new dummy file slot within a writeable phar for a newly created file
     513             :  */
     514        7665 : 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        7665 :         is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0;
     527             : 
     528        7665 :         if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
     529           0 :                 return NULL;
     530             :         }
     531             : 
     532        7665 :         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        7660 :         } else if (ret) {
     535        4126 :                 return ret;
     536             :         }
     537             : 
     538        3534 :         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        3526 :         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        3526 :         ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
     554             : 
     555             :         /* create an entry, this is a new file */
     556        3526 :         memset(&etemp, 0, sizeof(phar_entry_info));
     557        3526 :         etemp.filename_len = path_len;
     558        3526 :         etemp.fp_type = PHAR_MOD;
     559        3526 :         etemp.fp = php_stream_fopen_tmpfile();
     560             : 
     561        3526 :         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        3526 :         etemp.fp_refcount = 1;
     570             : 
     571        3526 :         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        3510 :                 etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
     576             :         }
     577        3526 :         if (is_dir) {
     578           2 :                 etemp.filename_len--; /* strip trailing / */
     579           2 :                 path_len--;
     580             :         }
     581             : 
     582        3526 :         phar_add_virtual_dirs(phar, path, path_len TSRMLS_CC);
     583        3526 :         etemp.is_modified = 1;
     584        3526 :         etemp.timestamp = time(0);
     585        3526 :         etemp.is_crc_checked = 1;
     586        3526 :         etemp.phar = phar;
     587        3526 :         etemp.filename = estrndup(path, path_len);
     588        3526 :         etemp.is_zip = phar->is_zip;
     589             : 
     590        3526 :         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        3526 :         if (FAILURE == zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry)) {
     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        3526 :         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        3526 :         ++(phar->refcount);
     613        3526 :         ret->phar = phar;
     614        3526 :         ret->fp = entry->fp;
     615        3526 :         ret->position = ret->zero = 0;
     616        3526 :         ret->for_write = 1;
     617        3526 :         ret->is_zip = entry->is_zip;
     618        3526 :         ret->is_tar = entry->is_tar;
     619        3526 :         ret->internal_file = entry;
     620             : 
     621        3526 :         return ret;
     622             : }
     623             : /* }}} */
     624             : 
     625             : /* initialize a phar_archive_data's read-only fp for existing phar data */
     626         350 : int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) /* {{{ */
     627             : {
     628         350 :         if (phar_get_pharfp(phar TSRMLS_CC)) {
     629         177 :                 return SUCCESS;
     630             :         }
     631             : 
     632         173 :         if (php_check_open_basedir(phar->fname TSRMLS_CC)) {
     633           0 :                 return FAILURE;
     634             :         }
     635             : 
     636         173 :         phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC);
     637             : 
     638         173 :         if (!phar_get_pharfp(phar TSRMLS_CC)) {
     639           4 :                 return FAILURE;
     640             :         }
     641             : 
     642         169 :         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        2434 : int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) /* {{{ */
     692             : {
     693             :         php_stream_filter *filter;
     694        2434 :         phar_archive_data *phar = entry->phar;
     695             :         char *filtername;
     696             :         off_t loc;
     697             :         php_stream *ufp;
     698             :         phar_entry_data dummy;
     699             : 
     700        2434 :         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        2431 :         if (entry->is_modified) {
     708        1362 :                 return SUCCESS;
     709             :         }
     710             : 
     711        1069 :         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        1060 :         if (entry->fp_type != PHAR_FP) {
     719             :                 /* either newly created or already modified */
     720           2 :                 return SUCCESS;
     721             :         }
     722             : 
     723        1058 :         if (!phar_get_pharfp(phar TSRMLS_CC)) {
     724         151 :                 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        1057 :         if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
     731        1016 :                 dummy.internal_file = entry;
     732        1016 :                 dummy.phar = phar;
     733        1016 :                 dummy.zero = entry->offset;
     734        1016 :                 dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
     735        1016 :                 if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
     736           0 :                         return FAILURE;
     737             :                 }
     738        1016 :                 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 != (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.arBuckets
     929           0 :                         && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) {
     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_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       20060 : 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       20060 :         ulong fhash, ahash = 0;
     967             : 
     968       20060 :         phar_request_initialize(TSRMLS_C);
     969             : 
     970       20060 :         if (error) {
     971       19468 :                 *error = NULL;
     972             :         }
     973             : 
     974       20060 :         *archive = NULL;
     975             : 
     976       20060 :         if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
     977       18352 :                 *archive = PHAR_G(last_phar);
     978       18352 :                 if (alias && alias_len) {
     979             : 
     980         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))) {
     981           3 :                                 if (error) {
     982           3 :                                         spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
     983             :                                 }
     984           3 :                                 *archive = NULL;
     985           3 :                                 return FAILURE;
     986             :                         }
     987             : 
     988         172 :                         if (PHAR_G(last_phar)->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len, (void**)&fd_ptr)) {
     989         135 :                                 zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
     990             :                         }
     991             : 
     992         172 :                         zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(*archive), sizeof(phar_archive_data*), NULL);
     993         172 :                         PHAR_G(last_alias) = alias;
     994         172 :                         PHAR_G(last_alias_len) = alias_len;
     995             :                 }
     996             : 
     997       18349 :                 return SUCCESS;
     998             :         }
     999             : 
    1000        1708 :         if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
    1001           3 :                 fd = PHAR_G(last_phar);
    1002           3 :                 fd_ptr = &fd;
    1003           3 :                 goto alias_success;
    1004             :         }
    1005             : 
    1006        1705 :         if (alias && alias_len) {
    1007         127 :                 ahash = zend_inline_hash_func(alias, alias_len);
    1008         127 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) {
    1009             : alias_success:
    1010          21 :                         if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) {
    1011           5 :                                 if (error) {
    1012           5 :                                         spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
    1013             :                                 }
    1014           5 :                                 if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
    1015           0 :                                         if (error) {
    1016           0 :                                                 efree(*error);
    1017           0 :                                                 *error = NULL;
    1018             :                                         }
    1019             :                                 }
    1020           5 :                                 return FAILURE;
    1021             :                         }
    1022             : 
    1023          16 :                         *archive = *fd_ptr;
    1024          16 :                         fd = *fd_ptr;
    1025          16 :                         PHAR_G(last_phar) = fd;
    1026          16 :                         PHAR_G(last_phar_name) = fd->fname;
    1027          16 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1028          16 :                         PHAR_G(last_alias) = alias;
    1029          16 :                         PHAR_G(last_alias_len) = alias_len;
    1030             : 
    1031          16 :                         return SUCCESS;
    1032             :                 }
    1033             : 
    1034         109 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
    1035           0 :                         goto alias_success;
    1036             :                 }
    1037             :         }
    1038             : 
    1039        1687 :         fhash = zend_inline_hash_func(fname, fname_len);
    1040        1687 :         my_realpath = NULL;
    1041        1687 :         save = fname;
    1042        1687 :         save_len = fname_len;
    1043             : 
    1044        1687 :         if (fname && fname_len) {
    1045        1687 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
    1046         780 :                         *archive = *fd_ptr;
    1047         780 :                         fd = *fd_ptr;
    1048             : 
    1049         780 :                         if (alias && alias_len) {
    1050          43 :                                 if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
    1051           0 :                                         if (error) {
    1052           0 :                                                 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
    1053             :                                         }
    1054           0 :                                         return FAILURE;
    1055             :                                 }
    1056             : 
    1057          43 :                                 if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
    1058           1 :                                         zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
    1059             :                                 }
    1060             : 
    1061          43 :                                 zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
    1062             :                         }
    1063             : 
    1064         780 :                         PHAR_G(last_phar) = fd;
    1065         780 :                         PHAR_G(last_phar_name) = fd->fname;
    1066         780 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1067         780 :                         PHAR_G(last_alias) = fd->alias;
    1068         780 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1069             : 
    1070         780 :                         return SUCCESS;
    1071             :                 }
    1072             : 
    1073         907 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
    1074           3 :                         *archive = *fd_ptr;
    1075           3 :                         fd = *fd_ptr;
    1076             : 
    1077             :                         /* this could be problematic - alias should never be different from manifest alias
    1078             :                            for cached phars */
    1079           3 :                         if (!fd->is_temporary_alias && alias && alias_len) {
    1080           0 :                                 if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
    1081           0 :                                         if (error) {
    1082           0 :                                                 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
    1083             :                                         }
    1084           0 :                                         return FAILURE;
    1085             :                                 }
    1086             :                         }
    1087             : 
    1088           3 :                         PHAR_G(last_phar) = fd;
    1089           3 :                         PHAR_G(last_phar_name) = fd->fname;
    1090           3 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1091           3 :                         PHAR_G(last_alias) = fd->alias;
    1092           3 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1093             : 
    1094           3 :                         return SUCCESS;
    1095             :                 }
    1096             : 
    1097         904 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
    1098         128 :                         fd = *archive = *fd_ptr;
    1099             : 
    1100         128 :                         PHAR_G(last_phar) = fd;
    1101         128 :                         PHAR_G(last_phar_name) = fd->fname;
    1102         128 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1103         128 :                         PHAR_G(last_alias) = fd->alias;
    1104         128 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1105             : 
    1106         128 :                         return SUCCESS;
    1107             :                 }
    1108             : 
    1109         776 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
    1110           0 :                         fd = *archive = *fd_ptr;
    1111             : 
    1112           0 :                         PHAR_G(last_phar) = fd;
    1113           0 :                         PHAR_G(last_phar_name) = fd->fname;
    1114           0 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1115           0 :                         PHAR_G(last_alias) = fd->alias;
    1116           0 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1117             : 
    1118           0 :                         return SUCCESS;
    1119             :                 }
    1120             : 
    1121             :                 /* not found, try converting \ to / */
    1122         776 :                 my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
    1123             : 
    1124         776 :                 if (my_realpath) {
    1125         776 :                         fname_len = strlen(my_realpath);
    1126         776 :                         fname = my_realpath;
    1127             :                 } else {
    1128           0 :                         return FAILURE;
    1129             :                 }
    1130             : #ifdef PHP_WIN32
    1131             :                 phar_unixify_path_separators(fname, fname_len);
    1132             : #endif
    1133         776 :                 fhash = zend_inline_hash_func(fname, fname_len);
    1134             : 
    1135         776 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
    1136             : realpath_success:
    1137          15 :                         *archive = *fd_ptr;
    1138          15 :                         fd = *fd_ptr;
    1139             : 
    1140          15 :                         if (alias && alias_len) {
    1141           0 :                                 zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
    1142             :                         }
    1143             : 
    1144          15 :                         efree(my_realpath);
    1145             : 
    1146          15 :                         PHAR_G(last_phar) = fd;
    1147          15 :                         PHAR_G(last_phar_name) = fd->fname;
    1148          15 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1149          15 :                         PHAR_G(last_alias) = fd->alias;
    1150          15 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1151             : 
    1152          15 :                         return SUCCESS;
    1153             :                 }
    1154             : 
    1155         761 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
    1156           0 :                         goto realpath_success;
    1157             :                 }
    1158             : 
    1159         761 :                 efree(my_realpath);
    1160             :         }
    1161             : 
    1162         761 :         return FAILURE;
    1163             : }
    1164             : /* }}} */
    1165             : 
    1166             : /**
    1167             :  * Determine which stream compression filter (if any) we need to read this file
    1168             :  */
    1169          49 : char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
    1170             : {
    1171          49 :         switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
    1172             :         case PHAR_ENT_COMPRESSED_GZ:
    1173          33 :                 return "zlib.deflate";
    1174             :         case PHAR_ENT_COMPRESSED_BZ2:
    1175          16 :                 return "bzip2.compress";
    1176             :         default:
    1177           0 :                 return return_unknown ? "unknown" : NULL;
    1178             :         }
    1179             : }
    1180             : /* }}} */
    1181             : 
    1182             : /**
    1183             :  * Determine which stream decompression filter (if any) we need to read this file
    1184             :  */
    1185          41 : char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
    1186             : {
    1187             :         php_uint32 flags;
    1188             : 
    1189          41 :         if (entry->is_modified) {
    1190           0 :                 flags = entry->old_flags;
    1191             :         } else {
    1192          41 :                 flags = entry->flags;
    1193             :         }
    1194             : 
    1195          41 :         switch (flags & PHAR_ENT_COMPRESSION_MASK) {
    1196             :                 case PHAR_ENT_COMPRESSED_GZ:
    1197          28 :                         return "zlib.inflate";
    1198             :                 case PHAR_ENT_COMPRESSED_BZ2:
    1199          13 :                         return "bzip2.decompress";
    1200             :                 default:
    1201           0 :                         return return_unknown ? "unknown" : NULL;
    1202             :         }
    1203             : }
    1204             : /* }}} */
    1205             : 
    1206             : /**
    1207             :  * retrieve information on a file contained within a phar, or null if it ain't there
    1208             :  */
    1209        8284 : phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */
    1210             : {
    1211        8284 :         return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC);
    1212             : }
    1213             : /* }}} */
    1214             : /**
    1215             :  * retrieve information on a file or directory contained within a phar, or null if none found
    1216             :  * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only
    1217             :  * valid pre-existing empty directory entries
    1218             :  */
    1219        9068 : 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) /* {{{ */
    1220             : {
    1221             :         const char *pcr_error;
    1222             :         phar_entry_info *entry;
    1223             :         int is_dir;
    1224             : 
    1225             : #ifdef PHP_WIN32
    1226             :         phar_unixify_path_separators(path, path_len);
    1227             : #endif
    1228             : 
    1229        9068 :         is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0;
    1230             : 
    1231        9068 :         if (error) {
    1232        1334 :                 *error = NULL;
    1233             :         }
    1234             : 
    1235        9068 :         if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
    1236           0 :                 if (error) {
    1237           0 :                         spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it");
    1238             :                 }
    1239           0 :                 return NULL;
    1240             :         }
    1241             : 
    1242        9068 :         if (!path_len && !dir) {
    1243           2 :                 if (error) {
    1244           2 :                         spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
    1245             :                 }
    1246           2 :                 return NULL;
    1247             :         }
    1248             : 
    1249        9066 :         if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
    1250           8 :                 if (error) {
    1251           0 :                         spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
    1252             :                 }
    1253           8 :                 return NULL;
    1254             :         }
    1255             : 
    1256        9058 :         if (!phar->manifest.arBuckets) {
    1257           0 :                 return NULL;
    1258             :         }
    1259             : 
    1260        9058 :         if (is_dir) {
    1261           5 :                 if (!path_len || path_len == 1) {
    1262           0 :                         return NULL;
    1263             :                 }
    1264           5 :                 path_len--;
    1265             :         }
    1266             : 
    1267        9058 :         if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
    1268        5451 :                 if (entry->is_deleted) {
    1269             :                         /* entry is deleted, but has not been flushed to disk yet */
    1270           0 :                         return NULL;
    1271             :                 }
    1272        5451 :                 if (entry->is_dir && !dir) {
    1273           3 :                         if (error) {
    1274           3 :                                 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
    1275             :                         }
    1276           3 :                         return NULL;
    1277             :                 }
    1278        5448 :                 if (!entry->is_dir && dir == 2) {
    1279             :                         /* user requested a directory, we must return one */
    1280           3 :                         if (error) {
    1281           3 :                                 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
    1282             :                         }
    1283           3 :                         return NULL;
    1284             :                 }
    1285        5445 :                 return entry;
    1286             :         }
    1287             : 
    1288        3607 :         if (dir) {
    1289          55 :                 if (zend_hash_exists(&phar->virtual_dirs, path, path_len)) {
    1290             :                         /* a file or directory exists in a sub-directory of this path */
    1291          20 :                         entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
    1292             :                         /* this next line tells PharFileInfo->__destruct() to efree the filename */
    1293          20 :                         entry->is_temp_dir = entry->is_dir = 1;
    1294          20 :                         entry->filename = (char *) estrndup(path, path_len + 1);
    1295          20 :                         entry->filename_len = path_len;
    1296          20 :                         entry->phar = phar;
    1297          20 :                         return entry;
    1298             :                 }
    1299             :         }
    1300             : 
    1301        3587 :         if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
    1302             :                 char *str_key;
    1303             :                 ulong unused;
    1304             :                 uint keylen;
    1305             : 
    1306           3 :                 zend_hash_internal_pointer_reset(&phar->mounted_dirs);
    1307           3 :                 while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
    1308           3 :                         if (HASH_KEY_NON_EXISTENT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &str_key, &keylen, &unused, 0, NULL)) {
    1309           0 :                                 break;
    1310             :                         }
    1311             : 
    1312           3 :                         if ((int)keylen >= path_len || strncmp(str_key, path, keylen)) {
    1313           0 :                                 continue;
    1314             :                         } else {
    1315             :                                 char *test;
    1316             :                                 int test_len;
    1317             :                                 php_stream_statbuf ssb;
    1318             : 
    1319           3 :                                 if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
    1320           0 :                                         if (error) {
    1321           0 :                                                 spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key);
    1322             :                                         }
    1323           0 :                                         return NULL;
    1324             :                                 }
    1325             : 
    1326           3 :                                 if (!entry->tmp || !entry->is_mounted) {
    1327           0 :                                         if (error) {
    1328           0 :                                                 spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key);
    1329             :                                         }
    1330           0 :                                         return NULL;
    1331             :                                 }
    1332             : 
    1333           3 :                                 test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
    1334             : 
    1335           3 :                                 if (SUCCESS != php_stream_stat_path(test, &ssb)) {
    1336           0 :                                         efree(test);
    1337           0 :                                         return NULL;
    1338             :                                 }
    1339             : 
    1340           3 :                                 if (ssb.sb.st_mode & S_IFDIR && !dir) {
    1341           1 :                                         efree(test);
    1342           1 :                                         if (error) {
    1343           1 :                                                 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
    1344             :                                         }
    1345           1 :                                         return NULL;
    1346             :                                 }
    1347             : 
    1348           2 :                                 if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
    1349           0 :                                         efree(test);
    1350             :                                         /* user requested a directory, we must return one */
    1351           0 :                                         if (error) {
    1352           0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
    1353             :                                         }
    1354           0 :                                         return NULL;
    1355             :                                 }
    1356             : 
    1357             :                                 /* mount the file just in time */
    1358           2 :                                 if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
    1359           0 :                                         efree(test);
    1360           0 :                                         if (error) {
    1361           0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
    1362             :                                         }
    1363           0 :                                         return NULL;
    1364             :                                 }
    1365             : 
    1366           2 :                                 efree(test);
    1367             : 
    1368           2 :                                 if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
    1369           0 :                                         if (error) {
    1370           0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
    1371             :                                         }
    1372           0 :                                         return NULL;
    1373             :                                 }
    1374           2 :                                 return entry;
    1375             :                         }
    1376             :                 }
    1377             :         }
    1378             : 
    1379        3584 :         return NULL;
    1380             : }
    1381             : /* }}} */
    1382             : 
    1383             : static const char hexChars[] = "0123456789ABCDEF";
    1384             : 
    1385        5113 : static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
    1386             : {
    1387        5113 :         int pos = -1;
    1388        5113 :         size_t len = 0;
    1389             : 
    1390        5113 :         *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
    1391             : 
    1392      108401 :         for (; len < digest_len; ++len) {
    1393      103288 :                 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
    1394      103288 :                 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
    1395             :         }
    1396        5113 :         (*signature)[++pos] = '\0';
    1397        5113 :         return pos;
    1398             : }
    1399             : /* }}} */
    1400             : 
    1401             : #ifndef PHAR_HAVE_OPENSSL
    1402             : static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC) /* {{{ */
    1403             : {
    1404             :         zend_fcall_info fci;
    1405             :         zend_fcall_info_cache fcc;
    1406             :         zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
    1407             : 
    1408             :         MAKE_STD_ZVAL(zdata);
    1409             :         MAKE_STD_ZVAL(openssl);
    1410             :         ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
    1411             :         MAKE_STD_ZVAL(zsig);
    1412             :         ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
    1413             :         MAKE_STD_ZVAL(zkey);
    1414             :         ZVAL_STRINGL(zkey, key, key_len, 1);
    1415             :         zp[0] = &zdata;
    1416             :         zp[1] = &zsig;
    1417             :         zp[2] = &zkey;
    1418             : 
    1419             :         php_stream_rewind(fp);
    1420             :         Z_TYPE_P(zdata) = IS_STRING;
    1421             :         Z_STRLEN_P(zdata) = end;
    1422             : 
    1423             :         if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
    1424             :                 zval_dtor(zdata);
    1425             :                 zval_dtor(zsig);
    1426             :                 zval_dtor(zkey);
    1427             :                 zval_dtor(openssl);
    1428             :                 efree(openssl);
    1429             :                 efree(zdata);
    1430             :                 efree(zkey);
    1431             :                 efree(zsig);
    1432             :                 return FAILURE;
    1433             :         }
    1434             : 
    1435             :         if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
    1436             :                 zval_dtor(zdata);
    1437             :                 zval_dtor(zsig);
    1438             :                 zval_dtor(zkey);
    1439             :                 zval_dtor(openssl);
    1440             :                 efree(openssl);
    1441             :                 efree(zdata);
    1442             :                 efree(zkey);
    1443             :                 efree(zsig);
    1444             :                 return FAILURE;
    1445             :         }
    1446             : 
    1447             :         fci.param_count = 3;
    1448             :         fci.params = zp;
    1449             :         Z_ADDREF_P(zdata);
    1450             :         if (is_sign) {
    1451             :                 Z_SET_ISREF_P(zsig);
    1452             :         } else {
    1453             :                 Z_ADDREF_P(zsig);
    1454             :         }
    1455             :         Z_ADDREF_P(zkey);
    1456             : 
    1457             :         fci.retval_ptr_ptr = &retval_ptr;
    1458             : 
    1459             :         if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
    1460             :                 zval_dtor(zdata);
    1461             :                 zval_dtor(zsig);
    1462             :                 zval_dtor(zkey);
    1463             :                 zval_dtor(openssl);
    1464             :                 efree(openssl);
    1465             :                 efree(zdata);
    1466             :                 efree(zkey);
    1467             :                 efree(zsig);
    1468             :                 return FAILURE;
    1469             :         }
    1470             : 
    1471             :         zval_dtor(openssl);
    1472             :         efree(openssl);
    1473             :         Z_DELREF_P(zdata);
    1474             : 
    1475             :         if (is_sign) {
    1476             :                 Z_UNSET_ISREF_P(zsig);
    1477             :         } else {
    1478             :                 Z_DELREF_P(zsig);
    1479             :         }
    1480             :         Z_DELREF_P(zkey);
    1481             : 
    1482             :         zval_dtor(zdata);
    1483             :         efree(zdata);
    1484             :         zval_dtor(zkey);
    1485             :         efree(zkey);
    1486             : 
    1487             :         switch (Z_TYPE_P(retval_ptr)) {
    1488             :                 default:
    1489             :                 case IS_LONG:
    1490             :                         zval_dtor(zsig);
    1491             :                         efree(zsig);
    1492             :                         if (1 == Z_LVAL_P(retval_ptr)) {
    1493             :                                 efree(retval_ptr);
    1494             :                                 return SUCCESS;
    1495             :                         }
    1496             :                         efree(retval_ptr);
    1497             :                         return FAILURE;
    1498             :                 case IS_BOOL:
    1499             :                         efree(retval_ptr);
    1500             :                         if (Z_BVAL_P(retval_ptr)) {
    1501             :                                 *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
    1502             :                                 *signature_len = Z_STRLEN_P(zsig);
    1503             :                                 zval_dtor(zsig);
    1504             :                                 efree(zsig);
    1505             :                                 return SUCCESS;
    1506             :                         }
    1507             :                         zval_dtor(zsig);
    1508             :                         efree(zsig);
    1509             :                         return FAILURE;
    1510             :         }
    1511             : }
    1512             : /* }}} */
    1513             : #endif /* #ifndef PHAR_HAVE_OPENSSL */
    1514             : 
    1515         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) /* {{{ */
    1516             : {
    1517             :         int read_size, len;
    1518             :         off_t read_len;
    1519             :         unsigned char buf[1024];
    1520             : 
    1521         233 :         php_stream_rewind(fp);
    1522             : 
    1523         233 :         switch (sig_type) {
    1524             :                 case PHAR_SIG_OPENSSL: {
    1525             : #ifdef PHAR_HAVE_OPENSSL
    1526             :                         BIO *in;
    1527             :                         EVP_PKEY *key;
    1528           3 :                         EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
    1529             :                         EVP_MD_CTX md_ctx;
    1530             : #else
    1531             :                         int tempsig;
    1532             : #endif
    1533             :                         php_uint32 pubkey_len;
    1534           3 :                         char *pubkey = NULL, *pfile;
    1535             :                         php_stream *pfp;
    1536             : #ifndef PHAR_HAVE_OPENSSL
    1537             :                         if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
    1538             :                                 if (error) {
    1539             :                                         spprintf(error, 0, "openssl not loaded");
    1540             :                                 }
    1541             :                                 return FAILURE;
    1542             :                         }
    1543             : #endif
    1544             :                         /* use __FILE__ . '.pubkey' for public key file */
    1545           3 :                         spprintf(&pfile, 0, "%s.pubkey", fname);
    1546           3 :                         pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
    1547           3 :                         efree(pfile);
    1548             : 
    1549             : #if PHP_MAJOR_VERSION > 5
    1550             :                         if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, (void **) &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
    1551             : #else
    1552           3 :                         if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
    1553             : #endif
    1554           0 :                                 if (pfp) {
    1555           0 :                                         php_stream_close(pfp);
    1556             :                                 }
    1557           0 :                                 if (error) {
    1558           0 :                                         spprintf(error, 0, "openssl public key could not be read");
    1559             :                                 }
    1560           0 :                                 return FAILURE;
    1561             :                         }
    1562             : 
    1563           3 :                         php_stream_close(pfp);
    1564             : #ifndef PHAR_HAVE_OPENSSL
    1565             :                         tempsig = sig_len;
    1566             : 
    1567             :                         if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey, pubkey_len, &sig, &tempsig TSRMLS_CC)) {
    1568             :                                 if (pubkey) {
    1569             :                                         efree(pubkey);
    1570             :                                 }
    1571             : 
    1572             :                                 if (error) {
    1573             :                                         spprintf(error, 0, "openssl signature could not be verified");
    1574             :                                 }
    1575             : 
    1576             :                                 return FAILURE;
    1577             :                         }
    1578             : 
    1579             :                         if (pubkey) {
    1580             :                                 efree(pubkey);
    1581             :                         }
    1582             : 
    1583             :                         sig_len = tempsig;
    1584             : #else
    1585           3 :                         in = BIO_new_mem_buf(pubkey, pubkey_len);
    1586             : 
    1587           3 :                         if (NULL == in) {
    1588           0 :                                 efree(pubkey);
    1589           0 :                                 if (error) {
    1590           0 :                                         spprintf(error, 0, "openssl signature could not be processed");
    1591             :                                 }
    1592           0 :                                 return FAILURE;
    1593             :                         }
    1594             : 
    1595           3 :                         key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
    1596           3 :                         BIO_free(in);
    1597           3 :                         efree(pubkey);
    1598             : 
    1599           3 :                         if (NULL == key) {
    1600           0 :                                 if (error) {
    1601           0 :                                         spprintf(error, 0, "openssl signature could not be processed");
    1602             :                                 }
    1603           0 :                                 return FAILURE;
    1604             :                         }
    1605             : 
    1606           3 :                         EVP_VerifyInit(&md_ctx, mdtype);
    1607           3 :                         read_len = end_of_phar;
    1608             : 
    1609           3 :                         if (read_len > sizeof(buf)) {
    1610           2 :                                 read_size = sizeof(buf);
    1611             :                         } else {
    1612           1 :                                 read_size = (int)read_len;
    1613             :                         }
    1614             : 
    1615           3 :                         php_stream_seek(fp, 0, SEEK_SET);
    1616             : 
    1617          22 :                         while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1618          16 :                                 EVP_VerifyUpdate (&md_ctx, buf, len);
    1619          16 :                                 read_len -= (off_t)len;
    1620             : 
    1621          16 :                                 if (read_len < read_size) {
    1622           5 :                                         read_size = (int)read_len;
    1623             :                                 }
    1624             :                         }
    1625             : 
    1626           3 :                         if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
    1627             :                                 /* 1: signature verified, 0: signature does not match, -1: failed signature operation */
    1628           0 :                                 EVP_MD_CTX_cleanup(&md_ctx);
    1629             : 
    1630           0 :                                 if (error) {
    1631           0 :                                         spprintf(error, 0, "broken openssl signature");
    1632             :                                 }
    1633             : 
    1634           0 :                                 return FAILURE;
    1635             :                         }
    1636             : 
    1637           3 :                         EVP_MD_CTX_cleanup(&md_ctx);
    1638             : #endif
    1639             : 
    1640           3 :                         *signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
    1641             :                 }
    1642           3 :                 break;
    1643             : #ifdef PHAR_HASH_OK
    1644             :                 case PHAR_SIG_SHA512: {
    1645             :                         unsigned char digest[64];
    1646             :                         PHP_SHA512_CTX context;
    1647             : 
    1648           2 :                         PHP_SHA512Init(&context);
    1649           2 :                         read_len = end_of_phar;
    1650             : 
    1651           2 :                         if (read_len > sizeof(buf)) {
    1652           0 :                                 read_size = sizeof(buf);
    1653             :                         } else {
    1654           2 :                                 read_size = (int)read_len;
    1655             :                         }
    1656             : 
    1657           6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1658           2 :                                 PHP_SHA512Update(&context, buf, len);
    1659           2 :                                 read_len -= (off_t)len;
    1660           2 :                                 if (read_len < read_size) {
    1661           2 :                                         read_size = (int)read_len;
    1662             :                                 }
    1663             :                         }
    1664             : 
    1665           2 :                         PHP_SHA512Final(digest, &context);
    1666             : 
    1667           2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1668           0 :                                 if (error) {
    1669           0 :                                         spprintf(error, 0, "broken signature");
    1670             :                                 }
    1671           0 :                                 return FAILURE;
    1672             :                         }
    1673             : 
    1674           2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1675           2 :                         break;
    1676             :                 }
    1677             :                 case PHAR_SIG_SHA256: {
    1678             :                         unsigned char digest[32];
    1679             :                         PHP_SHA256_CTX context;
    1680             : 
    1681           2 :                         PHP_SHA256Init(&context);
    1682           2 :                         read_len = end_of_phar;
    1683             : 
    1684           2 :                         if (read_len > sizeof(buf)) {
    1685           0 :                                 read_size = sizeof(buf);
    1686             :                         } else {
    1687           2 :                                 read_size = (int)read_len;
    1688             :                         }
    1689             : 
    1690           6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1691           2 :                                 PHP_SHA256Update(&context, buf, len);
    1692           2 :                                 read_len -= (off_t)len;
    1693           2 :                                 if (read_len < read_size) {
    1694           2 :                                         read_size = (int)read_len;
    1695             :                                 }
    1696             :                         }
    1697             : 
    1698           2 :                         PHP_SHA256Final(digest, &context);
    1699             : 
    1700           2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1701           0 :                                 if (error) {
    1702           0 :                                         spprintf(error, 0, "broken signature");
    1703             :                                 }
    1704           0 :                                 return FAILURE;
    1705             :                         }
    1706             : 
    1707           2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1708           2 :                         break;
    1709             :                 }
    1710             : #else
    1711             :                 case PHAR_SIG_SHA512:
    1712             :                 case PHAR_SIG_SHA256:
    1713             :                         if (error) {
    1714             :                                 spprintf(error, 0, "unsupported signature");
    1715             :                         }
    1716             :                         return FAILURE;
    1717             : #endif
    1718             :                 case PHAR_SIG_SHA1: {
    1719             :                         unsigned char digest[20];
    1720             :                         PHP_SHA1_CTX  context;
    1721             : 
    1722         224 :                         PHP_SHA1Init(&context);
    1723         224 :                         read_len = end_of_phar;
    1724             : 
    1725         224 :                         if (read_len > sizeof(buf)) {
    1726          97 :                                 read_size = sizeof(buf);
    1727             :                         } else {
    1728         127 :                                 read_size = (int)read_len;
    1729             :                         }
    1730             : 
    1731        1656 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1732        1208 :                                 PHP_SHA1Update(&context, buf, len);
    1733        1208 :                                 read_len -= (off_t)len;
    1734        1208 :                                 if (read_len < read_size) {
    1735         288 :                                         read_size = (int)read_len;
    1736             :                                 }
    1737             :                         }
    1738             : 
    1739         224 :                         PHP_SHA1Final(digest, &context);
    1740             : 
    1741         224 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1742           0 :                                 if (error) {
    1743           0 :                                         spprintf(error, 0, "broken signature");
    1744             :                                 }
    1745           0 :                                 return FAILURE;
    1746             :                         }
    1747             : 
    1748         224 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1749         224 :                         break;
    1750             :                 }
    1751             :                 case PHAR_SIG_MD5: {
    1752             :                         unsigned char digest[16];
    1753             :                         PHP_MD5_CTX   context;
    1754             : 
    1755           2 :                         PHP_MD5Init(&context);
    1756           2 :                         read_len = end_of_phar;
    1757             : 
    1758           2 :                         if (read_len > sizeof(buf)) {
    1759           0 :                                 read_size = sizeof(buf);
    1760             :                         } else {
    1761           2 :                                 read_size = (int)read_len;
    1762             :                         }
    1763             : 
    1764           6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1765           2 :                                 PHP_MD5Update(&context, buf, len);
    1766           2 :                                 read_len -= (off_t)len;
    1767           2 :                                 if (read_len < read_size) {
    1768           2 :                                         read_size = (int)read_len;
    1769             :                                 }
    1770             :                         }
    1771             : 
    1772           2 :                         PHP_MD5Final(digest, &context);
    1773             : 
    1774           2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1775           0 :                                 if (error) {
    1776           0 :                                         spprintf(error, 0, "broken signature");
    1777             :                                 }
    1778           0 :                                 return FAILURE;
    1779             :                         }
    1780             : 
    1781           2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1782           2 :                         break;
    1783             :                 }
    1784             :                 default:
    1785           0 :                         if (error) {
    1786           0 :                                 spprintf(error, 0, "broken or unsupported signature");
    1787             :                         }
    1788           0 :                         return FAILURE;
    1789             :         }
    1790         233 :         return SUCCESS;
    1791             : }
    1792             : /* }}} */
    1793             : 
    1794        4880 : int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
    1795             : {
    1796             :         unsigned char buf[1024];
    1797             :         int sig_len;
    1798             : 
    1799        4880 :         php_stream_rewind(fp);
    1800             : 
    1801        4880 :         if (phar->signature) {
    1802         272 :                 efree(phar->signature);
    1803         272 :                 phar->signature = NULL;
    1804             :         }
    1805             : 
    1806        4880 :         switch(phar->sig_flags) {
    1807             : #ifdef PHAR_HASH_OK
    1808             :                 case PHAR_SIG_SHA512: {
    1809             :                         unsigned char digest[64];
    1810             :                         PHP_SHA512_CTX context;
    1811             : 
    1812           3 :                         PHP_SHA512Init(&context);
    1813             : 
    1814          16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    1815          10 :                                 PHP_SHA512Update(&context, buf, sig_len);
    1816             :                         }
    1817             : 
    1818           3 :                         PHP_SHA512Final(digest, &context);
    1819           3 :                         *signature = estrndup((char *) digest, 64);
    1820           3 :                         *signature_length = 64;
    1821           3 :                         break;
    1822             :                 }
    1823             :                 case PHAR_SIG_SHA256: {
    1824             :                         unsigned char digest[32];
    1825             :                         PHP_SHA256_CTX  context;
    1826             : 
    1827           3 :                         PHP_SHA256Init(&context);
    1828             : 
    1829          16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    1830          10 :                                 PHP_SHA256Update(&context, buf, sig_len);
    1831             :                         }
    1832             : 
    1833           3 :                         PHP_SHA256Final(digest, &context);
    1834           3 :                         *signature = estrndup((char *) digest, 32);
    1835           3 :                         *signature_length = 32;
    1836           3 :                         break;
    1837             :                 }
    1838             : #else
    1839             :                 case PHAR_SIG_SHA512:
    1840             :                 case PHAR_SIG_SHA256:
    1841             :                         if (error) {
    1842             :                                 spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
    1843             :                         }
    1844             : 
    1845             :                         return FAILURE;
    1846             : #endif
    1847             :                 case PHAR_SIG_OPENSSL: {
    1848             :                         int siglen;
    1849             :                         unsigned char *sigbuf;
    1850             : #ifdef PHAR_HAVE_OPENSSL
    1851             :                         BIO *in;
    1852             :                         EVP_PKEY *key;
    1853             :                         EVP_MD_CTX *md_ctx;
    1854             : 
    1855           3 :                         in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
    1856             : 
    1857           3 :                         if (in == NULL) {
    1858           0 :                                 if (error) {
    1859           0 :                                         spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
    1860             :                                 }
    1861           0 :                                 return FAILURE;
    1862             :                         }
    1863             : 
    1864           3 :                         key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
    1865           3 :                         BIO_free(in);
    1866             : 
    1867           3 :                         if (!key) {
    1868           0 :                                 if (error) {
    1869           0 :                                         spprintf(error, 0, "unable to process private key");
    1870             :                                 }
    1871           0 :                                 return FAILURE;
    1872             :                         }
    1873             : 
    1874           3 :                         md_ctx = EVP_MD_CTX_create();
    1875             : 
    1876           3 :                         siglen = EVP_PKEY_size(key);
    1877           3 :                         sigbuf = emalloc(siglen + 1);
    1878             : 
    1879           3 :                         if (!EVP_SignInit(md_ctx, EVP_sha1())) {
    1880           0 :                                 efree(sigbuf);
    1881           0 :                                 if (error) {
    1882           0 :                                         spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname);
    1883             :                                 }
    1884           0 :                                 return FAILURE;
    1885             :                         }
    1886             : 
    1887          16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    1888          10 :                                 if (!EVP_SignUpdate(md_ctx, buf, sig_len)) {
    1889           0 :                                         efree(sigbuf);
    1890           0 :                                         if (error) {
    1891           0 :                                                 spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname);
    1892             :                                         }
    1893           0 :                                         return FAILURE;
    1894             :                                 }
    1895             :                         }
    1896             : 
    1897           3 :                         if (!EVP_SignFinal (md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
    1898           0 :                                 efree(sigbuf);
    1899           0 :                                 if (error) {
    1900           0 :                                         spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
    1901             :                                 }
    1902           0 :                                 return FAILURE;
    1903             :                         }
    1904             : 
    1905           3 :                         sigbuf[siglen] = '\0';
    1906           3 :                         EVP_MD_CTX_destroy(md_ctx);
    1907             : #else
    1908             :                         sigbuf = NULL;
    1909             :                         siglen = 0;
    1910             :                         php_stream_seek(fp, 0, SEEK_END);
    1911             : 
    1912             :                         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)) {
    1913             :                                 if (error) {
    1914             :                                         spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
    1915             :                                 }
    1916             :                                 return FAILURE;
    1917             :                         }
    1918             : #endif
    1919           3 :                         *signature = (char *) sigbuf;
    1920           3 :                         *signature_length = siglen;
    1921             :                 }
    1922           3 :                 break;
    1923             :                 default:
    1924         171 :                         phar->sig_flags = PHAR_SIG_SHA1;
    1925             :                 case PHAR_SIG_SHA1: {
    1926             :                         unsigned char digest[20];
    1927             :                         PHP_SHA1_CTX  context;
    1928             : 
    1929        4866 :                         PHP_SHA1Init(&context);
    1930             : 
    1931       42629 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    1932       32897 :                                 PHP_SHA1Update(&context, buf, sig_len);
    1933             :                         }
    1934             : 
    1935        4866 :                         PHP_SHA1Final(digest, &context);
    1936        4866 :                         *signature = estrndup((char *) digest, 20);
    1937        4866 :                         *signature_length = 20;
    1938        4866 :                         break;
    1939             :                 }
    1940             :                 case PHAR_SIG_MD5: {
    1941             :                         unsigned char digest[16];
    1942             :                         PHP_MD5_CTX   context;
    1943             : 
    1944           5 :                         PHP_MD5Init(&context);
    1945             : 
    1946          22 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    1947          12 :                                 PHP_MD5Update(&context, buf, sig_len);
    1948             :                         }
    1949             : 
    1950           5 :                         PHP_MD5Final(digest, &context);
    1951           5 :                         *signature = estrndup((char *) digest, 16);
    1952           5 :                         *signature_length = 16;
    1953             :                         break;
    1954             :                 }
    1955             :         }
    1956             : 
    1957        4880 :         phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
    1958        4880 :         return SUCCESS;
    1959             : }
    1960             : /* }}} */
    1961             : 
    1962       21176 : void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
    1963             : {
    1964             :         const char *s;
    1965             : 
    1966       70584 :         while ((s = zend_memrchr(filename, '/', filename_len))) {
    1967       35276 :                 filename_len = s - filename;
    1968       35276 :                 if (FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
    1969        7044 :                         break;
    1970             :                 }
    1971             :         }
    1972       21176 : }
    1973             : /* }}} */
    1974             : 
    1975           4 : static int phar_update_cached_entry(void *data, void *argument) /* {{{ */
    1976             : {
    1977           4 :         phar_entry_info *entry = (phar_entry_info *)data;
    1978             :         TSRMLS_FETCH();
    1979             : 
    1980           4 :         entry->phar = (phar_archive_data *)argument;
    1981             : 
    1982           4 :         if (entry->link) {
    1983           0 :                 entry->link = estrdup(entry->link);
    1984             :         }
    1985             : 
    1986           4 :         if (entry->tmp) {
    1987           0 :                 entry->tmp = estrdup(entry->tmp);
    1988             :         }
    1989             : 
    1990           4 :         entry->metadata_str.c = 0;
    1991           4 :         entry->filename = estrndup(entry->filename, entry->filename_len);
    1992           4 :         entry->is_persistent = 0;
    1993             : 
    1994           4 :         if (entry->metadata) {
    1995           3 :                 if (entry->metadata_len) {
    1996           3 :                         char *buf = estrndup((char *) entry->metadata, entry->metadata_len);
    1997             :                         /* assume success, we would have failed before */
    1998           3 :                         phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len TSRMLS_CC);
    1999           3 :                         efree(buf);
    2000             :                 } else {
    2001             :                         zval *t;
    2002             : 
    2003           0 :                         t = entry->metadata;
    2004           0 :                         ALLOC_ZVAL(entry->metadata);
    2005           0 :                         *entry->metadata = *t;
    2006           0 :                         zval_copy_ctor(entry->metadata);
    2007           0 :                         Z_SET_REFCOUNT_P(entry->metadata, 1);
    2008           0 :                         entry->metadata_str.c = NULL;
    2009           0 :                         entry->metadata_str.len = 0;
    2010             :                 }
    2011             :         }
    2012           4 :         return ZEND_HASH_APPLY_KEEP;
    2013             : }
    2014             : /* }}} */
    2015             : 
    2016           3 : static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
    2017             : {
    2018             :         phar_archive_data *phar;
    2019             :         HashTable newmanifest;
    2020             :         char *fname;
    2021             :         phar_archive_object **objphar;
    2022             : 
    2023           3 :         phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
    2024           3 :         *phar = **pphar;
    2025           3 :         phar->is_persistent = 0;
    2026           3 :         fname = phar->fname;
    2027           3 :         phar->fname = estrndup(phar->fname, phar->fname_len);
    2028           3 :         phar->ext = phar->fname + (phar->ext - fname);
    2029             : 
    2030           3 :         if (phar->alias) {
    2031           3 :                 phar->alias = estrndup(phar->alias, phar->alias_len);
    2032             :         }
    2033             : 
    2034           3 :         if (phar->signature) {
    2035           3 :                 phar->signature = estrdup(phar->signature);
    2036             :         }
    2037             : 
    2038           3 :         if (phar->metadata) {
    2039             :                 /* assume success, we would have failed before */
    2040           3 :                 if (phar->metadata_len) {
    2041           3 :                         char *buf = estrndup((char *) phar->metadata, phar->metadata_len);
    2042           3 :                         phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC);
    2043           3 :                         efree(buf);
    2044             :                 } else {
    2045             :                         zval *t;
    2046             : 
    2047           0 :                         t = phar->metadata;
    2048           0 :                         ALLOC_ZVAL(phar->metadata);
    2049           0 :                         *phar->metadata = *t;
    2050           0 :                         zval_copy_ctor(phar->metadata);
    2051           0 :                         Z_SET_REFCOUNT_P(phar->metadata, 1);
    2052             :                 }
    2053             :         }
    2054             : 
    2055           3 :         zend_hash_init(&newmanifest, sizeof(phar_entry_info),
    2056             :                 zend_get_hash_value, destroy_phar_manifest_entry, 0);
    2057           3 :         zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info));
    2058           3 :         zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC);
    2059           3 :         phar->manifest = newmanifest;
    2060           3 :         zend_hash_init(&phar->mounted_dirs, sizeof(char *),
    2061             :                 zend_get_hash_value, NULL, 0);
    2062           3 :         zend_hash_init(&phar->virtual_dirs, sizeof(char *),
    2063             :                 zend_get_hash_value, NULL, 0);
    2064           3 :         zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
    2065           3 :         *pphar = phar;
    2066             : 
    2067             :         /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
    2068           8 :         for (zend_hash_internal_pointer_reset(&PHAR_GLOBALS->phar_persist_map);
    2069           5 :         SUCCESS == zend_hash_get_current_data(&PHAR_GLOBALS->phar_persist_map, (void **) &objphar);
    2070           2 :         zend_hash_move_forward(&PHAR_GLOBALS->phar_persist_map)) {
    2071           2 :                 if (objphar[0]->arc.archive->fname_len == phar->fname_len && !memcmp(objphar[0]->arc.archive->fname, phar->fname, phar->fname_len)) {
    2072           2 :                         objphar[0]->arc.archive = phar;
    2073             :                 }
    2074             :         }
    2075           3 : }
    2076             : /* }}} */
    2077             : 
    2078           3 : int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
    2079             : {
    2080           3 :         phar_archive_data **newpphar, *newphar = NULL;
    2081             : 
    2082           3 :         if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) {
    2083           0 :                 return FAILURE;
    2084             :         }
    2085             : 
    2086           3 :         *newpphar = *pphar;
    2087           3 :         phar_copy_cached_phar(newpphar TSRMLS_CC);
    2088             :         /* invalidate phar cache */
    2089           3 :         PHAR_G(last_phar) = NULL;
    2090           3 :         PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
    2091             : 
    2092           3 :         if (newpphar[0]->alias_len && FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), newpphar[0]->alias, newpphar[0]->alias_len, (void*)newpphar, sizeof(phar_archive_data*), NULL)) {
    2093           0 :                 zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
    2094           0 :                 return FAILURE;
    2095             :         }
    2096             : 
    2097           3 :         *pphar = *newpphar;
    2098           3 :         return SUCCESS;
    2099             : }
    2100             : /* }}} */
    2101             : 
    2102             : /*
    2103             :  * Local variables:
    2104             :  * tab-width: 4
    2105             :  * c-basic-offset: 4
    2106             :  * End:
    2107             :  * vim600: noet sw=4 ts=4 fdm=marker
    2108             :  * vim<600: noet sw=4 ts=4
    2109             :  */

Generated by: LCOV version 1.10

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

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