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

LTP GCOV extension - code coverage report
Current view: directory - phar - zip.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 769
Code covered: 73.6 % Executed lines: 566
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

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

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