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

LTP GCOV extension - code coverage report
Current view: directory - phar - util.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 974
Code covered: 76.5 % Executed lines: 745
Legend: not executed executed

       1                 : /*
       2                 :   +----------------------------------------------------------------------+
       3                 :   | phar php single-file executable PHP extension                        |
       4                 :   | utility functions                                                    |
       5                 :   +----------------------------------------------------------------------+
       6                 :   | Copyright (c) 2005-2009 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: util.c 284729 2009-07-24 23:53:24Z cellog $ */
      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                 : static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC) /* {{{ */
      50              31 : {
      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                 : phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC) /* {{{ */
      69            7848 : {
      70                 :         phar_entry_info *link_entry;
      71                 :         char *link;
      72                 : 
      73            7848 :         if (!entry->link) {
      74            7817 :                 return entry;
      75                 :         }
      76                 : 
      77              31 :         link = phar_get_link_location(entry TSRMLS_CC);
      78              31 :         if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) ||
      79                 :                 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                 : php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) /* {{{ */
      95           46248 : {
      96           46248 :         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           46245 :         if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) {
     105            3090 :                 if (!phar_get_entrypfp(entry TSRMLS_CC)) {
     106                 :                         /* re-open just in time for cases where our refcount reached 0 on the phar archive */
     107              19 :                         phar_open_archive_fp(entry->phar TSRMLS_CC);
     108                 :                 }
     109            3090 :                 return phar_get_entrypfp(entry TSRMLS_CC);
     110           43155 :         } else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) {
     111           15615 :                 return phar_get_entrypufp(entry TSRMLS_CC);
     112           27540 :         } else if (entry->fp_type == PHAR_MOD) {
     113           27529 :                 return entry->fp;
     114                 :         } else {
     115                 :                 /* temporary manifest entry */
     116              11 :                 if (!entry->fp) {
     117               0 :                         entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
     118                 :                 }
     119              11 :                 return entry->fp;
     120                 :         }
     121                 : }
     122                 : /* }}} */
     123                 : 
     124                 : int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC) /* {{{ */
     125           17117 : {
     126           17117 :         php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
     127                 :         off_t temp, eoffset;
     128                 : 
     129           17117 :         if (!fp) {
     130               1 :                 return -1;
     131                 :         }
     132                 : 
     133           17116 :         if (follow_links) {
     134                 :                 phar_entry_info *t;
     135            7593 :                 t = phar_get_link_source(entry TSRMLS_CC);
     136            7593 :                 if (t) {
     137            7593 :                         entry = t;
     138                 :                 }
     139                 :         }
     140                 : 
     141           17116 :         if (entry->is_dir) {
     142              18 :                 return 0;
     143                 :         }
     144                 : 
     145           17098 :         eoffset = phar_get_fp_offset(entry TSRMLS_CC);
     146                 : 
     147           17098 :         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           17098 :                         temp = eoffset + offset;
     156                 :                         break;
     157                 :         }
     158                 : 
     159           17098 :         if (temp > eoffset + (off_t) entry->uncompressed_filesize) {
     160               0 :                 return -1;
     161                 :         }
     162                 : 
     163           17098 :         if (temp < eoffset) {
     164               0 :                 return -1;
     165                 :         }
     166                 : 
     167           17098 :         return php_stream_seek(fp, temp, SEEK_SET);
     168                 : }
     169                 : /* }}} */
     170                 : 
     171                 : /* mount an absolute path or uri to a path internal to the phar archive */
     172                 : int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC) /* {{{ */
     173              23 : {
     174              23 :         phar_entry_info entry = {0};
     175                 :         php_stream_statbuf ssb;
     176                 :         int is_phar;
     177                 :         const char *err;
     178                 : 
     179              23 :         if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) {
     180               0 :                 return FAILURE;
     181                 :         }
     182                 : 
     183              23 :         if (path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
     184                 :                 /* no creating magic phar files by mounting them */
     185               1 :                 return FAILURE;
     186                 :         }
     187                 : 
     188              22 :         is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7));
     189                 : 
     190              22 :         entry.phar = phar;
     191              22 :         entry.filename = estrndup(path, path_len);
     192                 : #ifdef PHP_WIN32
     193                 :         phar_unixify_path_separators(entry.filename, path_len);
     194                 : #endif
     195              22 :         entry.filename_len = path_len;
     196              22 :         if (is_phar) {
     197               4 :                 entry.tmp = estrndup(filename, filename_len);
     198                 :         } else {
     199              18 :                 entry.tmp = expand_filepath(filename, NULL TSRMLS_CC);
     200              18 :                 if (!entry.tmp) {
     201               0 :                         entry.tmp = estrndup(filename, filename_len);
     202                 :                 }
     203                 :         }
     204                 : #if PHP_MAJOR_VERSION < 6
     205              22 :         if (PG(safe_mode) && !is_phar && (!php_checkuid(entry.tmp, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
     206               0 :                 efree(entry.tmp);
     207               0 :                 efree(entry.filename);
     208               0 :                 return FAILURE;
     209                 :         }
     210                 : #endif
     211                 : 
     212              22 :         filename_len = strlen(entry.tmp);
     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                 : char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */
     258           14081 : {
     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           14081 :         if (pphar) {
     265               0 :                 *pphar = NULL;
     266                 :         } else {
     267           14081 :                 pphar = &phar;
     268                 :         }
     269                 : 
     270           14081 :         if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
     271           14058 :                 return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
     272                 :         }
     273                 : 
     274              23 :         fname = 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               6 : 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 = 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 = 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                 : 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            8087 : {
     577                 :         phar_archive_data *phar;
     578                 :         phar_entry_info *entry;
     579            8087 :         int for_write  = mode[0] != 'r' || mode[1] == '+';
     580            8087 :         int for_append = mode[0] == 'a';
     581            8087 :         int for_create = mode[0] != 'r';
     582            8087 :         int for_trunc  = mode[0] == 'w';
     583                 : 
     584            8087 :         if (!ret) {
     585               0 :                 return FAILURE;
     586                 :         }
     587                 : 
     588            8087 :         *ret = NULL;
     589                 : 
     590            8087 :         if (error) {
     591            8087 :                 *error = NULL;
     592                 :         }
     593                 : 
     594            8087 :         if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
     595               0 :                 return FAILURE;
     596                 :         }
     597                 : 
     598            8087 :         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            8087 :         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            8084 : really_get_entry:
     612            8084 :         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            8066 :                 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            3418 :                         if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
     622            3392 :                                 return SUCCESS;
     623                 :                         }
     624              26 :                         return FAILURE;
     625                 :                 }
     626                 :         }
     627                 : 
     628            4650 :         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            4649 :         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            4649 :         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            4648 :         if (entry->is_deleted) {
     654               0 :                 if (!for_create) {
     655               0 :                         return FAILURE;
     656                 :                 }
     657               0 :                 entry->is_deleted = 0;
     658                 :         }
     659                 : 
     660            4648 :         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            4646 :         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            4646 :                 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             522 :                         if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
     705               4 :                                 return FAILURE;
     706                 :                         }
     707                 :                 }
     708                 :         }
     709                 : 
     710            4642 :         *ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
     711            4642 :         (*ret)->position = 0;
     712            4642 :         (*ret)->phar = phar;
     713            4642 :         (*ret)->for_write = for_write;
     714            4642 :         (*ret)->internal_file = entry;
     715            4642 :         (*ret)->is_zip = entry->is_zip;
     716            4642 :         (*ret)->is_tar = entry->is_tar;
     717            4642 :         (*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
     718            4642 :         if (entry->link) {
     719               3 :                 (*ret)->zero = phar_get_fp_offset(phar_get_link_source(entry TSRMLS_CC) TSRMLS_CC);
     720                 :         } else {
     721            4639 :                 (*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC);
     722                 :         }
     723                 : 
     724            4642 :         if (!phar->is_persistent) {
     725            4642 :                 ++(entry->fp_refcount);
     726            4642 :                 ++(entry->phar->refcount);
     727                 :         }
     728                 : 
     729            4642 :         return SUCCESS;
     730                 : }
     731                 : /* }}} */
     732                 : 
     733                 : /**
     734                 :  * Create a new dummy file slot within a writeable phar for a newly created file
     735                 :  */
     736                 : 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            7539 : {
     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            7539 :         is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0;
     749                 : 
     750            7539 :         if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
     751               0 :                 return NULL;
     752                 :         }
     753                 : 
     754            7539 :         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            7534 :         } else if (ret) {
     757            4126 :                 return ret;
     758                 :         }
     759                 : 
     760            3408 :         if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
     761               3 :                 if (error) {
     762               3 :                         spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
     763                 :                 }
     764               3 :                 return NULL;
     765                 :         }
     766                 : 
     767            3405 :         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            3405 :         ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
     776                 : 
     777                 :         /* create an entry, this is a new file */
     778            3405 :         memset(&etemp, 0, sizeof(phar_entry_info));
     779            3405 :         etemp.filename_len = path_len;
     780            3405 :         etemp.fp_type = PHAR_MOD;
     781            3405 :         etemp.fp = php_stream_fopen_tmpfile();
     782                 : 
     783            3405 :         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            3405 :         etemp.fp_refcount = 1;
     792                 : 
     793            3405 :         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            3389 :                 etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
     798                 :         }
     799            3405 :         if (is_dir) {
     800               2 :                 etemp.filename_len--; /* strip trailing / */
     801               2 :                 path_len--;
     802                 :         }
     803                 : 
     804            3405 :         phar_add_virtual_dirs(phar, path, path_len TSRMLS_CC);
     805            3405 :         etemp.is_modified = 1;
     806            3405 :         etemp.timestamp = time(0);
     807            3405 :         etemp.is_crc_checked = 1;
     808            3405 :         etemp.phar = phar;
     809            3405 :         etemp.filename = estrndup(path, path_len);
     810            3405 :         etemp.is_zip = phar->is_zip;
     811                 : 
     812            3405 :         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            3405 :         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            3405 :         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            3405 :         ++(phar->refcount);
     835            3405 :         ret->phar = phar;
     836            3405 :         ret->fp = entry->fp;
     837            3405 :         ret->position = ret->zero = 0;
     838            3405 :         ret->for_write = 1;
     839            3405 :         ret->is_zip = entry->is_zip;
     840            3405 :         ret->is_tar = entry->is_tar;
     841            3405 :         ret->internal_file = entry;
     842                 : 
     843            3405 :         return ret;
     844                 : }
     845                 : /* }}} */
     846                 : 
     847                 : /* initialize a phar_archive_data's read-only fp for existing phar data */
     848                 : int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) /* {{{ */
     849             346 : {
     850             346 :         if (phar_get_pharfp(phar TSRMLS_CC)) {
     851             177 :                 return SUCCESS;
     852                 :         }
     853                 : #if PHP_MAJOR_VERSION < 6
     854             169 :         if (PG(safe_mode) && (!php_checkuid(phar->fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
     855               0 :                 return FAILURE;
     856                 :         }
     857                 : #endif
     858                 : 
     859             169 :         if (php_check_open_basedir(phar->fname TSRMLS_CC)) {
     860               0 :                 return FAILURE;
     861                 :         }
     862                 : 
     863             169 :         phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC);
     864                 : 
     865             169 :         if (!phar_get_pharfp(phar TSRMLS_CC)) {
     866               4 :                 return FAILURE;
     867                 :         }
     868                 : 
     869             165 :         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                 : int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC) /* {{{ */
     875               6 : {
     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 :         phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC);
     893               6 :         link = phar_get_link_source(source TSRMLS_CC);
     894                 : 
     895               6 :         if (!link) {
     896               0 :                 link = source;
     897                 :         }
     898                 : 
     899               6 :         if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize, NULL)) {
     900               0 :                 php_stream_close(dest->fp);
     901               0 :                 dest->fp_type = PHAR_FP;
     902               0 :                 if (error) {
     903               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);
     904                 :                 }
     905               0 :                 return FAILURE;
     906                 :         }
     907                 : 
     908               6 :         return SUCCESS;
     909                 : }
     910                 : /* }}} */
     911                 : 
     912                 : /* open and decompress a compressed phar entry
     913                 :  */
     914                 : int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) /* {{{ */
     915            2429 : {
     916                 :         php_stream_filter *filter;
     917            2429 :         phar_archive_data *phar = entry->phar;
     918                 :         char *filtername;
     919                 :         off_t loc;
     920                 :         php_stream *ufp;
     921                 :         phar_entry_data dummy;
     922                 : 
     923            2429 :         if (follow_links && entry->link) {
     924               3 :                 phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
     925               3 :                 if (link_entry && link_entry != entry) {
     926               3 :                         return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC);
     927                 :                 }
     928                 :         }
     929                 : 
     930            2426 :         if (entry->is_modified) {
     931            1362 :                 return SUCCESS;
     932                 :         }
     933                 : 
     934            1064 :         if (entry->fp_type == PHAR_TMP) {
     935               9 :                 if (!entry->fp) {
     936               8 :                         entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
     937                 :                 }
     938               9 :                 return SUCCESS;
     939                 :         }
     940                 : 
     941            1055 :         if (entry->fp_type != PHAR_FP) {
     942                 :                 /* either newly created or already modified */
     943               2 :                 return SUCCESS;
     944                 :         }
     945                 : 
     946            1053 :         if (!phar_get_pharfp(phar TSRMLS_CC)) {
     947             150 :                 if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) {
     948               1 :                         spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
     949               1 :                         return FAILURE;
     950                 :                 }
     951                 :         }
     952                 : 
     953            1052 :         if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
     954            1014 :                 dummy.internal_file = entry;
     955            1014 :                 dummy.phar = phar;
     956            1014 :                 dummy.zero = entry->offset;
     957            1014 :                 dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
     958            1014 :                 if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
     959               0 :                         return FAILURE;
     960                 :                 }
     961            1014 :                 return SUCCESS;
     962                 :         }
     963                 : 
     964              38 :         if (!phar_get_entrypufp(entry TSRMLS_CC)) {
     965              23 :                 phar_set_entrypufp(entry, php_stream_fopen_tmpfile() TSRMLS_CC);
     966              23 :                 if (!phar_get_entrypufp(entry TSRMLS_CC)) {
     967               0 :                         spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
     968               0 :                         return FAILURE;
     969                 :                 }
     970                 :         }
     971                 : 
     972              38 :         dummy.internal_file = entry;
     973              38 :         dummy.phar = phar;
     974              38 :         dummy.zero = entry->offset;
     975              38 :         dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
     976              38 :         if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
     977               0 :                 return FAILURE;
     978                 :         }
     979                 : 
     980              38 :         ufp = phar_get_entrypufp(entry TSRMLS_CC);
     981                 : 
     982              38 :         if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
     983              38 :                 filter = php_stream_filter_create(filtername, NULL, 0 TSRMLS_CC);
     984                 :         } else {
     985               0 :                 filter = NULL;
     986                 :         }
     987                 : 
     988              38 :         if (!filter) {
     989               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);
     990               0 :                 return FAILURE;
     991                 :         }
     992                 : 
     993                 :         /* now we can safely use proper decompression */
     994                 :         /* save the new offset location within ufp */
     995              38 :         php_stream_seek(ufp, 0, SEEK_END);
     996              38 :         loc = php_stream_tell(ufp);
     997              38 :         php_stream_filter_append(&ufp->writefilters, filter);
     998              38 :         php_stream_seek(phar_get_entrypfp(entry TSRMLS_CC), phar_get_fp_offset(entry TSRMLS_CC), SEEK_SET);
     999                 : 
    1000              38 :         if (SUCCESS != phar_stream_copy_to_stream(phar_get_entrypfp(entry TSRMLS_CC), ufp, entry->compressed_filesize, NULL)) {
    1001               0 :                 spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
    1002               0 :                 php_stream_filter_remove(filter, 1 TSRMLS_CC);
    1003               0 :                 return FAILURE;
    1004                 :         }
    1005                 : 
    1006              38 :         php_stream_filter_flush(filter, 1);
    1007              38 :         php_stream_flush(ufp);
    1008              38 :         php_stream_filter_remove(filter, 1 TSRMLS_CC);
    1009                 : 
    1010              38 :         if (php_stream_tell(ufp) - loc != (off_t) entry->uncompressed_filesize) {
    1011               4 :                 spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
    1012               4 :                 return FAILURE;
    1013                 :         }
    1014                 : 
    1015              34 :         entry->old_flags = entry->flags;
    1016                 : 
    1017                 :         /* this is now the new location of the file contents within this fp */
    1018              34 :         phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
    1019              34 :         dummy.zero = entry->offset;
    1020              34 :         dummy.fp = ufp;
    1021              34 :         if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0 TSRMLS_CC)) {
    1022               0 :                 return FAILURE;
    1023                 :         }
    1024              34 :         return SUCCESS;
    1025                 : }
    1026                 : /* }}} */
    1027                 : 
    1028                 : #if defined(PHP_VERSION_ID) && PHP_VERSION_ID < 50202
    1029                 : typedef struct {
    1030                 :         char        *data;
    1031                 :         size_t      fpos;
    1032                 :         size_t      fsize;
    1033                 :         size_t      smax;
    1034                 :         int         mode;
    1035                 :         php_stream  **owner_ptr;
    1036                 : } php_stream_memory_data;
    1037                 : #endif
    1038                 : 
    1039                 : int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
    1040            4123 : {
    1041            4123 :         if (entry->fp_type == PHAR_MOD) {
    1042                 :                 /* already newly created, truncate */
    1043                 : #if PHP_VERSION_ID >= 50202
    1044               0 :                 php_stream_truncate_set_size(entry->fp, 0);
    1045                 : #else
    1046                 :                 if (php_stream_is(entry->fp, PHP_STREAM_IS_TEMP)) {
    1047                 :                         if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_MEMORY)) {
    1048                 :                                 php_stream *inner = *(php_stream**)entry->fp->abstract;
    1049                 :                                 php_stream_memory_data *memfp = (php_stream_memory_data*)inner->abstract;
    1050                 :                                 memfp->fpos = 0;
    1051                 :                                 memfp->fsize = 0;
    1052                 :                         } else if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_STDIO)) {
    1053                 :                                 php_stream_truncate_set_size(*(php_stream**)entry->fp->abstract, 0);
    1054                 :                         } else {
    1055                 :                                 if (error) {
    1056                 :                                         spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
    1057                 :                                 }
    1058                 :                                 return FAILURE;
    1059                 :                         }
    1060                 :                 } else if (php_stream_is(entry->fp, PHP_STREAM_IS_STDIO)) {
    1061                 :                         php_stream_truncate_set_size(entry->fp, 0);
    1062                 :                 } else {
    1063                 :                         if (error) {
    1064                 :                                 spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
    1065                 :                         }
    1066                 :                         return FAILURE;
    1067                 :                 }
    1068                 : #endif
    1069               0 :                 entry->old_flags = entry->flags;
    1070               0 :                 entry->is_modified = 1;
    1071               0 :                 phar->is_modified = 1;
    1072                 :                 /* reset file size */
    1073               0 :                 entry->uncompressed_filesize = 0;
    1074               0 :                 entry->compressed_filesize = 0;
    1075               0 :                 entry->crc32 = 0;
    1076               0 :                 entry->flags = PHAR_ENT_PERM_DEF_FILE;
    1077               0 :                 entry->fp_type = PHAR_MOD;
    1078               0 :                 entry->offset = 0;
    1079               0 :                 return SUCCESS;
    1080                 :         }
    1081                 : 
    1082            4123 :         if (error) {
    1083            4123 :                 *error = NULL;
    1084                 :         }
    1085                 : 
    1086                 :         /* open a new temp file for writing */
    1087            4123 :         if (entry->link) {
    1088               0 :                 efree(entry->link);
    1089               0 :                 entry->link = NULL;
    1090               0 :                 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
    1091                 :         }
    1092                 : 
    1093            4123 :         entry->fp = php_stream_fopen_tmpfile();
    1094                 : 
    1095            4123 :         if (!entry->fp) {
    1096               0 :                 if (error) {
    1097               0 :                         spprintf(error, 0, "phar error: unable to create temporary file");
    1098                 :                 }
    1099               0 :                 return FAILURE;
    1100                 :         }
    1101                 : 
    1102            4123 :         entry->old_flags = entry->flags;
    1103            4123 :         entry->is_modified = 1;
    1104            4123 :         phar->is_modified = 1;
    1105                 :         /* reset file size */
    1106            4123 :         entry->uncompressed_filesize = 0;
    1107            4123 :         entry->compressed_filesize = 0;
    1108            4123 :         entry->crc32 = 0;
    1109            4123 :         entry->flags = PHAR_ENT_PERM_DEF_FILE;
    1110            4123 :         entry->fp_type = PHAR_MOD;
    1111            4123 :         entry->offset = 0;
    1112            4123 :         return SUCCESS;
    1113                 : }
    1114                 : /* }}} */
    1115                 : 
    1116                 : int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
    1117               1 : {
    1118                 :         php_stream *fp;
    1119                 :         phar_entry_info *link;
    1120                 : 
    1121               1 :         if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
    1122               0 :                 return FAILURE;
    1123                 :         }
    1124                 : 
    1125               1 :         if (entry->fp_type == PHAR_MOD) {
    1126               0 :                 return SUCCESS;
    1127                 :         }
    1128                 : 
    1129               1 :         fp = php_stream_fopen_tmpfile();
    1130               1 :         phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
    1131               1 :         link = phar_get_link_source(entry TSRMLS_CC);
    1132                 : 
    1133               1 :         if (!link) {
    1134               0 :                 link = entry;
    1135                 :         }
    1136                 : 
    1137               1 :         if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize, NULL)) {
    1138               0 :                 if (error) {
    1139               0 :                         spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
    1140                 :                 }
    1141               0 :                 return FAILURE;
    1142                 :         }
    1143                 : 
    1144               1 :         if (entry->link) {
    1145               0 :                 efree(entry->link);
    1146               0 :                 entry->link = NULL;
    1147               0 :                 entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
    1148                 :         }
    1149                 : 
    1150               1 :         entry->offset = 0;
    1151               1 :         entry->fp = fp;
    1152               1 :         entry->fp_type = PHAR_MOD;
    1153               1 :         entry->is_modified = 1;
    1154               1 :         return SUCCESS;
    1155                 : }
    1156                 : /* }}} */
    1157                 : 
    1158                 : /**
    1159                 :  * helper function to open an internal file's fp just-in-time
    1160                 :  */
    1161                 : phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
    1162               1 : {
    1163               1 :         if (error) {
    1164               1 :                 *error = NULL;
    1165                 :         }
    1166                 :         /* seek to start of internal file and read it */
    1167               1 :         if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
    1168               1 :                 return NULL;
    1169                 :         }
    1170               0 :         if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
    1171               0 :                 spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname);
    1172               0 :                 return NULL;
    1173                 :         }
    1174               0 :         return entry;
    1175                 : }
    1176                 : /* }}} */
    1177                 : 
    1178                 : int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
    1179              16 : {
    1180              16 :         if (phar->refcount || phar->is_persistent) {
    1181              13 :                 return FAILURE;
    1182                 :         }
    1183                 : 
    1184                 :         /* this archive has no open references, so emit an E_STRICT and remove it */
    1185               3 :         if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
    1186               0 :                 return FAILURE;
    1187                 :         }
    1188                 : 
    1189                 :         /* invalidate phar cache */
    1190               3 :         PHAR_G(last_phar) = NULL;
    1191               3 :         PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
    1192                 : 
    1193               3 :         return SUCCESS;
    1194                 : }
    1195                 : /* }}} */
    1196                 : 
    1197                 : /**
    1198                 :  * Looks up a phar archive in the filename map, connecting it to the alias
    1199                 :  * (if any) or returns null
    1200                 :  */
    1201                 : int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
    1202           19707 : {
    1203                 :         phar_archive_data *fd, **fd_ptr;
    1204                 :         char *my_realpath, *save;
    1205                 :         int save_len;
    1206                 :         ulong fhash, ahash;
    1207                 : 
    1208           19707 :         phar_request_initialize(TSRMLS_C);
    1209                 : 
    1210           19707 :         if (error) {
    1211           19115 :                 *error = NULL;
    1212                 :         }
    1213                 : 
    1214           19707 :         *archive = NULL;
    1215                 : 
    1216           19707 :         if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
    1217           18019 :                 *archive = PHAR_G(last_phar);
    1218           18019 :                 if (alias && alias_len) {
    1219                 : 
    1220             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))) {
    1221               3 :                                 if (error) {
    1222               3 :                                         spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
    1223                 :                                 }
    1224               3 :                                 *archive = NULL;
    1225               3 :                                 return FAILURE;
    1226                 :                         }
    1227                 : 
    1228             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)) {
    1229             135 :                                 zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
    1230                 :                         }
    1231                 : 
    1232             172 :                         zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(*archive), sizeof(phar_archive_data*), NULL);
    1233             172 :                         PHAR_G(last_alias) = alias;
    1234             172 :                         PHAR_G(last_alias_len) = alias_len;
    1235                 :                 }
    1236                 : 
    1237           18016 :                 return SUCCESS;
    1238                 :         }
    1239                 : 
    1240            1688 :         if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
    1241               3 :                 fd = PHAR_G(last_phar);
    1242               3 :                 fd_ptr = &fd;
    1243               3 :                 goto alias_success;
    1244                 :         }
    1245                 : 
    1246            1685 :         if (alias && alias_len) {
    1247             126 :                 ahash = zend_inline_hash_func(alias, alias_len);
    1248             126 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) {
    1249              21 : alias_success:
    1250              21 :                         if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) {
    1251               5 :                                 if (error) {
    1252               5 :                                         spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
    1253                 :                                 }
    1254               5 :                                 if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
    1255               0 :                                         efree(*error);
    1256               0 :                                         *error = NULL;
    1257                 :                                 }
    1258               5 :                                 return FAILURE;
    1259                 :                         }
    1260                 : 
    1261              16 :                         *archive = *fd_ptr;
    1262              16 :                         fd = *fd_ptr;
    1263              16 :                         PHAR_G(last_phar) = fd;
    1264              16 :                         PHAR_G(last_phar_name) = fd->fname;
    1265              16 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1266              16 :                         PHAR_G(last_alias) = alias;
    1267              16 :                         PHAR_G(last_alias_len) = alias_len;
    1268                 : 
    1269              16 :                         return SUCCESS;
    1270                 :                 }
    1271                 : 
    1272             108 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
    1273               0 :                         goto alias_success;
    1274                 :                 }
    1275                 :         }
    1276                 : 
    1277            1667 :         fhash = zend_inline_hash_func(fname, fname_len);
    1278            1667 :         my_realpath = NULL;
    1279            1667 :         save = fname;
    1280            1667 :         save_len = fname_len;
    1281                 : 
    1282            1667 :         if (fname && fname_len) {
    1283            1667 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
    1284             771 :                         *archive = *fd_ptr;
    1285             771 :                         fd = *fd_ptr;
    1286                 : 
    1287             771 :                         if (alias && alias_len) {
    1288              43 :                                 if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
    1289               0 :                                         if (error) {
    1290               0 :                                                 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
    1291                 :                                         }
    1292               0 :                                         return FAILURE;
    1293                 :                                 }
    1294                 : 
    1295              43 :                                 if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
    1296               1 :                                         zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
    1297                 :                                 }
    1298                 : 
    1299              43 :                                 zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
    1300                 :                         }
    1301                 : 
    1302             771 :                         PHAR_G(last_phar) = fd;
    1303             771 :                         PHAR_G(last_phar_name) = fd->fname;
    1304             771 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1305             771 :                         PHAR_G(last_alias) = fd->alias;
    1306             771 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1307                 : 
    1308             771 :                         return SUCCESS;
    1309                 :                 }
    1310                 : 
    1311             896 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
    1312               3 :                         *archive = *fd_ptr;
    1313               3 :                         fd = *fd_ptr;
    1314                 : 
    1315                 :                         /* this could be problematic - alias should never be different from manifest alias
    1316                 :                            for cached phars */
    1317               3 :                         if (!fd->is_temporary_alias && alias && alias_len) {
    1318               0 :                                 if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
    1319               0 :                                         if (error) {
    1320               0 :                                                 spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
    1321                 :                                         }
    1322               0 :                                         return FAILURE;
    1323                 :                                 }
    1324                 :                         }
    1325                 : 
    1326               3 :                         PHAR_G(last_phar) = fd;
    1327               3 :                         PHAR_G(last_phar_name) = fd->fname;
    1328               3 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1329               3 :                         PHAR_G(last_alias) = fd->alias;
    1330               3 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1331                 : 
    1332               3 :                         return SUCCESS;
    1333                 :                 }
    1334                 : 
    1335             893 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
    1336             128 :                         fd = *archive = *fd_ptr;
    1337                 : 
    1338             128 :                         PHAR_G(last_phar) = fd;
    1339             128 :                         PHAR_G(last_phar_name) = fd->fname;
    1340             128 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1341             128 :                         PHAR_G(last_alias) = fd->alias;
    1342             128 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1343                 : 
    1344             128 :                         return SUCCESS;
    1345                 :                 }
    1346                 : 
    1347             765 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
    1348               0 :                         fd = *archive = *fd_ptr;
    1349                 : 
    1350               0 :                         PHAR_G(last_phar) = fd;
    1351               0 :                         PHAR_G(last_phar_name) = fd->fname;
    1352               0 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1353               0 :                         PHAR_G(last_alias) = fd->alias;
    1354               0 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1355                 : 
    1356               0 :                         return SUCCESS;
    1357                 :                 }
    1358                 : 
    1359                 :                 /* not found, try converting \ to / */
    1360             765 :                 my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
    1361                 : 
    1362             765 :                 if (my_realpath) {
    1363             765 :                         fname_len = strlen(my_realpath);
    1364             765 :                         fname = my_realpath;
    1365                 :                 } else {
    1366               0 :                         return FAILURE;
    1367                 :                 }
    1368                 : #ifdef PHP_WIN32
    1369                 :                 phar_unixify_path_separators(fname, fname_len);
    1370                 : #endif
    1371             765 :                 fhash = zend_inline_hash_func(fname, fname_len);
    1372                 : 
    1373             765 :                 if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
    1374               9 : realpath_success:
    1375               9 :                         *archive = *fd_ptr;
    1376               9 :                         fd = *fd_ptr;
    1377                 : 
    1378               9 :                         if (alias && alias_len) {
    1379               0 :                                 zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
    1380                 :                         }
    1381                 : 
    1382               9 :                         efree(my_realpath);
    1383                 : 
    1384               9 :                         PHAR_G(last_phar) = fd;
    1385               9 :                         PHAR_G(last_phar_name) = fd->fname;
    1386               9 :                         PHAR_G(last_phar_name_len) = fd->fname_len;
    1387               9 :                         PHAR_G(last_alias) = fd->alias;
    1388               9 :                         PHAR_G(last_alias_len) = fd->alias_len;
    1389                 : 
    1390               9 :                         return SUCCESS;
    1391                 :                 }
    1392                 : 
    1393             756 :                 if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
    1394               0 :                         goto realpath_success;
    1395                 :                 }
    1396                 : 
    1397             756 :                 efree(my_realpath);
    1398                 :         }
    1399                 : 
    1400             756 :         return FAILURE;
    1401                 : }
    1402                 : /* }}} */
    1403                 : 
    1404                 : /**
    1405                 :  * Determine which stream compression filter (if any) we need to read this file
    1406                 :  */
    1407                 : char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
    1408              45 : {
    1409              45 :         switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
    1410                 :         case PHAR_ENT_COMPRESSED_GZ:
    1411              29 :                 return "zlib.deflate";
    1412                 :         case PHAR_ENT_COMPRESSED_BZ2:
    1413              16 :                 return "bzip2.compress";
    1414                 :         default:
    1415               0 :                 return return_unknown ? "unknown" : NULL;
    1416                 :         }
    1417                 : }
    1418                 : /* }}} */
    1419                 : 
    1420                 : /**
    1421                 :  * Determine which stream decompression filter (if any) we need to read this file
    1422                 :  */
    1423                 : char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
    1424              38 : {
    1425                 :         php_uint32 flags;
    1426                 : 
    1427              38 :         if (entry->is_modified) {
    1428               0 :                 flags = entry->old_flags;
    1429                 :         } else {
    1430              38 :                 flags = entry->flags;
    1431                 :         }
    1432                 : 
    1433              38 :         switch (flags & PHAR_ENT_COMPRESSION_MASK) {
    1434                 :                 case PHAR_ENT_COMPRESSED_GZ:
    1435              25 :                         return "zlib.inflate";
    1436                 :                 case PHAR_ENT_COMPRESSED_BZ2:
    1437              13 :                         return "bzip2.decompress";
    1438                 :                 default:
    1439               0 :                         return return_unknown ? "unknown" : NULL;
    1440                 :         }
    1441                 : }
    1442                 : /* }}} */
    1443                 : 
    1444                 : /**
    1445                 :  * retrieve information on a file contained within a phar, or null if it ain't there
    1446                 :  */
    1447                 : phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */
    1448            8153 : {
    1449            8153 :         return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC);
    1450                 : }
    1451                 : /* }}} */
    1452                 : /**
    1453                 :  * retrieve information on a file or directory contained within a phar, or null if none found
    1454                 :  * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only
    1455                 :  * valid pre-existing empty directory entries
    1456                 :  */
    1457                 : 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) /* {{{ */
    1458            8935 : {
    1459                 :         const char *pcr_error;
    1460                 :         phar_entry_info *entry;
    1461                 :         int is_dir;
    1462                 : 
    1463                 : #ifdef PHP_WIN32
    1464                 :         phar_unixify_path_separators(path, path_len);
    1465                 : #endif
    1466                 : 
    1467            8935 :         is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0;
    1468                 : 
    1469            8935 :         if (error) {
    1470            1327 :                 *error = NULL;
    1471                 :         }
    1472                 : 
    1473            8935 :         if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
    1474               0 :                 if (error) {
    1475               0 :                         spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it");
    1476                 :                 }
    1477               0 :                 return NULL;
    1478                 :         }
    1479                 : 
    1480            8935 :         if (!path_len && !dir) {
    1481               2 :                 if (error) {
    1482               2 :                         spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
    1483                 :                 }
    1484               2 :                 return NULL;
    1485                 :         }
    1486                 : 
    1487            8933 :         if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
    1488               3 :                 if (error) {
    1489               0 :                         spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
    1490                 :                 }
    1491               3 :                 return NULL;
    1492                 :         }
    1493                 : 
    1494            8930 :         if (!phar->manifest.arBuckets) {
    1495               0 :                 return NULL;
    1496                 :         }
    1497                 : 
    1498            8930 :         if (is_dir) {
    1499               5 :                 if (!path_len || path_len == 1) {
    1500               0 :                         return NULL;
    1501                 :                 }
    1502               5 :                 path_len--;
    1503                 :         }
    1504                 : 
    1505            8930 :         if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
    1506            5444 :                 if (entry->is_deleted) {
    1507                 :                         /* entry is deleted, but has not been flushed to disk yet */
    1508               0 :                         return NULL;
    1509                 :                 }
    1510            5444 :                 if (entry->is_dir && !dir) {
    1511               3 :                         if (error) {
    1512               3 :                                 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
    1513                 :                         }
    1514               3 :                         return NULL;
    1515                 :                 }
    1516            5441 :                 if (!entry->is_dir && dir == 2) {
    1517                 :                         /* user requested a directory, we must return one */
    1518               3 :                         if (error) {
    1519               3 :                                 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
    1520                 :                         }
    1521               3 :                         return NULL;
    1522                 :                 }
    1523            5438 :                 return entry;
    1524                 :         }
    1525                 : 
    1526            3486 :         if (dir) {
    1527              55 :                 if (zend_hash_exists(&phar->virtual_dirs, path, path_len)) {
    1528                 :                         /* a file or directory exists in a sub-directory of this path */
    1529              20 :                         entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
    1530                 :                         /* this next line tells PharFileInfo->__destruct() to efree the filename */
    1531              20 :                         entry->is_temp_dir = entry->is_dir = 1;
    1532              20 :                         entry->filename = (char *) estrndup(path, path_len + 1);
    1533              20 :                         entry->filename_len = path_len;
    1534              20 :                         entry->phar = phar;
    1535              20 :                         return entry;
    1536                 :                 }
    1537                 :         }
    1538                 : 
    1539            3466 :         if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
    1540                 :                 phar_zstr key;
    1541                 :                 char *str_key;
    1542                 :                 ulong unused;
    1543                 :                 uint keylen;
    1544                 : 
    1545               3 :                 zend_hash_internal_pointer_reset(&phar->mounted_dirs);
    1546               3 :                 while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
    1547               3 :                         if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
    1548               0 :                                 break;
    1549                 :                         }
    1550                 : 
    1551               3 :                         PHAR_STR(key, str_key);
    1552                 : 
    1553               3 :                         if ((int)keylen >= path_len || strncmp(str_key, path, keylen)) {
    1554                 :                                 PHAR_STR_FREE(str_key);
    1555                 :                                 continue;
    1556                 :                         } else {
    1557                 :                                 char *test;
    1558                 :                                 int test_len;
    1559                 :                                 php_stream_statbuf ssb;
    1560                 : 
    1561               3 :                                 if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
    1562               0 :                                         if (error) {
    1563               0 :                                                 spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key);
    1564                 :                                         }
    1565                 :                                         PHAR_STR_FREE(str_key);
    1566               0 :                                         return NULL;
    1567                 :                                 }
    1568                 : 
    1569               3 :                                 if (!entry->tmp || !entry->is_mounted) {
    1570               0 :                                         if (error) {
    1571               0 :                                                 spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key);
    1572                 :                                         }
    1573                 :                                         PHAR_STR_FREE(str_key);
    1574               0 :                                         return NULL;
    1575                 :                                 }
    1576                 :                                 PHAR_STR_FREE(str_key);
    1577                 : 
    1578               3 :                                 test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
    1579                 : 
    1580               3 :                                 if (SUCCESS != php_stream_stat_path(test, &ssb)) {
    1581               0 :                                         efree(test);
    1582               0 :                                         return NULL;
    1583                 :                                 }
    1584                 : 
    1585               3 :                                 if (ssb.sb.st_mode & S_IFDIR && !dir) {
    1586               1 :                                         efree(test);
    1587               1 :                                         if (error) {
    1588               1 :                                                 spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
    1589                 :                                         }
    1590               1 :                                         return NULL;
    1591                 :                                 }
    1592                 : 
    1593               2 :                                 if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
    1594               0 :                                         efree(test);
    1595                 :                                         /* user requested a directory, we must return one */
    1596               0 :                                         if (error) {
    1597               0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
    1598                 :                                         }
    1599               0 :                                         return NULL;
    1600                 :                                 }
    1601                 : 
    1602                 :                                 /* mount the file just in time */
    1603               2 :                                 if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
    1604               0 :                                         efree(test);
    1605               0 :                                         if (error) {
    1606               0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
    1607                 :                                         }
    1608               0 :                                         return NULL;
    1609                 :                                 }
    1610                 : 
    1611               2 :                                 efree(test);
    1612                 : 
    1613               2 :                                 if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
    1614               0 :                                         if (error) {
    1615               0 :                                                 spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
    1616                 :                                         }
    1617               0 :                                         return NULL;
    1618                 :                                 }
    1619               2 :                                 return entry;
    1620                 :                         }
    1621                 :                 }
    1622                 :         }
    1623                 : 
    1624            3463 :         return NULL;
    1625                 : }
    1626                 : /* }}} */
    1627                 : 
    1628                 : static const char hexChars[] = "0123456789ABCDEF";
    1629                 : 
    1630                 : static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
    1631            4983 : {
    1632            4983 :         int pos = -1;
    1633            4983 :         size_t len = 0;
    1634                 : 
    1635            4983 :         *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
    1636                 : 
    1637          105671 :         for (; len < digest_len; ++len) {
    1638          100688 :                 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
    1639          100688 :                 (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
    1640                 :         }
    1641            4983 :         (*signature)[++pos] = '\0';
    1642            4983 :         return pos;
    1643                 : }
    1644                 : /* }}} */
    1645                 : 
    1646                 : #ifndef PHAR_HAVE_OPENSSL
    1647                 : 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) /* {{{ */
    1648                 : {
    1649                 :         zend_fcall_info fci;
    1650                 :         zend_fcall_info_cache fcc;
    1651                 :         zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
    1652                 : 
    1653                 :         MAKE_STD_ZVAL(zdata);
    1654                 :         MAKE_STD_ZVAL(openssl);
    1655                 :         ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
    1656                 :         MAKE_STD_ZVAL(zsig);
    1657                 :         ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
    1658                 :         MAKE_STD_ZVAL(zkey);
    1659                 :         ZVAL_STRINGL(zkey, key, key_len, 1);
    1660                 :         zp[0] = &zdata;
    1661                 :         zp[1] = &zsig;
    1662                 :         zp[2] = &zkey;
    1663                 : 
    1664                 :         php_stream_rewind(fp);
    1665                 :         Z_TYPE_P(zdata) = IS_STRING;
    1666                 :         Z_STRLEN_P(zdata) = end;
    1667                 : 
    1668                 : #if PHP_MAJOR_VERSION > 5
    1669                 :         if (end != (off_t) php_stream_copy_to_mem(fp, (void **) &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
    1670                 : #else
    1671                 :         if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
    1672                 : #endif
    1673                 :                 zval_dtor(zdata);
    1674                 :                 zval_dtor(zsig);
    1675                 :                 zval_dtor(zkey);
    1676                 :                 zval_dtor(openssl);
    1677                 :                 efree(openssl);
    1678                 :                 efree(zdata);
    1679                 :                 efree(zkey);
    1680                 :                 efree(zsig);
    1681                 :                 return FAILURE;
    1682                 :         }
    1683                 : 
    1684                 : #if PHP_VERSION_ID < 50300
    1685                 :         if (FAILURE == zend_fcall_info_init(openssl, &fci, &fcc TSRMLS_CC)) {
    1686                 : #else
    1687                 :         if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
    1688                 : #endif
    1689                 :                 zval_dtor(zdata);
    1690                 :                 zval_dtor(zsig);
    1691                 :                 zval_dtor(zkey);
    1692                 :                 zval_dtor(openssl);
    1693                 :                 efree(openssl);
    1694                 :                 efree(zdata);
    1695                 :                 efree(zkey);
    1696                 :                 efree(zsig);
    1697                 :                 return FAILURE;
    1698                 :         }
    1699                 : 
    1700                 :         fci.param_count = 3;
    1701                 :         fci.params = zp;
    1702                 : #if PHP_VERSION_ID < 50300
    1703                 :         ++(zdata->refcount);
    1704                 :         if (!is_sign) {
    1705                 :                 ++(zsig->refcount);
    1706                 :         }
    1707                 :         ++(zkey->refcount);
    1708                 : #else
    1709                 :         Z_ADDREF_P(zdata);
    1710                 :         if (is_sign) {
    1711                 :                 Z_SET_ISREF_P(zsig);
    1712                 :         } else {
    1713                 :                 Z_ADDREF_P(zsig);
    1714                 :         }
    1715                 :         Z_ADDREF_P(zkey);
    1716                 : #endif
    1717                 :         fci.retval_ptr_ptr = &retval_ptr;
    1718                 : 
    1719                 :         if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
    1720                 :                 zval_dtor(zdata);
    1721                 :                 zval_dtor(zsig);
    1722                 :                 zval_dtor(zkey);
    1723                 :                 zval_dtor(openssl);
    1724                 :                 efree(openssl);
    1725                 :                 efree(zdata);
    1726                 :                 efree(zkey);
    1727                 :                 efree(zsig);
    1728                 :                 return FAILURE;
    1729                 :         }
    1730                 : 
    1731                 :         zval_dtor(openssl);
    1732                 :         efree(openssl);
    1733                 : #if PHP_VERSION_ID < 50300
    1734                 :         --(zdata->refcount);
    1735                 :         if (!is_sign) {
    1736                 :                 --(zsig->refcount);
    1737                 :         }
    1738                 :         --(zkey->refcount);
    1739                 : #else
    1740                 :         Z_DELREF_P(zdata);
    1741                 :         if (is_sign) {
    1742                 :                 Z_UNSET_ISREF_P(zsig);
    1743                 :         } else {
    1744                 :                 Z_DELREF_P(zsig);
    1745                 :         }
    1746                 :         Z_DELREF_P(zkey);
    1747                 : #endif
    1748                 :         zval_dtor(zdata);
    1749                 :         efree(zdata);
    1750                 :         zval_dtor(zkey);
    1751                 :         efree(zkey);
    1752                 : 
    1753                 :         switch (Z_TYPE_P(retval_ptr)) {
    1754                 :                 default:
    1755                 :                 case IS_LONG:
    1756                 :                         zval_dtor(zsig);
    1757                 :                         efree(zsig);
    1758                 :                         if (1 == Z_LVAL_P(retval_ptr)) {
    1759                 :                                 efree(retval_ptr);
    1760                 :                                 return SUCCESS;
    1761                 :                         }
    1762                 :                         efree(retval_ptr);
    1763                 :                         return FAILURE;
    1764                 :                 case IS_BOOL:
    1765                 :                         efree(retval_ptr);
    1766                 :                         if (Z_BVAL_P(retval_ptr)) {
    1767                 :                                 *signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
    1768                 :                                 *signature_len = Z_STRLEN_P(zsig);
    1769                 :                                 zval_dtor(zsig);
    1770                 :                                 efree(zsig);
    1771                 :                                 return SUCCESS;
    1772                 :                         }
    1773                 :                         zval_dtor(zsig);
    1774                 :                         efree(zsig);
    1775                 :                         return FAILURE;
    1776                 :         }
    1777                 : }
    1778                 : /* }}} */
    1779                 : #endif /* #ifndef PHAR_HAVE_OPENSSL */
    1780                 : 
    1781                 : 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) /* {{{ */
    1782             227 : {
    1783                 :         int read_size, len;
    1784                 :         off_t read_len;
    1785                 :         unsigned char buf[1024];
    1786                 : 
    1787             227 :         php_stream_rewind(fp);
    1788                 : 
    1789             227 :         switch (sig_type) {
    1790                 :                 case PHAR_SIG_OPENSSL: {
    1791                 : #ifdef PHAR_HAVE_OPENSSL
    1792                 :                         BIO *in;
    1793                 :                         EVP_PKEY *key;
    1794               3 :                         EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
    1795                 :                         EVP_MD_CTX md_ctx;
    1796                 : #else
    1797                 :                         int tempsig;
    1798                 : #endif
    1799                 :                         php_uint32 pubkey_len;
    1800               3 :                         char *pubkey = NULL, *pfile;
    1801                 :                         php_stream *pfp;
    1802                 : #ifndef PHAR_HAVE_OPENSSL
    1803                 :                         if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
    1804                 :                                 if (error) {
    1805                 :                                         spprintf(error, 0, "openssl not loaded");
    1806                 :                                 }
    1807                 :                                 return FAILURE;
    1808                 :                         }
    1809                 : #endif
    1810                 :                         /* use __FILE__ . '.pubkey' for public key file */
    1811               3 :                         spprintf(&pfile, 0, "%s.pubkey", fname);
    1812               3 :                         pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
    1813               3 :                         efree(pfile);
    1814                 : 
    1815                 : #if PHP_MAJOR_VERSION > 5
    1816                 :                         if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, (void **) &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
    1817                 : #else
    1818               3 :                         if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
    1819                 : #endif
    1820               0 :                                 if (pfp) {
    1821               0 :                                         php_stream_close(pfp);
    1822                 :                                 }
    1823               0 :                                 if (error) {
    1824               0 :                                         spprintf(error, 0, "openssl public key could not be read");
    1825                 :                                 }
    1826               0 :                                 return FAILURE;
    1827                 :                         }
    1828                 : 
    1829               3 :                         php_stream_close(pfp);
    1830                 : #ifndef PHAR_HAVE_OPENSSL
    1831                 :                         tempsig = sig_len;
    1832                 : 
    1833                 :                         if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey, pubkey_len, &sig, &tempsig TSRMLS_CC)) {
    1834                 :                                 if (pubkey) {
    1835                 :                                         efree(pubkey);
    1836                 :                                 }
    1837                 : 
    1838                 :                                 if (error) {
    1839                 :                                         spprintf(error, 0, "openssl signature could not be verified");
    1840                 :                                 }
    1841                 : 
    1842                 :                                 return FAILURE;
    1843                 :                         }
    1844                 : 
    1845                 :                         if (pubkey) {
    1846                 :                                 efree(pubkey);
    1847                 :                         }
    1848                 : 
    1849                 :                         sig_len = tempsig;
    1850                 : #else
    1851               3 :                         in = BIO_new_mem_buf(pubkey, pubkey_len);
    1852                 : 
    1853               3 :                         if (NULL == in) {
    1854               0 :                                 efree(pubkey);
    1855               0 :                                 if (error) {
    1856               0 :                                         spprintf(error, 0, "openssl signature could not be processed");
    1857                 :                                 }
    1858               0 :                                 return FAILURE;
    1859                 :                         }
    1860                 : 
    1861               3 :                         key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
    1862               3 :                         BIO_free(in);
    1863               3 :                         efree(pubkey);
    1864                 : 
    1865               3 :                         if (NULL == key) {
    1866               0 :                                 if (error) {
    1867               0 :                                         spprintf(error, 0, "openssl signature could not be processed");
    1868                 :                                 }
    1869               0 :                                 return FAILURE;
    1870                 :                         }
    1871                 : 
    1872               3 :                         EVP_VerifyInit(&md_ctx, mdtype);
    1873               3 :                         read_len = end_of_phar;
    1874                 : 
    1875               3 :                         if (read_len > sizeof(buf)) {
    1876               2 :                                 read_size = sizeof(buf);
    1877                 :                         } else {
    1878               1 :                                 read_size = (int)read_len;
    1879                 :                         }
    1880                 : 
    1881               3 :                         php_stream_seek(fp, 0, SEEK_SET);
    1882                 : 
    1883              22 :                         while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1884              16 :                                 EVP_VerifyUpdate (&md_ctx, buf, len);
    1885              16 :                                 read_len -= (off_t)len;
    1886                 : 
    1887              16 :                                 if (read_len < read_size) {
    1888               5 :                                         read_size = (int)read_len;
    1889                 :                                 }
    1890                 :                         }
    1891                 : 
    1892               3 :                         if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
    1893                 :                                 /* 1: signature verified, 0: signature does not match, -1: failed signature operation */
    1894               0 :                                 EVP_MD_CTX_cleanup(&md_ctx);
    1895                 : 
    1896               0 :                                 if (error) {
    1897               0 :                                         spprintf(error, 0, "broken openssl signature");
    1898                 :                                 }
    1899                 : 
    1900               0 :                                 return FAILURE;
    1901                 :                         }
    1902                 : 
    1903               3 :                         EVP_MD_CTX_cleanup(&md_ctx);
    1904                 : #endif
    1905                 : 
    1906               3 :                         *signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
    1907                 :                 }
    1908               3 :                 break;
    1909                 : #ifdef PHAR_HASH_OK
    1910                 :                 case PHAR_SIG_SHA512: {
    1911                 :                         unsigned char digest[64];
    1912                 :                         PHP_SHA512_CTX context;
    1913                 : 
    1914               2 :                         PHP_SHA512Init(&context);
    1915               2 :                         read_len = end_of_phar;
    1916                 : 
    1917               2 :                         if (read_len > sizeof(buf)) {
    1918               0 :                                 read_size = sizeof(buf);
    1919                 :                         } else {
    1920               2 :                                 read_size = (int)read_len;
    1921                 :                         }
    1922                 : 
    1923               6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1924               2 :                                 PHP_SHA512Update(&context, buf, len);
    1925               2 :                                 read_len -= (off_t)len;
    1926               2 :                                 if (read_len < read_size) {
    1927               2 :                                         read_size = (int)read_len;
    1928                 :                                 }
    1929                 :                         }
    1930                 : 
    1931               2 :                         PHP_SHA512Final(digest, &context);
    1932                 : 
    1933               2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1934               0 :                                 if (error) {
    1935               0 :                                         spprintf(error, 0, "broken signature");
    1936                 :                                 }
    1937               0 :                                 return FAILURE;
    1938                 :                         }
    1939                 : 
    1940               2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1941               2 :                         break;
    1942                 :                 }
    1943                 :                 case PHAR_SIG_SHA256: {
    1944                 :                         unsigned char digest[32];
    1945                 :                         PHP_SHA256_CTX context;
    1946                 : 
    1947               2 :                         PHP_SHA256Init(&context);
    1948               2 :                         read_len = end_of_phar;
    1949                 : 
    1950               2 :                         if (read_len > sizeof(buf)) {
    1951               0 :                                 read_size = sizeof(buf);
    1952                 :                         } else {
    1953               2 :                                 read_size = (int)read_len;
    1954                 :                         }
    1955                 : 
    1956               6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1957               2 :                                 PHP_SHA256Update(&context, buf, len);
    1958               2 :                                 read_len -= (off_t)len;
    1959               2 :                                 if (read_len < read_size) {
    1960               2 :                                         read_size = (int)read_len;
    1961                 :                                 }
    1962                 :                         }
    1963                 : 
    1964               2 :                         PHP_SHA256Final(digest, &context);
    1965                 : 
    1966               2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    1967               0 :                                 if (error) {
    1968               0 :                                         spprintf(error, 0, "broken signature");
    1969                 :                                 }
    1970               0 :                                 return FAILURE;
    1971                 :                         }
    1972                 : 
    1973               2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    1974               2 :                         break;
    1975                 :                 }
    1976                 : #else
    1977                 :                 case PHAR_SIG_SHA512:
    1978                 :                 case PHAR_SIG_SHA256:
    1979                 :                         if (error) {
    1980                 :                                 spprintf(error, 0, "unsupported signature");
    1981                 :                         }
    1982                 :                         return FAILURE;
    1983                 : #endif
    1984                 :                 case PHAR_SIG_SHA1: {
    1985                 :                         unsigned char digest[20];
    1986                 :                         PHP_SHA1_CTX  context;
    1987                 : 
    1988             218 :                         PHP_SHA1Init(&context);
    1989             218 :                         read_len = end_of_phar;
    1990                 : 
    1991             218 :                         if (read_len > sizeof(buf)) {
    1992              91 :                                 read_size = sizeof(buf);
    1993                 :                         } else {
    1994             127 :                                 read_size = (int)read_len;
    1995                 :                         }
    1996                 : 
    1997            1596 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    1998            1160 :                                 PHP_SHA1Update(&context, buf, len);
    1999            1160 :                                 read_len -= (off_t)len;
    2000            1160 :                                 if (read_len < read_size) {
    2001             276 :                                         read_size = (int)read_len;
    2002                 :                                 }
    2003                 :                         }
    2004                 : 
    2005             218 :                         PHP_SHA1Final(digest, &context);
    2006                 : 
    2007             218 :                         if (memcmp(digest, sig, sizeof(digest))) {
    2008               0 :                                 if (error) {
    2009               0 :                                         spprintf(error, 0, "broken signature");
    2010                 :                                 }
    2011               0 :                                 return FAILURE;
    2012                 :                         }
    2013                 : 
    2014             218 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    2015             218 :                         break;
    2016                 :                 }
    2017                 :                 case PHAR_SIG_MD5: {
    2018                 :                         unsigned char digest[16];
    2019                 :                         PHP_MD5_CTX   context;
    2020                 : 
    2021               2 :                         PHP_MD5Init(&context);
    2022               2 :                         read_len = end_of_phar;
    2023                 : 
    2024               2 :                         if (read_len > sizeof(buf)) {
    2025               0 :                                 read_size = sizeof(buf);
    2026                 :                         } else {
    2027               2 :                                 read_size = (int)read_len;
    2028                 :                         }
    2029                 : 
    2030               6 :                         while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
    2031               2 :                                 PHP_MD5Update(&context, buf, len);
    2032               2 :                                 read_len -= (off_t)len;
    2033               2 :                                 if (read_len < read_size) {
    2034               2 :                                         read_size = (int)read_len;
    2035                 :                                 }
    2036                 :                         }
    2037                 : 
    2038               2 :                         PHP_MD5Final(digest, &context);
    2039                 : 
    2040               2 :                         if (memcmp(digest, sig, sizeof(digest))) {
    2041               0 :                                 if (error) {
    2042               0 :                                         spprintf(error, 0, "broken signature");
    2043                 :                                 }
    2044               0 :                                 return FAILURE;
    2045                 :                         }
    2046                 : 
    2047               2 :                         *signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
    2048               2 :                         break;
    2049                 :                 }
    2050                 :                 default:
    2051               0 :                         if (error) {
    2052               0 :                                 spprintf(error, 0, "broken or unsupported signature");
    2053                 :                         }
    2054               0 :                         return FAILURE;
    2055                 :         }
    2056             227 :         return SUCCESS;
    2057                 : }
    2058                 : /* }}} */
    2059                 : 
    2060                 : int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
    2061            4756 : {
    2062                 :         unsigned char buf[1024];
    2063                 :         int sig_len;
    2064                 : 
    2065            4756 :         php_stream_rewind(fp);
    2066                 : 
    2067            4756 :         if (phar->signature) {
    2068             272 :                 efree(phar->signature);
    2069             272 :                 phar->signature = NULL;
    2070                 :         }
    2071                 : 
    2072            4756 :         switch(phar->sig_flags) {
    2073                 : #ifdef PHAR_HASH_OK
    2074                 :                 case PHAR_SIG_SHA512: {
    2075                 :                         unsigned char digest[64];
    2076                 :                         PHP_SHA512_CTX context;
    2077                 : 
    2078               3 :                         PHP_SHA512Init(&context);
    2079                 : 
    2080              16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    2081              10 :                                 PHP_SHA512Update(&context, buf, sig_len);
    2082                 :                         }
    2083                 : 
    2084               3 :                         PHP_SHA512Final(digest, &context);
    2085               3 :                         *signature = estrndup((char *) digest, 64);
    2086               3 :                         *signature_length = 64;
    2087               3 :                         break;
    2088                 :                 }
    2089                 :                 case PHAR_SIG_SHA256: {
    2090                 :                         unsigned char digest[32];
    2091                 :                         PHP_SHA256_CTX  context;
    2092                 : 
    2093               3 :                         PHP_SHA256Init(&context);
    2094                 : 
    2095              16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    2096              10 :                                 PHP_SHA256Update(&context, buf, sig_len);
    2097                 :                         }
    2098                 : 
    2099               3 :                         PHP_SHA256Final(digest, &context);
    2100               3 :                         *signature = estrndup((char *) digest, 32);
    2101               3 :                         *signature_length = 32;
    2102               3 :                         break;
    2103                 :                 }
    2104                 : #else
    2105                 :                 case PHAR_SIG_SHA512:
    2106                 :                 case PHAR_SIG_SHA256:
    2107                 :                         if (error) {
    2108                 :                                 spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
    2109                 :                         }
    2110                 : 
    2111                 :                         return FAILURE;
    2112                 : #endif
    2113                 :                 case PHAR_SIG_OPENSSL: {
    2114                 :                         int siglen;
    2115                 :                         unsigned char *sigbuf;
    2116                 : #ifdef PHAR_HAVE_OPENSSL
    2117                 :                         BIO *in;
    2118                 :                         EVP_PKEY *key;
    2119               3 :                         EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
    2120                 :                         EVP_MD_CTX md_ctx;
    2121                 : 
    2122               3 :                         in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
    2123                 : 
    2124               3 :                         if (in == NULL) {
    2125               0 :                                 if (error) {
    2126               0 :                                         spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
    2127                 :                                 }
    2128               0 :                                 return FAILURE;
    2129                 :                         }
    2130                 : 
    2131               3 :                         key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
    2132               3 :                         BIO_free(in);
    2133                 : 
    2134               3 :                         if (!key) {
    2135               0 :                                 if (error) {
    2136               0 :                                         spprintf(error, 0, "unable to process private key");
    2137                 :                                 }
    2138               0 :                                 return FAILURE;
    2139                 :                         }
    2140                 : 
    2141               3 :                         siglen = EVP_PKEY_size(key);
    2142               3 :                         sigbuf = emalloc(siglen + 1);
    2143               3 :                         EVP_SignInit(&md_ctx, mdtype);
    2144                 : 
    2145              16 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    2146              10 :                                 EVP_SignUpdate(&md_ctx, buf, sig_len);
    2147                 :                         }
    2148                 : 
    2149               3 :                         if (!EVP_SignFinal (&md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
    2150               0 :                                 efree(sigbuf);
    2151               0 :                                 if (error) {
    2152               0 :                                         spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
    2153                 :                                 }
    2154               0 :                                 return FAILURE;
    2155                 :                         }
    2156                 : 
    2157               3 :                         sigbuf[siglen] = '\0';
    2158               3 :                         EVP_MD_CTX_cleanup(&md_ctx);
    2159                 : #else
    2160                 :                         sigbuf = NULL;
    2161                 :                         siglen = 0;
    2162                 :                         php_stream_seek(fp, 0, SEEK_END);
    2163                 : 
    2164                 :                         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)) {
    2165                 :                                 if (error) {
    2166                 :                                         spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
    2167                 :                                 }
    2168                 :                                 return FAILURE;
    2169                 :                         }
    2170                 : #endif
    2171               3 :                         *signature = (char *) sigbuf;
    2172               3 :                         *signature_length = siglen;
    2173                 :                 }
    2174               3 :                 break;
    2175                 :                 default:
    2176             168 :                         phar->sig_flags = PHAR_SIG_SHA1;
    2177                 :                 case PHAR_SIG_SHA1: {
    2178                 :                         unsigned char digest[20];
    2179                 :                         PHP_SHA1_CTX  context;
    2180                 : 
    2181            4742 :                         PHP_SHA1Init(&context);
    2182                 : 
    2183           41092 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    2184           31608 :                                 PHP_SHA1Update(&context, buf, sig_len);
    2185                 :                         }
    2186                 : 
    2187            4742 :                         PHP_SHA1Final(digest, &context);
    2188            4742 :                         *signature = estrndup((char *) digest, 20);
    2189            4742 :                         *signature_length = 20;
    2190            4742 :                         break;
    2191                 :                 }
    2192                 :                 case PHAR_SIG_MD5: {
    2193                 :                         unsigned char digest[16];
    2194                 :                         PHP_MD5_CTX   context;
    2195                 : 
    2196               5 :                         PHP_MD5Init(&context);
    2197                 : 
    2198              22 :                         while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
    2199              12 :                                 PHP_MD5Update(&context, buf, sig_len);
    2200                 :                         }
    2201                 : 
    2202               5 :                         PHP_MD5Final(digest, &context);
    2203               5 :                         *signature = estrndup((char *) digest, 16);
    2204               5 :                         *signature_length = 16;
    2205                 :                         break;
    2206                 :                 }
    2207                 :         }
    2208                 : 
    2209            4756 :         phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
    2210            4756 :         return SUCCESS;
    2211                 : }
    2212                 : /* }}} */
    2213                 : 
    2214                 : void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
    2215           14362 : {
    2216                 :         char *s;
    2217                 : 
    2218           50185 :         while ((s = zend_memrchr(filename, '/', filename_len))) {
    2219           22262 :                 filename_len = s - filename;
    2220           22262 :                 if (FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
    2221             801 :                         break;
    2222                 :                 }
    2223                 :         }
    2224           14362 : }
    2225                 : /* }}} */
    2226                 : 
    2227                 : static int phar_update_cached_entry(void *data, void *argument) /* {{{ */
    2228               4 : {
    2229               4 :         phar_entry_info *entry = (phar_entry_info *)data;
    2230                 :         TSRMLS_FETCH();
    2231                 : 
    2232               4 :         entry->phar = (phar_archive_data *)argument;
    2233                 : 
    2234               4 :         if (entry->link) {
    2235               0 :                 entry->link = estrdup(entry->link);
    2236                 :         }
    2237                 : 
    2238               4 :         if (entry->tmp) {
    2239               0 :                 entry->tmp = estrdup(entry->tmp);
    2240                 :         }
    2241                 : 
    2242               4 :         entry->metadata_str.c = 0;
    2243               4 :         entry->filename = estrndup(entry->filename, entry->filename_len);
    2244               4 :         entry->is_persistent = 0;
    2245                 : 
    2246               4 :         if (entry->metadata) {
    2247               3 :                 if (entry->metadata_len) {
    2248               3 :                         char *buf = estrndup((char *) entry->metadata, entry->metadata_len);
    2249                 :                         /* assume success, we would have failed before */
    2250               3 :                         phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len TSRMLS_CC);
    2251               3 :                         efree(buf);
    2252                 :                 } else {
    2253                 :                         zval *t;
    2254                 : 
    2255               0 :                         t = entry->metadata;
    2256               0 :                         ALLOC_ZVAL(entry->metadata);
    2257               0 :                         *entry->metadata = *t;
    2258               0 :                         zval_copy_ctor(entry->metadata);
    2259                 : #if PHP_VERSION_ID < 50300
    2260                 :                         entry->metadata->refcount = 1;
    2261                 : #else
    2262               0 :                         Z_SET_REFCOUNT_P(entry->metadata, 1);
    2263                 : #endif
    2264               0 :                         entry->metadata_str.c = NULL;
    2265               0 :                         entry->metadata_str.len = 0;
    2266                 :                 }
    2267                 :         }
    2268               4 :         return ZEND_HASH_APPLY_KEEP;
    2269                 : }
    2270                 : /* }}} */
    2271                 : 
    2272                 : static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
    2273               3 : {
    2274                 :         phar_archive_data *phar;
    2275                 :         HashTable newmanifest;
    2276                 :         char *fname;
    2277                 :         phar_archive_object **objphar;
    2278                 : 
    2279               3 :         phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
    2280               3 :         *phar = **pphar;
    2281               3 :         phar->is_persistent = 0;
    2282               3 :         fname = phar->fname;
    2283               3 :         phar->fname = estrndup(phar->fname, phar->fname_len);
    2284               3 :         phar->ext = phar->fname + (phar->ext - fname);
    2285                 : 
    2286               3 :         if (phar->alias) {
    2287               3 :                 phar->alias = estrndup(phar->alias, phar->alias_len);
    2288                 :         }
    2289                 : 
    2290               3 :         if (phar->signature) {
    2291               3 :                 phar->signature = estrdup(phar->signature);
    2292                 :         }
    2293                 : 
    2294               3 :         if (phar->metadata) {
    2295                 :                 /* assume success, we would have failed before */
    2296               3 :                 if (phar->metadata_len) {
    2297               3 :                         char *buf = estrndup((char *) phar->metadata, phar->metadata_len);
    2298               3 :                         phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC);
    2299               3 :                         efree(buf);
    2300                 :                 } else {
    2301                 :                         zval *t;
    2302                 : 
    2303               0 :                         t = phar->metadata;
    2304               0 :                         ALLOC_ZVAL(phar->metadata);
    2305               0 :                         *phar->metadata = *t;
    2306               0 :                         zval_copy_ctor(phar->metadata);
    2307                 : #if PHP_VERSION_ID < 50300
    2308                 :                         phar->metadata->refcount = 1;
    2309                 : #else
    2310               0 :                         Z_SET_REFCOUNT_P(phar->metadata, 1);
    2311                 : #endif
    2312                 :                 }
    2313                 :         }
    2314                 : 
    2315               3 :         zend_hash_init(&newmanifest, sizeof(phar_entry_info),
    2316                 :                 zend_get_hash_value, destroy_phar_manifest_entry, 0);
    2317               3 :         zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info));
    2318               3 :         zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC);
    2319               3 :         phar->manifest = newmanifest;
    2320               3 :         zend_hash_init(&phar->mounted_dirs, sizeof(char *),
    2321                 :                 zend_get_hash_value, NULL, 0);
    2322               3 :         zend_hash_init(&phar->virtual_dirs, sizeof(char *),
    2323                 :                 zend_get_hash_value, NULL, 0);
    2324               3 :         zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
    2325               3 :         *pphar = phar;
    2326                 : 
    2327                 :         /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
    2328               3 :         for (zend_hash_internal_pointer_reset(&PHAR_GLOBALS->phar_persist_map);
    2329               8 :         SUCCESS == zend_hash_get_current_data(&PHAR_GLOBALS->phar_persist_map, (void **) &objphar);
    2330               2 :         zend_hash_move_forward(&PHAR_GLOBALS->phar_persist_map)) {
    2331               2 :                 if (objphar[0]->arc.archive->fname_len == phar->fname_len && !memcmp(objphar[0]->arc.archive->fname, phar->fname, phar->fname_len)) {
    2332               2 :                         objphar[0]->arc.archive = phar;
    2333                 :                 }
    2334                 :         }
    2335               3 : }
    2336                 : /* }}} */
    2337                 : 
    2338                 : int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
    2339               3 : {
    2340               3 :         phar_archive_data **newpphar, *newphar = NULL;
    2341                 : 
    2342               3 :         if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) {
    2343               0 :                 return FAILURE;
    2344                 :         }
    2345                 : 
    2346               3 :         *newpphar = *pphar;
    2347               3 :         phar_copy_cached_phar(newpphar TSRMLS_CC);
    2348                 :         /* invalidate phar cache */
    2349               3 :         PHAR_G(last_phar) = NULL;
    2350               3 :         PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
    2351                 : 
    2352               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)) {
    2353               0 :                 zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
    2354               0 :                 return FAILURE;
    2355                 :         }
    2356                 : 
    2357               3 :         *pphar = *newpphar;
    2358               3 :         return SUCCESS;
    2359                 : }
    2360                 : /* }}} */
    2361                 : 
    2362                 : /*
    2363                 :  * Local variables:
    2364                 :  * tab-width: 4
    2365                 :  * c-basic-offset: 4
    2366                 :  * End:
    2367                 :  * vim600: noet sw=4 ts=4 fdm=marker
    2368                 :  * vim<600: noet sw=4 ts=4
    2369                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:07 +0000 (3 days ago)

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