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

LCOV - code coverage report
Current view: top level - ext/phar - zip.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 584 800 73.0 %
Date: 2014-11-22 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | ZIP archive support for Phar                                         |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2007-2014 The PHP Group                                |
       6             :   +----------------------------------------------------------------------+
       7             :   | This source file is subject to version 3.01 of the PHP license,      |
       8             :   | that is bundled with this package in the file LICENSE, and is        |
       9             :   | available through the world-wide-web at the following url:           |
      10             :   | http://www.php.net/license/3_01.txt.                                 |
      11             :   | If you did not receive a copy of the PHP license and are unable to   |
      12             :   | obtain it through the world-wide-web, please send a note to          |
      13             :   | license@php.net so we can mail you a copy immediately.               |
      14             :   +----------------------------------------------------------------------+
      15             :   | Authors: Gregory Beaver <cellog@php.net>                             |
      16             :   +----------------------------------------------------------------------+
      17             : */
      18             : 
      19             : #include "phar_internal.h"
      20             : 
      21             : #define PHAR_GET_16(var) ((php_uint16)((((php_uint16)var[0]) & 0xff) | \
      22             :         (((php_uint16)var[1]) & 0xff) << 8))
      23             : #define PHAR_GET_32(var) ((php_uint32)((((php_uint32)var[0]) & 0xff) | \
      24             :         (((php_uint32)var[1]) & 0xff) << 8 | \
      25             :         (((php_uint32)var[2]) & 0xff) << 16 | \
      26             :         (((php_uint32)var[3]) & 0xff) << 24))
      27        7542 : static inline void phar_write_32(char buffer[4], php_uint32 value)
      28             : {
      29        7542 :         buffer[3] = (unsigned char) ((value & 0xff000000) >> 24);
      30        7542 :         buffer[2] = (unsigned char) ((value & 0xff0000) >> 16);
      31        7542 :         buffer[1] = (unsigned char) ((value & 0xff00) >> 8);
      32        7542 :         buffer[0] = (unsigned char) (value & 0xff);
      33        7542 : }
      34        7323 : static inline void phar_write_16(char buffer[2], php_uint32 value)
      35             : {
      36        7323 :         buffer[1] = (unsigned char) ((value & 0xff00) >> 8);
      37        7323 :         buffer[0] = (unsigned char) (value & 0xff);
      38        7323 : }
      39             : # define PHAR_SET_32(var, value) phar_write_32(var, (php_uint32) (value));
      40             : # define PHAR_SET_16(var, value) phar_write_16(var, (php_uint16) (value));
      41             : 
      42         196 : static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_uint16 len TSRMLS_DC) /* {{{ */
      43             : {
      44             :         union {
      45             :                 phar_zip_extra_field_header header;
      46             :                 phar_zip_unix3 unix3;
      47             :         } h;
      48             :         int read;
      49             : 
      50             :         do {
      51         196 :                 if (sizeof(h.header) != php_stream_read(fp, (char *) &h.header, sizeof(h.header))) {
      52           1 :                         return FAILURE;
      53             :                 }
      54             : 
      55         195 :                 if (h.header.tag[0] != 'n' || h.header.tag[1] != 'u') {
      56             :                         /* skip to next header */
      57          34 :                         php_stream_seek(fp, PHAR_GET_16(h.header.size), SEEK_CUR);
      58          34 :                         len -= PHAR_GET_16(h.header.size) + 4;
      59          34 :                         continue;
      60             :                 }
      61             : 
      62             :                 /* unix3 header found */
      63         161 :                 read = php_stream_read(fp, (char *) &(h.unix3.crc32), sizeof(h.unix3) - sizeof(h.header));
      64         161 :                 len -= read + 4;
      65             : 
      66         161 :                 if (sizeof(h.unix3) - sizeof(h.header) != read) {
      67           0 :                         return FAILURE;
      68             :                 }
      69             : 
      70         161 :                 if (PHAR_GET_16(h.unix3.size) > sizeof(h.unix3) - 4) {
      71             :                         /* skip symlink filename - we may add this support in later */
      72           1 :                         php_stream_seek(fp, PHAR_GET_16(h.unix3.size) - sizeof(h.unix3.size), SEEK_CUR);
      73             :                 }
      74             : 
      75             :                 /* set permissions */
      76         161 :                 entry->flags &= PHAR_ENT_COMPRESSION_MASK;
      77             : 
      78         161 :                 if (entry->is_dir) {
      79           3 :                         entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
      80             :                 } else {
      81         158 :                         entry->flags |= PHAR_GET_16(h.unix3.perms) & PHAR_ENT_PERM_MASK;
      82             :                 }
      83             : 
      84         195 :         } while (len);
      85             : 
      86         177 :         return SUCCESS;
      87             : }
      88             : /* }}} */
      89             : 
      90             : /*
      91             :   extracted from libzip
      92             :   zip_dirent.c -- read directory entry (local or central), clean dirent
      93             :   Copyright (C) 1999, 2003, 2004, 2005 Dieter Baron and Thomas Klausner
      94             : 
      95             :   This function is part of libzip, a library to manipulate ZIP archives.
      96             :   The authors can be contacted at <nih@giga.or.at>
      97             : 
      98             :   Redistribution and use in source and binary forms, with or without
      99             :   modification, are permitted provided that the following conditions
     100             :   are met:
     101             :   1. Redistributions of source code must retain the above copyright
     102             :      notice, this list of conditions and the following disclaimer.
     103             :   2. Redistributions in binary form must reproduce the above copyright
     104             :      notice, this list of conditions and the following disclaimer in
     105             :      the documentation and/or other materials provided with the
     106             :      distribution.
     107             :   3. The names of the authors may not be used to endorse or promote
     108             :      products derived from this software without specific prior
     109             :      written permission.
     110             : 
     111             :   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
     112             :   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     113             :   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     114             :   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
     115             :   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     116             :   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     117             :   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     118             :   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
     119             :   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     120             :   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     121             :   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     122             :  */
     123         262 : static time_t phar_zip_d2u_time(char *cdtime, char *cddate) /* {{{ */
     124             : {
     125         262 :         int dtime = PHAR_GET_16(cdtime), ddate = PHAR_GET_16(cddate);
     126             :         struct tm *tm, tmbuf;
     127             :         time_t now;
     128             : 
     129         262 :         now = time(NULL);
     130         262 :         tm = php_localtime_r(&now, &tmbuf);
     131             : 
     132         262 :         tm->tm_year = ((ddate>>9)&127) + 1980 - 1900;
     133         262 :         tm->tm_mon = ((ddate>>5)&15) - 1;
     134         262 :         tm->tm_mday = ddate&31;
     135             : 
     136         262 :         tm->tm_hour = (dtime>>11)&31;
     137         262 :         tm->tm_min = (dtime>>5)&63;
     138         262 :         tm->tm_sec = (dtime<<1)&62;
     139             : 
     140         262 :         return mktime(tm);
     141             : }
     142             : /* }}} */
     143             : 
     144         849 : static void phar_zip_u2d_time(time_t time, char *dtime, char *ddate) /* {{{ */
     145             : {
     146             :         php_uint16 ctime, cdate;
     147             :         struct tm *tm, tmbuf;
     148             : 
     149         849 :         tm = php_localtime_r(&time, &tmbuf);
     150         849 :         cdate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday;
     151         849 :         ctime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1);
     152         849 :         PHAR_SET_16(dtime, ctime);
     153         849 :         PHAR_SET_16(ddate, cdate);
     154         849 : }
     155             : /* }}} */
     156             : 
     157             : /**
     158             :  * Does not check for a previously opened phar in the cache.
     159             :  *
     160             :  * Parse a new one and add it to the cache, returning either SUCCESS or
     161             :  * FAILURE, and setting pphar to the pointer to the manifest entry
     162             :  * 
     163             :  * This is used by phar_open_from_fp to process a zip-based phar, but can be called
     164             :  * directly.
     165             :  */
     166          79 : int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
     167             : {
     168             :         phar_zip_dir_end locator;
     169             :         char buf[sizeof(locator) + 65536];
     170             :         zend_long size;
     171             :         php_uint16 i;
     172          79 :         phar_archive_data *mydata = NULL;
     173          79 :         phar_entry_info entry = {0};
     174          79 :         char *p = buf, *ext, *actual_alias = NULL;
     175          79 :         char *metadata = NULL;
     176             : 
     177          79 :         size = php_stream_tell(fp);
     178             : 
     179          79 :         if (size > sizeof(locator) + 65536) {
     180             :                 /* seek to max comment length + end of central directory record */
     181           2 :                 size = sizeof(locator) + 65536;
     182           2 :                 if (FAILURE == php_stream_seek(fp, -size, SEEK_END)) {
     183           0 :                         php_stream_close(fp);
     184           0 :                         if (error) {
     185           0 :                                 spprintf(error, 4096, "phar error: unable to search for end of central directory in zip-based phar \"%s\"", fname);
     186             :                         }
     187           0 :                         return FAILURE;
     188             :                 }
     189             :         } else {
     190          77 :                 php_stream_seek(fp, 0, SEEK_SET);
     191             :         }
     192             : 
     193          79 :         if (!php_stream_read(fp, buf, size)) {
     194           0 :                 php_stream_close(fp);
     195           0 :                 if (error) {
     196           0 :                         spprintf(error, 4096, "phar error: unable to read in data to search for end of central directory in zip-based phar \"%s\"", fname);
     197             :                 }
     198           0 :                 return FAILURE;
     199             :         }
     200             : 
     201        1094 :         while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) {
     202        1014 :                 if (!memcmp(p + 1, "K\5\6", 3)) {
     203          78 :                         memcpy((void *)&locator, (void *) p, sizeof(locator));
     204          78 :                         if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
     205             :                                 /* split archives not handled */
     206           1 :                                 php_stream_close(fp);
     207           1 :                                 if (error) {
     208           1 :                                         spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
     209             :                                 }
     210           1 :                                 return FAILURE;
     211             :                         }
     212             : 
     213          77 :                         if (PHAR_GET_16(locator.counthere) != PHAR_GET_16(locator.count)) {
     214           2 :                                 if (error) {
     215           2 :                                         spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
     216             :                                 }
     217           2 :                                 php_stream_close(fp);
     218           2 :                                 return FAILURE;
     219             :                         }
     220             : 
     221          75 :                         mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
     222          75 :                         mydata->is_persistent = PHAR_G(persist);
     223             : 
     224             :                         /* read in archive comment, if any */
     225          75 :                         if (PHAR_GET_16(locator.comment_len)) {
     226             : 
     227           4 :                                 metadata = p + sizeof(locator);
     228             : 
     229           4 :                                 if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
     230           1 :                                         if (error) {
     231           1 :                                                 spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
     232             :                                         }
     233           1 :                                         php_stream_close(fp);
     234           1 :                                         pefree(mydata, mydata->is_persistent);
     235           1 :                                         return FAILURE;
     236             :                                 }
     237             : 
     238           3 :                                 mydata->metadata_len = PHAR_GET_16(locator.comment_len);
     239             : 
     240           3 :                                 if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len) TSRMLS_CC) == FAILURE) {
     241           2 :                                         mydata->metadata_len = 0;
     242             :                                         /* if not valid serialized data, it is a regular string */
     243             : 
     244           4 :                                         ZVAL_NEW_STR(&mydata->metadata, zend_string_init(metadata, PHAR_GET_16(locator.comment_len), mydata->is_persistent));
     245             :                                 }
     246             :                         } else {
     247          71 :                                 ZVAL_UNDEF(&mydata->metadata);
     248             :                         }
     249             : 
     250          74 :                         goto foundit;
     251             :                 }
     252             :         }
     253             : 
     254           1 :         php_stream_close(fp);
     255             : 
     256           1 :         if (error) {
     257           1 :                 spprintf(error, 4096, "phar error: end of central directory not found in zip-based phar \"%s\"", fname);
     258             :         }
     259             : 
     260           1 :         return FAILURE;
     261             : foundit:
     262          74 :         mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
     263             : #ifdef PHP_WIN32
     264             :         phar_unixify_path_separators(mydata->fname, fname_len);
     265             : #endif
     266          74 :         mydata->is_zip = 1;
     267          74 :         mydata->fname_len = fname_len;
     268          74 :         ext = strrchr(mydata->fname, '/');
     269             : 
     270          74 :         if (ext) {
     271          74 :                 mydata->ext = memchr(ext, '.', (mydata->fname + fname_len) - ext);
     272          74 :                 if (mydata->ext == ext) {
     273           0 :                         mydata->ext = memchr(ext + 1, '.', (mydata->fname + fname_len) - ext - 1);
     274             :                 }
     275          74 :                 if (mydata->ext) {
     276          74 :                         mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
     277             :                 }
     278             :         }
     279             : 
     280             :         /* clean up on big-endian systems */
     281             :         /* seek to central directory */
     282          74 :         php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET);
     283             :         /* read in central directory */
     284          74 :         zend_hash_init(&mydata->manifest, PHAR_GET_16(locator.count),
     285             :                 zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)mydata->is_persistent);
     286          74 :         zend_hash_init(&mydata->mounted_dirs, 5,
     287             :                 zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
     288          74 :         zend_hash_init(&mydata->virtual_dirs, PHAR_GET_16(locator.count) * 2,
     289             :                 zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
     290          74 :         entry.phar = mydata;
     291          74 :         entry.is_zip = 1;
     292          74 :         entry.fp_type = PHAR_FP;
     293          74 :         entry.is_persistent = mydata->is_persistent;
     294             : #define PHAR_ZIP_FAIL_FREE(errmsg, save) \
     295             :                         zend_hash_destroy(&mydata->manifest); \
     296             :                         mydata->manifest.arHash = 0; \
     297             :                         zend_hash_destroy(&mydata->mounted_dirs); \
     298             :                         mydata->mounted_dirs.arHash = 0; \
     299             :                         zend_hash_destroy(&mydata->virtual_dirs); \
     300             :                         mydata->virtual_dirs.arHash = 0; \
     301             :                         php_stream_close(fp); \
     302             :                         zval_dtor(&mydata->metadata); \
     303             :                         if (mydata->signature) { \
     304             :                                 efree(mydata->signature); \
     305             :                         } \
     306             :                         if (error) { \
     307             :                                 spprintf(error, 4096, "phar error: %s in zip-based phar \"%s\"", errmsg, mydata->fname); \
     308             :                         } \
     309             :                         pefree(mydata->fname, mydata->is_persistent); \
     310             :                         if (mydata->alias) { \
     311             :                                 pefree(mydata->alias, mydata->is_persistent); \
     312             :                         } \
     313             :                         pefree(mydata, mydata->is_persistent); \
     314             :                         efree(save); \
     315             :                         return FAILURE;
     316             : #define PHAR_ZIP_FAIL(errmsg) \
     317             :                         zend_hash_destroy(&mydata->manifest); \
     318             :                         mydata->manifest.arHash = 0; \
     319             :                         zend_hash_destroy(&mydata->mounted_dirs); \
     320             :                         mydata->mounted_dirs.arHash = 0; \
     321             :                         zend_hash_destroy(&mydata->virtual_dirs); \
     322             :                         mydata->virtual_dirs.arHash = 0; \
     323             :                         php_stream_close(fp); \
     324             :                         zval_dtor(&mydata->metadata); \
     325             :                         if (mydata->signature) { \
     326             :                                 efree(mydata->signature); \
     327             :                         } \
     328             :                         if (error) { \
     329             :                                 spprintf(error, 4096, "phar error: %s in zip-based phar \"%s\"", errmsg, mydata->fname); \
     330             :                         } \
     331             :                         pefree(mydata->fname, mydata->is_persistent); \
     332             :                         if (mydata->alias) { \
     333             :                                 pefree(mydata->alias, mydata->is_persistent); \
     334             :                         } \
     335             :                         pefree(mydata, mydata->is_persistent); \
     336             :                         return FAILURE;
     337             : 
     338             :         /* add each central directory item to the manifest */
     339         317 :         for (i = 0; i < PHAR_GET_16(locator.count); ++i) {
     340             :                 phar_zip_central_dir_file zipentry;
     341         264 :                 zend_off_t beforeus = php_stream_tell(fp);
     342             : 
     343         264 :                 if (sizeof(zipentry) != php_stream_read(fp, (char *) &zipentry, sizeof(zipentry))) {
     344           0 :                         PHAR_ZIP_FAIL("unable to read central directory entry, truncated");
     345             :                 }
     346             : 
     347             :                 /* clean up for bigendian systems */
     348         264 :                 if (memcmp("PK\1\2", zipentry.signature, 4)) {
     349             :                         /* corrupted entry */
     350           4 :                         PHAR_ZIP_FAIL("corrupted central directory entry, no magic signature");
     351             :                 }
     352             : 
     353         262 :                 if (entry.is_persistent) {
     354           0 :                         entry.manifest_pos = i;
     355             :                 }
     356             : 
     357         262 :                 entry.compressed_filesize = PHAR_GET_32(zipentry.compsize);
     358         262 :                 entry.uncompressed_filesize = PHAR_GET_32(zipentry.uncompsize);
     359         262 :                 entry.crc32 = PHAR_GET_32(zipentry.crc32);
     360             :                 /* do not PHAR_GET_16 either on the next line */
     361         262 :                 entry.timestamp = phar_zip_d2u_time(zipentry.timestamp, zipentry.datestamp);
     362         262 :                 entry.flags = PHAR_ENT_PERM_DEF_FILE;
     363         262 :                 entry.header_offset = PHAR_GET_32(zipentry.offset);
     364         524 :                 entry.offset = entry.offset_abs = PHAR_GET_32(zipentry.offset) + sizeof(phar_zip_file_header) + PHAR_GET_16(zipentry.filename_len) +
     365         262 :                         PHAR_GET_16(zipentry.extra_len);
     366             : 
     367         262 :                 if (PHAR_GET_16(zipentry.flags) & PHAR_ZIP_FLAG_ENCRYPTED) {
     368           2 :                         PHAR_ZIP_FAIL("Cannot process encrypted zip files");
     369             :                 }
     370             : 
     371         261 :                 if (!PHAR_GET_16(zipentry.filename_len)) {
     372           2 :                         PHAR_ZIP_FAIL("Cannot process zips created from stdin (zero-length filename)");
     373             :                 }
     374             : 
     375         260 :                 entry.filename_len = PHAR_GET_16(zipentry.filename_len);
     376         520 :                 entry.filename = (char *) pemalloc(entry.filename_len + 1, entry.is_persistent);
     377             : 
     378         260 :                 if (entry.filename_len != php_stream_read(fp, entry.filename, entry.filename_len)) {
     379           0 :                         pefree(entry.filename, entry.is_persistent);
     380           0 :                         PHAR_ZIP_FAIL("unable to read in filename from central directory, truncated");
     381             :                 }
     382             : 
     383         260 :                 entry.filename[entry.filename_len] = '\0';
     384             : 
     385         260 :                 if (entry.filename[entry.filename_len - 1] == '/') {
     386          23 :                         entry.is_dir = 1;
     387          23 :                         entry.filename_len--;
     388          23 :                         entry.flags |= PHAR_ENT_PERM_DEF_DIR;
     389             :                 } else {
     390         237 :                         entry.is_dir = 0;
     391             :                 }
     392             : 
     393         260 :                 if (entry.filename_len == sizeof(".phar/signature.bin")-1 && !strncmp(entry.filename, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) {
     394             :                         size_t read;
     395             :                         php_stream *sigfile;
     396             :                         zend_off_t now;
     397             :                         char *sig;
     398             : 
     399          18 :                         now = php_stream_tell(fp);
     400          18 :                         pefree(entry.filename, entry.is_persistent);
     401          18 :                         sigfile = php_stream_fopen_tmpfile();
     402          18 :                         if (!sigfile) {
     403           0 :                                 PHAR_ZIP_FAIL("couldn't open temporary file");
     404             :                         }
     405             : 
     406          18 :                         php_stream_seek(fp, 0, SEEK_SET);
     407             :                         /* copy file contents + local headers and zip comment, if any, to be hashed for signature */
     408          18 :                         php_stream_copy_to_stream_ex(fp, sigfile, entry.header_offset, NULL);
     409             :                         /* seek to central directory */
     410          18 :                         php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET);
     411             :                         /* copy central directory header */
     412          18 :                         php_stream_copy_to_stream_ex(fp, sigfile, beforeus - PHAR_GET_32(locator.cdir_offset), NULL);
     413          18 :                         if (metadata) {
     414           1 :                                 php_stream_write(sigfile, metadata, PHAR_GET_16(locator.comment_len));
     415             :                         }
     416          18 :                         php_stream_seek(fp, sizeof(phar_zip_file_header) + entry.header_offset + entry.filename_len + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
     417          18 :                         sig = (char *) emalloc(entry.uncompressed_filesize);
     418          18 :                         read = php_stream_read(fp, sig, entry.uncompressed_filesize);
     419          18 :                         if (read != entry.uncompressed_filesize) {
     420           0 :                                 php_stream_close(sigfile);
     421           0 :                                 efree(sig);
     422           0 :                                 PHAR_ZIP_FAIL("signature cannot be read");
     423             :                         }
     424          18 :                         mydata->sig_flags = PHAR_GET_32(sig);
     425          18 :                         if (FAILURE == phar_verify_signature(sigfile, php_stream_tell(sigfile), mydata->sig_flags, sig + 8, entry.uncompressed_filesize - 8, fname, &mydata->signature, &mydata->sig_len, error TSRMLS_CC)) {
     426           0 :                                 efree(sig);
     427           0 :                                 if (error) {
     428             :                                         char *save;
     429           0 :                                         php_stream_close(sigfile);
     430           0 :                                         spprintf(&save, 4096, "signature cannot be verified: %s", *error);
     431           0 :                                         efree(*error);
     432           0 :                                         PHAR_ZIP_FAIL_FREE(save, save);
     433             :                                 } else {
     434           0 :                                         php_stream_close(sigfile);
     435           0 :                                         PHAR_ZIP_FAIL("signature cannot be verified");
     436             :                                 }
     437             :                         }
     438          18 :                         php_stream_close(sigfile);
     439          18 :                         efree(sig);
     440             :                         /* signature checked out, let's ensure this is the last file in the phar */
     441          18 :                         if (i != PHAR_GET_16(locator.count) - 1) {
     442           2 :                                 PHAR_ZIP_FAIL("entries exist after signature, invalid phar");
     443             :                         }
     444             : 
     445          17 :                         continue;
     446             :                 }
     447             : 
     448         242 :                 phar_add_virtual_dirs(mydata, entry.filename, entry.filename_len TSRMLS_CC);
     449             : 
     450         242 :                 if (PHAR_GET_16(zipentry.extra_len)) {
     451         178 :                         zend_off_t loc = php_stream_tell(fp);
     452         178 :                         if (FAILURE == phar_zip_process_extra(fp, &entry, PHAR_GET_16(zipentry.extra_len) TSRMLS_CC)) {
     453           1 :                                 pefree(entry.filename, entry.is_persistent);
     454           2 :                                 PHAR_ZIP_FAIL("Unable to process extra field header for file in central directory");
     455             :                         }
     456         177 :                         php_stream_seek(fp, loc + PHAR_GET_16(zipentry.extra_len), SEEK_SET);
     457             :                 }
     458             : 
     459         241 :                 switch (PHAR_GET_16(zipentry.compressed)) {
     460             :                         case PHAR_ZIP_COMP_NONE :
     461             :                                 /* compression flag already set */
     462         181 :                                 break;
     463             :                         case PHAR_ZIP_COMP_DEFLATE :
     464          33 :                                 entry.flags |= PHAR_ENT_COMPRESSED_GZ;
     465          33 :                                 if (!PHAR_G(has_zlib)) {
     466           0 :                                         pefree(entry.filename, entry.is_persistent);
     467           0 :                                         PHAR_ZIP_FAIL("zlib extension is required");
     468             :                                 }
     469          33 :                                 break;
     470             :                         case PHAR_ZIP_COMP_BZIP2 :
     471          12 :                                 entry.flags |= PHAR_ENT_COMPRESSED_BZ2;
     472          12 :                                 if (!PHAR_G(has_bz2)) {
     473           0 :                                         pefree(entry.filename, entry.is_persistent);
     474           0 :                                         PHAR_ZIP_FAIL("bzip2 extension is required");
     475             :                                 }
     476          12 :                                 break;
     477             :                         case 1 :
     478           1 :                                 pefree(entry.filename, entry.is_persistent);
     479           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (Shrunk) used in this zip");
     480             :                         case 2 :
     481             :                         case 3 :
     482             :                         case 4 :
     483             :                         case 5 :
     484           4 :                                 pefree(entry.filename, entry.is_persistent);
     485           8 :                                 PHAR_ZIP_FAIL("unsupported compression method (Reduce) used in this zip");
     486             :                         case 6 :
     487           1 :                                 pefree(entry.filename, entry.is_persistent);
     488           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (Implode) used in this zip");
     489             :                         case 7 :
     490           1 :                                 pefree(entry.filename, entry.is_persistent);
     491           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (Tokenize) used in this zip");
     492             :                         case 9 :
     493           1 :                                 pefree(entry.filename, entry.is_persistent);
     494           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (Deflate64) used in this zip");
     495             :                         case 10 :
     496           1 :                                 pefree(entry.filename, entry.is_persistent);
     497           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (PKWare Implode/old IBM TERSE) used in this zip");
     498             :                         case 14 :
     499           1 :                                 pefree(entry.filename, entry.is_persistent);
     500           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (LZMA) used in this zip");
     501             :                         case 18 :
     502           1 :                                 pefree(entry.filename, entry.is_persistent);
     503           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (IBM TERSE) used in this zip");
     504             :                         case 19 :
     505           1 :                                 pefree(entry.filename, entry.is_persistent);
     506           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (IBM LZ77) used in this zip");
     507             :                         case 97 :
     508           1 :                                 pefree(entry.filename, entry.is_persistent);
     509           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (WavPack) used in this zip");
     510             :                         case 98 :
     511           1 :                                 pefree(entry.filename, entry.is_persistent);
     512           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (PPMd) used in this zip");
     513             :                         default :
     514           1 :                                 pefree(entry.filename, entry.is_persistent);
     515           2 :                                 PHAR_ZIP_FAIL("unsupported compression method (unknown) used in this zip");
     516             :                 }
     517             : 
     518             :                 /* get file metadata */
     519         226 :                 if (PHAR_GET_16(zipentry.comment_len)) {
     520          14 :                         if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) {
     521           0 :                                 pefree(entry.filename, entry.is_persistent);
     522           0 :                                 PHAR_ZIP_FAIL("unable to read in file comment, truncated");
     523             :                         }
     524             : 
     525          14 :                         p = buf;
     526          14 :                         entry.metadata_len = PHAR_GET_16(zipentry.comment_len);
     527             : 
     528          14 :                         if (phar_parse_metadata(&p, &(entry.metadata), PHAR_GET_16(zipentry.comment_len) TSRMLS_CC) == FAILURE) {
     529           4 :                                 entry.metadata_len = 0;
     530             :                                 /* if not valid serialized data, it is a regular string */
     531             : 
     532           8 :                                 ZVAL_NEW_STR(&entry.metadata, zend_string_init(buf, PHAR_GET_16(zipentry.comment_len), entry.is_persistent));
     533             :                         }
     534             :                 } else {
     535         212 :                         ZVAL_UNDEF(&entry.metadata);
     536             :                 }
     537             : 
     538         226 :                 if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) {
     539             :                         php_stream_filter *filter;
     540             :                         zend_off_t saveloc;
     541             :                         /* verify local file header */
     542             :                         phar_zip_file_header local;
     543             : 
     544             :                         /* archive alias found */
     545          12 :                         saveloc = php_stream_tell(fp);
     546          12 :                         php_stream_seek(fp, PHAR_GET_32(zipentry.offset), SEEK_SET);
     547             : 
     548          12 :                         if (sizeof(local) != php_stream_read(fp, (char *) &local, sizeof(local))) {
     549           0 :                                 pefree(entry.filename, entry.is_persistent);
     550           0 :                                 PHAR_ZIP_FAIL("phar error: internal corruption of zip-based phar (cannot read local file header for alias)");
     551             :                         }
     552             : 
     553             :                         /* verify local header */
     554          12 :                         if (entry.filename_len != PHAR_GET_16(local.filename_len) || entry.crc32 != PHAR_GET_32(local.crc32) || entry.uncompressed_filesize != PHAR_GET_32(local.uncompsize) || entry.compressed_filesize != PHAR_GET_32(local.compsize)) {
     555           0 :                                 pefree(entry.filename, entry.is_persistent);
     556           0 :                                 PHAR_ZIP_FAIL("phar error: internal corruption of zip-based phar (local header of alias does not match central directory)");
     557             :                         }
     558             : 
     559             :                         /* construct actual offset to file start - local extra_len can be different from central extra_len */
     560          12 :                         entry.offset = entry.offset_abs =
     561          12 :                                 sizeof(local) + entry.header_offset + PHAR_GET_16(local.filename_len) + PHAR_GET_16(local.extra_len);
     562          12 :                         php_stream_seek(fp, entry.offset, SEEK_SET);
     563             :                         /* these next lines should be for php < 5.2.6 after 5.3 filters are fixed */
     564          12 :                         fp->writepos = 0;
     565          12 :                         fp->readpos = 0;
     566          12 :                         php_stream_seek(fp, entry.offset, SEEK_SET);
     567          12 :                         fp->writepos = 0;
     568          12 :                         fp->readpos = 0;
     569             :                         /* the above lines should be for php < 5.2.6 after 5.3 filters are fixed */
     570             : 
     571          12 :                         mydata->alias_len = entry.uncompressed_filesize;
     572          12 :                         if (entry.flags & PHAR_ENT_COMPRESSED_GZ) {
     573           6 :                                 filter = php_stream_filter_create("zlib.inflate", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
     574             : 
     575           6 :                                 if (!filter) {
     576           0 :                                         pefree(entry.filename, entry.is_persistent);
     577           0 :                                         PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed");
     578             :                                 }
     579             : 
     580           6 :                                 php_stream_filter_append(&fp->readfilters, filter);
     581             : 
     582             :                                 // TODO: refactor to avoid reallocation ???
     583             : //???                   entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)
     584             :                                 {
     585           6 :                                         zend_string *str = php_stream_copy_to_mem(fp, entry.uncompressed_filesize, 0);
     586           6 :                                         if (str) {
     587           6 :                                                 entry.uncompressed_filesize = str->len;
     588           6 :                                                 actual_alias = estrndup(str->val, str->len);
     589             :                                                 zend_string_release(str);
     590             :                                         } else {
     591           0 :                                                 actual_alias = NULL;
     592           0 :                                                 entry.uncompressed_filesize = 0;
     593             :                                         }
     594             :                                 }
     595             : 
     596           6 :                                 if (!entry.uncompressed_filesize || !actual_alias) {
     597           0 :                                         pefree(entry.filename, entry.is_persistent);
     598           0 :                                         PHAR_ZIP_FAIL("unable to read in alias, truncated");
     599             :                                 }
     600             : 
     601           6 :                                 php_stream_filter_flush(filter, 1);
     602           6 :                                 php_stream_filter_remove(filter, 1 TSRMLS_CC);
     603             : 
     604           6 :                         } else if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) {
     605           1 :                                 filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
     606             : 
     607           1 :                                 if (!filter) {
     608           0 :                                         pefree(entry.filename, entry.is_persistent);
     609           0 :                                         PHAR_ZIP_FAIL("unable to read in alias, bzip2 filter creation failed");
     610             :                                 }
     611             : 
     612           1 :                                 php_stream_filter_append(&fp->readfilters, filter);
     613             : 
     614             :                                 // TODO: refactor to avoid reallocation ???
     615             : //???                   entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)
     616             :                                 {
     617           1 :                                         zend_string *str = php_stream_copy_to_mem(fp, entry.uncompressed_filesize, 0);
     618           1 :                                         if (str) {
     619           1 :                                                 entry.uncompressed_filesize = str->len;
     620           1 :                                                 actual_alias = estrndup(str->val, str->len);
     621             :                                                 zend_string_release(str);
     622             :                                         } else {
     623           0 :                                                 actual_alias = NULL;
     624           0 :                                                 entry.uncompressed_filesize = 0;
     625             :                                         }
     626             :                                 }
     627             : 
     628           1 :                                 if (!entry.uncompressed_filesize || !actual_alias) {
     629           0 :                                         pefree(entry.filename, entry.is_persistent);
     630           0 :                                         PHAR_ZIP_FAIL("unable to read in alias, truncated");
     631             :                                 }
     632             : 
     633           1 :                                 php_stream_filter_flush(filter, 1);
     634           1 :                                 php_stream_filter_remove(filter, 1 TSRMLS_CC);
     635             :                         } else {
     636             :                                 // TODO: refactor to avoid reallocation ???
     637             : //???                   entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)
     638             :                                 {
     639           5 :                                         zend_string *str = php_stream_copy_to_mem(fp, entry.uncompressed_filesize, 0);
     640           5 :                                         if (str) {
     641           5 :                                                 entry.uncompressed_filesize = str->len;
     642           5 :                                                 actual_alias = estrndup(str->val, str->len);
     643             :                                                 zend_string_release(str);
     644             :                                         } else {
     645           0 :                                                 actual_alias = NULL;
     646           0 :                                                 entry.uncompressed_filesize = 0;
     647             :                                         }
     648             :                                 }
     649             : 
     650           5 :                                 if (!entry.uncompressed_filesize || !actual_alias) {
     651           0 :                                         pefree(entry.filename, entry.is_persistent);
     652           0 :                                         PHAR_ZIP_FAIL("unable to read in alias, truncated");
     653             :                                 }
     654             :                         }
     655             : 
     656             :                         /* return to central directory parsing */
     657          12 :                         php_stream_seek(fp, saveloc, SEEK_SET);
     658             :                 }
     659             : 
     660         226 :                 phar_set_inode(&entry TSRMLS_CC);
     661         226 :                 zend_hash_str_add_mem(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry, sizeof(phar_entry_info));
     662             :         }
     663             : 
     664          53 :         mydata->fp = fp;
     665             : 
     666          53 :         if (zend_hash_str_exists(&(mydata->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
     667          47 :                 mydata->is_data = 0;
     668             :         } else {
     669           6 :                 mydata->is_data = 1;
     670             :         }
     671             : 
     672          53 :         zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, mydata);
     673             : 
     674          53 :         if (actual_alias) {
     675             :                 phar_archive_data *fd_ptr;
     676             : 
     677          12 :                 if (!phar_validate_alias(actual_alias, mydata->alias_len)) {
     678           5 :                         if (error) {
     679           5 :                                 spprintf(error, 4096, "phar error: invalid alias \"%s\" in zip-based phar \"%s\"", actual_alias, fname);
     680             :                         }
     681           5 :                         efree(actual_alias);
     682           5 :                         zend_hash_str_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
     683           5 :                         return FAILURE;
     684             :                 }
     685             : 
     686           7 :                 mydata->is_temporary_alias = 0;
     687             : 
     688          14 :                 if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len))) {
     689           1 :                         if (SUCCESS != phar_free_alias(fd_ptr, actual_alias, mydata->alias_len TSRMLS_CC)) {
     690           1 :                                 if (error) {
     691           1 :                                         spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with implicit alias, alias is already in use", fname);
     692             :                                 }
     693           1 :                                 efree(actual_alias);
     694           1 :                                 zend_hash_str_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
     695           1 :                                 return FAILURE;
     696             :                         }
     697             :                 }
     698             : 
     699           6 :                 mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias;
     700             : 
     701           6 :                 if (entry.is_persistent) {
     702           0 :                         efree(actual_alias);
     703             :                 }
     704             : 
     705           6 :                 zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, mydata);
     706             :         } else {
     707             :                 phar_archive_data *fd_ptr;
     708             : 
     709          41 :                 if (alias_len) {
     710           0 :                         if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len))) {
     711           0 :                                 if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len TSRMLS_CC)) {
     712           0 :                                         if (error) {
     713           0 :                                                 spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with explicit alias, alias is already in use", fname);
     714             :                                         }
     715           0 :                                         zend_hash_str_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
     716           0 :                                         return FAILURE;
     717             :                                 }
     718             :                         }
     719             : 
     720           0 :                         zend_hash_str_add_ptr(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, mydata);
     721           0 :                         mydata->alias = pestrndup(alias, alias_len, mydata->is_persistent);
     722           0 :                         mydata->alias_len = alias_len;
     723             :                 } else {
     724          41 :                         mydata->alias = pestrndup(mydata->fname, fname_len, mydata->is_persistent);
     725          41 :                         mydata->alias_len = fname_len;
     726             :                 }
     727             : 
     728          41 :                 mydata->is_temporary_alias = 1;
     729             :         }
     730             : 
     731          47 :         if (pphar) {
     732          44 :                 *pphar = mydata;
     733             :         }
     734             : 
     735          47 :         return SUCCESS;
     736             : }
     737             : /* }}} */
     738             : 
     739             : /**
     740             :  * Create or open a zip-based phar for writing
     741             :  */
     742          97 : int phar_open_or_create_zip(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
     743             : {
     744             :         phar_archive_data *phar;
     745          97 :         int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, &phar, error TSRMLS_CC);
     746             : 
     747          97 :         if (FAILURE == ret) {
     748          31 :                 return FAILURE;
     749             :         }
     750             : 
     751          66 :         if (pphar) {
     752          66 :                 *pphar = phar;
     753             :         }
     754             : 
     755          66 :         phar->is_data = is_data;
     756             : 
     757          66 :         if (phar->is_zip) {
     758          21 :                 return ret;
     759             :         }
     760             : 
     761          45 :         if (phar->is_brandnew) {
     762          44 :                 phar->internal_file_start = 0;
     763          44 :                 phar->is_zip = 1;
     764          44 :                 phar->is_tar = 0;
     765          44 :                 return SUCCESS;
     766             :         }
     767             : 
     768             :         /* we've reached here - the phar exists and is a regular phar */
     769           1 :         if (error) {
     770           1 :                 spprintf(error, 4096, "phar zip error: phar \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar", fname);
     771             :         }
     772             : 
     773           1 :         return FAILURE;
     774             : }
     775             : /* }}} */
     776             : 
     777             : struct _phar_zip_pass {
     778             :         php_stream *filefp;
     779             :         php_stream *centralfp;
     780             :         php_stream *old;
     781             :         int free_fp;
     782             :         int free_ufp;
     783             :         char **error;
     784             : };
     785             : /* perform final modification of zip contents for each file in the manifest before saving */
     786         853 : static int phar_zip_changed_apply_int(phar_entry_info *entry, void *arg TSRMLS_DC) /* {{{ */
     787             : {
     788             :         phar_zip_file_header local;
     789             :         phar_zip_unix3 perms;
     790             :         phar_zip_central_dir_file central;
     791             :         struct _phar_zip_pass *p;
     792             :         php_uint32 newcrc32;
     793             :         zend_off_t offset;
     794         853 :         int not_really_modified = 0;
     795         853 :         p = (struct _phar_zip_pass*) arg;
     796             : 
     797         853 :         if (entry->is_mounted) {
     798           0 :                 return ZEND_HASH_APPLY_KEEP;
     799             :         }
     800             : 
     801         853 :         if (entry->is_deleted) {
     802           4 :                 if (entry->fp_refcount <= 0) {
     803           4 :                         return ZEND_HASH_APPLY_REMOVE;
     804             :                 } else {
     805             :                         /* we can't delete this in-memory until it is closed */
     806           0 :                         return ZEND_HASH_APPLY_KEEP;
     807             :                 }
     808             :         }
     809             : 
     810         849 :         phar_add_virtual_dirs(entry->phar, entry->filename, entry->filename_len TSRMLS_CC);
     811         849 :         memset(&local, 0, sizeof(local));
     812         849 :         memset(&central, 0, sizeof(central));
     813         849 :         memset(&perms, 0, sizeof(perms));
     814         849 :         strncpy(local.signature, "PK\3\4", 4);
     815         849 :         strncpy(central.signature, "PK\1\2", 4);
     816         849 :         PHAR_SET_16(central.extra_len, sizeof(perms));
     817         849 :         PHAR_SET_16(local.extra_len, sizeof(perms));
     818         849 :         perms.tag[0] = 'n';
     819         849 :         perms.tag[1] = 'u';
     820         849 :         PHAR_SET_16(perms.size, sizeof(perms) - 4);
     821         849 :         PHAR_SET_16(perms.perms, entry->flags & PHAR_ENT_PERM_MASK);
     822             :         {
     823         849 :                 php_uint32 crc = (php_uint32) ~0;
     824         849 :                 CRC32(crc, perms.perms[0]);
     825         849 :                 CRC32(crc, perms.perms[1]);
     826         849 :                 PHAR_SET_32(perms.crc32, ~crc);
     827             :         }
     828             : 
     829         849 :         if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
     830          18 :                 PHAR_SET_16(central.compressed, PHAR_ZIP_COMP_DEFLATE);
     831          18 :                 PHAR_SET_16(local.compressed, PHAR_ZIP_COMP_DEFLATE);
     832             :         }
     833             : 
     834         849 :         if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
     835          20 :                 PHAR_SET_16(central.compressed, PHAR_ZIP_COMP_BZIP2);
     836          20 :                 PHAR_SET_16(local.compressed, PHAR_ZIP_COMP_BZIP2);
     837             :         }
     838             : 
     839             :         /* do not use PHAR_GET_16 on either field of the next line */
     840         849 :         phar_zip_u2d_time(entry->timestamp, local.timestamp, local.datestamp);
     841         849 :         memcpy(central.timestamp, local.timestamp, sizeof(local.timestamp));
     842         849 :         memcpy(central.datestamp, local.datestamp, sizeof(local.datestamp));
     843         849 :         PHAR_SET_16(central.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0));
     844         849 :         PHAR_SET_16(local.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0));
     845         849 :         PHAR_SET_32(central.offset, php_stream_tell(p->filefp));
     846             : 
     847             :         /* do extra field for perms later */
     848         849 :         if (entry->is_modified) {
     849             :                 php_uint32 loc;
     850             :                 php_stream_filter *filter;
     851             :                 php_stream *efp;
     852             : 
     853         473 :                 if (entry->is_dir) {
     854           7 :                         entry->is_modified = 0;
     855           7 :                         if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) {
     856           4 :                                 php_stream_close(entry->fp);
     857           4 :                                 entry->fp = NULL;
     858           4 :                                 entry->fp_type = PHAR_FP;
     859             :                         }
     860           7 :                         goto continue_dir;
     861             :                 }
     862             : 
     863         466 :                 if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
     864           0 :                         spprintf(p->error, 0, "unable to open file contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     865           0 :                         return ZEND_HASH_APPLY_STOP;
     866             :                 }
     867             : 
     868             :                 /* we can be modified and already be compressed, such as when chmod() is executed */
     869         466 :                 if (entry->flags & PHAR_ENT_COMPRESSION_MASK && (entry->old_flags == entry->flags || !entry->old_flags)) {
     870           1 :                         not_really_modified = 1;
     871           1 :                         goto is_compressed;
     872             :                 }
     873             : 
     874         465 :                 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
     875           0 :                         spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     876           0 :                         return ZEND_HASH_APPLY_STOP;
     877             :                 }
     878             : 
     879         465 :                 efp = phar_get_efp(entry, 0 TSRMLS_CC);
     880         465 :                 newcrc32 = ~0;
     881             : 
     882      425568 :                 for (loc = 0;loc < entry->uncompressed_filesize; ++loc) {
     883      425103 :                         CRC32(newcrc32, php_stream_getc(efp));
     884             :                 }
     885             : 
     886         465 :                 entry->crc32 = ~newcrc32;
     887         465 :                 PHAR_SET_32(central.uncompsize, entry->uncompressed_filesize);
     888         465 :                 PHAR_SET_32(local.uncompsize, entry->uncompressed_filesize);
     889             : 
     890         465 :                 if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
     891             :                         /* not compressed */
     892         447 :                         entry->compressed_filesize = entry->uncompressed_filesize;
     893         447 :                         PHAR_SET_32(central.compsize, entry->uncompressed_filesize);
     894         447 :                         PHAR_SET_32(local.compsize, entry->uncompressed_filesize);
     895         447 :                         goto not_compressed;
     896             :                 }
     897             : 
     898          18 :                 filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
     899             : 
     900          18 :                 if (!filter) {
     901           0 :                         if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
     902           0 :                                 spprintf(p->error, 0, "unable to gzip compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     903             :                         } else {
     904           0 :                                 spprintf(p->error, 0, "unable to bzip2 compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     905             :                         }
     906           0 :                         return ZEND_HASH_APPLY_STOP;
     907             :                 }
     908             : 
     909             :                 /* create new file that holds the compressed version */
     910             :                 /* work around inability to specify freedom in write and strictness
     911             :                 in read count */
     912          18 :                 entry->cfp = php_stream_fopen_tmpfile();
     913             : 
     914          18 :                 if (!entry->cfp) {
     915           0 :                         spprintf(p->error, 0, "unable to create temporary file for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     916           0 :                         return ZEND_HASH_APPLY_STOP;
     917             :                 }
     918             : 
     919          18 :                 php_stream_flush(efp);
     920             : 
     921          18 :                 if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
     922           0 :                         spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     923           0 :                         return ZEND_HASH_APPLY_STOP;
     924             :                 }
     925             : 
     926          18 :                 php_stream_filter_append((&entry->cfp->writefilters), filter);
     927             : 
     928          18 :                 if (SUCCESS != php_stream_copy_to_stream_ex(efp, entry->cfp, entry->uncompressed_filesize, NULL)) {
     929           0 :                         spprintf(p->error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, entry->phar->fname);
     930           0 :                         return ZEND_HASH_APPLY_STOP;
     931             :                 }
     932             : 
     933          18 :                 php_stream_filter_flush(filter, 1);
     934          18 :                 php_stream_flush(entry->cfp);
     935          18 :                 php_stream_filter_remove(filter, 1 TSRMLS_CC);
     936          18 :                 php_stream_seek(entry->cfp, 0, SEEK_END);
     937          18 :                 entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp);
     938          18 :                 PHAR_SET_32(central.compsize, entry->compressed_filesize);
     939          18 :                 PHAR_SET_32(local.compsize, entry->compressed_filesize);
     940             :                 /* generate crc on compressed file */
     941          18 :                 php_stream_rewind(entry->cfp);
     942          18 :                 entry->old_flags = entry->flags;
     943          18 :                 entry->is_modified = 1;
     944             :         } else {
     945             : is_compressed:
     946         377 :                 PHAR_SET_32(central.uncompsize, entry->uncompressed_filesize);
     947         377 :                 PHAR_SET_32(local.uncompsize, entry->uncompressed_filesize);
     948         377 :                 PHAR_SET_32(central.compsize, entry->compressed_filesize);
     949         377 :                 PHAR_SET_32(local.compsize, entry->compressed_filesize);
     950         377 :                 if (p->old) {
     951         377 :                         if (-1 == php_stream_seek(p->old, entry->offset_abs, SEEK_SET)) {
     952           0 :                                 spprintf(p->error, 0, "unable to seek to start of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     953           0 :                                 return ZEND_HASH_APPLY_STOP;
     954             :                         }
     955             :                 }
     956             :         }
     957             : not_compressed:
     958         842 :         PHAR_SET_32(central.crc32, entry->crc32);
     959         842 :         PHAR_SET_32(local.crc32, entry->crc32);
     960             : continue_dir:
     961             :         /* set file metadata */
     962        1698 :         if (Z_TYPE(entry->metadata) != IS_UNDEF) {
     963             :                 php_serialize_data_t metadata_hash;
     964             : 
     965          40 :                 if (entry->metadata_str.s) {
     966           0 :                         smart_str_free(&entry->metadata_str);
     967             :                 }
     968          40 :                 entry->metadata_str.s = NULL;
     969          40 :                 PHP_VAR_SERIALIZE_INIT(metadata_hash);
     970          40 :                 php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC);
     971          40 :                 PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
     972          40 :                 PHAR_SET_16(central.comment_len, entry->metadata_str.s->len);
     973             :         }
     974             : 
     975         849 :         entry->header_offset = php_stream_tell(p->filefp);
     976         849 :         offset = entry->header_offset + sizeof(local) + entry->filename_len + (entry->is_dir ? 1 : 0) + sizeof(perms);
     977             : 
     978         849 :         if (sizeof(local) != php_stream_write(p->filefp, (char *)&local, sizeof(local))) {
     979           0 :                 spprintf(p->error, 0, "unable to write local file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     980           0 :                 return ZEND_HASH_APPLY_STOP;
     981             :         }
     982             : 
     983         849 :         if (sizeof(central) != php_stream_write(p->centralfp, (char *)&central, sizeof(central))) {
     984           0 :                 spprintf(p->error, 0, "unable to write central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     985           0 :                 return ZEND_HASH_APPLY_STOP;
     986             :         }
     987             : 
     988         849 :         if (entry->is_dir) {
     989          17 :                 if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
     990           0 :                         spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     991           0 :                         return ZEND_HASH_APPLY_STOP;
     992             :                 }
     993             : 
     994          17 :                 if (1 != php_stream_write(p->filefp, "/", 1)) {
     995           0 :                         spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
     996           0 :                         return ZEND_HASH_APPLY_STOP;
     997             :                 }
     998             : 
     999          17 :                 if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
    1000           0 :                         spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
    1001           0 :                         return ZEND_HASH_APPLY_STOP;
    1002             :                 }
    1003             : 
    1004          17 :                 if (1 != php_stream_write(p->centralfp, "/", 1)) {
    1005           0 :                         spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
    1006           0 :                         return ZEND_HASH_APPLY_STOP;
    1007             :                 }
    1008             :         } else {
    1009         832 :                 if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
    1010           0 :                         spprintf(p->error, 0, "unable to write filename to local directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
    1011           0 :                         return ZEND_HASH_APPLY_STOP;
    1012             :                 }
    1013             : 
    1014         832 :                 if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
    1015           0 :                         spprintf(p->error, 0, "unable to write filename to central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
    1016           0 :                         return ZEND_HASH_APPLY_STOP;
    1017             :                 }
    1018             :         }
    1019             : 
    1020         849 :         if (sizeof(perms) != php_stream_write(p->filefp, (char *)&perms, sizeof(perms))) {
    1021           0 :                 spprintf(p->error, 0, "unable to write local extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
    1022           0 :                 return ZEND_HASH_APPLY_STOP;
    1023             :         }
    1024             : 
    1025         849 :         if (sizeof(perms) != php_stream_write(p->centralfp, (char *)&perms, sizeof(perms))) {
    1026           0 :                 spprintf(p->error, 0, "unable to write central extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
    1027           0 :                 return ZEND_HASH_APPLY_STOP;
    1028             :         }
    1029             : 
    1030        1314 :         if (!not_really_modified && entry->is_modified) {
    1031         465 :                 if (entry->cfp) {
    1032          18 :                         if (SUCCESS != php_stream_copy_to_stream_ex(entry->cfp, p->filefp, entry->compressed_filesize, NULL)) {
    1033           0 :                                 spprintf(p->error, 0, "unable to write compressed contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
    1034           0 :                                 return ZEND_HASH_APPLY_STOP;
    1035             :                         }
    1036             : 
    1037          18 :                         php_stream_close(entry->cfp);
    1038          18 :                         entry->cfp = NULL;
    1039             :                 } else {
    1040         447 :                         if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
    1041           0 :                                 return ZEND_HASH_APPLY_STOP;
    1042             :                         }
    1043             : 
    1044         447 :                         phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC);
    1045             : 
    1046         447 :                         if (SUCCESS != php_stream_copy_to_stream_ex(phar_get_efp(entry, 0 TSRMLS_CC), p->filefp, entry->uncompressed_filesize, NULL)) {
    1047           0 :                                 spprintf(p->error, 0, "unable to write contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
    1048           0 :                                 return ZEND_HASH_APPLY_STOP;
    1049             :                         }
    1050             :                 }
    1051             : 
    1052         465 :                 if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp && entry->fp_refcount == 0) {
    1053         379 :                         php_stream_close(entry->fp);
    1054             :                 }
    1055             : 
    1056         465 :                 entry->is_modified = 0;
    1057             :         } else {
    1058         384 :                 entry->is_modified = 0;
    1059         384 :                 if (entry->fp_refcount) {
    1060             :                         /* open file pointers refer to this fp, do not free the stream */
    1061           0 :                         switch (entry->fp_type) {
    1062             :                                 case PHAR_FP:
    1063           0 :                                         p->free_fp = 0;
    1064           0 :                                         break;
    1065             :                                 case PHAR_UFP:
    1066           0 :                                         p->free_ufp = 0;
    1067             :                                 default:
    1068             :                                         break;
    1069             :                         }
    1070             :                 }
    1071             : 
    1072         384 :                 if (!entry->is_dir && entry->compressed_filesize && SUCCESS != php_stream_copy_to_stream_ex(p->old, p->filefp, entry->compressed_filesize, NULL)) {
    1073           0 :                         spprintf(p->error, 0, "unable to copy contents of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
    1074           0 :                         return ZEND_HASH_APPLY_STOP;
    1075             :                 }
    1076             :         }
    1077             : 
    1078         849 :         entry->fp = NULL;
    1079         849 :         entry->offset = entry->offset_abs = offset;
    1080         849 :         entry->fp_type = PHAR_FP;
    1081             : 
    1082         849 :         if (entry->metadata_str.s) {
    1083          40 :                 if (entry->metadata_str.s->len != php_stream_write(p->centralfp, entry->metadata_str.s->val, entry->metadata_str.s->len)) {
    1084           0 :                         spprintf(p->error, 0, "unable to write metadata as file comment for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
    1085           0 :                         smart_str_free(&entry->metadata_str);
    1086           0 :                         return ZEND_HASH_APPLY_STOP;
    1087             :                 }
    1088             : 
    1089          40 :                 smart_str_free(&entry->metadata_str);
    1090             :         }
    1091             : 
    1092         849 :         return ZEND_HASH_APPLY_KEEP;
    1093             : }
    1094             : /* }}} */
    1095             : 
    1096         659 : static int phar_zip_changed_apply(zval *zv, void *arg TSRMLS_DC) /* {{{ */
    1097             : {
    1098         659 :         return phar_zip_changed_apply_int(Z_PTR_P(zv), arg TSRMLS_CC);
    1099             : }
    1100             : /* }}} */
    1101             : 
    1102         202 : static int phar_zip_applysignature(phar_archive_data *phar, struct _phar_zip_pass *pass,
    1103             :                                    smart_str *metadata TSRMLS_DC) /* {{{ */
    1104             : {
    1105             :         /* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */
    1106         202 :         if (!phar->is_data || phar->sig_flags) {
    1107             :                 int signature_length;
    1108             :                 char *signature, sigbuf[8];
    1109         194 :                 phar_entry_info entry = {0};
    1110             :                 php_stream *newfile;
    1111             :                 zend_off_t tell, st;
    1112             : 
    1113         194 :                 newfile = php_stream_fopen_tmpfile();
    1114         194 :                 if (newfile == NULL) {
    1115           0 :                         spprintf(pass->error, 0, "phar error: unable to create temporary file for the signature file");
    1116           0 :                         return FAILURE;
    1117             :                 }
    1118         194 :                 st = tell = php_stream_tell(pass->filefp);
    1119             :                 /* copy the local files, central directory, and the zip comment to generate the hash */
    1120         194 :                 php_stream_seek(pass->filefp, 0, SEEK_SET);
    1121         194 :                 php_stream_copy_to_stream_ex(pass->filefp, newfile, tell, NULL);
    1122         194 :                 tell = php_stream_tell(pass->centralfp);
    1123         194 :                 php_stream_seek(pass->centralfp, 0, SEEK_SET);
    1124         194 :                 php_stream_copy_to_stream_ex(pass->centralfp, newfile, tell, NULL);
    1125         194 :                 if (metadata->s) {
    1126          11 :                         php_stream_write(newfile, metadata->s->val, metadata->s->len);
    1127             :                 }
    1128             : 
    1129         194 :                 if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, pass->error TSRMLS_CC)) {
    1130           0 :                         if (pass->error) {
    1131           0 :                                 char *save = *(pass->error);
    1132           0 :                                 spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar: %s", save);
    1133           0 :                                 efree(save);
    1134             :                         }
    1135             : 
    1136           0 :                         php_stream_close(newfile);
    1137           0 :                         return FAILURE;
    1138             :                 }
    1139             : 
    1140         194 :                 entry.filename = ".phar/signature.bin";
    1141         194 :                 entry.filename_len = sizeof(".phar/signature.bin")-1;
    1142         194 :                 entry.fp = php_stream_fopen_tmpfile();
    1143         194 :                 entry.fp_type = PHAR_MOD;
    1144         194 :                 entry.is_modified = 1;
    1145         194 :                 if (entry.fp == NULL) {
    1146           0 :                         spprintf(pass->error, 0, "phar error: unable to create temporary file for signature");
    1147           0 :                         return FAILURE;
    1148             :                 }
    1149             : 
    1150         194 :                 PHAR_SET_32(sigbuf, phar->sig_flags);
    1151         194 :                 PHAR_SET_32(sigbuf + 4, signature_length);
    1152             : 
    1153         194 :                 if (8 != (int)php_stream_write(entry.fp, sigbuf, 8) || signature_length != (int)php_stream_write(entry.fp, signature, signature_length)) {
    1154           0 :                         efree(signature);
    1155           0 :                         if (pass->error) {
    1156           0 :                                 spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar %s", phar->fname);
    1157             :                         }
    1158             : 
    1159           0 :                         php_stream_close(newfile);
    1160           0 :                         return FAILURE;
    1161             :                 }
    1162             : 
    1163         194 :                 efree(signature);
    1164         194 :                 entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8;
    1165         194 :                 entry.phar = phar;
    1166             :                 /* throw out return value and write the signature */
    1167         194 :                 phar_zip_changed_apply_int(&entry, (void *)pass TSRMLS_CC);
    1168         194 :                 php_stream_close(newfile);
    1169             : 
    1170         194 :                 if (pass->error && *(pass->error)) {
    1171             :                         /* error is set by writeheaders */
    1172           0 :                         php_stream_close(newfile);
    1173           0 :                         return FAILURE;
    1174             :                 }
    1175             :         } /* signature */
    1176         202 :         return SUCCESS;
    1177             : }
    1178             : /* }}} */
    1179             : 
    1180         203 : int phar_zip_flush(phar_archive_data *phar, char *user_stub, zend_long len, int defaultstub, char **error TSRMLS_DC) /* {{{ */
    1181             : {
    1182             :         char *pos;
    1183         203 :         smart_str main_metadata_str = {0};
    1184             :         static const char newstub[] = "<?php // zip-based phar archive stub file\n__HALT_COMPILER();";
    1185         203 :         char halt_stub[] = "__HALT_COMPILER();";
    1186             :         char *tmp;
    1187             :         
    1188             :         php_stream *stubfile, *oldfile;
    1189             :         php_serialize_data_t metadata_hash;
    1190         203 :         int free_user_stub, closeoldfile = 0;
    1191         203 :         phar_entry_info entry = {0};
    1192         203 :         char *temperr = NULL;
    1193             :         struct _phar_zip_pass pass;
    1194             :         phar_zip_dir_end eocd;
    1195             :         php_uint32 cdir_size, cdir_offset;
    1196             : 
    1197         203 :         pass.error = &temperr;
    1198         203 :         entry.flags = PHAR_ENT_PERM_DEF_FILE;
    1199         203 :         entry.timestamp = time(NULL);
    1200         203 :         entry.is_modified = 1;
    1201         203 :         entry.is_zip = 1;
    1202         203 :         entry.phar = phar;
    1203         203 :         entry.fp_type = PHAR_MOD;
    1204             : 
    1205         203 :         if (phar->is_persistent) {
    1206           0 :                 if (error) {
    1207           0 :                         spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
    1208             :                 }
    1209           0 :                 return EOF;
    1210             :         }
    1211             : 
    1212         203 :         if (phar->is_data) {
    1213           8 :                 goto nostub;
    1214             :         }
    1215             : 
    1216             :         /* set alias */
    1217         247 :         if (!phar->is_temporary_alias && phar->alias_len) {
    1218          52 :                 entry.fp = php_stream_fopen_tmpfile();
    1219          52 :                 if (entry.fp == NULL) {
    1220           0 :                         spprintf(error, 0, "phar error: unable to create temporary file");
    1221           0 :                         return EOF;
    1222             :                 }
    1223          52 :                 if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) {
    1224           0 :                         if (error) {
    1225           0 :                                 spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
    1226             :                         }
    1227           0 :                         return EOF;
    1228             :                 }
    1229             : 
    1230          52 :                 entry.uncompressed_filesize = entry.compressed_filesize = phar->alias_len;
    1231          52 :                 entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1);
    1232          52 :                 entry.filename_len = sizeof(".phar/alias.txt")-1;
    1233             : 
    1234         104 :                 if (NULL == zend_hash_str_update_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
    1235           0 :                         if (error) {
    1236           0 :                                 spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname);
    1237             :                         }
    1238           0 :                         return EOF;
    1239             :                 }
    1240             :         } else {
    1241         143 :                 zend_hash_str_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1);
    1242             :         }
    1243             : 
    1244             :         /* register alias */
    1245         195 :         if (phar->alias_len) {
    1246         189 :                 if (FAILURE == phar_get_archive(&phar, phar->fname, phar->fname_len, phar->alias, phar->alias_len, error TSRMLS_CC)) {
    1247           0 :                         return EOF;
    1248             :                 }
    1249             :         }
    1250             : 
    1251             :         /* set stub */
    1252         224 :         if (user_stub && !defaultstub) {
    1253          30 :                 if (len < 0) {
    1254             :                         /* resource passed in */
    1255           4 :                         if (!(php_stream_from_zval_no_verify(stubfile, (zval *)user_stub))) {
    1256           0 :                                 if (error) {
    1257           0 :                                         spprintf(error, 0, "unable to access resource to copy stub to new zip-based phar \"%s\"", phar->fname);
    1258             :                                 }
    1259           0 :                                 return EOF;
    1260             :                         }
    1261             : 
    1262           4 :                         if (len == -1) {
    1263           2 :                                 len = PHP_STREAM_COPY_ALL;
    1264             :                         } else {
    1265           2 :                                 len = -len;
    1266             :                         }
    1267             : 
    1268           4 :                         user_stub = 0;
    1269             : 
    1270             :                         // TODO: refactor to avoid reallocation ???
    1271             : //???           len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)
    1272             :                         {
    1273           4 :                                 zend_string *str = php_stream_copy_to_mem(stubfile, len, 0);
    1274           4 :                                 if (str) {
    1275           4 :                                         len = str->len;
    1276           4 :                                         user_stub = estrndup(str->val, str->len);
    1277             :                                         zend_string_release(str);
    1278             :                                 } else {
    1279           0 :                                         user_stub = NULL;
    1280           0 :                                         len = 0;
    1281             :                                 }
    1282             :                         }
    1283             : 
    1284           4 :                         if (!len || !user_stub) {
    1285           0 :                                 if (error) {
    1286           0 :                                         spprintf(error, 0, "unable to read resource to copy stub to new zip-based phar \"%s\"", phar->fname);
    1287             :                                 }
    1288           0 :                                 return EOF;
    1289             :                         }
    1290           4 :                         free_user_stub = 1;
    1291             :                 } else {
    1292          26 :                         free_user_stub = 0;
    1293             :                 }
    1294             : 
    1295          30 :                 tmp = estrndup(user_stub, len);
    1296          30 :                 if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) {
    1297           1 :                         efree(tmp);
    1298           1 :                         if (error) {
    1299           1 :                                 spprintf(error, 0, "illegal stub for zip-based phar \"%s\"", phar->fname);
    1300             :                         }
    1301           1 :                         if (free_user_stub) {
    1302           0 :                                 efree(user_stub);
    1303             :                         }
    1304           1 :                         return EOF;
    1305             :                 }
    1306          29 :                 pos = user_stub + (pos - tmp);
    1307          29 :                 efree(tmp);
    1308             : 
    1309          29 :                 len = pos - user_stub + 18;
    1310          29 :                 entry.fp = php_stream_fopen_tmpfile();
    1311          29 :                 if (entry.fp == NULL) {
    1312           0 :                         spprintf(error, 0, "phar error: unable to create temporary file");
    1313           0 :                         return EOF;
    1314             :                 }
    1315          29 :                 entry.uncompressed_filesize = len + 5;
    1316             : 
    1317          58 :                 if ((size_t)len != php_stream_write(entry.fp, user_stub, len)
    1318          58 :                 ||            5 != php_stream_write(entry.fp, " ?>\r\n", 5)) {
    1319           0 :                         if (error) {
    1320           0 :                                 spprintf(error, 0, "unable to create stub from string in new zip-based phar \"%s\"", phar->fname);
    1321             :                         }
    1322           0 :                         if (free_user_stub) {
    1323           0 :                                 efree(user_stub);
    1324             :                         }
    1325           0 :                         php_stream_close(entry.fp);
    1326           0 :                         return EOF;
    1327             :                 }
    1328             : 
    1329          29 :                 entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
    1330          29 :                 entry.filename_len = sizeof(".phar/stub.php")-1;
    1331             : 
    1332          58 :                 if (NULL == zend_hash_str_update_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
    1333           0 :                         if (free_user_stub) {
    1334           0 :                                 efree(user_stub);
    1335             :                         }
    1336           0 :                         if (error) {
    1337           0 :                                 spprintf(error, 0, "unable to set stub in zip-based phar \"%s\"", phar->fname);
    1338             :                         }
    1339           0 :                         return EOF;
    1340             :                 }
    1341             : 
    1342          29 :                 if (free_user_stub) {
    1343           4 :                         efree(user_stub);
    1344             :                 }
    1345             :         } else {
    1346             :                 /* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */
    1347         165 :                 entry.fp = php_stream_fopen_tmpfile();
    1348         165 :                 if (entry.fp == NULL) {
    1349           0 :                         spprintf(error, 0, "phar error: unable to create temporary file");
    1350           0 :                         return EOF;
    1351             :                 }
    1352         165 :                 if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) {
    1353           0 :                         php_stream_close(entry.fp);
    1354           0 :                         if (error) {
    1355           0 :                                 spprintf(error, 0, "unable to %s stub in%szip-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname);
    1356             :                         }
    1357           0 :                         return EOF;
    1358             :                 }
    1359             : 
    1360         165 :                 entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1;
    1361         165 :                 entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
    1362         165 :                 entry.filename_len = sizeof(".phar/stub.php")-1;
    1363             : 
    1364         165 :                 if (!defaultstub) {
    1365         157 :                         if (!zend_hash_str_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
    1366          42 :                                 if (NULL == zend_hash_str_add_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
    1367           0 :                                         php_stream_close(entry.fp);
    1368           0 :                                         efree(entry.filename);
    1369           0 :                                         if (error) {
    1370           0 :                                                 spprintf(error, 0, "unable to create stub in zip-based phar \"%s\"", phar->fname);
    1371             :                                         }
    1372           0 :                                         return EOF;
    1373             :                                 }
    1374             :                         } else {
    1375         136 :                                 php_stream_close(entry.fp);
    1376         136 :                                 efree(entry.filename);
    1377             :                         }
    1378             :                 } else {
    1379          16 :                         if (NULL == zend_hash_str_update_mem(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info))) {
    1380           0 :                                 php_stream_close(entry.fp);
    1381           0 :                                 efree(entry.filename);
    1382           0 :                                 if (error) {
    1383           0 :                                         spprintf(error, 0, "unable to overwrite stub in zip-based phar \"%s\"", phar->fname);
    1384             :                                 }
    1385           0 :                                 return EOF;
    1386             :                         }
    1387             :                 }
    1388             :         }
    1389             : nostub:
    1390         366 :         if (phar->fp && !phar->is_brandnew) {
    1391         164 :                 oldfile = phar->fp;
    1392         164 :                 closeoldfile = 0;
    1393         164 :                 php_stream_rewind(oldfile);
    1394             :         } else {
    1395          38 :                 oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
    1396          38 :                 closeoldfile = oldfile != NULL;
    1397             :         }
    1398             : 
    1399             :         /* save modified files to the zip */
    1400         202 :         pass.old = oldfile;
    1401         202 :         pass.filefp = php_stream_fopen_tmpfile();
    1402             : 
    1403         202 :         if (!pass.filefp) {
    1404             : fperror:
    1405           0 :                 if (closeoldfile) {
    1406           0 :                         php_stream_close(oldfile);
    1407             :                 }
    1408           0 :                 if (error) {
    1409           0 :                         spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname);
    1410             :                 }
    1411           0 :                 return EOF;
    1412             :         }
    1413             : 
    1414         202 :         pass.centralfp = php_stream_fopen_tmpfile();
    1415             : 
    1416         202 :         if (!pass.centralfp) {
    1417           0 :                 goto fperror;
    1418             :         }
    1419             : 
    1420         202 :         pass.free_fp = pass.free_ufp = 1;
    1421         202 :         memset(&eocd, 0, sizeof(eocd));
    1422             : 
    1423         202 :         strncpy(eocd.signature, "PK\5\6", 4);
    1424         202 :         if (!phar->is_data && !phar->sig_flags) {
    1425          44 :                 phar->sig_flags = PHAR_SIG_SHA1;
    1426             :         }
    1427         202 :         if (phar->sig_flags) {
    1428         194 :                 PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest) + 1);
    1429         194 :                 PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest) + 1);
    1430             :         } else {
    1431           8 :                 PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest));
    1432           8 :                 PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest));
    1433             :         }
    1434         202 :         zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass TSRMLS_CC);
    1435             : 
    1436         404 :         if (Z_TYPE(phar->metadata) != IS_UNDEF) {
    1437             :                 /* set phar metadata */
    1438          11 :                 PHP_VAR_SERIALIZE_INIT(metadata_hash);
    1439          11 :                 php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
    1440          11 :                 PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
    1441             :         }
    1442         202 :         if (temperr) {
    1443           0 :                 if (error) {
    1444           0 :                         spprintf(error, 4096, "phar zip flush of \"%s\" failed: %s", phar->fname, temperr);
    1445             :                 }
    1446           0 :                 efree(temperr);
    1447             : temperror:
    1448           0 :                 php_stream_close(pass.centralfp);
    1449             : nocentralerror:
    1450           0 :                 if (Z_TYPE(phar->metadata) != IS_UNDEF) {
    1451             :                         smart_str_free(&main_metadata_str);
    1452             :                 }
    1453           0 :                 php_stream_close(pass.filefp);
    1454           0 :                 if (closeoldfile) {
    1455           0 :                         php_stream_close(oldfile);
    1456             :                 }
    1457           0 :                 return EOF;
    1458             :         }
    1459             : 
    1460         202 :         if (FAILURE == phar_zip_applysignature(phar, &pass, &main_metadata_str TSRMLS_CC)) {
    1461           0 :                 goto temperror;
    1462             :         }
    1463             : 
    1464             :         /* save zip */
    1465         202 :         cdir_size = php_stream_tell(pass.centralfp);
    1466         202 :         cdir_offset = php_stream_tell(pass.filefp);
    1467         202 :         PHAR_SET_32(eocd.cdir_size, cdir_size);
    1468         202 :         PHAR_SET_32(eocd.cdir_offset, cdir_offset);
    1469         202 :         php_stream_seek(pass.centralfp, 0, SEEK_SET);
    1470             : 
    1471             :         {
    1472             :                 size_t clen;
    1473         202 :                 int ret = php_stream_copy_to_stream_ex(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL, &clen);
    1474         202 :                 if (SUCCESS != ret || clen != cdir_size) {
    1475           0 :                         if (error) {
    1476           0 :                                 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write central-directory", phar->fname);
    1477             :                         }
    1478           0 :                         goto temperror;
    1479             :                 }
    1480             :         }
    1481             : 
    1482         202 :         php_stream_close(pass.centralfp);
    1483             : 
    1484         404 :         if (Z_TYPE(phar->metadata) != IS_UNDEF) {
    1485             :                 /* set phar metadata */
    1486          11 :                 PHAR_SET_16(eocd.comment_len, main_metadata_str.s->len);
    1487             : 
    1488          11 :                 if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
    1489           0 :                         if (error) {
    1490           0 :                                 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname);
    1491             :                         }
    1492           0 :                         goto nocentralerror;
    1493             :                 }
    1494             : 
    1495          11 :                 if (main_metadata_str.s->len != php_stream_write(pass.filefp, main_metadata_str.s->val, main_metadata_str.s->len)) {
    1496           0 :                         if (error) {
    1497           0 :                                 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write metadata to zip comment", phar->fname);
    1498             :                         }
    1499           0 :                         goto nocentralerror;
    1500             :                 }
    1501             : 
    1502             :                 smart_str_free(&main_metadata_str);
    1503             : 
    1504             :         } else {
    1505         191 :                 if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
    1506           0 :                         if (error) {
    1507           0 :                                 spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname);
    1508             :                         }
    1509           0 :                         goto nocentralerror;
    1510             :                 }
    1511             :         }
    1512             : 
    1513         202 :         if (phar->fp && pass.free_fp) {
    1514         164 :                 php_stream_close(phar->fp);
    1515             :         }
    1516             : 
    1517         202 :         if (phar->ufp) {
    1518           3 :                 if (pass.free_ufp) {
    1519           3 :                         php_stream_close(phar->ufp);
    1520             :                 }
    1521           3 :                 phar->ufp = NULL;
    1522             :         }
    1523             : 
    1524             :         /* re-open */
    1525         202 :         phar->is_brandnew = 0;
    1526             : 
    1527         202 :         if (phar->donotflush) {
    1528             :                 /* deferred flush */
    1529          11 :                 phar->fp = pass.filefp;
    1530             :         } else {
    1531         191 :                 phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
    1532         191 :                 if (!phar->fp) {
    1533           0 :                         if (closeoldfile) {
    1534           0 :                                 php_stream_close(oldfile);
    1535             :                         }
    1536           0 :                         phar->fp = pass.filefp;
    1537           0 :                         if (error) {
    1538           0 :                                 spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
    1539             :                         }
    1540           0 :                         return EOF;
    1541             :                 }
    1542         191 :                 php_stream_rewind(pass.filefp);
    1543         191 :                 php_stream_copy_to_stream_ex(pass.filefp, phar->fp, PHP_STREAM_COPY_ALL, NULL);
    1544             :                 /* we could also reopen the file in "rb" mode but there is no need for that */
    1545         191 :                 php_stream_close(pass.filefp);
    1546             :         }
    1547             : 
    1548         202 :         if (closeoldfile) {
    1549           1 :                 php_stream_close(oldfile);
    1550             :         }
    1551         202 :         return EOF;
    1552             : }
    1553             : /* }}} */
    1554             : 
    1555             : /*
    1556             :  * Local variables:
    1557             :  * tab-width: 4
    1558             :  * c-basic-offset: 4
    1559             :  * End:
    1560             :  * vim600: noet sw=4 ts=4 fdm=marker
    1561             :  * vim<600: noet sw=4 ts=4
    1562             :  */

Generated by: LCOV version 1.10

Generated at Sat, 22 Nov 2014 23:01:21 +0000 (3 days ago)

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