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: 576 787 73.2 %
Date: 2014-07-29 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Tue, 29 Jul 2014 09:53:09 +0000 (10 hours ago)

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