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: 746 989 75.4 %
Date: 2014-07-27 Functions: 27 27 100.0 %
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-2013 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             : #if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300
      45             : extern php_stream_wrapper php_stream_phar_wrapper;
      46             : #endif
      47             : 
      48             : /* for links to relative location, prepend cwd of the entry */
      49          31 : static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC) /* {{{ */
      50             : {
      51          31 :         char *p, *ret = NULL;
      52          31 :         if (!entry->link) {
      53           0 :                 return NULL;
      54             :         }
      55          31 :         if (entry->link[0] == '/') {
      56           1 :                 return estrdup(entry->link + 1);
      57             :         }
      58          30 :         p = strrchr(entry->filename, '/');
      59          30 :         if (p) {
      60           3 :                 *p = '\0';
      61           3 :                 spprintf(&ret, 0, "%s/%s", entry->filename, entry->link);
      62           3 :                 return ret;
      63             :         }
      64          27 :         return entry->link;
      65             : }
      66             : /* }}} */
      67             : 
      68        7857 : phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC) /* {{{ */
      69             : {
      70             :         phar_entry_info *link_entry;
      71             :         char *link;
      72             : 
      73        7857 :         if (!entry->link) {
      74        7826 :                 return entry;
      75             :         }
      76             : 
      77          31 :         link = phar_get_link_location(entry TSRMLS_CC);
      78          34 :         if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) ||
      79           3 :                 SUCCESS == zend_hash_find(&(entry->phar->manifest), link, strlen(link), (void **)&link_entry)) {
      80          31 :                 if (link != entry->link) {
      81           4 :                         efree(link);
      82             :                 }
      83          31 :                 return phar_get_link_source(link_entry TSRMLS_CC);
      84             :         } else {
      85           0 :                 if (link != entry->link) {
      86           0 :                         efree(link);
      87             :                 }
      88           0 :                 return NULL;
      89             :         }
      90             : }
      91             : /* }}} */
      92             : 
      93             : /* retrieve a phar_entry_info's current file pointer for reading contents */
      94       46300 : php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) /* {{{ */
      95             : {
      96       46300 :         if (follow_links && entry->link) {
      97           3 :                 phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
      98             : 
      99           3 :                 if (link_entry && link_entry != entry) {
     100           3 :                         return phar_get_efp(link_entry, 1 TSRMLS_CC);
     101             :                 }
     102             :         }
     103             : 
     104       46297 :         if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) {
     105        3119 :                 if (!phar_get_entrypfp(entry TSRMLS_CC)) {
     106             :                         /* re-open just in time for cases where our refcount reached 0 on the phar archive */
     107          19 :                         phar_open_archive_fp(entry->phar TSRMLS_CC);
     108             :                 }
     109        3119 :                 return phar_get_entrypfp(entry TSRMLS_CC);
     110       43178 :         } else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) {
     111       15638 :                 return phar_get_entrypufp(entry TSRMLS_CC);
     112       27540 :         } else if (entry->fp_type == PHAR_MOD) {
     113       27529 :                 return entry->fp;
     114             :         } else {
     115             :                 /* temporary manifest entry */
     116          11 :                 if (!entry->fp) {
     117           0 :                         entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
     118             :                 }
     119          11 :                 return entry->fp;
     120             :         }
     121             : }
     122             : /* }}} */
     123             : 
     124       17139 : int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC) /* {{{ */
     125             : {
     126       17139 :         php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
     127             :         off_t temp, eoffset;
     128             : 
     129       17139 :         if (!fp) {
     130           1 :                 return -1;
     131             :         }
     132             : 
     133       17138 :         if (follow_links) {
     134             :                 phar_entry_info *t;
     135        7602 :                 t = phar_get_link_source(entry TSRMLS_CC);
     136        7602 :                 if (t) {
     137        7602 :                         entry = t;
     138             :                 }
     139             :         }
     140             : 
     141       17138 :         if (entry->is_dir) {
     142          18 :                 return 0;
     143             :         }
     144             : 
     145       17120 :         eoffset = phar_get_fp_offset(entry TSRMLS_CC);
     146             : 
     147       17120 :         switch (whence) {
     148             :                 case SEEK_END:
     149           0 :                         temp = eoffset + entry->uncompressed_filesize + offset;
     150           0 :                         break;
     151             :                 case SEEK_CUR:
     152           0 :                         temp = eoffset + position + offset;
     153           0 :                         break;
     154             :                 case SEEK_SET:
     155       17120 :                         temp = eoffset + offset;
     156       17120 :                         break;
     157             :                 default:
     158           0 :                         temp = 0;
     159             :                         break;
     160             :         }
     161             : 
     162       17120 :         if (temp > eoffset + (off_t) entry->uncompressed_filesize) {
     163           0 :                 return -1;
     164             :         }
     165             : 
     166       17120 :         if (temp < eoffset) {
     167           0 :                 return -1;
     168             :         }
     169             : 
     170       17120 :         return php_stream_seek(fp, temp, SEEK_SET);
     171             : }
     172             : /* }}} */
     173             : 
     174             : /* mount an absolute path or uri to a path internal to the phar archive */
     175          23 : int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC) /* {{{ */
     176             : {
     177          23 :         phar_entry_info entry = {0};
     178             :         php_stream_statbuf ssb;
     179             :         int is_phar;
     180             :         const char *err;
     181             : 
     182          23 :         if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) {
     183           0 :                 return FAILURE;
     184             :         }
     185             : 
     186          23 :         if (path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
     187             :                 /* no creating magic phar files by mounting them */
     188           1 :                 return FAILURE;
     189             :         }
     190             : 
     191          22 :         is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7));
     192             : 
     193          22 :         entry.phar = phar;
     194          22 :         entry.filename = estrndup(path, path_len);
     195             : #ifdef PHP_WIN32
     196             :         phar_unixify_path_separators(entry.filename, path_len);
     197             : #endif
     198          22 :         entry.filename_len = path_len;
     199          22 :         if (is_phar) {
     200           4 :                 entry.tmp = estrndup(filename, filename_len);
     201             :         } else {
     202          18 :                 entry.tmp = expand_filepath(filename, NULL TSRMLS_CC);
     203          18 :                 if (!entry.tmp) {
     204           0 :                         entry.tmp = estrndup(filename, filename_len);
     205             :                 }
     206             :         }
     207             : #if PHP_API_VERSION < 20100412
     208          22 :         if (PG(safe_mode) && !is_phar && (!php_checkuid(entry.tmp, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
     209           0 :                 efree(entry.tmp);
     210           0 :                 efree(entry.filename);
     211           0 :                 return FAILURE;
     212             :         }
     213             : #endif
     214          22 :         filename = entry.tmp;
     215             : 
     216             :         /* only check openbasedir for files, not for phar streams */
     217          22 :         if (!is_phar && php_check_open_basedir(filename TSRMLS_CC)) {
     218           0 :                 efree(entry.tmp);
     219           0 :                 efree(entry.filename);
     220           0 :                 return FAILURE;
     221             :         }
     222             : 
     223          22 :         entry.is_mounted = 1;
     224          22 :         entry.is_crc_checked = 1;
     225          22 :         entry.fp_type = PHAR_TMP;
     226             : 
     227          22 :         if (SUCCESS != php_stream_stat_path(filename, &ssb)) {
     228           3 :                 efree(entry.tmp);
     229           3 :                 efree(entry.filename);
     230           3 :                 return FAILURE;
     231             :         }
     232             : 
     233          19 :         if (ssb.sb.st_mode & S_IFDIR) {
     234           5 :                 entry.is_dir = 1;
     235           5 :                 if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) {
     236             :                         /* directory already mounted */
     237           1 :                         efree(entry.tmp);
     238           1 :                         efree(entry.filename);
     239           1 :                         return FAILURE;
     240             :                 }
     241             :         } else {
     242          14 :                 entry.is_dir = 0;
     243          14 :                 entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
     244             :         }
     245             : 
     246          18 :         entry.flags = ssb.sb.st_mode;
     247             : 
     248          18 :         if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
     249          15 :                 return SUCCESS;
     250             :         }
     251             : 
     252           3 :         efree(entry.tmp);
     253           3 :         efree(entry.filename);
     254           3 :         return FAILURE;
     255             : }
     256             : /* }}} */
     257             : 
     258       16182 : char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */
     259             : {
     260             : #if PHP_VERSION_ID >= 50300
     261             :         char *path, *fname, *arch, *entry, *ret, *test;
     262             :         int arch_len, entry_len, fname_len, ret_len;
     263             :         phar_archive_data *phar;
     264             : 
     265       16182 :         if (pphar) {
     266           0 :                 *pphar = NULL;
     267             :         } else {
     268       16182 :                 pphar = &phar;
     269             :         }
     270             : 
     271       16182 :         if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
     272       16159 :                 return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
     273             :         }
     274             : 
     275          23 :         fname = zend_get_executed_filename(TSRMLS_C);
     276          23 :         fname_len = strlen(fname);
     277             : 
     278          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))) {
     279           2 :                 arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
     280           2 :                 arch_len = PHAR_G(last_phar_name_len);
     281           2 :                 phar = PHAR_G(last_phar);
     282           2 :                 goto splitted;
     283             :         }
     284             : 
     285          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)) {
     286          14 :                 return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
     287             :         }
     288             : 
     289           7 :         efree(entry);
     290             : 
     291           7 :         if (*filename == '.') {
     292             :                 int try_len;
     293             : 
     294           4 :                 if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
     295           0 :                         efree(arch);
     296           0 :                         return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
     297             :                 }
     298             : splitted:
     299           6 :                 if (pphar) {
     300           6 :                         *pphar = phar;
     301             :                 }
     302             : 
     303           6 :                 try_len = filename_len;
     304           6 :                 test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
     305             : 
     306           6 :                 if (*test == '/') {
     307           2 :                         if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
     308           2 :                                 spprintf(&ret, 0, "phar://%s%s", arch, test);
     309           2 :                                 efree(arch);
     310           2 :                                 efree(test);
     311           2 :                                 return ret;
     312             :                         }
     313             :                 } else {
     314           4 :                         if (zend_hash_exists(&(phar->manifest), test, try_len)) {
     315           2 :                                 spprintf(&ret, 0, "phar://%s/%s", arch, test);
     316           2 :                                 efree(arch);
     317           2 :                                 efree(test);
     318           2 :                                 return ret;
     319             :                         }
     320             :                 }
     321           2 :                 efree(test);
     322             :         }
     323             : 
     324           5 :         spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
     325           5 :         efree(arch);
     326           5 :         ret = php_resolve_path(filename, filename_len, path TSRMLS_CC);
     327           5 :         efree(path);
     328             : 
     329           5 :         if (ret && strlen(ret) > 8 && !strncmp(ret, "phar://", 7)) {
     330           2 :                 ret_len = strlen(ret);
     331             :                 /* found phar:// */
     332             : 
     333           2 :                 if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
     334           0 :                         return ret;
     335             :                 }
     336             : 
     337           2 :                 zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
     338             : 
     339           2 :                 if (!pphar && PHAR_G(manifest_cached)) {
     340           0 :                         zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
     341             :                 }
     342             : 
     343           2 :                 efree(arch);
     344           2 :                 efree(entry);
     345             :         }
     346             : 
     347           5 :         return ret;
     348             : #else /* PHP 5.2 */
     349             :         char resolved_path[MAXPATHLEN];
     350             :         char trypath[MAXPATHLEN];
     351             :         char *ptr, *end, *path = PG(include_path);
     352             :         php_stream_wrapper *wrapper;
     353             :         const char *p;
     354             :         int n = 0;
     355             :         char *fname, *arch, *entry, *ret, *test;
     356             :         int arch_len, entry_len;
     357             :         phar_archive_data *phar = NULL;
     358             : 
     359             :         if (!filename) {
     360             :                 return NULL;
     361             :         }
     362             : 
     363             :         if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
     364             :                 goto doit;
     365             :         }
     366             : 
     367             :         fname = zend_get_executed_filename(TSRMLS_C);
     368             : 
     369             :         if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
     370             :                 goto doit;
     371             :         }
     372             : 
     373             :         efree(entry);
     374             : 
     375             :         if (*filename == '.') {
     376             :                 int try_len;
     377             : 
     378             :                 if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
     379             :                         efree(arch);
     380             :                         goto doit;
     381             :                 }
     382             : 
     383             :                 try_len = filename_len;
     384             :                 test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
     385             : 
     386             :                 if (*test == '/') {
     387             :                         if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
     388             :                                 spprintf(&ret, 0, "phar://%s%s", arch, test);
     389             :                                 efree(arch);
     390             :                                 efree(test);
     391             :                                 return ret;
     392             :                         }
     393             :                 } else {
     394             :                         if (zend_hash_exists(&(phar->manifest), test, try_len)) {
     395             :                                 spprintf(&ret, 0, "phar://%s/%s", arch, test);
     396             :                                 efree(arch);
     397             :                                 efree(test);
     398             :                                 return ret;
     399             :                         }
     400             :                 }
     401             : 
     402             :                 efree(test);
     403             :         }
     404             : 
     405             :         efree(arch);
     406             : doit:
     407             :         if (*filename == '.' || IS_ABSOLUTE_PATH(filename, filename_len) || !path || !*path) {
     408             :                 if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
     409             :                         return estrdup(resolved_path);
     410             :                 } else {
     411             :                         return NULL;
     412             :                 }
     413             :         }
     414             : 
     415             :         /* test for stream wrappers and return */
     416             :         for (p = filename; p - filename < filename_len && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
     417             : 
     418             :         if (n < filename_len - 3 && (*p == ':') && (!strncmp("//", p+1, 2) || ( filename_len > 4 && !memcmp("data", filename, 4)))) {
     419             :                 /* found stream wrapper, this is an absolute path until stream wrappers implement realpath */
     420             :                 return estrndup(filename, filename_len);
     421             :         }
     422             : 
     423             :         ptr = (char *) path;
     424             :         while (ptr && *ptr) {
     425             :                 int len, is_stream_wrapper = 0, maybe_stream = 1;
     426             : 
     427             :                 end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
     428             : #ifndef PHP_WIN32
     429             :                 /* search for stream wrapper */
     430             :                 if (end - ptr  <= 1) {
     431             :                         maybe_stream = 0;
     432             :                         goto not_stream;
     433             :                 }
     434             : 
     435             :                 for (p = ptr, n = 0; p < end && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
     436             : 
     437             :                 if (n == end - ptr && *p && !strncmp("//", p+1, 2)) {
     438             :                         is_stream_wrapper = 1;
     439             :                         /* seek to real end of include_path portion */
     440             :                         end = strchr(end + 1, DEFAULT_DIR_SEPARATOR);
     441             :                 } else {
     442             :                         maybe_stream = 0;
     443             :                 }
     444             : not_stream:
     445             : #endif
     446             :                 if (end) {
     447             :                         if ((end-ptr) + 1 + filename_len + 1 >= MAXPATHLEN) {
     448             :                                 ptr = end + 1;
     449             :                                 continue;
     450             :                         }
     451             : 
     452             :                         memcpy(trypath, ptr, end-ptr);
     453             :                         len = end-ptr;
     454             :                         trypath[end-ptr] = '/';
     455             :                         memcpy(trypath+(end-ptr)+1, filename, filename_len+1);
     456             :                         ptr = end+1;
     457             :                 } else {
     458             :                         len = strlen(ptr);
     459             : 
     460             :                         if (len + 1 + filename_len + 1 >= MAXPATHLEN) {
     461             :                                 break;
     462             :                         }
     463             : 
     464             :                         memcpy(trypath, ptr, len);
     465             :                         trypath[len] = '/';
     466             :                         memcpy(trypath+len+1, filename, filename_len+1);
     467             :                         ptr = NULL;
     468             :                 }
     469             : 
     470             :                 if (!is_stream_wrapper && maybe_stream) {
     471             :                         /* search for stream wrapper */
     472             :                         for (p = trypath, n = 0; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
     473             :                 }
     474             : 
     475             :                 if (is_stream_wrapper || (n < len - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4)))) {
     476             :                         char *actual;
     477             : 
     478             :                         wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
     479             :                         if (wrapper == &php_plain_files_wrapper) {
     480             :                                 strlcpy(trypath, actual, sizeof(trypath));
     481             :                         } else if (!wrapper) {
     482             :                                 /* if wrapper is NULL, there was a mal-formed include_path stream wrapper, so skip this ptr */
     483             :                                 continue;
     484             :                         } else {
     485             :                                 if (wrapper->wops->url_stat) {
     486             :                                         php_stream_statbuf ssb;
     487             : 
     488             :                                         if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
     489             :                                                 if (wrapper == &php_stream_phar_wrapper) {
     490             :                                                         char *arch, *entry;
     491             :                                                         int arch_len, entry_len, ret_len;
     492             : 
     493             :                                                         ret_len = strlen(trypath);
     494             :                                                         /* found phar:// */
     495             : 
     496             :                                                         if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
     497             :                                                                 return estrndup(trypath, ret_len);
     498             :                                                         }
     499             : 
     500             :                                                         zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
     501             : 
     502             :                                                         if (!pphar && PHAR_G(manifest_cached)) {
     503             :                                                                 zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
     504             :                                                         }
     505             : 
     506             :                                                         efree(arch);
     507             :                                                         efree(entry);
     508             : 
     509             :                                                         return estrndup(trypath, ret_len);
     510             :                                                 }
     511             :                                                 return estrdup(trypath);
     512             :                                         }
     513             :                                 }
     514             :                                 continue;
     515             :                         }
     516             :                 }
     517             : 
     518             :                 if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
     519             :                         return estrdup(resolved_path);
     520             :                 }
     521             :         } /* end provided path */
     522             : 
     523             :         /* check in calling scripts' current working directory as a fall back case */
     524             :         if (zend_is_executing(TSRMLS_C)) {
     525             :                 char *exec_fname = zend_get_executed_filename(TSRMLS_C);
     526             :                 int exec_fname_length = strlen(exec_fname);
     527             :                 const char *p;
     528             :                 int n = 0;
     529             : 
     530             :                 while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
     531             :                 if (exec_fname && exec_fname[0] != '[' && 
     532             :                         exec_fname_length > 0 && 
     533             :                         exec_fname_length + 1 + filename_len + 1 < MAXPATHLEN) {
     534             :                         memcpy(trypath, exec_fname, exec_fname_length + 1);
     535             :                         memcpy(trypath+exec_fname_length + 1, filename, filename_len+1);
     536             : 
     537             :                         /* search for stream wrapper */
     538             :                         for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
     539             : 
     540             :                         if (n < exec_fname_length - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4))) {
     541             :                                 char *actual;
     542             : 
     543             :                                 wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
     544             : 
     545             :                                 if (wrapper == &php_plain_files_wrapper) {
     546             :                                         /* this should never technically happen, but we'll leave it here for completeness */
     547             :                                         strlcpy(trypath, actual, sizeof(trypath));
     548             :                                 } else if (!wrapper) {
     549             :                                         /* if wrapper is NULL, there was a malformed include_path stream wrapper
     550             :                                            this also should be impossible */
     551             :                                         return NULL;
     552             :                                 } else {
     553             :                                         return estrdup(trypath);
     554             :                                 }
     555             :                         }
     556             : 
     557             :                         if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
     558             :                                 return estrdup(resolved_path);
     559             :                         }
     560             :                 }
     561             :         }
     562             : 
     563             :         return NULL;
     564             : #endif /* PHP 5.2 */
     565             : }
     566             : /* }}} */
     567             : 
     568             : /**
     569             :  * Retrieve a copy of the file information on a single file within a phar, or null.
     570             :  * This also transfers the open file pointer, if any, to the entry.
     571             :  *
     572             :  * If the file does not already exist, this will fail.  Pre-existing files can be
     573             :  * appended, truncated, or read.  For read, if the entry is marked unmodified, it is
     574             :  * assumed that the file pointer, if present, is opened for reading
     575             :  */
     576        8094 : int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */
     577             : {
     578             :         phar_archive_data *phar;
     579             :         phar_entry_info *entry;
     580        8094 :         int for_write  = mode[0] != 'r' || mode[1] == '+';
     581        8094 :         int for_append = mode[0] == 'a';
     582        8094 :         int for_create = mode[0] != 'r';
     583        8094 :         int for_trunc  = mode[0] == 'w';
     584             : 
     585        8094 :         if (!ret) {
     586           0 :                 return FAILURE;
     587             :         }
     588             : 
     589        8094 :         *ret = NULL;
     590             : 
     591        8094 :         if (error) {
     592        8094 :                 *error = NULL;
     593             :         }
     594             : 
     595        8094 :         if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
     596           0 :                 return FAILURE;
     597             :         }
     598             : 
     599        8094 :         if (for_write && PHAR_G(readonly) && !phar->is_data) {
     600           0 :                 if (error) {
     601           0 :                         spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname);
     602             :                 }
     603           0 :                 return FAILURE;
     604             :         }
     605             : 
     606        8094 :         if (!path_len) {
     607           4 :                 if (error) {
     608           4 :                         spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname);
     609             :                 }
     610           4 :                 return FAILURE;
     611             :         }
     612             : really_get_entry:
     613        8091 :         if (allow_dir) {
     614          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) {
     615          16 :                         if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
     616          16 :                                 return SUCCESS;
     617             :                         }
     618           0 :                         return FAILURE;
     619             :                 }
     620             :         } else {
     621        8073 :                 if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) {
     622        3422 :                         if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
     623        3396 :                                 return SUCCESS;
     624             :                         }
     625          26 :                         return FAILURE;
     626             :                 }
     627             :         }
     628             : 
     629        4653 :         if (for_write && phar->is_persistent) {
     630           1 :                 if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
     631           0 :                         if (error) {
     632           0 :                                 spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname);
     633             :                         }
     634           0 :                         return FAILURE;
     635             :                 } else {
     636           1 :                         goto really_get_entry;
     637             :                 }
     638             :         }
     639             : 
     640        4652 :         if (entry->is_modified && !for_write) {
     641           0 :                 if (error) {
     642           0 :                         spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname);
     643             :                 }
     644           0 :                 return FAILURE;
     645             :         }
     646             : 
     647        4652 :         if (entry->fp_refcount && for_write) {
     648           1 :                 if (error) {
     649           1 :                         spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname);
     650             :                 }
     651           1 :                 return FAILURE;
     652             :         }
     653             : 
     654        4651 :         if (entry->is_deleted) {
     655           0 :                 if (!for_create) {
     656           0 :                         return FAILURE;
     657             :                 }
     658           0 :                 entry->is_deleted = 0;
     659             :         }
     660             : 
     661        4651 :         if (entry->is_dir) {
     662           2 :                 *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
     663           2 :                 (*ret)->position = 0;
     664           2 :                 (*ret)->fp = NULL;
     665           2 :                 (*ret)->phar = phar;
     666           2 :                 (*ret)->for_write = for_write;
     667           2 :                 (*ret)->internal_file = entry;
     668           2 :                 (*ret)->is_zip = entry->is_zip;
     669           2 :                 (*ret)->is_tar = entry->is_tar;
     670             : 
     671           2 :                 if (!phar->is_persistent) {
     672           2 :                         ++(entry->phar->refcount);
     673           2 :                         ++(entry->fp_refcount);
     674             :                 }
     675             : 
     676           2 :                 return SUCCESS;
     677             :         }
     678             : 
     679        4649 :         if (entry->fp_type == PHAR_MOD) {
     680           0 :                 if (for_trunc) {
     681           0 :                         if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
     682           0 :                                 return FAILURE;
     683             :                         }
     684           0 :                 } else if (for_append) {
     685           0 :                         phar_seek_efp(entry, 0, SEEK_END, 0, 0 TSRMLS_CC);
     686             :                 }
     687             :         } else {
     688        4649 :                 if (for_write) {
     689        4124 :                         if (entry->link) {
     690           1 :                                 efree(entry->link);
     691           1 :                                 entry->link = NULL;
     692           1 :                                 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
     693             :                         }
     694             : 
     695        4124 :                         if (for_trunc) {
     696        4123 :                                 if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
     697           0 :                                         return FAILURE;
     698             :                                 }
     699             :                         } else {
     700           1 :                                 if (FAILURE == phar_separate_entry_fp(entry, error TSRMLS_CC)) {
     701           0 :                                         return FAILURE;
     702             :                                 }
     703             :                         }
     704             :                 } else {
     705         525 :                         if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
     706           4 :                                 return FAILURE;
     707             :                         }
     708             :                 }
     709             :         }
     710             : 
     711        4645 :         *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
     712        4645 :         (*ret)->position = 0;
     713        4645 :         (*ret)->phar = phar;
     714        4645 :         (*ret)->for_write = for_write;
     715        4645 :         (*ret)->internal_file = entry;
     716        4645 :         (*ret)->is_zip = entry->is_zip;
     717        4645 :         (*ret)->is_tar = entry->is_tar;
     718        4645 :         (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
     719        4645 :         if (entry->link) {
     720           3 :                 (*ret)->zero = phar_get_fp_offset(phar_get_link_source(entry TSRMLS_CC) TSRMLS_CC);
     721             :         } else {
     722        4642 :                 (*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC);
     723             :         }
     724             : 
     725        4645 :         if (!phar->is_persistent) {
     726        4645 :                 ++(entry->fp_refcount);
     727        4645 :                 ++(entry->phar->refcount);
     728             :         }
     729             : 
     730        4645 :         return SUCCESS;
     731             : }
     732             : /* }}} */
     733             : 
     734             : /**
     735             :  * Create a new dummy file slot within a writeable phar for a newly created file
     736             :  */
     737        7543 : phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */
     738             : {
     739             :         phar_archive_data *phar;
     740             :         phar_entry_info *entry, etemp;
     741             :         phar_entry_data *ret;
     742             :         const char *pcr_error;
     743             :         char is_dir;
     744             : 
     745             : #ifdef PHP_WIN32
     746             :         phar_unixify_path_separators(path, path_len);
     747             : #endif
     748             : 
     749        7543 :         is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0;
     750             : 
     751        7543 :         if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
     752           0 :                 return NULL;
     753             :         }
     754             : 
     755        7543 :         if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error, security TSRMLS_CC)) {
     756           5 :                 return NULL;
     757        7538 :         } else if (ret) {
     758        4126 :                 return ret;
     759             :         }
     760             : 
     761        3412 :         if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
     762           3 :                 if (error) {
     763           3 :                         spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
     764             :                 }
     765           3 :                 return NULL;
     766             :         }
     767             : 
     768        3409 :         if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
     769           0 :                 if (error) {
     770           0 :                         spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname);
     771             :                 }
     772           0 :                 return NULL;
     773             :         }
     774             : 
     775             :         /* create a new phar data holder */
     776        3409 :         ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
     777             : 
     778             :         /* create an entry, this is a new file */
     779        3409 :         memset(&etemp, 0, sizeof(phar_entry_info));
     780        3409 :         etemp.filename_len = path_len;
     781        3409 :         etemp.fp_type = PHAR_MOD;
     782        3409 :         etemp.fp = php_stream_fopen_tmpfile();
     783             : 
     784        3409 :         if (!etemp.fp) {
     785           0 :                 if (error) {
     786           0 :                         spprintf(error, 0, "phar error: unable to create temporary file");
     787             :                 }
     788           0 :                 efree(ret);
     789           0 :                 return NULL;
     790             :         }
     791             : 
     792        3409 :         etemp.fp_refcount = 1;
     793             : 
     794        3409 :         if (allow_dir == 2) {
     795          16 :                 etemp.is_dir = 1;
     796          16 :                 etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_DIR;
     797             :         } else {
     798        3393 :                 etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
     799             :         }
     800        3409 :         if (is_dir) {
     801           2 :                 etemp.filename_len--; /* strip trailing / */
     802           2 :                 path_len--;
     803             :         }
     804             : 
     805        3409 :         phar_add_virtual_dirs(phar, path, path_len TSRMLS_CC);
     806        3409 :         etemp.is_modified = 1;
     807        3409 :         etemp.timestamp = time(0);
     808        3409 :         etemp.is_crc_checked = 1;
     809        3409 :         etemp.phar = phar;
     810        3409 :         etemp.filename = estrndup(path, path_len);
     811        3409 :         etemp.is_zip = phar->is_zip;
     812             : 
     813        3409 :         if (phar->is_tar) {
     814         100 :                 etemp.is_tar = phar->is_tar;
     815         100 :                 etemp.tar_type = etemp.is_dir ? TAR_DIR : TAR_FILE;
     816             :         }
     817             : 
     818        3409 :         if (FAILURE == zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry)) {
     819           0 :                 php_stream_close(etemp.fp);
     820           0 :                 if (error) {
     821           0 :                         spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname);
     822             :                 }
     823           0 :                 efree(ret);
     824           0 :                 efree(etemp.filename);
     825           0 :                 return NULL;
     826             :         }
     827             : 
     828        3409 :         if (!entry) {
     829           0 :                 php_stream_close(etemp.fp);
     830           0 :                 efree(etemp.filename);
     831           0 :                 efree(ret);
     832           0 :                 return NULL;
     833             :         }
     834             : 
     835        3409 :         ++(phar->refcount);
     836        3409 :         ret->phar = phar;
     837        3409 :         ret->fp = entry->fp;
     838        3409 :         ret->position = ret->zero = 0;
     839        3409 :         ret->for_write = 1;
     840        3409 :         ret->is_zip = entry->is_zip;
     841        3409 :         ret->is_tar = entry->is_tar;
     842        3409 :         ret->internal_file = entry;
     843             : 
     844        3409 :         return ret;
     845             : }
     846             : /* }}} */
     847             : 
     848             : /* initialize a phar_archive_data's read-only fp for existing phar data */
     849         346 : int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) /* {{{ */
     850             : {
     851         346 :         if (phar_get_pharfp(phar TSRMLS_CC)) {
     852         177 :                 return SUCCESS;
     853             :         }
     854             : #if PHP_API_VERSION < 20100412
     855         169 :         if (PG(safe_mode) && (!php_checkuid(phar->fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
     856           0 :                 return FAILURE;
     857             :         }
     858             : #endif
     859             : 
     860         169 :         if (php_check_open_basedir(phar->fname TSRMLS_CC)) {
     861           0 :                 return FAILURE;
     862             :         }
     863             : 
     864         169 :         phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC);
     865             : 
     866         169 :         if (!phar_get_pharfp(phar TSRMLS_CC)) {
     867           4 :                 return FAILURE;
     868             :         }
     869             : 
     870         165 :         return SUCCESS;
     871             : }
     872             : /* }}} */
     873             : 
     874             : /* copy file data from an existing to a new phar_entry_info that is not in the manifest */
     875           6 : int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC) /* {{{ */
     876             : {
     877             :         phar_entry_info *link;
     878             : 
     879           6 :         if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) {
     880           0 :                 return FAILURE;
     881             :         }
     882             : 
     883           6 :         if (dest->link) {
     884           0 :                 efree(dest->link);
     885           0 :                 dest->link = NULL;
     886           0 :                 dest->tar_type = (dest->is_tar ? TAR_FILE : '\0');
     887             :         }
     888             : 
     889           6 :         dest->fp_type = PHAR_MOD;
     890           6 :         dest->offset = 0;
     891           6 :         dest->is_modified = 1;
     892           6 :         dest->fp = php_stream_fopen_tmpfile();
     893           6 :         if (dest->fp == NULL) {
     894           0 :                 spprintf(error, 0, "phar error: unable to create temporary file");
     895           0 :                 return EOF;
     896             :         }
     897           6 :         phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC);
     898           6 :         link = phar_get_link_source(source TSRMLS_CC);
     899             : 
     900           6 :         if (!link) {
     901           0 :                 link = source;
     902             :         }
     903             : 
     904           6 :         if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize, NULL)) {
     905           0 :                 php_stream_close(dest->fp);
     906           0 :                 dest->fp_type = PHAR_FP;
     907           0 :                 if (error) {
     908           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);
     909             :                 }
     910           0 :                 return FAILURE;
     911             :         }
     912             : 
     913           6 :         return SUCCESS;
     914             : }
     915             : /* }}} */
     916             : 
     917             : /* open and decompress a compressed phar entry
     918             :  */
     919        2432 : int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) /* {{{ */
     920             : {
     921             :         php_stream_filter *filter;
     922        2432 :         phar_archive_data *phar = entry->phar;
     923             :         char *filtername;
     924             :         off_t loc;
     925             :         php_stream *ufp;
     926             :         phar_entry_data dummy;
     927             : 
     928        2432 :         if (follow_links && entry->link) {
     929           3 :                 phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
     930           3 :                 if (link_entry && link_entry != entry) {
     931           3 :                         return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC);
     932             :                 }
     933             :         }
     934             : 
     935        2429 :         if (entry->is_modified) {
     936        1362 :                 return SUCCESS;
     937             :         }
     938             : 
     939        1067 :         if (entry->fp_type == PHAR_TMP) {
     940           9 :                 if (!entry->fp) {
     941           8 :                         entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
     942             :                 }
     943           9 :                 return SUCCESS;
     944             :         }
     945             : 
     946        1058 :         if (entry->fp_type != PHAR_FP) {
     947             :                 /* either newly created or already modified */
     948           2 :                 return SUCCESS;
     949             :         }
     950             : 
     951        1056 :         if (!phar_get_pharfp(phar TSRMLS_CC)) {
     952         150 :                 if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) {
     953           1 :                         spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
     954           1 :                         return FAILURE;
     955             :                 }
     956             :         }
     957             : 
     958        1055 :         if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
     959        1014 :                 dummy.internal_file = entry;
     960        1014 :                 dummy.phar = phar;
     961        1014 :                 dummy.zero = entry->offset;
     962        1014 :                 dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
     963        1014 :                 if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
     964           0 :                         return FAILURE;
     965             :                 }
     966        1014 :                 return SUCCESS;
     967             :         }
     968             : 
     969          41 :         if (!phar_get_entrypufp(entry TSRMLS_CC)) {
     970          24 :                 phar_set_entrypufp(entry, php_stream_fopen_tmpfile() TSRMLS_CC);
     971          24 :                 if (!phar_get_entrypufp(entry TSRMLS_CC)) {
     972           0 :                         spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
     973           0 :                         return FAILURE;
     974             :                 }
     975             :         }
     976             : 
     977          41 :         dummy.internal_file = entry;
     978          41 :         dummy.phar = phar;
     979          41 :         dummy.zero = entry->offset;
     980          41 :         dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
     981          41 :         if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
     982           0 :                 return FAILURE;
     983             :         }
     984             : 
     985          41 :         ufp = phar_get_entrypufp(entry TSRMLS_CC);
     986             : 
     987          41 :         if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
     988          41 :                 filter = php_stream_filter_create(filtername, NULL, 0 TSRMLS_CC);
     989             :         } else {
     990           0 :                 filter = NULL;
     991             :         }
     992             : 
     993          41 :         if (!filter) {
     994           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);
     995           0 :                 return FAILURE;
     996             :         }
     997             : 
     998             :         /* now we can safely use proper decompression */
     999             :         /* save the new offset location within ufp */
    1000          41 :         php_stream_seek(ufp, 0, SEEK_END);
    1001          41 :         loc = php_stream_tell(ufp);
    1002          41 :         php_stream_filter_append(&ufp->writefilters, filter);
    1003          41 :         php_stream_seek(phar_get_entrypfp(entry TSRMLS_CC), phar_get_fp_offset(entry TSRMLS_CC), SEEK_SET);
    1004             : 
    1005          41 :         if (entry->uncompressed_filesize) {
    1006          40 :                 if (SUCCESS != phar_stream_copy_to_stream(phar_get_entrypfp(entry TSRMLS_CC), ufp, entry->compressed_filesize, NULL)) {
    1007           0 :                         spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
    1008           0 :                         php_stream_filter_remove(filter, 1 TSRMLS_CC);
    1009           0 :                         return FAILURE;
    1010             :                 }
    1011             :         }
    1012             : 
    1013          41 :         php_stream_filter_flush(filter, 1);
    1014          41 :         php_stream_flush(ufp);
    1015          41 :         php_stream_filter_remove(filter, 1 TSRMLS_CC);
    1016             : 
    1017          41 :         if (php_stream_tell(ufp) - loc != (off_t) entry->uncompressed_filesize) {
    1018           4 :                 spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
    1019           4 :                 return FAILURE;
    1020             :         }
    1021             : 
    1022          37 :         entry->old_flags = entry->flags;
    1023             : 
    1024             :         /* this is now the new location of the file contents within this fp */
    1025          37 :         phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
    1026          37 :         dummy.zero = entry->offset;
    1027          37 :         dummy.fp = ufp;
    1028          37 :         if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0 TSRMLS_CC)) {
    1029           0 :                 return FAILURE;
    1030             :         }
    1031          37 :         return SUCCESS;
    1032             : }
    1033             : /* }}} */
    1034             : 
    1035             : #if defined(PHP_VERSION_ID) && PHP_VERSION_ID < 50202
    1036             : typedef struct {
    1037             :         char        *data;
    1038             :         size_t      fpos;
    1039             :         size_t      fsize;
    1040             :         size_t      smax;
    1041             :         int         mode;
    1042             :         php_stream  **owner_ptr;
    1043             : } php_stream_memory_data;
    1044             : #endif
    1045             : 
    1046        4123 : int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
    1047             : {
    1048        4123 :         if (entry->fp_type == PHAR_MOD) {
    1049             :                 /* already newly created, truncate */
    1050             : #if PHP_VERSION_ID >= 50202
    1051           0 :                 php_stream_truncate_set_size(entry->fp, 0);
    1052             : #else
    1053             :                 if (php_stream_is(entry->fp, PHP_STREAM_IS_TEMP)) {
    1054             :                         if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_MEMORY)) {
    1055             :                                 php_stream *inner = *(php_stream**)entry->fp->abstract;
    1056             :                                 php_stream_memory_data *memfp = (php_stream_memory_data*)inner->abstract;
    1057             :                                 memfp->fpos = 0;
    1058             :                                 memfp->fsize = 0;
    1059             :                         } else if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_STDIO)) {
    1060             :                                 php_stream_truncate_set_size(*(php_stream**)entry->fp->abstract, 0);
    1061             :                         } else {
    1062             :                                 if (error) {
    1063             :                                         spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
    1064             :                                 }
    1065             :                                 return FAILURE;
    1066             :                         }
    1067             :                 } else if (php_stream_is(entry->fp, PHP_STREAM_IS_STDIO)) {
    1068             :                         php_stream_truncate_set_size(entry->fp, 0);
    1069             :                 } else {
    1070             :                         if (error) {
    1071             :                                 spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
    1072             :                         }
    1073             :                         return FAILURE;
    1074             :                 }
    1075             : #endif
    1076           0 :                 entry->old_flags = entry->flags;
    1077           0 :                 entry->is_modified = 1;
    1078           0 :                 phar->is_modified = 1;
    1079             :                 /* reset file size */
    1080           0 :                 entry->uncompressed_filesize = 0;
    1081           0 :                 entry->compressed_filesize = 0;
    1082           0 :                 entry->crc32 = 0;
    1083           0 :                 entry->flags = PHAR_ENT_PERM_DEF_FILE;
    1084           0 :                 entry->fp_type = PHAR_MOD;
    1085           0 :                 entry->offset = 0;
    1086           0 :                 return SUCCESS;
    1087             :         }
    1088             : 
    1089        4123 :         if (error) {
    1090        4123 :                 *error = NULL;
    1091             :         }
    1092             : 
    1093             :         /* open a new temp file for writing */
    1094        4123 :         if (entry->link) {
    1095           0 :                 efree(entry->link);
    1096           0 :                 entry->link = NULL;
    1097           0 :                 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
    1098             :         }
    1099             : 
    1100        4123 :         entry->fp = php_stream_fopen_tmpfile();
    1101             : 
    1102        4123 :         if (!entry->fp) {
    1103           0 :                 if (error) {
    1104           0 :                         spprintf(error, 0, "phar error: unable to create temporary file");
    1105             :                 }
    1106           0 :                 return FAILURE;
    1107             :         }
    1108             : 
    1109        4123 :         entry->old_flags = entry->flags;
    1110        4123 :         entry->is_modified = 1;
    1111        4123 :         phar->is_modified = 1;
    1112             :         /* reset file size */
    1113        4123 :         entry->uncompressed_filesize = 0;
    1114        4123 :         entry->compressed_filesize = 0;
    1115        4123 :         entry->crc32 = 0;
    1116        4123 :         entry->flags = PHAR_ENT_PERM_DEF_FILE;
    1117        4123 :         entry->fp_type = PHAR_MOD;
    1118        4123 :         entry->offset = 0;
    1119        4123 :         return SUCCESS;
    1120             : }
    1121             : /* }}} */
    1122             : 
    1123           1 : int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
    1124             : {
    1125             :         php_stream *fp;
    1126             :         phar_entry_info *link;
    1127             : 
    1128           1 :         if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
    1129           0 :                 return FAILURE;
    1130             :         }
    1131             : 
    1132           1 :         if (entry->fp_type == PHAR_MOD) {
    1133           0 :                 return SUCCESS;
    1134             :         }
    1135             : 
    1136           1 :         fp = php_stream_fopen_tmpfile();
    1137           1 :         if (fp == NULL) {
    1138           0 :                 spprintf(error, 0, "phar error: unable to create temporary file");
    1139           0 :                 return FAILURE;
    1140             :         }
    1141           1 :         phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
    1142           1 :         link = phar_get_link_source(entry TSRMLS_CC);
    1143             : 
    1144           1 :         if (!link) {
    1145           0 :                 link = entry;
    1146             :         }
    1147             : 
    1148           1 :         if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize, NULL)) {
    1149           0 :                 if (error) {
    1150           0 :                         spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
    1151             :                 }
    1152           0 :                 return FAILURE;
    1153             :         }
    1154             : 
    1155           1 :         if (entry->link) {
    1156           0 :                 efree(entry->link);
    1157           0 :                 entry->link = NULL;
    1158           0 :                 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
    1159             :         }
    1160             : 
    1161           1 :         entry->offset = 0;
    1162           1 :         entry->fp = fp;
    1163           1 :         entry->fp_type = PHAR_MOD;
    1164           1 :         entry->is_modified = 1;
    1165           1 :         return SUCCESS;
    1166             : }
    1167             : /* }}} */
    1168             : 
    1169             : /**
    1170             :  * helper function to open an internal file's fp just-in-time
    1171             :  */
    1172           1 : phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
    1173             : {
    1174           1 :         if (error) {
    1175           1 :                 *error = NULL;
    1176             :         }
    1177             :         /* seek to start of internal file and read it */
    1178           1 :         if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
    1179           1 :                 return NULL;
    1180             :         }
    1181           0 :         if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
    1182           0 :                 spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname);
    1183           0 :                 return NULL;
    1184             :         }
    1185           0 :         return entry;
    1186             : }
    1187             : /* }}} */
    1188             : 
    1189          16 : int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
    1190             : {
    1191          16 :         if (phar->refcount || phar->is_persistent) {
    1192          13 :                 return FAILURE;
    1193             :         }
    1194             : 
    1195             :         /* this archive has no open references, so emit an E_STRICT and remove it */
    1196           3 :         if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
    1197           0 :                 return FAILURE;
    1198             :         }
    1199             : 
    1200             :         /* invalidate phar cache */
    1201           3 :         PHAR_G(last_phar) = NULL;
    1202           3 :         PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
    1203             : 
    1204           3 :         return SUCCESS;
    1205             : }
    1206             : /* }}} */
    1207             : 
    1208             : /**
    1209             :  * Looks up a phar archive in the filename map, connecting it to the alias
    1210             :  * (if any) or returns null
    1211             :  */
    1212       19758 : int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
    1213             : {
    1214             :         phar_archive_data *fd, **fd_ptr;
    1215             :         char *my_realpath, *save;
    1216             :         int save_len;
    1217       19758 :         ulong fhash, ahash = 0;
    1218             : 
    1219       19758 :         phar_request_initialize(TSRMLS_C);
    1220             : 
    1221       19758 :         if (error) {
    1222       19166 :                 *error = NULL;
    1223             :         }
    1224             : 
    1225       19758 :         *archive = NULL;
    1226             : 
    1227       19758 :         if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
    1228       18058 :                 *archive = PHAR_G(last_phar);
    1229       18058 :                 if (alias && alias_len) {
    1230             : 
    1231         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))) {
    1232           3 :                                 if (error) {
    1233           3 :                                         spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
    1234             :                                 }
    1235           3 :                                 *archive = NULL;
    1236           3 :                                 return FAILURE;
    1237             :                         }
    1238             : 
    1239         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)) {
    1240         135 :                                 zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
    1241             :                         }
    1242             : 
    1243         172 :                         zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(*archive), sizeof(phar_archive_data*), NULL);
    1244         172 :                         PHAR_G(last_alias) = alias;
    1245         172 :                         PHAR_G(last_alias_len) = alias_len;
    1246             :                 }
    1247             : 
    1248       18055 :                 return SUCCESS;
    1249             :         }
    1250             : 
    1251        1700 :         if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
    1252           3 :                 fd = PHAR_G(last_phar);
    1253           3 :                 fd_ptr = &fd;
    1254           3 :                 goto alias_success;
    1255             :         }
    1256             : 
    1257        1697 :         if (alias && alias_len) {
    1258         127 :                 ahash = zend_inline_hash_func(alias, alias_len);
    1259         127 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) {
    1260             : alias_success:
    1261          21 :                         if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) {
    1262           5 :                                 if (error) {
    1263           5 :                                         spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
    1264             :                                 }
    1265           5 :                                 if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
    1266           0 :                                         efree(*error);
    1267           0 :                                         *error = NULL;
    1268             :                                 }
    1269           5 :                                 return FAILURE;
    1270             :                         }
    1271             : 
    1272          16 :                         *archive = *fd_ptr;
    1273          16 :                         fd = *fd_ptr;
    1274          16 :                         PHAR_G(last_phar) = fd;
    1275          16 :                         PHAR_G(last_phar_name) = fd->fname;
    1276          16 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1277          16 :                         PHAR_G(last_alias) = alias;
    1278          16 :                         PHAR_G(last_alias_len) = alias_len;
    1279             : 
    1280          16 :                         return SUCCESS;
    1281             :                 }
    1282             : 
    1283         109 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
    1284           0 :                         goto alias_success;
    1285             :                 }
    1286             :         }
    1287             : 
    1288        1679 :         fhash = zend_inline_hash_func(fname, fname_len);
    1289        1679 :         my_realpath = NULL;
    1290        1679 :         save = fname;
    1291        1679 :         save_len = fname_len;
    1292             : 
    1293        1679 :         if (fname && fname_len) {
    1294        1679 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
    1295         774 :                         *archive = *fd_ptr;
    1296         774 :                         fd = *fd_ptr;
    1297             : 
    1298         774 :                         if (alias && alias_len) {
    1299          43 :                                 if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
    1300           0 :                                         if (error) {
    1301           0 :                                                 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
    1302             :                                         }
    1303           0 :                                         return FAILURE;
    1304             :                                 }
    1305             : 
    1306          43 :                                 if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
    1307           1 :                                         zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
    1308             :                                 }
    1309             : 
    1310          43 :                                 zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
    1311             :                         }
    1312             : 
    1313         774 :                         PHAR_G(last_phar) = fd;
    1314         774 :                         PHAR_G(last_phar_name) = fd->fname;
    1315         774 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1316         774 :                         PHAR_G(last_alias) = fd->alias;
    1317         774 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1318             : 
    1319         774 :                         return SUCCESS;
    1320             :                 }
    1321             : 
    1322         905 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
    1323           3 :                         *archive = *fd_ptr;
    1324           3 :                         fd = *fd_ptr;
    1325             : 
    1326             :                         /* this could be problematic - alias should never be different from manifest alias
    1327             :                            for cached phars */
    1328           3 :                         if (!fd->is_temporary_alias && alias && alias_len) {
    1329           0 :                                 if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
    1330           0 :                                         if (error) {
    1331           0 :                                                 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
    1332             :                                         }
    1333           0 :                                         return FAILURE;
    1334             :                                 }
    1335             :                         }
    1336             : 
    1337           3 :                         PHAR_G(last_phar) = fd;
    1338           3 :                         PHAR_G(last_phar_name) = fd->fname;
    1339           3 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1340           3 :                         PHAR_G(last_alias) = fd->alias;
    1341           3 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1342             : 
    1343           3 :                         return SUCCESS;
    1344             :                 }
    1345             : 
    1346         902 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
    1347         128 :                         fd = *archive = *fd_ptr;
    1348             : 
    1349         128 :                         PHAR_G(last_phar) = fd;
    1350         128 :                         PHAR_G(last_phar_name) = fd->fname;
    1351         128 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1352         128 :                         PHAR_G(last_alias) = fd->alias;
    1353         128 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1354             : 
    1355         128 :                         return SUCCESS;
    1356             :                 }
    1357             : 
    1358         774 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
    1359           0 :                         fd = *archive = *fd_ptr;
    1360             : 
    1361           0 :                         PHAR_G(last_phar) = fd;
    1362           0 :                         PHAR_G(last_phar_name) = fd->fname;
    1363           0 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1364           0 :                         PHAR_G(last_alias) = fd->alias;
    1365           0 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1366             : 
    1367           0 :                         return SUCCESS;
    1368             :                 }
    1369             : 
    1370             :                 /* not found, try converting \ to / */
    1371         774 :                 my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
    1372             : 
    1373         774 :                 if (my_realpath) {
    1374         774 :                         fname_len = strlen(my_realpath);
    1375         774 :                         fname = my_realpath;
    1376             :                 } else {
    1377           0 :                         return FAILURE;
    1378             :                 }
    1379             : #ifdef PHP_WIN32
    1380             :                 phar_unixify_path_separators(fname, fname_len);
    1381             : #endif
    1382         774 :                 fhash = zend_inline_hash_func(fname, fname_len);
    1383             : 
    1384         774 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
    1385             : realpath_success:
    1386          15 :                         *archive = *fd_ptr;
    1387          15 :                         fd = *fd_ptr;
    1388             : 
    1389          15 :                         if (alias && alias_len) {
    1390           0 :                                 zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
    1391             :                         }
    1392             : 
    1393          15 :                         efree(my_realpath);
    1394             : 
    1395          15 :                         PHAR_G(last_phar) = fd;
    1396          15 :                         PHAR_G(last_phar_name) = fd->fname;
    1397          15 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1398          15 :                         PHAR_G(last_alias) = fd->alias;
    1399          15 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1400             : 
    1401          15 :                         return SUCCESS;
    1402             :                 }
    1403             : 
    1404         759 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
    1405           0 :                         goto realpath_success;
    1406             :                 }
    1407             : 
    1408         759 :                 efree(my_realpath);
    1409             :         }
    1410             : 
    1411         759 :         return FAILURE;
    1412             : }
    1413             : /* }}} */
    1414             : 
    1415             : /**
    1416             :  * Determine which stream compression filter (if any) we need to read this file
    1417             :  */
    1418          49 : char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
    1419             : {
    1420          49 :         switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
    1421             :         case PHAR_ENT_COMPRESSED_GZ:
    1422          33 :                 return "zlib.deflate";
    1423             :         case PHAR_ENT_COMPRESSED_BZ2:
    1424          16 :                 return "bzip2.compress";
    1425             :         default:
    1426           0 :                 return return_unknown ? "unknown" : NULL;
    1427             :         }
    1428             : }
    1429             : /* }}} */
    1430             : 
    1431             : /**
    1432             :  * Determine which stream decompression filter (if any) we need to read this file
    1433             :  */
    1434          41 : char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
    1435             : {
    1436             :         php_uint32 flags;
    1437             : 
    1438          41 :         if (entry->is_modified) {
    1439           0 :                 flags = entry->old_flags;
    1440             :         } else {
    1441          41 :                 flags = entry->flags;
    1442             :         }
    1443             : 
    1444          41 :         switch (flags & PHAR_ENT_COMPRESSION_MASK) {
    1445             :                 case PHAR_ENT_COMPRESSED_GZ:
    1446          28 :                         return "zlib.inflate";
    1447             :                 case PHAR_ENT_COMPRESSED_BZ2:
    1448          13 :                         return "bzip2.decompress";
    1449             :                 default:
    1450           0 :                         return return_unknown ? "unknown" : NULL;
    1451             :         }
    1452             : }
    1453             : /* }}} */
    1454             : 
    1455             : /**
    1456             :  * retrieve information on a file contained within a phar, or null if it ain't there
    1457             :  */
    1458        8160 : phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */
    1459             : {
    1460        8160 :         return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC);
    1461             : }
    1462             : /* }}} */
    1463             : /**
    1464             :  * retrieve information on a file or directory contained within a phar, or null if none found
    1465             :  * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only
    1466             :  * valid pre-existing empty directory entries
    1467             :  */
    1468        8944 : 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) /* {{{ */
    1469             : {
    1470             :         const char *pcr_error;
    1471             :         phar_entry_info *entry;
    1472             :         int is_dir;
    1473             : 
    1474             : #ifdef PHP_WIN32
    1475             :         phar_unixify_path_separators(path, path_len);
    1476             : #endif
    1477             : 
    1478        8944 :         is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0;
    1479             : 
    1480        8944 :         if (error) {
    1481        1332 :                 *error = NULL;
    1482             :         }
    1483             : 
    1484        8944 :         if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
    1485           0 :                 if (error) {
    1486           0 :                         spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it");
    1487             :                 }
    1488           0 :                 return NULL;
    1489             :         }
    1490             : 
    1491        8944 :         if (!path_len && !dir) {
    1492           2 :                 if (error) {
    1493           2 :                         spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
    1494             :                 }
    1495           2 :                 return NULL;
    1496             :         }
    1497             : 
    1498        8942 :         if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
    1499           3 :                 if (error) {
    1500           0 :                         spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
    1501             :                 }
    1502           3 :                 return NULL;
    1503             :         }
    1504             : 
    1505        8939 :         if (!phar->manifest.arBuckets) {
    1506           0 :                 return NULL;
    1507             :         }
    1508             : 
    1509        8939 :         if (is_dir) {
    1510           5 :                 if (!path_len || path_len == 1) {
    1511           0 :                         return NULL;
    1512             :                 }
    1513           5 :                 path_len--;
    1514             :         }
    1515             : 
    1516        8939 :         if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
    1517        5449 :                 if (entry->is_deleted) {
    1518             :                         /* entry is deleted, but has not been flushed to disk yet */
    1519           0 :                         return NULL;
    1520             :                 }
    1521        5449 :                 if (entry->is_dir && !dir) {
    1522           3 :                         if (error) {
    1523           3 :                                 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
    1524             :                         }
    1525           3 :                         return NULL;
    1526             :                 }
    1527        5446 :                 if (!entry->is_dir && dir == 2) {
    1528             :                         /* user requested a directory, we must return one */
    1529           3 :                         if (error) {
    1530           3 :                                 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
    1531             :                         }
    1532           3 :                         return NULL;
    1533             :                 }
    1534        5443 :                 return entry;
    1535             :         }
    1536             : 
    1537        3490 :         if (dir) {
    1538          55 :                 if (zend_hash_exists(&phar->virtual_dirs, path, path_len)) {
    1539             :                         /* a file or directory exists in a sub-directory of this path */
    1540          20 :                         entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
    1541             :                         /* this next line tells PharFileInfo->__destruct() to efree the filename */
    1542          20 :                         entry->is_temp_dir = entry->is_dir = 1;
    1543          20 :                         entry->filename = (char *) estrndup(path, path_len + 1);
    1544          20 :                         entry->filename_len = path_len;
    1545          20 :                         entry->phar = phar;
    1546          20 :                         return entry;
    1547             :                 }
    1548             :         }
    1549             : 
    1550        3470 :         if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
    1551             :                 phar_zstr key;
    1552             :                 char *str_key;
    1553             :                 ulong unused;
    1554             :                 uint keylen;
    1555             : 
    1556           3 :                 zend_hash_internal_pointer_reset(&phar->mounted_dirs);
    1557           3 :                 while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
    1558           3 :                         if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
    1559           0 :                                 break;
    1560             :                         }
    1561             : 
    1562           3 :                         PHAR_STR(key, str_key);
    1563             : 
    1564           3 :                         if ((int)keylen >= path_len || strncmp(str_key, path, keylen)) {
    1565             :                                 PHAR_STR_FREE(str_key);
    1566           0 :                                 continue;
    1567             :                         } else {
    1568             :                                 char *test;
    1569             :                                 int test_len;
    1570             :                                 php_stream_statbuf ssb;
    1571             : 
    1572           3 :                                 if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
    1573           0 :                                         if (error) {
    1574           0 :                                                 spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key);
    1575             :                                         }
    1576             :                                         PHAR_STR_FREE(str_key);
    1577           0 :                                         return NULL;
    1578             :                                 }
    1579             : 
    1580           3 :                                 if (!entry->tmp || !entry->is_mounted) {
    1581           0 :                                         if (error) {
    1582           0 :                                                 spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key);
    1583             :                                         }
    1584             :                                         PHAR_STR_FREE(str_key);
    1585           0 :                                         return NULL;
    1586             :                                 }
    1587             :                                 PHAR_STR_FREE(str_key);
    1588             : 
    1589           3 :                                 test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
    1590             : 
    1591           3 :                                 if (SUCCESS != php_stream_stat_path(test, &ssb)) {
    1592           0 :                                         efree(test);
    1593           0 :                                         return NULL;
    1594             :                                 }
    1595             : 
    1596           3 :                                 if (ssb.sb.st_mode & S_IFDIR && !dir) {
    1597           1 :                                         efree(test);
    1598           1 :                                         if (error) {
    1599           1 :                                                 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
    1600             :                                         }
    1601           1 :                                         return NULL;
    1602             :                                 }
    1603             : 
    1604           2 :                                 if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
    1605           0 :                                         efree(test);
    1606             :                                         /* user requested a directory, we must return one */
    1607           0 :                                         if (error) {
    1608           0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
    1609             :                                         }
    1610           0 :                                         return NULL;
    1611             :                                 }
    1612             : 
    1613             :                                 /* mount the file just in time */
    1614           2 :                                 if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
    1615           0 :                                         efree(test);
    1616           0 :                                         if (error) {
    1617           0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
    1618             :                                         }
    1619           0 :                                         return NULL;
    1620             :                                 }
    1621             : 
    1622           2 :                                 efree(test);
    1623             : 
    1624           2 :                                 if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
    1625           0 :                                         if (error) {
    1626           0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
    1627             :                                         }
    1628           0 :                                         return NULL;
    1629             :                                 }
    1630           2 :                                 return entry;
    1631             :                         }
    1632             :                 }
    1633             :         }
    1634             : 
    1635        3467 :         return NULL;
    1636             : }
    1637             : /* }}} */
    1638             : 
    1639             : static const char hexChars[] = "0123456789ABCDEF";
    1640             : 
    1641        4994 : static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
    1642             : {
    1643        4994 :         int pos = -1;
    1644        4994 :         size_t len = 0;
    1645             : 
    1646        4994 :         *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
    1647             : 
    1648      105902 :         for (; len < digest_len; ++len) {
    1649      100908 :                 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
    1650      100908 :                 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
    1651             :         }
    1652        4994 :         (*signature)[++pos] = '\0';
    1653        4994 :         return pos;
    1654             : }
    1655             : /* }}} */
    1656             : 
    1657             : #ifndef PHAR_HAVE_OPENSSL
    1658             : 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) /* {{{ */
    1659             : {
    1660             :         zend_fcall_info fci;
    1661             :         zend_fcall_info_cache fcc;
    1662             :         zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
    1663             : 
    1664             :         MAKE_STD_ZVAL(zdata);
    1665             :         MAKE_STD_ZVAL(openssl);
    1666             :         ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
    1667             :         MAKE_STD_ZVAL(zsig);
    1668             :         ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
    1669             :         MAKE_STD_ZVAL(zkey);
    1670             :         ZVAL_STRINGL(zkey, key, key_len, 1);
    1671             :         zp[0] = &zdata;
    1672             :         zp[1] = &zsig;
    1673             :         zp[2] = &zkey;
    1674             : 
    1675             :         php_stream_rewind(fp);
    1676             :         Z_TYPE_P(zdata) = IS_STRING;
    1677             :         Z_STRLEN_P(zdata) = end;
    1678             : 
    1679             : #if PHP_MAJOR_VERSION > 5
    1680             :         if (end != (off_t) php_stream_copy_to_mem(fp, (void **) &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
    1681             : #else
    1682             :         if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
    1683             : #endif
    1684             :                 zval_dtor(zdata);
    1685             :                 zval_dtor(zsig);
    1686             :                 zval_dtor(zkey);
    1687             :                 zval_dtor(openssl);
    1688             :                 efree(openssl);
    1689             :                 efree(zdata);
    1690             :                 efree(zkey);
    1691             :                 efree(zsig);
    1692             :                 return FAILURE;
    1693             :         }
    1694             : 
    1695             : #if PHP_VERSION_ID < 50300
    1696             :         if (FAILURE == zend_fcall_info_init(openssl, &fci, &fcc TSRMLS_CC)) {
    1697             : #else
    1698             :         if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
    1699             : #endif
    1700             :                 zval_dtor(zdata);
    1701             :                 zval_dtor(zsig);
    1702             :                 zval_dtor(zkey);
    1703             :                 zval_dtor(openssl);
    1704             :                 efree(openssl);
    1705             :                 efree(zdata);
    1706             :                 efree(zkey);
    1707             :                 efree(zsig);
    1708             :                 return FAILURE;
    1709             :         }
    1710             : 
    1711             :         fci.param_count = 3;
    1712             :         fci.params = zp;
    1713             : #if PHP_VERSION_ID < 50300
    1714             :         ++(zdata->refcount);
    1715             :         if (!is_sign) {
    1716             :                 ++(zsig->refcount);
    1717             :         }
    1718             :         ++(zkey->refcount);
    1719             : #else
    1720             :         Z_ADDREF_P(zdata);
    1721             :         if (is_sign) {
    1722             :                 Z_SET_ISREF_P(zsig);
    1723             :         } else {
    1724             :                 Z_ADDREF_P(zsig);
    1725             :         }
    1726             :         Z_ADDREF_P(zkey);
    1727             : #endif
    1728             :         fci.retval_ptr_ptr = &retval_ptr;
    1729             : 
    1730             :         if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
    1731             :                 zval_dtor(zdata);
    1732             :                 zval_dtor(zsig);
    1733             :                 zval_dtor(zkey);
    1734             :                 zval_dtor(openssl);
    1735             :                 efree(openssl);
    1736             :                 efree(zdata);
    1737             :                 efree(zkey);
    1738             :                 efree(zsig);
    1739             :                 return FAILURE;
    1740             :         }
    1741             : 
    1742             :         zval_dtor(openssl);
    1743             :         efree(openssl);
    1744             : #if PHP_VERSION_ID < 50300
    1745             :         --(zdata->refcount);
    1746             :         if (!is_sign) {
    1747             :                 --(zsig->refcount);
    1748             :         }
    1749             :         --(zkey->refcount);
    1750             : #else
    1751             :         Z_DELREF_P(zdata);
    1752             :         if (is_sign) {
    1753             :                 Z_UNSET_ISREF_P(zsig);
    1754             :         } else {
    1755             :                 Z_DELREF_P(zsig);
    1756             :         }
    1757             :         Z_DELREF_P(zkey);
    1758             : #endif
    1759             :         zval_dtor(zdata);
    1760             :         efree(zdata);
    1761             :         zval_dtor(zkey);
    1762             :         efree(zkey);
    1763             : 
    1764             :         switch (Z_TYPE_P(retval_ptr)) {
    1765             :                 default:
    1766             :                 case IS_LONG:
    1767             :                         zval_dtor(zsig);
    1768             :                         efree(zsig);
    1769             :                         if (1 == Z_LVAL_P(retval_ptr)) {
    1770             :                                 efree(retval_ptr);
    1771             :                                 return SUCCESS;
    1772             :                         }
    1773             :                         efree(retval_ptr);
    1774             :                         return FAILURE;
    1775             :                 case IS_BOOL:
    1776             :                         efree(retval_ptr);
    1777             :                         if (Z_BVAL_P(retval_ptr)) {
    1778             :                                 *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
    1779             :                                 *signature_len = Z_STRLEN_P(zsig);
    1780             :                                 zval_dtor(zsig);
    1781             :                                 efree(zsig);
    1782             :                                 return SUCCESS;
    1783             :                         }
    1784             :                         zval_dtor(zsig);
    1785             :                         efree(zsig);
    1786             :                         return FAILURE;
    1787             :         }
    1788             : }
    1789             : /* }}} */
    1790             : #endif /* #ifndef PHAR_HAVE_OPENSSL */
    1791             : 
    1792         231 : 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) /* {{{ */
    1793             : {
    1794             :         int read_size, len;
    1795             :         off_t read_len;
    1796             :         unsigned char buf[1024];
    1797             : 
    1798         231 :         php_stream_rewind(fp);
    1799             : 
    1800         231 :         switch (sig_type) {
    1801             :                 case PHAR_SIG_OPENSSL: {
    1802             : #ifdef PHAR_HAVE_OPENSSL
    1803             :                         BIO *in;
    1804             :                         EVP_PKEY *key;
    1805           3 :                         EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
    1806             :                         EVP_MD_CTX md_ctx;
    1807             : #else
    1808             :                         int tempsig;
    1809             : #endif
    1810             :                         php_uint32 pubkey_len;
    1811           3 :                         char *pubkey = NULL, *pfile;
    1812             :                         php_stream *pfp;
    1813             : #ifndef PHAR_HAVE_OPENSSL
    1814             :                         if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
    1815             :                                 if (error) {
    1816             :                                         spprintf(error, 0, "openssl not loaded");
    1817             :                                 }
    1818             :                                 return FAILURE;
    1819             :                         }
    1820             : #endif
    1821             :                         /* use __FILE__ . '.pubkey' for public key file */
    1822           3 :                         spprintf(&pfile, 0, "%s.pubkey", fname);
    1823           3 :                         pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
    1824           3 :                         efree(pfile);
    1825             : 
    1826             : #if PHP_MAJOR_VERSION > 5
    1827             :                         if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, (void **) &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
    1828             : #else
    1829           3 :                         if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
    1830             : #endif
    1831           0 :                                 if (pfp) {
    1832           0 :                                         php_stream_close(pfp);
    1833             :                                 }
    1834           0 :                                 if (error) {
    1835           0 :                                         spprintf(error, 0, "openssl public key could not be read");
    1836             :                                 }
    1837           0 :                                 return FAILURE;
    1838             :                         }
    1839             : 
    1840           3 :                         php_stream_close(pfp);
    1841             : #ifndef PHAR_HAVE_OPENSSL
    1842             :                         tempsig = sig_len;
    1843             : 
    1844             :                         if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey, pubkey_len, &sig, &tempsig TSRMLS_CC)) {
    1845             :                                 if (pubkey) {
    1846             :                                         efree(pubkey);
    1847             :                                 }
    1848             : 
    1849             :                                 if (error) {
    1850             :                                         spprintf(error, 0, "openssl signature could not be verified");
    1851             :                                 }
    1852             : 
    1853             :                                 return FAILURE;
    1854             :                         }
    1855             : 
    1856             :                         if (pubkey) {
    1857             :                                 efree(pubkey);
    1858             :                         }
    1859             : 
    1860             :                         sig_len = tempsig;
    1861             : #else
    1862           3 :                         in = BIO_new_mem_buf(pubkey, pubkey_len);
    1863             : 
    1864           3 :                         if (NULL == in) {
    1865           0 :                                 efree(pubkey);
    1866           0 :                                 if (error) {
    1867           0 :                                         spprintf(error, 0, "openssl signature could not be processed");
    1868             :                                 }
    1869           0 :                                 return FAILURE;
    1870             :                         }
    1871             : 
    1872           3 :                         key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
    1873           3 :                         BIO_free(in);
    1874           3 :                         efree(pubkey);
    1875             : 
    1876           3 :                         if (NULL == key) {
    1877           0 :                                 if (error) {
    1878           0 :                                         spprintf(error, 0, "openssl signature could not be processed");
    1879             :                                 }
    1880           0 :                                 return FAILURE;
    1881             :                         }
    1882             : 
    1883           3 :                         EVP_VerifyInit(&md_ctx, mdtype);
    1884           3 :                         read_len = end_of_phar;
    1885             : 
    1886           3 :                         if (read_len > sizeof(buf)) {
    1887           2 :                                 read_size = sizeof(buf);
    1888             :                         } else {
    1889           1 :                                 read_size = (int)read_len;
    1890             :                         }
    1891             : 
    1892           3 :                         php_stream_seek(fp, 0, SEEK_SET);
    1893             : 
    1894          22 :                         while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1895          16 :                                 EVP_VerifyUpdate (&md_ctx, buf, len);
    1896          16 :                                 read_len -= (off_t)len;
    1897             : 
    1898          16 :                                 if (read_len < read_size) {
    1899           5 :                                         read_size = (int)read_len;
    1900             :                                 }
    1901             :                         }
    1902             : 
    1903           3 :                         if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
    1904             :                                 /* 1: signature verified, 0: signature does not match, -1: failed signature operation */
    1905           0 :                                 EVP_MD_CTX_cleanup(&md_ctx);
    1906             : 
    1907           0 :                                 if (error) {
    1908           0 :                                         spprintf(error, 0, "broken openssl signature");
    1909             :                                 }
    1910             : 
    1911           0 :                                 return FAILURE;
    1912             :                         }
    1913             : 
    1914           3 :                         EVP_MD_CTX_cleanup(&md_ctx);
    1915             : #endif
    1916             : 
    1917           3 :                         *signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
    1918             :                 }
    1919           3 :                 break;
    1920             : #ifdef PHAR_HASH_OK
    1921             :                 case PHAR_SIG_SHA512: {
    1922             :                         unsigned char digest[64];
    1923             :                         PHP_SHA512_CTX context;
    1924             : 
    1925           2 :                         PHP_SHA512Init(&context);
    1926           2 :                         read_len = end_of_phar;
    1927             : 
    1928           2 :                         if (read_len > sizeof(buf)) {
    1929           0 :                                 read_size = sizeof(buf);
    1930             :                         } else {
    1931           2 :                                 read_size = (int)read_len;
    1932             :                         }
    1933             : 
    1934           6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1935           2 :                                 PHP_SHA512Update(&context, buf, len);
    1936           2 :                                 read_len -= (off_t)len;
    1937           2 :                                 if (read_len < read_size) {
    1938           2 :                                         read_size = (int)read_len;
    1939             :                                 }
    1940             :                         }
    1941             : 
    1942           2 :                         PHP_SHA512Final(digest, &context);
    1943             : 
    1944           2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1945           0 :                                 if (error) {
    1946           0 :                                         spprintf(error, 0, "broken signature");
    1947             :                                 }
    1948           0 :                                 return FAILURE;
    1949             :                         }
    1950             : 
    1951           2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1952           2 :                         break;
    1953             :                 }
    1954             :                 case PHAR_SIG_SHA256: {
    1955             :                         unsigned char digest[32];
    1956             :                         PHP_SHA256_CTX context;
    1957             : 
    1958           2 :                         PHP_SHA256Init(&context);
    1959           2 :                         read_len = end_of_phar;
    1960             : 
    1961           2 :                         if (read_len > sizeof(buf)) {
    1962           0 :                                 read_size = sizeof(buf);
    1963             :                         } else {
    1964           2 :                                 read_size = (int)read_len;
    1965             :                         }
    1966             : 
    1967           6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1968           2 :                                 PHP_SHA256Update(&context, buf, len);
    1969           2 :                                 read_len -= (off_t)len;
    1970           2 :                                 if (read_len < read_size) {
    1971           2 :                                         read_size = (int)read_len;
    1972             :                                 }
    1973             :                         }
    1974             : 
    1975           2 :                         PHP_SHA256Final(digest, &context);
    1976             : 
    1977           2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1978           0 :                                 if (error) {
    1979           0 :                                         spprintf(error, 0, "broken signature");
    1980             :                                 }
    1981           0 :                                 return FAILURE;
    1982             :                         }
    1983             : 
    1984           2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1985           2 :                         break;
    1986             :                 }
    1987             : #else
    1988             :                 case PHAR_SIG_SHA512:
    1989             :                 case PHAR_SIG_SHA256:
    1990             :                         if (error) {
    1991             :                                 spprintf(error, 0, "unsupported signature");
    1992             :                         }
    1993             :                         return FAILURE;
    1994             : #endif
    1995             :                 case PHAR_SIG_SHA1: {
    1996             :                         unsigned char digest[20];
    1997             :                         PHP_SHA1_CTX  context;
    1998             : 
    1999         222 :                         PHP_SHA1Init(&context);
    2000         222 :                         read_len = end_of_phar;
    2001             : 
    2002         222 :                         if (read_len > sizeof(buf)) {
    2003          95 :                                 read_size = sizeof(buf);
    2004             :                         } else {
    2005         127 :                                 read_size = (int)read_len;
    2006             :                         }
    2007             : 
    2008        1627 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    2009        1183 :                                 PHP_SHA1Update(&context, buf, len);
    2010        1183 :                                 read_len -= (off_t)len;
    2011        1183 :                                 if (read_len < read_size) {
    2012         284 :                                         read_size = (int)read_len;
    2013             :                                 }
    2014             :                         }
    2015             : 
    2016         222 :                         PHP_SHA1Final(digest, &context);
    2017             : 
    2018         222 :                         if (memcmp(digest, sig, sizeof(digest))) {
    2019           0 :                                 if (error) {
    2020           0 :                                         spprintf(error, 0, "broken signature");
    2021             :                                 }
    2022           0 :                                 return FAILURE;
    2023             :                         }
    2024             : 
    2025         222 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    2026         222 :                         break;
    2027             :                 }
    2028             :                 case PHAR_SIG_MD5: {
    2029             :                         unsigned char digest[16];
    2030             :                         PHP_MD5_CTX   context;
    2031             : 
    2032           2 :                         PHP_MD5Init(&context);
    2033           2 :                         read_len = end_of_phar;
    2034             : 
    2035           2 :                         if (read_len > sizeof(buf)) {
    2036           0 :                                 read_size = sizeof(buf);
    2037             :                         } else {
    2038           2 :                                 read_size = (int)read_len;
    2039             :                         }
    2040             : 
    2041           6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    2042           2 :                                 PHP_MD5Update(&context, buf, len);
    2043           2 :                                 read_len -= (off_t)len;
    2044           2 :                                 if (read_len < read_size) {
    2045           2 :                                         read_size = (int)read_len;
    2046             :                                 }
    2047             :                         }
    2048             : 
    2049           2 :                         PHP_MD5Final(digest, &context);
    2050             : 
    2051           2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    2052           0 :                                 if (error) {
    2053           0 :                                         spprintf(error, 0, "broken signature");
    2054             :                                 }
    2055           0 :                                 return FAILURE;
    2056             :                         }
    2057             : 
    2058           2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    2059           2 :                         break;
    2060             :                 }
    2061             :                 default:
    2062           0 :                         if (error) {
    2063           0 :                                 spprintf(error, 0, "broken or unsupported signature");
    2064             :                         }
    2065           0 :                         return FAILURE;
    2066             :         }
    2067         231 :         return SUCCESS;
    2068             : }
    2069             : /* }}} */
    2070             : 
    2071        4763 : int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
    2072             : {
    2073             :         unsigned char buf[1024];
    2074             :         int sig_len;
    2075             : 
    2076        4763 :         php_stream_rewind(fp);
    2077             : 
    2078        4763 :         if (phar->signature) {
    2079         272 :                 efree(phar->signature);
    2080         272 :                 phar->signature = NULL;
    2081             :         }
    2082             : 
    2083        4763 :         switch(phar->sig_flags) {
    2084             : #ifdef PHAR_HASH_OK
    2085             :                 case PHAR_SIG_SHA512: {
    2086             :                         unsigned char digest[64];
    2087             :                         PHP_SHA512_CTX context;
    2088             : 
    2089           3 :                         PHP_SHA512Init(&context);
    2090             : 
    2091          16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    2092          10 :                                 PHP_SHA512Update(&context, buf, sig_len);
    2093             :                         }
    2094             : 
    2095           3 :                         PHP_SHA512Final(digest, &context);
    2096           3 :                         *signature = estrndup((char *) digest, 64);
    2097           3 :                         *signature_length = 64;
    2098           3 :                         break;
    2099             :                 }
    2100             :                 case PHAR_SIG_SHA256: {
    2101             :                         unsigned char digest[32];
    2102             :                         PHP_SHA256_CTX  context;
    2103             : 
    2104           3 :                         PHP_SHA256Init(&context);
    2105             : 
    2106          16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    2107          10 :                                 PHP_SHA256Update(&context, buf, sig_len);
    2108             :                         }
    2109             : 
    2110           3 :                         PHP_SHA256Final(digest, &context);
    2111           3 :                         *signature = estrndup((char *) digest, 32);
    2112           3 :                         *signature_length = 32;
    2113           3 :                         break;
    2114             :                 }
    2115             : #else
    2116             :                 case PHAR_SIG_SHA512:
    2117             :                 case PHAR_SIG_SHA256:
    2118             :                         if (error) {
    2119             :                                 spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
    2120             :                         }
    2121             : 
    2122             :                         return FAILURE;
    2123             : #endif
    2124             :                 case PHAR_SIG_OPENSSL: {
    2125             :                         int siglen;
    2126             :                         unsigned char *sigbuf;
    2127             : #ifdef PHAR_HAVE_OPENSSL
    2128             :                         BIO *in;
    2129             :                         EVP_PKEY *key;
    2130             :                         EVP_MD_CTX *md_ctx;
    2131             : 
    2132           3 :                         in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
    2133             : 
    2134           3 :                         if (in == NULL) {
    2135           0 :                                 if (error) {
    2136           0 :                                         spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
    2137             :                                 }
    2138           0 :                                 return FAILURE;
    2139             :                         }
    2140             : 
    2141           3 :                         key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
    2142           3 :                         BIO_free(in);
    2143             : 
    2144           3 :                         if (!key) {
    2145           0 :                                 if (error) {
    2146           0 :                                         spprintf(error, 0, "unable to process private key");
    2147             :                                 }
    2148           0 :                                 return FAILURE;
    2149             :                         }
    2150             : 
    2151           3 :                         md_ctx = EVP_MD_CTX_create();
    2152             : 
    2153           3 :                         siglen = EVP_PKEY_size(key);
    2154           3 :                         sigbuf = emalloc(siglen + 1);
    2155             : 
    2156           3 :                         if (!EVP_SignInit(md_ctx, EVP_sha1())) {
    2157           0 :                                 efree(sigbuf);
    2158           0 :                                 if (error) {
    2159           0 :                                         spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname);
    2160             :                                 }
    2161           0 :                                 return FAILURE;
    2162             :                         }
    2163             : 
    2164          16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    2165          10 :                                 if (!EVP_SignUpdate(md_ctx, buf, sig_len)) {
    2166           0 :                                         efree(sigbuf);
    2167           0 :                                         if (error) {
    2168           0 :                                                 spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname);
    2169             :                                         }
    2170           0 :                                         return FAILURE;
    2171             :                                 }
    2172             :                         }
    2173             : 
    2174           3 :                         if (!EVP_SignFinal (md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
    2175           0 :                                 efree(sigbuf);
    2176           0 :                                 if (error) {
    2177           0 :                                         spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
    2178             :                                 }
    2179           0 :                                 return FAILURE;
    2180             :                         }
    2181             : 
    2182           3 :                         sigbuf[siglen] = '\0';
    2183           3 :                         EVP_MD_CTX_destroy(md_ctx);
    2184             : #else
    2185             :                         sigbuf = NULL;
    2186             :                         siglen = 0;
    2187             :                         php_stream_seek(fp, 0, SEEK_END);
    2188             : 
    2189             :                         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)) {
    2190             :                                 if (error) {
    2191             :                                         spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
    2192             :                                 }
    2193             :                                 return FAILURE;
    2194             :                         }
    2195             : #endif
    2196           3 :                         *signature = (char *) sigbuf;
    2197           3 :                         *signature_length = siglen;
    2198             :                 }
    2199           3 :                 break;
    2200             :                 default:
    2201         170 :                         phar->sig_flags = PHAR_SIG_SHA1;
    2202             :                 case PHAR_SIG_SHA1: {
    2203             :                         unsigned char digest[20];
    2204             :                         PHP_SHA1_CTX  context;
    2205             : 
    2206        4749 :                         PHP_SHA1Init(&context);
    2207             : 
    2208       41148 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    2209       31650 :                                 PHP_SHA1Update(&context, buf, sig_len);
    2210             :                         }
    2211             : 
    2212        4749 :                         PHP_SHA1Final(digest, &context);
    2213        4749 :                         *signature = estrndup((char *) digest, 20);
    2214        4749 :                         *signature_length = 20;
    2215        4749 :                         break;
    2216             :                 }
    2217             :                 case PHAR_SIG_MD5: {
    2218             :                         unsigned char digest[16];
    2219             :                         PHP_MD5_CTX   context;
    2220             : 
    2221           5 :                         PHP_MD5Init(&context);
    2222             : 
    2223          22 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    2224          12 :                                 PHP_MD5Update(&context, buf, sig_len);
    2225             :                         }
    2226             : 
    2227           5 :                         PHP_MD5Final(digest, &context);
    2228           5 :                         *signature = estrndup((char *) digest, 16);
    2229           5 :                         *signature_length = 16;
    2230             :                         break;
    2231             :                 }
    2232             :         }
    2233             : 
    2234        4763 :         phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
    2235        4763 :         return SUCCESS;
    2236             : }
    2237             : /* }}} */
    2238             : 
    2239       14381 : void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
    2240             : {
    2241             :         char *s;
    2242             : 
    2243       50223 :         while ((s = zend_memrchr(filename, '/', filename_len))) {
    2244       22262 :                 filename_len = s - filename;
    2245       22262 :                 if (FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
    2246         801 :                         break;
    2247             :                 }
    2248             :         }
    2249       14381 : }
    2250             : /* }}} */
    2251             : 
    2252           4 : static int phar_update_cached_entry(void *data, void *argument) /* {{{ */
    2253             : {
    2254           4 :         phar_entry_info *entry = (phar_entry_info *)data;
    2255             :         TSRMLS_FETCH();
    2256             : 
    2257           4 :         entry->phar = (phar_archive_data *)argument;
    2258             : 
    2259           4 :         if (entry->link) {
    2260           0 :                 entry->link = estrdup(entry->link);
    2261             :         }
    2262             : 
    2263           4 :         if (entry->tmp) {
    2264           0 :                 entry->tmp = estrdup(entry->tmp);
    2265             :         }
    2266             : 
    2267           4 :         entry->metadata_str.c = 0;
    2268           4 :         entry->filename = estrndup(entry->filename, entry->filename_len);
    2269           4 :         entry->is_persistent = 0;
    2270             : 
    2271           4 :         if (entry->metadata) {
    2272           3 :                 if (entry->metadata_len) {
    2273           3 :                         char *buf = estrndup((char *) entry->metadata, entry->metadata_len);
    2274             :                         /* assume success, we would have failed before */
    2275           3 :                         phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len TSRMLS_CC);
    2276           3 :                         efree(buf);
    2277             :                 } else {
    2278             :                         zval *t;
    2279             : 
    2280           0 :                         t = entry->metadata;
    2281           0 :                         ALLOC_ZVAL(entry->metadata);
    2282           0 :                         *entry->metadata = *t;
    2283           0 :                         zval_copy_ctor(entry->metadata);
    2284             : #if PHP_VERSION_ID < 50300
    2285             :                         entry->metadata->refcount = 1;
    2286             : #else
    2287           0 :                         Z_SET_REFCOUNT_P(entry->metadata, 1);
    2288             : #endif
    2289           0 :                         entry->metadata_str.c = NULL;
    2290           0 :                         entry->metadata_str.len = 0;
    2291             :                 }
    2292             :         }
    2293           4 :         return ZEND_HASH_APPLY_KEEP;
    2294             : }
    2295             : /* }}} */
    2296             : 
    2297           3 : static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
    2298             : {
    2299             :         phar_archive_data *phar;
    2300             :         HashTable newmanifest;
    2301             :         char *fname;
    2302             :         phar_archive_object **objphar;
    2303             : 
    2304           3 :         phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
    2305           3 :         *phar = **pphar;
    2306           3 :         phar->is_persistent = 0;
    2307           3 :         fname = phar->fname;
    2308           3 :         phar->fname = estrndup(phar->fname, phar->fname_len);
    2309           3 :         phar->ext = phar->fname + (phar->ext - fname);
    2310             : 
    2311           3 :         if (phar->alias) {
    2312           3 :                 phar->alias = estrndup(phar->alias, phar->alias_len);
    2313             :         }
    2314             : 
    2315           3 :         if (phar->signature) {
    2316           3 :                 phar->signature = estrdup(phar->signature);
    2317             :         }
    2318             : 
    2319           3 :         if (phar->metadata) {
    2320             :                 /* assume success, we would have failed before */
    2321           3 :                 if (phar->metadata_len) {
    2322           3 :                         char *buf = estrndup((char *) phar->metadata, phar->metadata_len);
    2323           3 :                         phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC);
    2324           3 :                         efree(buf);
    2325             :                 } else {
    2326             :                         zval *t;
    2327             : 
    2328           0 :                         t = phar->metadata;
    2329           0 :                         ALLOC_ZVAL(phar->metadata);
    2330           0 :                         *phar->metadata = *t;
    2331           0 :                         zval_copy_ctor(phar->metadata);
    2332             : #if PHP_VERSION_ID < 50300
    2333             :                         phar->metadata->refcount = 1;
    2334             : #else
    2335           0 :                         Z_SET_REFCOUNT_P(phar->metadata, 1);
    2336             : #endif
    2337             :                 }
    2338             :         }
    2339             : 
    2340           3 :         zend_hash_init(&newmanifest, sizeof(phar_entry_info),
    2341             :                 zend_get_hash_value, destroy_phar_manifest_entry, 0);
    2342           3 :         zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info));
    2343           3 :         zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC);
    2344           3 :         phar->manifest = newmanifest;
    2345           3 :         zend_hash_init(&phar->mounted_dirs, sizeof(char *),
    2346             :                 zend_get_hash_value, NULL, 0);
    2347           3 :         zend_hash_init(&phar->virtual_dirs, sizeof(char *),
    2348             :                 zend_get_hash_value, NULL, 0);
    2349           3 :         zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
    2350           3 :         *pphar = phar;
    2351             : 
    2352             :         /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
    2353           8 :         for (zend_hash_internal_pointer_reset(&PHAR_GLOBALS->phar_persist_map);
    2354           5 :         SUCCESS == zend_hash_get_current_data(&PHAR_GLOBALS->phar_persist_map, (void **) &objphar);
    2355           2 :         zend_hash_move_forward(&PHAR_GLOBALS->phar_persist_map)) {
    2356           2 :                 if (objphar[0]->arc.archive->fname_len == phar->fname_len && !memcmp(objphar[0]->arc.archive->fname, phar->fname, phar->fname_len)) {
    2357           2 :                         objphar[0]->arc.archive = phar;
    2358             :                 }
    2359             :         }
    2360           3 : }
    2361             : /* }}} */
    2362             : 
    2363           3 : int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
    2364             : {
    2365           3 :         phar_archive_data **newpphar, *newphar = NULL;
    2366             : 
    2367           3 :         if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) {
    2368           0 :                 return FAILURE;
    2369             :         }
    2370             : 
    2371           3 :         *newpphar = *pphar;
    2372           3 :         phar_copy_cached_phar(newpphar TSRMLS_CC);
    2373             :         /* invalidate phar cache */
    2374           3 :         PHAR_G(last_phar) = NULL;
    2375           3 :         PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
    2376             : 
    2377           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)) {
    2378           0 :                 zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
    2379           0 :                 return FAILURE;
    2380             :         }
    2381             : 
    2382           3 :         *pphar = *newpphar;
    2383           3 :         return SUCCESS;
    2384             : }
    2385             : /* }}} */
    2386             : 
    2387             : /*
    2388             :  * Local variables:
    2389             :  * tab-width: 4
    2390             :  * c-basic-offset: 4
    2391             :  * End:
    2392             :  * vim600: noet sw=4 ts=4 fdm=marker
    2393             :  * vim<600: noet sw=4 ts=4
    2394             :  */

Generated by: LCOV version 1.10

Generated at Sun, 27 Jul 2014 12:58:34 +0000 (5 days ago)

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