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

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