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