Return to zip.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / phar |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | ZIP archive support for Phar | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 2007-2012 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 (!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: entry.filename_len--; ! 400: entry.flags |= PHAR_ENT_PERM_DEF_DIR; ! 401: } else { ! 402: entry.is_dir = 0; ! 403: } ! 404: ! 405: if (entry.filename_len == sizeof(".phar/signature.bin")-1 && !strncmp(entry.filename, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) { ! 406: size_t read; ! 407: php_stream *sigfile; ! 408: off_t now; ! 409: char *sig; ! 410: ! 411: now = php_stream_tell(fp); ! 412: pefree(entry.filename, entry.is_persistent); ! 413: sigfile = php_stream_fopen_tmpfile(); ! 414: if (!sigfile) { ! 415: PHAR_ZIP_FAIL("couldn't open temporary file"); ! 416: } ! 417: ! 418: php_stream_seek(fp, 0, SEEK_SET); ! 419: /* copy file contents + local headers and zip comment, if any, to be hashed for signature */ ! 420: phar_stream_copy_to_stream(fp, sigfile, entry.header_offset, NULL); ! 421: /* seek to central directory */ ! 422: php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET); ! 423: /* copy central directory header */ ! 424: phar_stream_copy_to_stream(fp, sigfile, beforeus - PHAR_GET_32(locator.cdir_offset), NULL); ! 425: if (metadata) { ! 426: php_stream_write(sigfile, metadata, PHAR_GET_16(locator.comment_len)); ! 427: } ! 428: php_stream_seek(fp, sizeof(phar_zip_file_header) + entry.header_offset + entry.filename_len + PHAR_GET_16(zipentry.extra_len), SEEK_SET); ! 429: sig = (char *) emalloc(entry.uncompressed_filesize); ! 430: read = php_stream_read(fp, sig, entry.uncompressed_filesize); ! 431: if (read != entry.uncompressed_filesize) { ! 432: php_stream_close(sigfile); ! 433: efree(sig); ! 434: PHAR_ZIP_FAIL("signature cannot be read"); ! 435: } ! 436: mydata->sig_flags = PHAR_GET_32(sig); ! 437: if (FAILURE == phar_verify_signature(sigfile, php_stream_tell(sigfile), mydata->sig_flags, sig + 8, entry.uncompressed_filesize - 8, fname, &mydata->signature, &mydata->sig_len, error TSRMLS_CC)) { ! 438: efree(sig); ! 439: if (error) { ! 440: char *save; ! 441: php_stream_close(sigfile); ! 442: spprintf(&save, 4096, "signature cannot be verified: %s", *error); ! 443: efree(*error); ! 444: PHAR_ZIP_FAIL_FREE(save, save); ! 445: } else { ! 446: php_stream_close(sigfile); ! 447: PHAR_ZIP_FAIL("signature cannot be verified"); ! 448: } ! 449: } ! 450: php_stream_close(sigfile); ! 451: efree(sig); ! 452: /* signature checked out, let's ensure this is the last file in the phar */ ! 453: if (i != PHAR_GET_16(locator.count) - 1) { ! 454: PHAR_ZIP_FAIL("entries exist after signature, invalid phar"); ! 455: } ! 456: ! 457: continue; ! 458: } ! 459: ! 460: phar_add_virtual_dirs(mydata, entry.filename, entry.filename_len TSRMLS_CC); ! 461: ! 462: if (PHAR_GET_16(zipentry.extra_len)) { ! 463: off_t loc = php_stream_tell(fp); ! 464: if (FAILURE == phar_zip_process_extra(fp, &entry, PHAR_GET_16(zipentry.extra_len) TSRMLS_CC)) { ! 465: pefree(entry.filename, entry.is_persistent); ! 466: PHAR_ZIP_FAIL("Unable to process extra field header for file in central directory"); ! 467: } ! 468: php_stream_seek(fp, loc + PHAR_GET_16(zipentry.extra_len), SEEK_SET); ! 469: } ! 470: ! 471: switch (PHAR_GET_16(zipentry.compressed)) { ! 472: case PHAR_ZIP_COMP_NONE : ! 473: /* compression flag already set */ ! 474: break; ! 475: case PHAR_ZIP_COMP_DEFLATE : ! 476: entry.flags |= PHAR_ENT_COMPRESSED_GZ; ! 477: if (!PHAR_G(has_zlib)) { ! 478: pefree(entry.filename, entry.is_persistent); ! 479: PHAR_ZIP_FAIL("zlib extension is required"); ! 480: } ! 481: break; ! 482: case PHAR_ZIP_COMP_BZIP2 : ! 483: entry.flags |= PHAR_ENT_COMPRESSED_BZ2; ! 484: if (!PHAR_G(has_bz2)) { ! 485: pefree(entry.filename, entry.is_persistent); ! 486: PHAR_ZIP_FAIL("bzip2 extension is required"); ! 487: } ! 488: break; ! 489: case 1 : ! 490: pefree(entry.filename, entry.is_persistent); ! 491: PHAR_ZIP_FAIL("unsupported compression method (Shrunk) used in this zip"); ! 492: case 2 : ! 493: case 3 : ! 494: case 4 : ! 495: case 5 : ! 496: pefree(entry.filename, entry.is_persistent); ! 497: PHAR_ZIP_FAIL("unsupported compression method (Reduce) used in this zip"); ! 498: case 6 : ! 499: pefree(entry.filename, entry.is_persistent); ! 500: PHAR_ZIP_FAIL("unsupported compression method (Implode) used in this zip"); ! 501: case 7 : ! 502: pefree(entry.filename, entry.is_persistent); ! 503: PHAR_ZIP_FAIL("unsupported compression method (Tokenize) used in this zip"); ! 504: case 9 : ! 505: pefree(entry.filename, entry.is_persistent); ! 506: PHAR_ZIP_FAIL("unsupported compression method (Deflate64) used in this zip"); ! 507: case 10 : ! 508: pefree(entry.filename, entry.is_persistent); ! 509: PHAR_ZIP_FAIL("unsupported compression method (PKWare Implode/old IBM TERSE) used in this zip"); ! 510: case 14 : ! 511: pefree(entry.filename, entry.is_persistent); ! 512: PHAR_ZIP_FAIL("unsupported compression method (LZMA) used in this zip"); ! 513: case 18 : ! 514: pefree(entry.filename, entry.is_persistent); ! 515: PHAR_ZIP_FAIL("unsupported compression method (IBM TERSE) used in this zip"); ! 516: case 19 : ! 517: pefree(entry.filename, entry.is_persistent); ! 518: PHAR_ZIP_FAIL("unsupported compression method (IBM LZ77) used in this zip"); ! 519: case 97 : ! 520: pefree(entry.filename, entry.is_persistent); ! 521: PHAR_ZIP_FAIL("unsupported compression method (WavPack) used in this zip"); ! 522: case 98 : ! 523: pefree(entry.filename, entry.is_persistent); ! 524: PHAR_ZIP_FAIL("unsupported compression method (PPMd) used in this zip"); ! 525: default : ! 526: pefree(entry.filename, entry.is_persistent); ! 527: PHAR_ZIP_FAIL("unsupported compression method (unknown) used in this zip"); ! 528: } ! 529: ! 530: /* get file metadata */ ! 531: if (PHAR_GET_16(zipentry.comment_len)) { ! 532: if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) { ! 533: pefree(entry.filename, entry.is_persistent); ! 534: PHAR_ZIP_FAIL("unable to read in file comment, truncated"); ! 535: } ! 536: ! 537: p = buf; ! 538: entry.metadata_len = PHAR_GET_16(zipentry.comment_len); ! 539: ! 540: if (phar_parse_metadata(&p, &(entry.metadata), PHAR_GET_16(zipentry.comment_len) TSRMLS_CC) == FAILURE) { ! 541: entry.metadata_len = 0; ! 542: /* if not valid serialized data, it is a regular string */ ! 543: ! 544: if (entry.is_persistent) { ! 545: ALLOC_PERMANENT_ZVAL(entry.metadata); ! 546: } else { ! 547: ALLOC_ZVAL(entry.metadata); ! 548: } ! 549: ! 550: INIT_ZVAL(*entry.metadata); ! 551: ZVAL_STRINGL(entry.metadata, pestrndup(buf, PHAR_GET_16(zipentry.comment_len), entry.is_persistent), PHAR_GET_16(zipentry.comment_len), 0); ! 552: } ! 553: } else { ! 554: entry.metadata = NULL; ! 555: } ! 556: ! 557: if (!actual_alias && entry.filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry.filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) { ! 558: php_stream_filter *filter; ! 559: off_t saveloc; ! 560: /* verify local file header */ ! 561: phar_zip_file_header local; ! 562: ! 563: /* archive alias found */ ! 564: saveloc = php_stream_tell(fp); ! 565: php_stream_seek(fp, PHAR_GET_32(zipentry.offset), SEEK_SET); ! 566: ! 567: if (sizeof(local) != php_stream_read(fp, (char *) &local, sizeof(local))) { ! 568: pefree(entry.filename, entry.is_persistent); ! 569: PHAR_ZIP_FAIL("phar error: internal corruption of zip-based phar (cannot read local file header for alias)"); ! 570: } ! 571: ! 572: /* verify local header */ ! 573: if (entry.filename_len != PHAR_GET_16(local.filename_len) || entry.crc32 != PHAR_GET_32(local.crc32) || entry.uncompressed_filesize != PHAR_GET_32(local.uncompsize) || entry.compressed_filesize != PHAR_GET_32(local.compsize)) { ! 574: pefree(entry.filename, entry.is_persistent); ! 575: PHAR_ZIP_FAIL("phar error: internal corruption of zip-based phar (local header of alias does not match central directory)"); ! 576: } ! 577: ! 578: /* construct actual offset to file start - local extra_len can be different from central extra_len */ ! 579: entry.offset = entry.offset_abs = ! 580: sizeof(local) + entry.header_offset + PHAR_GET_16(local.filename_len) + PHAR_GET_16(local.extra_len); ! 581: #if PHP_VERSION_ID < 50207 ! 582: /* work around Bug #46147 */ ! 583: fp->writepos = fp->readpos = 0; ! 584: #endif ! 585: php_stream_seek(fp, entry.offset, SEEK_SET); ! 586: /* these next lines should be for php < 5.2.6 after 5.3 filters are fixed */ ! 587: fp->writepos = 0; ! 588: fp->readpos = 0; ! 589: php_stream_seek(fp, entry.offset, SEEK_SET); ! 590: fp->writepos = 0; ! 591: fp->readpos = 0; ! 592: /* the above lines should be for php < 5.2.6 after 5.3 filters are fixed */ ! 593: ! 594: mydata->alias_len = entry.uncompressed_filesize; ! 595: ! 596: if (entry.flags & PHAR_ENT_COMPRESSED_GZ) { ! 597: filter = php_stream_filter_create("zlib.inflate", NULL, php_stream_is_persistent(fp) TSRMLS_CC); ! 598: ! 599: if (!filter) { ! 600: pefree(entry.filename, entry.is_persistent); ! 601: PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed"); ! 602: } ! 603: ! 604: php_stream_filter_append(&fp->readfilters, filter); ! 605: ! 606: #if PHP_MAJOR_VERSION >= 6 ! 607: if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, (void **) &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { ! 608: #else ! 609: if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { ! 610: #endif ! 611: pefree(entry.filename, entry.is_persistent); ! 612: #if PHP_VERSION_ID < 50207 ! 613: PHAR_ZIP_FAIL("unable to read in alias, truncated (PHP 5.2.7 and newer has a potential fix for this problem)"); ! 614: #endif ! 615: PHAR_ZIP_FAIL("unable to read in alias, truncated"); ! 616: } ! 617: ! 618: php_stream_filter_flush(filter, 1); ! 619: php_stream_filter_remove(filter, 1 TSRMLS_CC); ! 620: ! 621: } else if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) { ! 622: filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC); ! 623: ! 624: if (!filter) { ! 625: pefree(entry.filename, entry.is_persistent); ! 626: PHAR_ZIP_FAIL("unable to read in alias, bzip2 filter creation failed"); ! 627: } ! 628: ! 629: php_stream_filter_append(&fp->readfilters, filter); ! 630: ! 631: #if PHP_MAJOR_VERSION >= 6 ! 632: if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, (void **) &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { ! 633: #else ! 634: if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { ! 635: #endif ! 636: pefree(entry.filename, entry.is_persistent); ! 637: #if PHP_VERSION_ID < 50207 ! 638: PHAR_ZIP_FAIL("unable to read in alias, truncated (PHP 5.2.7 and newer has a potential fix for this problem)"); ! 639: #endif ! 640: PHAR_ZIP_FAIL("unable to read in alias, truncated"); ! 641: } ! 642: ! 643: php_stream_filter_flush(filter, 1); ! 644: php_stream_filter_remove(filter, 1 TSRMLS_CC); ! 645: } else { ! 646: #if PHP_MAJOR_VERSION >= 6 ! 647: if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, (void **) &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { ! 648: #else ! 649: if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { ! 650: #endif ! 651: pefree(entry.filename, entry.is_persistent); ! 652: PHAR_ZIP_FAIL("unable to read in alias, truncated"); ! 653: } ! 654: } ! 655: ! 656: /* return to central directory parsing */ ! 657: php_stream_seek(fp, saveloc, SEEK_SET); ! 658: } ! 659: ! 660: phar_set_inode(&entry TSRMLS_CC); ! 661: zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry,sizeof(phar_entry_info), NULL); ! 662: } ! 663: ! 664: mydata->fp = fp; ! 665: ! 666: if (zend_hash_exists(&(mydata->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) { ! 667: mydata->is_data = 0; ! 668: } else { ! 669: mydata->is_data = 1; ! 670: } ! 671: ! 672: zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL); ! 673: ! 674: if (actual_alias) { ! 675: phar_archive_data **fd_ptr; ! 676: ! 677: if (!phar_validate_alias(actual_alias, mydata->alias_len)) { ! 678: if (error) { ! 679: spprintf(error, 4096, "phar error: invalid alias \"%s\" in zip-based phar \"%s\"", actual_alias, fname); ! 680: } ! 681: efree(actual_alias); ! 682: zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len); ! 683: return FAILURE; ! 684: } ! 685: ! 686: mydata->is_temporary_alias = 0; ! 687: ! 688: if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void **)&fd_ptr)) { ! 689: if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, mydata->alias_len TSRMLS_CC)) { ! 690: if (error) { ! 691: spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with implicit alias, alias is already in use", fname); ! 692: } ! 693: efree(actual_alias); ! 694: zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len); ! 695: return FAILURE; ! 696: } ! 697: } ! 698: ! 699: mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias; ! 700: ! 701: if (entry.is_persistent) { ! 702: efree(actual_alias); ! 703: } ! 704: ! 705: zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL); ! 706: } else { ! 707: phar_archive_data **fd_ptr; ! 708: ! 709: if (alias_len) { ! 710: if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) { ! 711: if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) { ! 712: if (error) { ! 713: spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with explicit alias, alias is already in use", fname); ! 714: } ! 715: zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len); ! 716: return FAILURE; ! 717: } ! 718: } ! 719: ! 720: zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL); ! 721: mydata->alias = pestrndup(alias, alias_len, mydata->is_persistent); ! 722: mydata->alias_len = alias_len; ! 723: } else { ! 724: mydata->alias = pestrndup(mydata->fname, fname_len, mydata->is_persistent); ! 725: mydata->alias_len = fname_len; ! 726: } ! 727: ! 728: mydata->is_temporary_alias = 1; ! 729: } ! 730: ! 731: if (pphar) { ! 732: *pphar = mydata; ! 733: } ! 734: ! 735: return SUCCESS; ! 736: } ! 737: /* }}} */ ! 738: ! 739: /** ! 740: * Create or open a zip-based phar for writing ! 741: */ ! 742: 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) /* {{{ */ ! 743: { ! 744: phar_archive_data *phar; ! 745: int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, &phar, error TSRMLS_CC); ! 746: ! 747: if (FAILURE == ret) { ! 748: return FAILURE; ! 749: } ! 750: ! 751: if (pphar) { ! 752: *pphar = phar; ! 753: } ! 754: ! 755: phar->is_data = is_data; ! 756: ! 757: if (phar->is_zip) { ! 758: return ret; ! 759: } ! 760: ! 761: if (phar->is_brandnew) { ! 762: phar->internal_file_start = 0; ! 763: phar->is_zip = 1; ! 764: phar->is_tar = 0; ! 765: return SUCCESS; ! 766: } ! 767: ! 768: /* we've reached here - the phar exists and is a regular phar */ ! 769: if (error) { ! 770: 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); ! 771: } ! 772: ! 773: return FAILURE; ! 774: } ! 775: /* }}} */ ! 776: ! 777: struct _phar_zip_pass { ! 778: php_stream *filefp; ! 779: php_stream *centralfp; ! 780: php_stream *old; ! 781: int free_fp; ! 782: int free_ufp; ! 783: char **error; ! 784: }; ! 785: /* perform final modification of zip contents for each file in the manifest before saving */ ! 786: static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */ ! 787: { ! 788: phar_entry_info *entry; ! 789: phar_zip_file_header local; ! 790: phar_zip_unix3 perms; ! 791: phar_zip_central_dir_file central; ! 792: struct _phar_zip_pass *p; ! 793: php_uint32 newcrc32; ! 794: off_t offset; ! 795: int not_really_modified = 0; ! 796: entry = (phar_entry_info *)data; ! 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 TSRMLS_CC); ! 813: memset(&local, 0, sizeof(local)); ! 814: memset(¢ral, 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 TSRMLS_CC)) { ! 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 TSRMLS_CC)) { ! 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 TSRMLS_CC); ! 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 TSRMLS_CC); ! 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 TSRMLS_CC)) { ! 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 != phar_stream_copy_to_stream(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 TSRMLS_CC); ! 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: ! 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: not_compressed: ! 959: PHAR_SET_32(central.crc32, entry->crc32); ! 960: PHAR_SET_32(local.crc32, entry->crc32); ! 961: continue_dir: ! 962: /* set file metadata */ ! 963: if (entry->metadata) { ! 964: php_serialize_data_t metadata_hash; ! 965: ! 966: if (entry->metadata_str.c) { ! 967: smart_str_free(&entry->metadata_str); ! 968: } ! 969: entry->metadata_str.c = 0; ! 970: entry->metadata_str.len = 0; ! 971: PHP_VAR_SERIALIZE_INIT(metadata_hash); ! 972: php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC); ! 973: PHP_VAR_SERIALIZE_DESTROY(metadata_hash); ! 974: PHAR_SET_16(central.comment_len, entry->metadata_str.len); ! 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 *)¢ral, 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 != phar_stream_copy_to_stream(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 TSRMLS_CC)) { ! 1043: return ZEND_HASH_APPLY_STOP; ! 1044: } ! 1045: ! 1046: phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC); ! 1047: ! 1048: if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), 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 != phar_stream_copy_to_stream(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.c) { ! 1085: if (entry->metadata_str.len != php_stream_write(p->centralfp, entry->metadata_str.c, entry->metadata_str.len)) { ! 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_applysignature(phar_archive_data *phar, struct _phar_zip_pass *pass, ! 1099: smart_str *metadata TSRMLS_DC) /* {{{ */ ! 1100: { ! 1101: /* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */ ! 1102: if (!phar->is_data || phar->sig_flags) { ! 1103: int signature_length; ! 1104: char *signature, sigbuf[8]; ! 1105: phar_entry_info entry = {0}; ! 1106: php_stream *newfile; ! 1107: off_t tell, st; ! 1108: ! 1109: newfile = php_stream_fopen_tmpfile(); ! 1110: st = tell = php_stream_tell(pass->filefp); ! 1111: /* copy the local files, central directory, and the zip comment to generate the hash */ ! 1112: php_stream_seek(pass->filefp, 0, SEEK_SET); ! 1113: phar_stream_copy_to_stream(pass->filefp, newfile, tell, NULL); ! 1114: tell = php_stream_tell(pass->centralfp); ! 1115: php_stream_seek(pass->centralfp, 0, SEEK_SET); ! 1116: phar_stream_copy_to_stream(pass->centralfp, newfile, tell, NULL); ! 1117: if (metadata->c) { ! 1118: php_stream_write(newfile, metadata->c, metadata->len); ! 1119: } ! 1120: ! 1121: if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, pass->error TSRMLS_CC)) { ! 1122: if (pass->error) { ! 1123: char *save = *(pass->error); ! 1124: spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar: %s", save); ! 1125: efree(save); ! 1126: } ! 1127: ! 1128: php_stream_close(newfile); ! 1129: return FAILURE; ! 1130: } ! 1131: ! 1132: entry.filename = ".phar/signature.bin"; ! 1133: entry.filename_len = sizeof(".phar/signature.bin")-1; ! 1134: entry.fp = php_stream_fopen_tmpfile(); ! 1135: entry.fp_type = PHAR_MOD; ! 1136: entry.is_modified = 1; ! 1137: ! 1138: PHAR_SET_32(sigbuf, phar->sig_flags); ! 1139: PHAR_SET_32(sigbuf + 4, signature_length); ! 1140: ! 1141: if (8 != (int)php_stream_write(entry.fp, sigbuf, 8) || signature_length != (int)php_stream_write(entry.fp, signature, signature_length)) { ! 1142: efree(signature); ! 1143: if (pass->error) { ! 1144: spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar %s", phar->fname); ! 1145: } ! 1146: ! 1147: php_stream_close(newfile); ! 1148: return FAILURE; ! 1149: } ! 1150: ! 1151: efree(signature); ! 1152: entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8; ! 1153: entry.phar = phar; ! 1154: /* throw out return value and write the signature */ ! 1155: phar_zip_changed_apply((void *)&entry, (void *)pass TSRMLS_CC); ! 1156: php_stream_close(newfile); ! 1157: ! 1158: if (pass->error && *(pass->error)) { ! 1159: /* error is set by writeheaders */ ! 1160: php_stream_close(newfile); ! 1161: return FAILURE; ! 1162: } ! 1163: } /* signature */ ! 1164: return SUCCESS; ! 1165: } ! 1166: /* }}} */ ! 1167: ! 1168: int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC) /* {{{ */ ! 1169: { ! 1170: char *pos; ! 1171: smart_str main_metadata_str = {0}; ! 1172: static const char newstub[] = "<?php // zip-based phar archive stub file\n__HALT_COMPILER();"; ! 1173: char halt_stub[] = "__HALT_COMPILER();"; ! 1174: char *tmp; ! 1175: ! 1176: php_stream *stubfile, *oldfile; ! 1177: php_serialize_data_t metadata_hash; ! 1178: int free_user_stub, closeoldfile = 0; ! 1179: phar_entry_info entry = {0}; ! 1180: char *temperr = NULL; ! 1181: struct _phar_zip_pass pass; ! 1182: phar_zip_dir_end eocd; ! 1183: php_uint32 cdir_size, cdir_offset; ! 1184: ! 1185: pass.error = &temperr; ! 1186: entry.flags = PHAR_ENT_PERM_DEF_FILE; ! 1187: entry.timestamp = time(NULL); ! 1188: entry.is_modified = 1; ! 1189: entry.is_zip = 1; ! 1190: entry.phar = phar; ! 1191: entry.fp_type = PHAR_MOD; ! 1192: ! 1193: if (phar->is_persistent) { ! 1194: if (error) { ! 1195: spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname); ! 1196: } ! 1197: return EOF; ! 1198: } ! 1199: ! 1200: if (phar->is_data) { ! 1201: goto nostub; ! 1202: } ! 1203: ! 1204: /* set alias */ ! 1205: if (!phar->is_temporary_alias && phar->alias_len) { ! 1206: entry.fp = php_stream_fopen_tmpfile(); ! 1207: ! 1208: if (phar->alias_len != (int)php_stream_write(entry.fp, phar->alias, phar->alias_len)) { ! 1209: if (error) { ! 1210: spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname); ! 1211: } ! 1212: return EOF; ! 1213: } ! 1214: ! 1215: entry.uncompressed_filesize = entry.compressed_filesize = phar->alias_len; ! 1216: entry.filename = estrndup(".phar/alias.txt", sizeof(".phar/alias.txt")-1); ! 1217: entry.filename_len = sizeof(".phar/alias.txt")-1; ! 1218: ! 1219: if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { ! 1220: if (error) { ! 1221: spprintf(error, 0, "unable to set alias in zip-based phar \"%s\"", phar->fname); ! 1222: } ! 1223: return EOF; ! 1224: } ! 1225: } else { ! 1226: zend_hash_del(&phar->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1); ! 1227: } ! 1228: ! 1229: /* register alias */ ! 1230: if (phar->alias_len) { ! 1231: if (FAILURE == phar_get_archive(&phar, phar->fname, phar->fname_len, phar->alias, phar->alias_len, error TSRMLS_CC)) { ! 1232: return EOF; ! 1233: } ! 1234: } ! 1235: ! 1236: /* set stub */ ! 1237: if (user_stub && !defaultstub) { ! 1238: if (len < 0) { ! 1239: /* resource passed in */ ! 1240: if (!(php_stream_from_zval_no_verify(stubfile, (zval **)user_stub))) { ! 1241: if (error) { ! 1242: spprintf(error, 0, "unable to access resource to copy stub to new zip-based phar \"%s\"", phar->fname); ! 1243: } ! 1244: return EOF; ! 1245: } ! 1246: ! 1247: if (len == -1) { ! 1248: len = PHP_STREAM_COPY_ALL; ! 1249: } else { ! 1250: len = -len; ! 1251: } ! 1252: ! 1253: user_stub = 0; ! 1254: ! 1255: #if PHP_MAJOR_VERSION >= 6 ! 1256: if (!(len = php_stream_copy_to_mem(stubfile, (void **) &user_stub, len, 0)) || !user_stub) { ! 1257: #else ! 1258: if (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) { ! 1259: #endif ! 1260: if (error) { ! 1261: spprintf(error, 0, "unable to read resource to copy stub to new zip-based phar \"%s\"", phar->fname); ! 1262: } ! 1263: return EOF; ! 1264: } ! 1265: free_user_stub = 1; ! 1266: } else { ! 1267: free_user_stub = 0; ! 1268: } ! 1269: ! 1270: tmp = estrndup(user_stub, len); ! 1271: if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) { ! 1272: efree(tmp); ! 1273: if (error) { ! 1274: spprintf(error, 0, "illegal stub for zip-based phar \"%s\"", phar->fname); ! 1275: } ! 1276: if (free_user_stub) { ! 1277: efree(user_stub); ! 1278: } ! 1279: return EOF; ! 1280: } ! 1281: pos = user_stub + (pos - tmp); ! 1282: efree(tmp); ! 1283: ! 1284: len = pos - user_stub + 18; ! 1285: entry.fp = php_stream_fopen_tmpfile(); ! 1286: entry.uncompressed_filesize = len + 5; ! 1287: ! 1288: if ((size_t)len != php_stream_write(entry.fp, user_stub, len) ! 1289: || 5 != php_stream_write(entry.fp, " ?>\r\n", 5)) { ! 1290: if (error) { ! 1291: spprintf(error, 0, "unable to create stub from string in new zip-based phar \"%s\"", phar->fname); ! 1292: } ! 1293: if (free_user_stub) { ! 1294: efree(user_stub); ! 1295: } ! 1296: php_stream_close(entry.fp); ! 1297: return EOF; ! 1298: } ! 1299: ! 1300: entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1); ! 1301: entry.filename_len = sizeof(".phar/stub.php")-1; ! 1302: ! 1303: if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { ! 1304: if (free_user_stub) { ! 1305: efree(user_stub); ! 1306: } ! 1307: if (error) { ! 1308: spprintf(error, 0, "unable to set stub in zip-based phar \"%s\"", phar->fname); ! 1309: } ! 1310: return EOF; ! 1311: } ! 1312: ! 1313: if (free_user_stub) { ! 1314: efree(user_stub); ! 1315: } ! 1316: } else { ! 1317: /* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */ ! 1318: entry.fp = php_stream_fopen_tmpfile(); ! 1319: ! 1320: if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) { ! 1321: php_stream_close(entry.fp); ! 1322: if (error) { ! 1323: spprintf(error, 0, "unable to %s stub in%szip-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname); ! 1324: } ! 1325: return EOF; ! 1326: } ! 1327: ! 1328: entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1; ! 1329: entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1); ! 1330: entry.filename_len = sizeof(".phar/stub.php")-1; ! 1331: ! 1332: if (!defaultstub) { ! 1333: if (!zend_hash_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) { ! 1334: if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { ! 1335: php_stream_close(entry.fp); ! 1336: efree(entry.filename); ! 1337: if (error) { ! 1338: spprintf(error, 0, "unable to create stub in zip-based phar \"%s\"", phar->fname); ! 1339: } ! 1340: return EOF; ! 1341: } ! 1342: } else { ! 1343: php_stream_close(entry.fp); ! 1344: efree(entry.filename); ! 1345: } ! 1346: } else { ! 1347: if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) { ! 1348: php_stream_close(entry.fp); ! 1349: efree(entry.filename); ! 1350: if (error) { ! 1351: spprintf(error, 0, "unable to overwrite stub in zip-based phar \"%s\"", phar->fname); ! 1352: } ! 1353: return EOF; ! 1354: } ! 1355: } ! 1356: } ! 1357: nostub: ! 1358: if (phar->fp && !phar->is_brandnew) { ! 1359: oldfile = phar->fp; ! 1360: closeoldfile = 0; ! 1361: php_stream_rewind(oldfile); ! 1362: } else { ! 1363: oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL); ! 1364: closeoldfile = oldfile != NULL; ! 1365: } ! 1366: ! 1367: /* save modified files to the zip */ ! 1368: pass.old = oldfile; ! 1369: pass.filefp = php_stream_fopen_tmpfile(); ! 1370: ! 1371: if (!pass.filefp) { ! 1372: fperror: ! 1373: if (closeoldfile) { ! 1374: php_stream_close(oldfile); ! 1375: } ! 1376: if (error) { ! 1377: spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname); ! 1378: } ! 1379: return EOF; ! 1380: } ! 1381: ! 1382: pass.centralfp = php_stream_fopen_tmpfile(); ! 1383: ! 1384: if (!pass.centralfp) { ! 1385: goto fperror; ! 1386: } ! 1387: ! 1388: pass.free_fp = pass.free_ufp = 1; ! 1389: memset(&eocd, 0, sizeof(eocd)); ! 1390: ! 1391: strncpy(eocd.signature, "PK\5\6", 4); ! 1392: if (!phar->is_data && !phar->sig_flags) { ! 1393: phar->sig_flags = PHAR_SIG_SHA1; ! 1394: } ! 1395: if (phar->sig_flags) { ! 1396: PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest) + 1); ! 1397: PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest) + 1); ! 1398: } else { ! 1399: PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest)); ! 1400: PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest)); ! 1401: } ! 1402: zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass TSRMLS_CC); ! 1403: ! 1404: if (phar->metadata) { ! 1405: /* set phar metadata */ ! 1406: PHP_VAR_SERIALIZE_INIT(metadata_hash); ! 1407: php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC); ! 1408: PHP_VAR_SERIALIZE_DESTROY(metadata_hash); ! 1409: } ! 1410: if (temperr) { ! 1411: if (error) { ! 1412: spprintf(error, 4096, "phar zip flush of \"%s\" failed: %s", phar->fname, temperr); ! 1413: } ! 1414: efree(temperr); ! 1415: temperror: ! 1416: php_stream_close(pass.centralfp); ! 1417: nocentralerror: ! 1418: if (phar->metadata) { ! 1419: smart_str_free(&main_metadata_str); ! 1420: } ! 1421: php_stream_close(pass.filefp); ! 1422: if (closeoldfile) { ! 1423: php_stream_close(oldfile); ! 1424: } ! 1425: return EOF; ! 1426: } ! 1427: ! 1428: if (FAILURE == phar_zip_applysignature(phar, &pass, &main_metadata_str TSRMLS_CC)) { ! 1429: goto temperror; ! 1430: } ! 1431: ! 1432: /* save zip */ ! 1433: cdir_size = php_stream_tell(pass.centralfp); ! 1434: cdir_offset = php_stream_tell(pass.filefp); ! 1435: PHAR_SET_32(eocd.cdir_size, cdir_size); ! 1436: PHAR_SET_32(eocd.cdir_offset, cdir_offset); ! 1437: php_stream_seek(pass.centralfp, 0, SEEK_SET); ! 1438: ! 1439: { ! 1440: size_t clen; ! 1441: int ret = phar_stream_copy_to_stream(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL, &clen); ! 1442: if (SUCCESS != ret || clen != cdir_size) { ! 1443: if (error) { ! 1444: spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write central-directory", phar->fname); ! 1445: } ! 1446: goto temperror; ! 1447: } ! 1448: } ! 1449: ! 1450: php_stream_close(pass.centralfp); ! 1451: ! 1452: if (phar->metadata) { ! 1453: /* set phar metadata */ ! 1454: PHAR_SET_16(eocd.comment_len, main_metadata_str.len); ! 1455: ! 1456: if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) { ! 1457: if (error) { ! 1458: spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname); ! 1459: } ! 1460: goto nocentralerror; ! 1461: } ! 1462: ! 1463: if (main_metadata_str.len != php_stream_write(pass.filefp, main_metadata_str.c, main_metadata_str.len)) { ! 1464: if (error) { ! 1465: spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write metadata to zip comment", phar->fname); ! 1466: } ! 1467: goto nocentralerror; ! 1468: } ! 1469: ! 1470: smart_str_free(&main_metadata_str); ! 1471: ! 1472: } else { ! 1473: if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) { ! 1474: if (error) { ! 1475: spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname); ! 1476: } ! 1477: goto nocentralerror; ! 1478: } ! 1479: } ! 1480: ! 1481: if (phar->fp && pass.free_fp) { ! 1482: php_stream_close(phar->fp); ! 1483: } ! 1484: ! 1485: if (phar->ufp) { ! 1486: if (pass.free_ufp) { ! 1487: php_stream_close(phar->ufp); ! 1488: } ! 1489: phar->ufp = NULL; ! 1490: } ! 1491: ! 1492: /* re-open */ ! 1493: phar->is_brandnew = 0; ! 1494: ! 1495: if (phar->donotflush) { ! 1496: /* deferred flush */ ! 1497: phar->fp = pass.filefp; ! 1498: } else { ! 1499: phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL); ! 1500: if (!phar->fp) { ! 1501: if (closeoldfile) { ! 1502: php_stream_close(oldfile); ! 1503: } ! 1504: phar->fp = pass.filefp; ! 1505: if (error) { ! 1506: spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname); ! 1507: } ! 1508: return EOF; ! 1509: } ! 1510: php_stream_rewind(pass.filefp); ! 1511: phar_stream_copy_to_stream(pass.filefp, phar->fp, PHP_STREAM_COPY_ALL, NULL); ! 1512: /* we could also reopen the file in "rb" mode but there is no need for that */ ! 1513: php_stream_close(pass.filefp); ! 1514: } ! 1515: ! 1516: if (closeoldfile) { ! 1517: php_stream_close(oldfile); ! 1518: } ! 1519: return EOF; ! 1520: } ! 1521: /* }}} */ ! 1522: ! 1523: /* ! 1524: * Local variables: ! 1525: * tab-width: 4 ! 1526: * c-basic-offset: 4 ! 1527: * End: ! 1528: * vim600: noet sw=4 ts=4 fdm=marker ! 1529: * vim<600: noet sw=4 ts=4 ! 1530: */