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

Generated by: LCOV version 1.10

Generated at Tue, 09 Feb 2016 10:48:48 +0000 (4 days ago)

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