File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / phar / zip.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:54 2014 UTC (10 years, 3 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

    1: /*
    2:   +----------------------------------------------------------------------+
    3:   | ZIP archive support for Phar                                         |
    4:   +----------------------------------------------------------------------+
    5:   | Copyright (c) 2007-2014 The PHP Group                                |
    6:   +----------------------------------------------------------------------+
    7:   | This source file is subject to version 3.01 of the PHP license,      |
    8:   | that is bundled with this package in the file LICENSE, and is        |
    9:   | available through the world-wide-web at the following url:           |
   10:   | http://www.php.net/license/3_01.txt.                                 |
   11:   | If you did not receive a copy of the PHP license and are unable to   |
   12:   | obtain it through the world-wide-web, please send a note to          |
   13:   | license@php.net so we can mail you a copy immediately.               |
   14:   +----------------------------------------------------------------------+
   15:   | Authors: Gregory Beaver <cellog@php.net>                             |
   16:   +----------------------------------------------------------------------+
   17: */
   18: 
   19: #include "phar_internal.h"
   20: 
   21: #define PHAR_GET_16(var) ((php_uint16)((((php_uint16)var[0]) & 0xff) | \
   22: 	(((php_uint16)var[1]) & 0xff) << 8))
   23: #define PHAR_GET_32(var) ((php_uint32)((((php_uint32)var[0]) & 0xff) | \
   24: 	(((php_uint32)var[1]) & 0xff) << 8 | \
   25: 	(((php_uint32)var[2]) & 0xff) << 16 | \
   26: 	(((php_uint32)var[3]) & 0xff) << 24))
   27: 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 (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
  607: 					pefree(entry.filename, entry.is_persistent);
  608: #if PHP_VERSION_ID < 50207
  609: 					PHAR_ZIP_FAIL("unable to read in alias, truncated (PHP 5.2.7 and newer has a potential fix for this problem)");
  610: #endif
  611: 					PHAR_ZIP_FAIL("unable to read in alias, truncated");
  612: 				}
  613: 
  614: 				php_stream_filter_flush(filter, 1);
  615: 				php_stream_filter_remove(filter, 1 TSRMLS_CC);
  616: 
  617: 			} else if (entry.flags & PHAR_ENT_COMPRESSED_BZ2) {
  618: 				filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC);
  619: 
  620: 				if (!filter) {
  621: 					pefree(entry.filename, entry.is_persistent);
  622: 					PHAR_ZIP_FAIL("unable to read in alias, bzip2 filter creation failed");
  623: 				}
  624: 
  625: 				php_stream_filter_append(&fp->readfilters, filter);
  626: 
  627: 				if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
  628: 					pefree(entry.filename, entry.is_persistent);
  629: #if PHP_VERSION_ID < 50207
  630: 					PHAR_ZIP_FAIL("unable to read in alias, truncated (PHP 5.2.7 and newer has a potential fix for this problem)");
  631: #endif
  632: 					PHAR_ZIP_FAIL("unable to read in alias, truncated");
  633: 				}
  634: 
  635: 				php_stream_filter_flush(filter, 1);
  636: 				php_stream_filter_remove(filter, 1 TSRMLS_CC);
  637: 			} else {
  638: 				if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) {
  639: 					pefree(entry.filename, entry.is_persistent);
  640: 					PHAR_ZIP_FAIL("unable to read in alias, truncated");
  641: 				}
  642: 			}
  643: 
  644: 			/* return to central directory parsing */
  645: 			php_stream_seek(fp, saveloc, SEEK_SET);
  646: 		}
  647: 
  648: 		phar_set_inode(&entry TSRMLS_CC);
  649: 		zend_hash_add(&mydata->manifest, entry.filename, entry.filename_len, (void *)&entry,sizeof(phar_entry_info), NULL);
  650: 	}
  651: 
  652: 	mydata->fp = fp;
  653: 
  654: 	if (zend_hash_exists(&(mydata->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
  655: 		mydata->is_data = 0;
  656: 	} else {
  657: 		mydata->is_data = 1;
  658: 	}
  659: 
  660: 	zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
  661: 
  662: 	if (actual_alias) {
  663: 		phar_archive_data **fd_ptr;
  664: 
  665: 		if (!phar_validate_alias(actual_alias, mydata->alias_len)) {
  666: 			if (error) {
  667: 				spprintf(error, 4096, "phar error: invalid alias \"%s\" in zip-based phar \"%s\"", actual_alias, fname);
  668: 			}
  669: 			efree(actual_alias);
  670: 			zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
  671: 			return FAILURE;
  672: 		}
  673: 
  674: 		mydata->is_temporary_alias = 0;
  675: 
  676: 		if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void **)&fd_ptr)) {
  677: 			if (SUCCESS != phar_free_alias(*fd_ptr, actual_alias, mydata->alias_len TSRMLS_CC)) {
  678: 				if (error) {
  679: 					spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with implicit alias, alias is already in use", 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: 
  687: 		mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias;
  688: 
  689: 		if (entry.is_persistent) {
  690: 			efree(actual_alias);
  691: 		}
  692: 
  693: 		zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
  694: 	} else {
  695: 		phar_archive_data **fd_ptr;
  696: 
  697: 		if (alias_len) {
  698: 			if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void **)&fd_ptr)) {
  699: 				if (SUCCESS != phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
  700: 					if (error) {
  701: 						spprintf(error, 4096, "phar error: Unable to add zip-based phar \"%s\" with explicit alias, alias is already in use", fname);
  702: 					}
  703: 					zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len);
  704: 					return FAILURE;
  705: 				}
  706: 			}
  707: 
  708: 			zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
  709: 			mydata->alias = pestrndup(alias, alias_len, mydata->is_persistent);
  710: 			mydata->alias_len = alias_len;
  711: 		} else {
  712: 			mydata->alias = pestrndup(mydata->fname, fname_len, mydata->is_persistent);
  713: 			mydata->alias_len = fname_len;
  714: 		}
  715: 
  716: 		mydata->is_temporary_alias = 1;
  717: 	}
  718: 
  719: 	if (pphar) {
  720: 		*pphar = mydata;
  721: 	}
  722: 
  723: 	return SUCCESS;
  724: }
  725: /* }}} */
  726: 
  727: /**
  728:  * Create or open a zip-based phar for writing
  729:  */
  730: int phar_open_or_create_zip(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC) /* {{{ */
  731: {
  732: 	phar_archive_data *phar;
  733: 	int ret = phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, &phar, error TSRMLS_CC);
  734: 
  735: 	if (FAILURE == ret) {
  736: 		return FAILURE;
  737: 	}
  738: 
  739: 	if (pphar) {
  740: 		*pphar = phar;
  741: 	}
  742: 
  743: 	phar->is_data = is_data;
  744: 
  745: 	if (phar->is_zip) {
  746: 		return ret;
  747: 	}
  748: 
  749: 	if (phar->is_brandnew) {
  750: 		phar->internal_file_start = 0;
  751: 		phar->is_zip = 1;
  752: 		phar->is_tar = 0;
  753: 		return SUCCESS;
  754: 	}
  755: 
  756: 	/* we've reached here - the phar exists and is a regular phar */
  757: 	if (error) {
  758: 		spprintf(error, 4096, "phar zip error: phar \"%s\" already exists as a regular phar and must be deleted from disk prior to creating as a zip-based phar", fname);
  759: 	}
  760: 
  761: 	return FAILURE;
  762: }
  763: /* }}} */
  764: 
  765: struct _phar_zip_pass {
  766: 	php_stream *filefp;
  767: 	php_stream *centralfp;
  768: 	php_stream *old;
  769: 	int free_fp;
  770: 	int free_ufp;
  771: 	char **error;
  772: };
  773: /* perform final modification of zip contents for each file in the manifest before saving */
  774: static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
  775: {
  776: 	phar_entry_info *entry;
  777: 	phar_zip_file_header local;
  778: 	phar_zip_unix3 perms;
  779: 	phar_zip_central_dir_file central;
  780: 	struct _phar_zip_pass *p;
  781: 	php_uint32 newcrc32;
  782: 	off_t offset;
  783: 	int not_really_modified = 0;
  784: 	entry = (phar_entry_info *)data;
  785: 	p = (struct _phar_zip_pass*) arg;
  786: 
  787: 	if (entry->is_mounted) {
  788: 		return ZEND_HASH_APPLY_KEEP;
  789: 	}
  790: 
  791: 	if (entry->is_deleted) {
  792: 		if (entry->fp_refcount <= 0) {
  793: 			return ZEND_HASH_APPLY_REMOVE;
  794: 		} else {
  795: 			/* we can't delete this in-memory until it is closed */
  796: 			return ZEND_HASH_APPLY_KEEP;
  797: 		}
  798: 	}
  799: 
  800: 	phar_add_virtual_dirs(entry->phar, entry->filename, entry->filename_len TSRMLS_CC);
  801: 	memset(&local, 0, sizeof(local));
  802: 	memset(&central, 0, sizeof(central));
  803: 	memset(&perms, 0, sizeof(perms));
  804: 	strncpy(local.signature, "PK\3\4", 4);
  805: 	strncpy(central.signature, "PK\1\2", 4);
  806: 	PHAR_SET_16(central.extra_len, sizeof(perms));
  807: 	PHAR_SET_16(local.extra_len, sizeof(perms));
  808: 	perms.tag[0] = 'n';
  809: 	perms.tag[1] = 'u';
  810: 	PHAR_SET_16(perms.size, sizeof(perms) - 4);
  811: 	PHAR_SET_16(perms.perms, entry->flags & PHAR_ENT_PERM_MASK);
  812: 	{
  813: 		php_uint32 crc = (php_uint32) ~0;
  814: 		CRC32(crc, perms.perms[0]);
  815: 		CRC32(crc, perms.perms[1]);
  816: 		PHAR_SET_32(perms.crc32, ~crc);
  817: 	}
  818: 
  819: 	if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
  820: 		PHAR_SET_16(central.compressed, PHAR_ZIP_COMP_DEFLATE);
  821: 		PHAR_SET_16(local.compressed, PHAR_ZIP_COMP_DEFLATE);
  822: 	}
  823: 
  824: 	if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) {
  825: 		PHAR_SET_16(central.compressed, PHAR_ZIP_COMP_BZIP2);
  826: 		PHAR_SET_16(local.compressed, PHAR_ZIP_COMP_BZIP2);
  827: 	}
  828: 
  829: 	/* do not use PHAR_GET_16 on either field of the next line */
  830: 	phar_zip_u2d_time(entry->timestamp, local.timestamp, local.datestamp);
  831: 	memcpy(central.timestamp, local.timestamp, sizeof(local.timestamp));
  832: 	memcpy(central.datestamp, local.datestamp, sizeof(local.datestamp));
  833: 	PHAR_SET_16(central.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0));
  834: 	PHAR_SET_16(local.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0));
  835: 	PHAR_SET_32(central.offset, php_stream_tell(p->filefp));
  836: 
  837: 	/* do extra field for perms later */
  838: 	if (entry->is_modified) {
  839: 		php_uint32 loc;
  840: 		php_stream_filter *filter;
  841: 		php_stream *efp;
  842: 
  843: 		if (entry->is_dir) {
  844: 			entry->is_modified = 0;
  845: 			if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp) {
  846: 				php_stream_close(entry->fp);
  847: 				entry->fp = NULL;
  848: 				entry->fp_type = PHAR_FP;
  849: 			}
  850: 			goto continue_dir;
  851: 		}
  852: 
  853: 		if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
  854: 			spprintf(p->error, 0, "unable to open file contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  855: 			return ZEND_HASH_APPLY_STOP;
  856: 		}
  857: 
  858: 		/* we can be modified and already be compressed, such as when chmod() is executed */
  859: 		if (entry->flags & PHAR_ENT_COMPRESSION_MASK && (entry->old_flags == entry->flags || !entry->old_flags)) {
  860: 			not_really_modified = 1;
  861: 			goto is_compressed;
  862: 		}
  863: 
  864: 		if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
  865: 			spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  866: 			return ZEND_HASH_APPLY_STOP;
  867: 		}
  868: 
  869: 		efp = phar_get_efp(entry, 0 TSRMLS_CC);
  870: 		newcrc32 = ~0;
  871: 
  872: 		for (loc = 0;loc < entry->uncompressed_filesize; ++loc) {
  873: 			CRC32(newcrc32, php_stream_getc(efp));
  874: 		}
  875: 
  876: 		entry->crc32 = ~newcrc32;
  877: 		PHAR_SET_32(central.uncompsize, entry->uncompressed_filesize);
  878: 		PHAR_SET_32(local.uncompsize, entry->uncompressed_filesize);
  879: 
  880: 		if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
  881: 			/* not compressed */
  882: 			entry->compressed_filesize = entry->uncompressed_filesize;
  883: 			PHAR_SET_32(central.compsize, entry->uncompressed_filesize);
  884: 			PHAR_SET_32(local.compsize, entry->uncompressed_filesize);
  885: 			goto not_compressed;
  886: 		}
  887: 
  888: 		filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0 TSRMLS_CC);
  889: 
  890: 		if (!filter) {
  891: 			if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
  892: 				spprintf(p->error, 0, "unable to gzip compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  893: 			} else {
  894: 				spprintf(p->error, 0, "unable to bzip2 compress file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  895: 			}
  896: 			return ZEND_HASH_APPLY_STOP;
  897: 		}
  898: 
  899: 		/* create new file that holds the compressed version */
  900: 		/* work around inability to specify freedom in write and strictness
  901: 		in read count */
  902: 		entry->cfp = php_stream_fopen_tmpfile();
  903: 
  904: 		if (!entry->cfp) {
  905: 			spprintf(p->error, 0, "unable to create temporary file for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  906: 			return ZEND_HASH_APPLY_STOP;
  907: 		}
  908: 
  909: 		php_stream_flush(efp);
  910: 
  911: 		if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
  912: 			spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  913: 			return ZEND_HASH_APPLY_STOP;
  914: 		}
  915: 
  916: 		php_stream_filter_append((&entry->cfp->writefilters), filter);
  917: 
  918: 		if (SUCCESS != phar_stream_copy_to_stream(efp, entry->cfp, entry->uncompressed_filesize, NULL)) {
  919: 			spprintf(p->error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, entry->phar->fname);
  920: 			return ZEND_HASH_APPLY_STOP;
  921: 		}
  922: 
  923: 		php_stream_filter_flush(filter, 1);
  924: 		php_stream_flush(entry->cfp);
  925: 		php_stream_filter_remove(filter, 1 TSRMLS_CC);
  926: 		php_stream_seek(entry->cfp, 0, SEEK_END);
  927: 		entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp);
  928: 		PHAR_SET_32(central.compsize, entry->compressed_filesize);
  929: 		PHAR_SET_32(local.compsize, entry->compressed_filesize);
  930: 		/* generate crc on compressed file */
  931: 		php_stream_rewind(entry->cfp);
  932: 		entry->old_flags = entry->flags;
  933: 		entry->is_modified = 1;
  934: 	} else {
  935: is_compressed:
  936: 		PHAR_SET_32(central.uncompsize, entry->uncompressed_filesize);
  937: 		PHAR_SET_32(local.uncompsize, entry->uncompressed_filesize);
  938: 		PHAR_SET_32(central.compsize, entry->compressed_filesize);
  939: 		PHAR_SET_32(local.compsize, entry->compressed_filesize);
  940: 		if (p->old) {
  941: 			if (-1 == php_stream_seek(p->old, entry->offset_abs, SEEK_SET)) {
  942: 				spprintf(p->error, 0, "unable to seek to start of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  943: 				return ZEND_HASH_APPLY_STOP;
  944: 			}
  945: 		}
  946: 	}
  947: not_compressed:
  948: 	PHAR_SET_32(central.crc32, entry->crc32);
  949: 	PHAR_SET_32(local.crc32, entry->crc32);
  950: continue_dir:
  951: 	/* set file metadata */
  952: 	if (entry->metadata) {
  953: 		php_serialize_data_t metadata_hash;
  954: 
  955: 		if (entry->metadata_str.c) {
  956: 			smart_str_free(&entry->metadata_str);
  957: 		}
  958: 		entry->metadata_str.c = 0;
  959: 		entry->metadata_str.len = 0;
  960: 		PHP_VAR_SERIALIZE_INIT(metadata_hash);
  961: 		php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC);
  962: 		PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
  963: 		PHAR_SET_16(central.comment_len, entry->metadata_str.len);
  964: 	}
  965: 
  966: 	entry->header_offset = php_stream_tell(p->filefp);
  967: 	offset = entry->header_offset + sizeof(local) + entry->filename_len + (entry->is_dir ? 1 : 0) + sizeof(perms);
  968: 
  969: 	if (sizeof(local) != php_stream_write(p->filefp, (char *)&local, sizeof(local))) {
  970: 		spprintf(p->error, 0, "unable to write local file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  971: 		return ZEND_HASH_APPLY_STOP;
  972: 	}
  973: 
  974: 	if (sizeof(central) != php_stream_write(p->centralfp, (char *)&central, sizeof(central))) {
  975: 		spprintf(p->error, 0, "unable to write central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  976: 		return ZEND_HASH_APPLY_STOP;
  977: 	}
  978: 
  979: 	if (entry->is_dir) {
  980: 		if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
  981: 			spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  982: 			return ZEND_HASH_APPLY_STOP;
  983: 		}
  984: 
  985: 		if (1 != php_stream_write(p->filefp, "/", 1)) {
  986: 			spprintf(p->error, 0, "unable to write filename to local directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  987: 			return ZEND_HASH_APPLY_STOP;
  988: 		}
  989: 
  990: 		if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
  991: 			spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  992: 			return ZEND_HASH_APPLY_STOP;
  993: 		}
  994: 
  995: 		if (1 != php_stream_write(p->centralfp, "/", 1)) {
  996: 			spprintf(p->error, 0, "unable to write filename to central directory entry for directory \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
  997: 			return ZEND_HASH_APPLY_STOP;
  998: 		}
  999: 	} else {
 1000: 		if (entry->filename_len != php_stream_write(p->filefp, entry->filename, entry->filename_len)) {
 1001: 			spprintf(p->error, 0, "unable to write filename to local directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
 1002: 			return ZEND_HASH_APPLY_STOP;
 1003: 		}
 1004: 
 1005: 		if (entry->filename_len != php_stream_write(p->centralfp, entry->filename, entry->filename_len)) {
 1006: 			spprintf(p->error, 0, "unable to write filename to central directory entry for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
 1007: 			return ZEND_HASH_APPLY_STOP;
 1008: 		}
 1009: 	}
 1010: 
 1011: 	if (sizeof(perms) != php_stream_write(p->filefp, (char *)&perms, sizeof(perms))) {
 1012: 		spprintf(p->error, 0, "unable to write local extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
 1013: 		return ZEND_HASH_APPLY_STOP;
 1014: 	}
 1015: 
 1016: 	if (sizeof(perms) != php_stream_write(p->centralfp, (char *)&perms, sizeof(perms))) {
 1017: 		spprintf(p->error, 0, "unable to write central extra permissions file header of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
 1018: 		return ZEND_HASH_APPLY_STOP;
 1019: 	}
 1020: 
 1021: 	if (!not_really_modified && entry->is_modified) {
 1022: 		if (entry->cfp) {
 1023: 			if (SUCCESS != phar_stream_copy_to_stream(entry->cfp, p->filefp, entry->compressed_filesize, NULL)) {
 1024: 				spprintf(p->error, 0, "unable to write compressed contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
 1025: 				return ZEND_HASH_APPLY_STOP;
 1026: 			}
 1027: 
 1028: 			php_stream_close(entry->cfp);
 1029: 			entry->cfp = NULL;
 1030: 		} else {
 1031: 			if (FAILURE == phar_open_entry_fp(entry, p->error, 0 TSRMLS_CC)) {
 1032: 				return ZEND_HASH_APPLY_STOP;
 1033: 			}
 1034: 
 1035: 			phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC);
 1036: 
 1037: 			if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(entry, 0 TSRMLS_CC), p->filefp, entry->uncompressed_filesize, NULL)) {
 1038: 				spprintf(p->error, 0, "unable to write contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
 1039: 				return ZEND_HASH_APPLY_STOP;
 1040: 			}
 1041: 		}
 1042: 
 1043: 		if (entry->fp_type == PHAR_MOD && entry->fp != entry->phar->fp && entry->fp != entry->phar->ufp && entry->fp_refcount == 0) {
 1044: 			php_stream_close(entry->fp);
 1045: 		}
 1046: 
 1047: 		entry->is_modified = 0;
 1048: 	} else {
 1049: 		entry->is_modified = 0;
 1050: 		if (entry->fp_refcount) {
 1051: 			/* open file pointers refer to this fp, do not free the stream */
 1052: 			switch (entry->fp_type) {
 1053: 				case PHAR_FP:
 1054: 					p->free_fp = 0;
 1055: 					break;
 1056: 				case PHAR_UFP:
 1057: 					p->free_ufp = 0;
 1058: 				default:
 1059: 					break;
 1060: 			}
 1061: 		}
 1062: 
 1063: 		if (!entry->is_dir && entry->compressed_filesize && SUCCESS != phar_stream_copy_to_stream(p->old, p->filefp, entry->compressed_filesize, NULL)) {
 1064: 			spprintf(p->error, 0, "unable to copy contents of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
 1065: 			return ZEND_HASH_APPLY_STOP;
 1066: 		}
 1067: 	}
 1068: 
 1069: 	entry->fp = NULL;
 1070: 	entry->offset = entry->offset_abs = offset;
 1071: 	entry->fp_type = PHAR_FP;
 1072: 
 1073: 	if (entry->metadata_str.c) {
 1074: 		if (entry->metadata_str.len != php_stream_write(p->centralfp, entry->metadata_str.c, entry->metadata_str.len)) {
 1075: 			spprintf(p->error, 0, "unable to write metadata as file comment for file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname);
 1076: 			smart_str_free(&entry->metadata_str);
 1077: 			return ZEND_HASH_APPLY_STOP;
 1078: 		}
 1079: 
 1080: 		smart_str_free(&entry->metadata_str);
 1081: 	}
 1082: 
 1083: 	return ZEND_HASH_APPLY_KEEP;
 1084: }
 1085: /* }}} */
 1086: 
 1087: static int phar_zip_applysignature(phar_archive_data *phar, struct _phar_zip_pass *pass,
 1088: 				   smart_str *metadata TSRMLS_DC) /* {{{ */
 1089: {
 1090: 	/* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */
 1091: 	if (!phar->is_data || phar->sig_flags) {
 1092: 		int signature_length;
 1093: 		char *signature, sigbuf[8];
 1094: 		phar_entry_info entry = {0};
 1095: 		php_stream *newfile;
 1096: 		off_t tell, st;
 1097: 
 1098: 		newfile = php_stream_fopen_tmpfile();
 1099: 		if (newfile == NULL) {
 1100: 			spprintf(pass->error, 0, "phar error: unable to create temporary file for the signature file");
 1101: 			return FAILURE;
 1102: 		}
 1103: 		st = tell = php_stream_tell(pass->filefp);
 1104: 		/* copy the local files, central directory, and the zip comment to generate the hash */
 1105: 		php_stream_seek(pass->filefp, 0, SEEK_SET);
 1106: 		phar_stream_copy_to_stream(pass->filefp, newfile, tell, NULL);
 1107: 		tell = php_stream_tell(pass->centralfp);
 1108: 		php_stream_seek(pass->centralfp, 0, SEEK_SET);
 1109: 		phar_stream_copy_to_stream(pass->centralfp, newfile, tell, NULL);
 1110: 		if (metadata->c) {
 1111: 			php_stream_write(newfile, metadata->c, metadata->len);
 1112: 		}
 1113: 
 1114: 		if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, pass->error TSRMLS_CC)) {
 1115: 			if (pass->error) {
 1116: 				char *save = *(pass->error);
 1117: 				spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar: %s", save);
 1118: 				efree(save);
 1119: 			}
 1120: 
 1121: 			php_stream_close(newfile);
 1122: 			return FAILURE;
 1123: 		}
 1124: 
 1125: 		entry.filename = ".phar/signature.bin";
 1126: 		entry.filename_len = sizeof(".phar/signature.bin")-1;
 1127: 		entry.fp = php_stream_fopen_tmpfile();
 1128: 		entry.fp_type = PHAR_MOD;
 1129: 		entry.is_modified = 1;
 1130: 		if (entry.fp == NULL) {
 1131: 			spprintf(pass->error, 0, "phar error: unable to create temporary file for signature");
 1132: 			return FAILURE;
 1133: 		}
 1134: 
 1135: 		PHAR_SET_32(sigbuf, phar->sig_flags);
 1136: 		PHAR_SET_32(sigbuf + 4, signature_length);
 1137: 
 1138: 		if (8 != (int)php_stream_write(entry.fp, sigbuf, 8) || signature_length != (int)php_stream_write(entry.fp, signature, signature_length)) {
 1139: 			efree(signature);
 1140: 			if (pass->error) {
 1141: 				spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar %s", phar->fname);
 1142: 			}
 1143: 
 1144: 			php_stream_close(newfile);
 1145: 			return FAILURE;
 1146: 		}
 1147: 
 1148: 		efree(signature);
 1149: 		entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8;
 1150: 		entry.phar = phar;
 1151: 		/* throw out return value and write the signature */
 1152: 		phar_zip_changed_apply((void *)&entry, (void *)pass TSRMLS_CC);
 1153: 		php_stream_close(newfile);
 1154: 
 1155: 		if (pass->error && *(pass->error)) {
 1156: 			/* error is set by writeheaders */
 1157: 			php_stream_close(newfile);
 1158: 			return FAILURE;
 1159: 		}
 1160: 	} /* signature */
 1161: 	return SUCCESS;
 1162: }
 1163: /* }}} */
 1164: 
 1165: int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defaultstub, char **error TSRMLS_DC) /* {{{ */
 1166: {
 1167: 	char *pos;
 1168: 	smart_str main_metadata_str = {0};
 1169: 	static const char newstub[] = "<?php // zip-based phar archive stub file\n__HALT_COMPILER();";
 1170: 	char halt_stub[] = "__HALT_COMPILER();";
 1171: 	char *tmp;
 1172: 	
 1173: 	php_stream *stubfile, *oldfile;
 1174: 	php_serialize_data_t metadata_hash;
 1175: 	int free_user_stub, closeoldfile = 0;
 1176: 	phar_entry_info entry = {0};
 1177: 	char *temperr = NULL;
 1178: 	struct _phar_zip_pass pass;
 1179: 	phar_zip_dir_end eocd;
 1180: 	php_uint32 cdir_size, cdir_offset;
 1181: 
 1182: 	pass.error = &temperr;
 1183: 	entry.flags = PHAR_ENT_PERM_DEF_FILE;
 1184: 	entry.timestamp = time(NULL);
 1185: 	entry.is_modified = 1;
 1186: 	entry.is_zip = 1;
 1187: 	entry.phar = phar;
 1188: 	entry.fp_type = PHAR_MOD;
 1189: 
 1190: 	if (phar->is_persistent) {
 1191: 		if (error) {
 1192: 			spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
 1193: 		}
 1194: 		return EOF;
 1195: 	}
 1196: 
 1197: 	if (phar->is_data) {
 1198: 		goto nostub;
 1199: 	}
 1200: 
 1201: 	/* set alias */
 1202: 	if (!phar->is_temporary_alias && phar->alias_len) {
 1203: 		entry.fp = php_stream_fopen_tmpfile();
 1204: 		if (entry.fp == NULL) {
 1205: 			spprintf(error, 0, "phar error: unable to create temporary file");
 1206: 			return EOF;
 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 (!(len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)) || !user_stub) {
 1256: 				if (error) {
 1257: 					spprintf(error, 0, "unable to read resource to copy stub to new zip-based phar \"%s\"", phar->fname);
 1258: 				}
 1259: 				return EOF;
 1260: 			}
 1261: 			free_user_stub = 1;
 1262: 		} else {
 1263: 			free_user_stub = 0;
 1264: 		}
 1265: 
 1266: 		tmp = estrndup(user_stub, len);
 1267: 		if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) {
 1268: 			efree(tmp);
 1269: 			if (error) {
 1270: 				spprintf(error, 0, "illegal stub for zip-based phar \"%s\"", phar->fname);
 1271: 			}
 1272: 			if (free_user_stub) {
 1273: 				efree(user_stub);
 1274: 			}
 1275: 			return EOF;
 1276: 		}
 1277: 		pos = user_stub + (pos - tmp);
 1278: 		efree(tmp);
 1279: 
 1280: 		len = pos - user_stub + 18;
 1281: 		entry.fp = php_stream_fopen_tmpfile();
 1282: 		if (entry.fp == NULL) {
 1283: 			spprintf(error, 0, "phar error: unable to create temporary file");
 1284: 			return EOF;
 1285: 		}
 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: 		if (entry.fp == NULL) {
 1320: 			spprintf(error, 0, "phar error: unable to create temporary file");
 1321: 			return EOF;
 1322: 		}
 1323: 		if (sizeof(newstub)-1 != php_stream_write(entry.fp, newstub, sizeof(newstub)-1)) {
 1324: 			php_stream_close(entry.fp);
 1325: 			if (error) {
 1326: 				spprintf(error, 0, "unable to %s stub in%szip-based phar \"%s\", failed", user_stub ? "overwrite" : "create", user_stub ? " " : " new ", phar->fname);
 1327: 			}
 1328: 			return EOF;
 1329: 		}
 1330: 
 1331: 		entry.uncompressed_filesize = entry.compressed_filesize = sizeof(newstub) - 1;
 1332: 		entry.filename = estrndup(".phar/stub.php", sizeof(".phar/stub.php")-1);
 1333: 		entry.filename_len = sizeof(".phar/stub.php")-1;
 1334: 
 1335: 		if (!defaultstub) {
 1336: 			if (!zend_hash_exists(&phar->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
 1337: 				if (SUCCESS != zend_hash_add(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
 1338: 					php_stream_close(entry.fp);
 1339: 					efree(entry.filename);
 1340: 					if (error) {
 1341: 						spprintf(error, 0, "unable to create stub in zip-based phar \"%s\"", phar->fname);
 1342: 					}
 1343: 					return EOF;
 1344: 				}
 1345: 			} else {
 1346: 				php_stream_close(entry.fp);
 1347: 				efree(entry.filename);
 1348: 			}
 1349: 		} else {
 1350: 			if (SUCCESS != zend_hash_update(&phar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
 1351: 				php_stream_close(entry.fp);
 1352: 				efree(entry.filename);
 1353: 				if (error) {
 1354: 					spprintf(error, 0, "unable to overwrite stub in zip-based phar \"%s\"", phar->fname);
 1355: 				}
 1356: 				return EOF;
 1357: 			}
 1358: 		}
 1359: 	}
 1360: nostub:
 1361: 	if (phar->fp && !phar->is_brandnew) {
 1362: 		oldfile = phar->fp;
 1363: 		closeoldfile = 0;
 1364: 		php_stream_rewind(oldfile);
 1365: 	} else {
 1366: 		oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
 1367: 		closeoldfile = oldfile != NULL;
 1368: 	}
 1369: 
 1370: 	/* save modified files to the zip */
 1371: 	pass.old = oldfile;
 1372: 	pass.filefp = php_stream_fopen_tmpfile();
 1373: 
 1374: 	if (!pass.filefp) {
 1375: fperror:
 1376: 		if (closeoldfile) {
 1377: 			php_stream_close(oldfile);
 1378: 		}
 1379: 		if (error) {
 1380: 			spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to open temporary file", phar->fname);
 1381: 		}
 1382: 		return EOF;
 1383: 	}
 1384: 
 1385: 	pass.centralfp = php_stream_fopen_tmpfile();
 1386: 
 1387: 	if (!pass.centralfp) {
 1388: 		goto fperror;
 1389: 	}
 1390: 
 1391: 	pass.free_fp = pass.free_ufp = 1;
 1392: 	memset(&eocd, 0, sizeof(eocd));
 1393: 
 1394: 	strncpy(eocd.signature, "PK\5\6", 4);
 1395: 	if (!phar->is_data && !phar->sig_flags) {
 1396: 		phar->sig_flags = PHAR_SIG_SHA1;
 1397: 	}
 1398: 	if (phar->sig_flags) {
 1399: 		PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest) + 1);
 1400: 		PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest) + 1);
 1401: 	} else {
 1402: 		PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest));
 1403: 		PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest));
 1404: 	}
 1405: 	zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass TSRMLS_CC);
 1406: 
 1407: 	if (phar->metadata) {
 1408: 		/* set phar metadata */
 1409: 		PHP_VAR_SERIALIZE_INIT(metadata_hash);
 1410: 		php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC);
 1411: 		PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
 1412: 	}
 1413: 	if (temperr) {
 1414: 		if (error) {
 1415: 			spprintf(error, 4096, "phar zip flush of \"%s\" failed: %s", phar->fname, temperr);
 1416: 		}
 1417: 		efree(temperr);
 1418: temperror:
 1419: 		php_stream_close(pass.centralfp);
 1420: nocentralerror:
 1421: 		if (phar->metadata) {
 1422: 			smart_str_free(&main_metadata_str);
 1423: 		}
 1424: 		php_stream_close(pass.filefp);
 1425: 		if (closeoldfile) {
 1426: 			php_stream_close(oldfile);
 1427: 		}
 1428: 		return EOF;
 1429: 	}
 1430: 
 1431: 	if (FAILURE == phar_zip_applysignature(phar, &pass, &main_metadata_str TSRMLS_CC)) {
 1432: 		goto temperror;
 1433: 	}
 1434: 
 1435: 	/* save zip */
 1436: 	cdir_size = php_stream_tell(pass.centralfp);
 1437: 	cdir_offset = php_stream_tell(pass.filefp);
 1438: 	PHAR_SET_32(eocd.cdir_size, cdir_size);
 1439: 	PHAR_SET_32(eocd.cdir_offset, cdir_offset);
 1440: 	php_stream_seek(pass.centralfp, 0, SEEK_SET);
 1441: 
 1442: 	{
 1443: 		size_t clen;
 1444: 		int ret = phar_stream_copy_to_stream(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL, &clen);
 1445: 		if (SUCCESS != ret || clen != cdir_size) {
 1446: 			if (error) {
 1447: 				spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write central-directory", phar->fname);
 1448: 			}
 1449: 			goto temperror;
 1450: 		}
 1451: 	}
 1452: 
 1453: 	php_stream_close(pass.centralfp);
 1454: 
 1455: 	if (phar->metadata) {
 1456: 		/* set phar metadata */
 1457: 		PHAR_SET_16(eocd.comment_len, main_metadata_str.len);
 1458: 
 1459: 		if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
 1460: 			if (error) {
 1461: 				spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname);
 1462: 			}
 1463: 			goto nocentralerror;
 1464: 		}
 1465: 
 1466: 		if (main_metadata_str.len != php_stream_write(pass.filefp, main_metadata_str.c, main_metadata_str.len)) {
 1467: 			if (error) {
 1468: 				spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write metadata to zip comment", phar->fname);
 1469: 			}
 1470: 			goto nocentralerror;
 1471: 		}
 1472: 
 1473: 		smart_str_free(&main_metadata_str);
 1474: 
 1475: 	} else {
 1476: 		if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) {
 1477: 			if (error) {
 1478: 				spprintf(error, 4096, "phar zip flush of \"%s\" failed: unable to write end of central-directory", phar->fname);
 1479: 			}
 1480: 			goto nocentralerror;
 1481: 		}
 1482: 	}
 1483: 
 1484: 	if (phar->fp && pass.free_fp) {
 1485: 		php_stream_close(phar->fp);
 1486: 	}
 1487: 
 1488: 	if (phar->ufp) {
 1489: 		if (pass.free_ufp) {
 1490: 			php_stream_close(phar->ufp);
 1491: 		}
 1492: 		phar->ufp = NULL;
 1493: 	}
 1494: 
 1495: 	/* re-open */
 1496: 	phar->is_brandnew = 0;
 1497: 
 1498: 	if (phar->donotflush) {
 1499: 		/* deferred flush */
 1500: 		phar->fp = pass.filefp;
 1501: 	} else {
 1502: 		phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
 1503: 		if (!phar->fp) {
 1504: 			if (closeoldfile) {
 1505: 				php_stream_close(oldfile);
 1506: 			}
 1507: 			phar->fp = pass.filefp;
 1508: 			if (error) {
 1509: 				spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
 1510: 			}
 1511: 			return EOF;
 1512: 		}
 1513: 		php_stream_rewind(pass.filefp);
 1514: 		phar_stream_copy_to_stream(pass.filefp, phar->fp, PHP_STREAM_COPY_ALL, NULL);
 1515: 		/* we could also reopen the file in "rb" mode but there is no need for that */
 1516: 		php_stream_close(pass.filefp);
 1517: 	}
 1518: 
 1519: 	if (closeoldfile) {
 1520: 		php_stream_close(oldfile);
 1521: 	}
 1522: 	return EOF;
 1523: }
 1524: /* }}} */
 1525: 
 1526: /*
 1527:  * Local variables:
 1528:  * tab-width: 4
 1529:  * c-basic-offset: 4
 1530:  * End:
 1531:  * vim600: noet sw=4 ts=4 fdm=marker
 1532:  * vim<600: noet sw=4 ts=4
 1533:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>