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

Generated by: LCOV version 1.10

Generated at Fri, 24 Oct 2014 05:21:53 +0000 (7 days ago)

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