root/ext/phar/zip.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. phar_write_32
  2. phar_write_16
  3. phar_zip_process_extra
  4. phar_zip_d2u_time
  5. phar_zip_u2d_time
  6. phar_parse_zipfile
  7. phar_open_or_create_zip
  8. phar_zip_changed_apply_int
  9. phar_zip_changed_apply
  10. phar_zip_applysignature
  11. phar_zip_flush

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

/* [<][>][^][v][top][bottom][index][help] */