xref: /PHP-7.2/ext/phar/phar.c (revision 46561dab)
1 /*
2   +----------------------------------------------------------------------+
3   | phar php single-file executable PHP extension                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 2005-2018 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   |          Marcus Boerger <helly@php.net>                              |
17   +----------------------------------------------------------------------+
18 */
19 
20 /* $Id: ba76a9b0e06d536a9b602c782e38e6826cb4ee02 $ */
21 
22 #define PHAR_MAIN 1
23 #include "phar_internal.h"
24 #include "SAPI.h"
25 #include "func_interceptors.h"
26 
27 static void destroy_phar_data(zval *zv);
28 
29 ZEND_DECLARE_MODULE_GLOBALS(phar)
30 zend_string *(*phar_save_resolve_path)(const char *filename, int filename_len);
31 
32 /**
33  * set's phar->is_writeable based on the current INI value
34  */
phar_set_writeable_bit(zval * zv,void * argument)35 static int phar_set_writeable_bit(zval *zv, void *argument) /* {{{ */
36 {
37 	zend_bool keep = *(zend_bool *)argument;
38 	phar_archive_data *phar = (phar_archive_data *)Z_PTR_P(zv);
39 
40 	if (!phar->is_data) {
41 		phar->is_writeable = !keep;
42 	}
43 
44 	return ZEND_HASH_APPLY_KEEP;
45 }
46 /* }}} */
47 
48 /* if the original value is 0 (disabled), then allow setting/unsetting at will. Otherwise only allow 1 (enabled), and error on disabling */
ZEND_INI_MH(phar_ini_modify_handler)49 ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */
50 {
51 	zend_bool old, ini;
52 
53 	if (ZSTR_LEN(entry->name) == sizeof("phar.readonly")-1) {
54 		old = PHAR_G(readonly_orig);
55 	} else {
56 		old = PHAR_G(require_hash_orig);
57 	}
58 
59 	if (ZSTR_LEN(new_value) == 2 && !strcasecmp("on", ZSTR_VAL(new_value))) {
60 		ini = (zend_bool) 1;
61 	}
62 	else if (ZSTR_LEN(new_value) == 3 && !strcasecmp("yes", ZSTR_VAL(new_value))) {
63 		ini = (zend_bool) 1;
64 	}
65 	else if (ZSTR_LEN(new_value) == 4 && !strcasecmp("true", ZSTR_VAL(new_value))) {
66 		ini = (zend_bool) 1;
67 	}
68 	else {
69 		ini = (zend_bool) atoi(ZSTR_VAL(new_value));
70 	}
71 
72 	/* do not allow unsetting in runtime */
73 	if (stage == ZEND_INI_STAGE_STARTUP) {
74 		if (ZSTR_LEN(entry->name) == sizeof("phar.readonly")-1) {
75 			PHAR_G(readonly_orig) = ini;
76 		} else {
77 			PHAR_G(require_hash_orig) = ini;
78 		}
79 	} else if (old && !ini) {
80 		return FAILURE;
81 	}
82 
83 	if (ZSTR_LEN(entry->name) == sizeof("phar.readonly")-1) {
84 		PHAR_G(readonly) = ini;
85 		if (PHAR_G(request_init) && PHAR_G(phar_fname_map.u.flags)) {
86 			zend_hash_apply_with_argument(&(PHAR_G(phar_fname_map)), phar_set_writeable_bit, (void *)&ini);
87 		}
88 	} else {
89 		PHAR_G(require_hash) = ini;
90 	}
91 
92 	return SUCCESS;
93 }
94 /* }}}*/
95 
96 /* this global stores the global cached pre-parsed manifests */
97 HashTable cached_phars;
98 HashTable cached_alias;
99 
phar_split_cache_list(void)100 static void phar_split_cache_list(void) /* {{{ */
101 {
102 	char *tmp;
103 	char *key, *lasts, *end;
104 	char ds[2];
105 	phar_archive_data *phar;
106 	uint32_t i = 0;
107 
108 	if (!PHAR_G(cache_list) || !(PHAR_G(cache_list)[0])) {
109 		return;
110 	}
111 
112 	ds[0] = DEFAULT_DIR_SEPARATOR;
113 	ds[1] = '\0';
114 	tmp = estrdup(PHAR_G(cache_list));
115 
116 	/* fake request startup */
117 	PHAR_G(request_init) = 1;
118 	zend_hash_init(&EG(regular_list), 0, NULL, NULL, 0);
119 	EG(regular_list).nNextFreeElement=1;	/* we don't want resource id 0 */
120 
121 	PHAR_G(has_bz2) = zend_hash_str_exists(&module_registry, "bz2", sizeof("bz2")-1);
122 	PHAR_G(has_zlib) = zend_hash_str_exists(&module_registry, "zlib", sizeof("zlib")-1);
123 	/* these two are dummies and will be destroyed later */
124 	zend_hash_init(&cached_phars, sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data,  1);
125 	zend_hash_init(&cached_alias, sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
126 	/* these two are real and will be copied over cached_phars/cached_alias later */
127 	zend_hash_init(&(PHAR_G(phar_fname_map)), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data,  1);
128 	zend_hash_init(&(PHAR_G(phar_alias_map)), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
129 	PHAR_G(manifest_cached) = 1;
130 	PHAR_G(persist) = 1;
131 
132 	for (key = php_strtok_r(tmp, ds, &lasts);
133 			key;
134 			key = php_strtok_r(NULL, ds, &lasts)) {
135 		end = strchr(key, DEFAULT_DIR_SEPARATOR);
136 
137 		if (end) {
138 			if (SUCCESS == phar_open_from_filename(key, end - key, NULL, 0, 0, &phar, NULL)) {
139 finish_up:
140 				phar->phar_pos = i++;
141 				php_stream_close(phar->fp);
142 				phar->fp = NULL;
143 			} else {
144 finish_error:
145 				PHAR_G(persist) = 0;
146 				PHAR_G(manifest_cached) = 0;
147 				efree(tmp);
148 				zend_hash_destroy(&(PHAR_G(phar_fname_map)));
149 				PHAR_G(phar_fname_map.u.flags) = 0;
150 				zend_hash_destroy(&(PHAR_G(phar_alias_map)));
151 				PHAR_G(phar_alias_map.u.flags) = 0;
152 				zend_hash_destroy(&cached_phars);
153 				zend_hash_destroy(&cached_alias);
154 				zend_hash_graceful_reverse_destroy(&EG(regular_list));
155 				memset(&EG(regular_list), 0, sizeof(HashTable));
156 				/* free cached manifests */
157 				PHAR_G(request_init) = 0;
158 				return;
159 			}
160 		} else {
161 			if (SUCCESS == phar_open_from_filename(key, strlen(key), NULL, 0, 0, &phar, NULL)) {
162 				goto finish_up;
163 			} else {
164 				goto finish_error;
165 			}
166 		}
167 	}
168 
169 	PHAR_G(persist) = 0;
170 	PHAR_G(request_init) = 0;
171 	/* destroy dummy values from before */
172 	zend_hash_destroy(&cached_phars);
173 	zend_hash_destroy(&cached_alias);
174 	cached_phars = PHAR_G(phar_fname_map);
175 	cached_alias = PHAR_G(phar_alias_map);
176 	PHAR_G(phar_fname_map.u.flags) = 0;
177 	PHAR_G(phar_alias_map.u.flags) = 0;
178 	zend_hash_graceful_reverse_destroy(&EG(regular_list));
179 	memset(&EG(regular_list), 0, sizeof(HashTable));
180 	efree(tmp);
181 }
182 /* }}} */
183 
ZEND_INI_MH(phar_ini_cache_list)184 ZEND_INI_MH(phar_ini_cache_list) /* {{{ */
185 {
186 	PHAR_G(cache_list) = ZSTR_VAL(new_value);
187 
188 	if (stage == ZEND_INI_STAGE_STARTUP) {
189 		phar_split_cache_list();
190 	}
191 
192 	return SUCCESS;
193 }
194 /* }}} */
195 
196 PHP_INI_BEGIN()
197 	STD_PHP_INI_BOOLEAN("phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals)
198 	STD_PHP_INI_BOOLEAN("phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals)
199 	STD_PHP_INI_ENTRY("phar.cache_list", "", PHP_INI_SYSTEM, phar_ini_cache_list, cache_list, zend_phar_globals, phar_globals)
PHP_INI_END()200 PHP_INI_END()
201 
202 /**
203  * When all uses of a phar have been concluded, this frees the manifest
204  * and the phar slot
205  */
206 void phar_destroy_phar_data(phar_archive_data *phar) /* {{{ */
207 {
208 	if (phar->alias && phar->alias != phar->fname) {
209 		pefree(phar->alias, phar->is_persistent);
210 		phar->alias = NULL;
211 	}
212 
213 	if (phar->fname) {
214 		pefree(phar->fname, phar->is_persistent);
215 		phar->fname = NULL;
216 	}
217 
218 	if (phar->signature) {
219 		pefree(phar->signature, phar->is_persistent);
220 		phar->signature = NULL;
221 	}
222 
223 	if (phar->manifest.u.flags) {
224 		zend_hash_destroy(&phar->manifest);
225 		phar->manifest.u.flags = 0;
226 	}
227 
228 	if (phar->mounted_dirs.u.flags) {
229 		zend_hash_destroy(&phar->mounted_dirs);
230 		phar->mounted_dirs.u.flags = 0;
231 	}
232 
233 	if (phar->virtual_dirs.u.flags) {
234 		zend_hash_destroy(&phar->virtual_dirs);
235 		phar->virtual_dirs.u.flags = 0;
236 	}
237 
238 	if (Z_TYPE(phar->metadata) != IS_UNDEF) {
239 		if (phar->is_persistent) {
240 			if (phar->metadata_len) {
241 				/* for zip comments that are strings */
242 				free(Z_PTR(phar->metadata));
243 			} else {
244 				zval_internal_ptr_dtor(&phar->metadata);
245 			}
246 		} else {
247 			zval_ptr_dtor(&phar->metadata);
248 		}
249 		phar->metadata_len = 0;
250 		ZVAL_UNDEF(&phar->metadata);
251 	}
252 
253 	if (phar->fp) {
254 		php_stream_close(phar->fp);
255 		phar->fp = 0;
256 	}
257 
258 	if (phar->ufp) {
259 		php_stream_close(phar->ufp);
260 		phar->ufp = 0;
261 	}
262 
263 	pefree(phar, phar->is_persistent);
264 }
265 /* }}}*/
266 
267 /**
268  * Delete refcount and destruct if needed. On destruct return 1 else 0.
269  */
phar_archive_delref(phar_archive_data * phar)270 int phar_archive_delref(phar_archive_data *phar) /* {{{ */
271 {
272 	if (phar->is_persistent) {
273 		return 0;
274 	}
275 
276 	if (--phar->refcount < 0) {
277 		if (PHAR_G(request_done)
278 		|| zend_hash_str_del(&(PHAR_G(phar_fname_map)), phar->fname, phar->fname_len) != SUCCESS) {
279 			phar_destroy_phar_data(phar);
280 		}
281 		return 1;
282 	} else if (!phar->refcount) {
283 		/* invalidate phar cache */
284 		PHAR_G(last_phar) = NULL;
285 		PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
286 
287 		if (phar->fp && (!(phar->flags & PHAR_FILE_COMPRESSION_MASK) || !phar->alias)) {
288 			/* close open file handle - allows removal or rename of
289 			the file on windows, which has greedy locking
290 			only close if the archive was not already compressed.  If it
291 			was compressed, then the fp does not refer to the original file.
292 			We're also closing compressed files to save resources,
293 			but only if the archive isn't aliased. */
294 			php_stream_close(phar->fp);
295 			phar->fp = NULL;
296 		}
297 
298 		if (!zend_hash_num_elements(&phar->manifest)) {
299 			/* this is a new phar that has perhaps had an alias/metadata set, but has never
300 			been flushed */
301 			if (zend_hash_str_del(&(PHAR_G(phar_fname_map)), phar->fname, phar->fname_len) != SUCCESS) {
302 				phar_destroy_phar_data(phar);
303 			}
304 			return 1;
305 		}
306 	}
307 	return 0;
308 }
309 /* }}}*/
310 
311 /**
312  * Destroy phar's in shutdown, here we don't care about aliases
313  */
destroy_phar_data_only(zval * zv)314 static void destroy_phar_data_only(zval *zv) /* {{{ */
315 {
316 	phar_archive_data *phar_data = (phar_archive_data *) Z_PTR_P(zv);
317 
318 	if (EG(exception) || --phar_data->refcount < 0) {
319 		phar_destroy_phar_data(phar_data);
320 	}
321 }
322 /* }}}*/
323 
324 /**
325  * Delete aliases to phar's that got kicked out of the global table
326  */
phar_unalias_apply(zval * zv,void * argument)327 static int phar_unalias_apply(zval *zv, void *argument) /* {{{ */
328 {
329 	return Z_PTR_P(zv) == argument ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_KEEP;
330 }
331 /* }}} */
332 
333 /**
334  * Delete aliases to phar's that got kicked out of the global table
335  */
phar_tmpclose_apply(zval * zv)336 static int phar_tmpclose_apply(zval *zv) /* {{{ */
337 {
338 	phar_entry_info *entry = (phar_entry_info *) Z_PTR_P(zv);
339 
340 	if (entry->fp_type != PHAR_TMP) {
341 		return ZEND_HASH_APPLY_KEEP;
342 	}
343 
344 	if (entry->fp && !entry->fp_refcount) {
345 		php_stream_close(entry->fp);
346 		entry->fp = NULL;
347 	}
348 
349 	return ZEND_HASH_APPLY_KEEP;
350 }
351 /* }}} */
352 
353 /**
354  * Filename map destructor
355  */
destroy_phar_data(zval * zv)356 static void destroy_phar_data(zval *zv) /* {{{ */
357 {
358 	phar_archive_data *phar_data = (phar_archive_data *)Z_PTR_P(zv);
359 
360 	if (PHAR_G(request_ends)) {
361 		/* first, iterate over the manifest and close all PHAR_TMP entry fp handles,
362 		this prevents unnecessary unfreed stream resources */
363 		zend_hash_apply(&(phar_data->manifest), phar_tmpclose_apply);
364 		destroy_phar_data_only(zv);
365 		return;
366 	}
367 
368 	zend_hash_apply_with_argument(&(PHAR_G(phar_alias_map)), phar_unalias_apply, phar_data);
369 
370 	if (--phar_data->refcount < 0) {
371 		phar_destroy_phar_data(phar_data);
372 	}
373 }
374 /* }}}*/
375 
376 /**
377  * destructor for the manifest hash, frees each file's entry
378  */
destroy_phar_manifest_entry_int(phar_entry_info * entry)379 void destroy_phar_manifest_entry_int(phar_entry_info *entry) /* {{{ */
380 {
381 
382 	if (entry->cfp) {
383 		php_stream_close(entry->cfp);
384 		entry->cfp = 0;
385 	}
386 
387 	if (entry->fp) {
388 		php_stream_close(entry->fp);
389 		entry->fp = 0;
390 	}
391 
392 	if (Z_TYPE(entry->metadata) != IS_UNDEF) {
393 		if (entry->is_persistent) {
394 			if (entry->metadata_len) {
395 				/* for zip comments that are strings */
396 				free(Z_PTR(entry->metadata));
397 			} else {
398 				zval_internal_ptr_dtor(&entry->metadata);
399 			}
400 		} else {
401 			zval_ptr_dtor(&entry->metadata);
402 		}
403 		entry->metadata_len = 0;
404 		ZVAL_UNDEF(&entry->metadata);
405 	}
406 
407 	if (entry->metadata_str.s) {
408 		smart_str_free(&entry->metadata_str);
409 		entry->metadata_str.s = NULL;
410 	}
411 
412 	pefree(entry->filename, entry->is_persistent);
413 
414 	if (entry->link) {
415 		pefree(entry->link, entry->is_persistent);
416 		entry->link = 0;
417 	}
418 
419 	if (entry->tmp) {
420 		pefree(entry->tmp, entry->is_persistent);
421 		entry->tmp = 0;
422 	}
423 }
424 /* }}} */
425 
destroy_phar_manifest_entry(zval * zv)426 void destroy_phar_manifest_entry(zval *zv) /* {{{ */
427 {
428 	phar_entry_info *entry = Z_PTR_P(zv);
429 	destroy_phar_manifest_entry_int(entry);
430 	pefree(entry, entry->is_persistent);
431 }
432 /* }}} */
433 
phar_entry_delref(phar_entry_data * idata)434 int phar_entry_delref(phar_entry_data *idata) /* {{{ */
435 {
436 	int ret = 0;
437 
438 	if (idata->internal_file && !idata->internal_file->is_persistent) {
439 		if (--idata->internal_file->fp_refcount < 0) {
440 			idata->internal_file->fp_refcount = 0;
441 		}
442 
443 		if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
444 			php_stream_close(idata->fp);
445 		}
446 		/* if phar_get_or_create_entry_data returns a sub-directory, we have to free it */
447 		if (idata->internal_file->is_temp_dir) {
448 			destroy_phar_manifest_entry_int(idata->internal_file);
449 			efree(idata->internal_file);
450 		}
451 	}
452 
453 	phar_archive_delref(idata->phar);
454 	efree(idata);
455 	return ret;
456 }
457 /* }}} */
458 
459 /**
460  * Removes an entry, either by actually removing it or by marking it.
461  */
phar_entry_remove(phar_entry_data * idata,char ** error)462 void phar_entry_remove(phar_entry_data *idata, char **error) /* {{{ */
463 {
464 	phar_archive_data *phar;
465 
466 	phar = idata->phar;
467 
468 	if (idata->internal_file->fp_refcount < 2) {
469 		if (idata->fp && idata->fp != idata->phar->fp && idata->fp != idata->phar->ufp && idata->fp != idata->internal_file->fp) {
470 			php_stream_close(idata->fp);
471 		}
472 		zend_hash_str_del(&idata->phar->manifest, idata->internal_file->filename, idata->internal_file->filename_len);
473 		idata->phar->refcount--;
474 		efree(idata);
475 	} else {
476 		idata->internal_file->is_deleted = 1;
477 		phar_entry_delref(idata);
478 	}
479 
480 	if (!phar->donotflush) {
481 		phar_flush(phar, 0, 0, 0, error);
482 	}
483 }
484 /* }}} */
485 
486 #define MAPPHAR_ALLOC_FAIL(msg) \
487 	if (fp) {\
488 		php_stream_close(fp);\
489 	}\
490 	if (error) {\
491 		spprintf(error, 0, msg, fname);\
492 	}\
493 	return FAILURE;
494 
495 #define MAPPHAR_FAIL(msg) \
496 	efree(savebuf);\
497 	if (mydata) {\
498 		phar_destroy_phar_data(mydata);\
499 	}\
500 	if (signature) {\
501 		pefree(signature, PHAR_G(persist));\
502 	}\
503 	MAPPHAR_ALLOC_FAIL(msg)
504 
505 #ifdef WORDS_BIGENDIAN
506 # define PHAR_GET_32(buffer, var) \
507 	var = ((((unsigned char*)(buffer))[3]) << 24) \
508 		| ((((unsigned char*)(buffer))[2]) << 16) \
509 		| ((((unsigned char*)(buffer))[1]) <<  8) \
510 		| (((unsigned char*)(buffer))[0]); \
511 	(buffer) += 4
512 # define PHAR_GET_16(buffer, var) \
513 	var = ((((unsigned char*)(buffer))[1]) <<  8) \
514 		| (((unsigned char*)(buffer))[0]); \
515 	(buffer) += 2
516 #else
517 # define PHAR_GET_32(buffer, var) \
518 	memcpy(&var, buffer, sizeof(var)); \
519 	buffer += 4
520 # define PHAR_GET_16(buffer, var) \
521 	var = *(uint16_t*)(buffer); \
522 	buffer += 2
523 #endif
524 #define PHAR_ZIP_16(var) ((uint16_t)((((uint16_t)var[0]) & 0xff) | \
525 	(((uint16_t)var[1]) & 0xff) << 8))
526 #define PHAR_ZIP_32(var) ((uint32_t)((((uint32_t)var[0]) & 0xff) | \
527 	(((uint32_t)var[1]) & 0xff) << 8 | \
528 	(((uint32_t)var[2]) & 0xff) << 16 | \
529 	(((uint32_t)var[3]) & 0xff) << 24))
530 
531 /**
532  * Open an already loaded phar
533  */
phar_open_parsed_phar(char * fname,int fname_len,char * alias,int alias_len,int is_data,int options,phar_archive_data ** pphar,char ** error)534 int phar_open_parsed_phar(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error) /* {{{ */
535 {
536 	phar_archive_data *phar;
537 #ifdef PHP_WIN32
538 	char *unixfname;
539 #endif
540 
541 	if (error) {
542 		*error = NULL;
543 	}
544 #ifdef PHP_WIN32
545 	unixfname = estrndup(fname, fname_len);
546 	phar_unixify_path_separators(unixfname, fname_len);
547 
548 	if (SUCCESS == phar_get_archive(&phar, unixfname, fname_len, alias, alias_len, error)
549 		&& ((alias && fname_len == phar->fname_len
550 		&& !strncmp(unixfname, phar->fname, fname_len)) || !alias)
551 	) {
552 		phar_entry_info *stub;
553 		efree(unixfname);
554 #else
555 	if (SUCCESS == phar_get_archive(&phar, fname, fname_len, alias, alias_len, error)
556 		&& ((alias && fname_len == phar->fname_len
557 		&& !strncmp(fname, phar->fname, fname_len)) || !alias)
558 	) {
559 		phar_entry_info *stub;
560 #endif
561 		/* logic above is as follows:
562 		   If an explicit alias was requested, ensure the filename passed in
563 		   matches the phar's filename.
564 		   If no alias was passed in, then it can match either and be valid
565 		 */
566 
567 		if (!is_data) {
568 			/* prevent any ".phar" without a stub getting through */
569 			if (!phar->halt_offset && !phar->is_brandnew && (phar->is_tar || phar->is_zip)) {
570 				if (PHAR_G(readonly) && NULL == (stub = zend_hash_str_find_ptr(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1))) {
571 					if (error) {
572 						spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
573 					}
574 					return FAILURE;
575 				}
576 			}
577 		}
578 
579 		if (pphar) {
580 			*pphar = phar;
581 		}
582 
583 		return SUCCESS;
584 	} else {
585 #ifdef PHP_WIN32
586 		efree(unixfname);
587 #endif
588 		if (pphar) {
589 			*pphar = NULL;
590 		}
591 
592 		if (phar && error && !(options & REPORT_ERRORS)) {
593 			efree(error);
594 		}
595 
596 		return FAILURE;
597 	}
598 }
599 /* }}}*/
600 
601 /**
602  * Parse out metadata from the manifest for a single file
603  *
604  * Meta-data is in this format:
605  * [len32][data...]
606  *
607  * data is the serialized zval
608  */
609 int phar_parse_metadata(char **buffer, zval *metadata, uint32_t zip_metadata_len) /* {{{ */
610 {
611 	php_unserialize_data_t var_hash;
612 
613 	if (zip_metadata_len) {
614 		const unsigned char *p;
615 		unsigned char *p_buff = (unsigned char *)estrndup(*buffer, zip_metadata_len);
616 		p = p_buff;
617 		ZVAL_NULL(metadata);
618 		PHP_VAR_UNSERIALIZE_INIT(var_hash);
619 
620 		if (!php_var_unserialize(metadata, &p, p + zip_metadata_len, &var_hash)) {
621 			efree(p_buff);
622 			PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
623 			zval_ptr_dtor(metadata);
624 			ZVAL_UNDEF(metadata);
625 			return FAILURE;
626 		}
627 		efree(p_buff);
628 		PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
629 
630 		if (PHAR_G(persist)) {
631 			/* lazy init metadata */
632 			zval_ptr_dtor(metadata);
633 			Z_PTR_P(metadata) = pemalloc(zip_metadata_len, 1);
634 			memcpy(Z_PTR_P(metadata), *buffer, zip_metadata_len);
635 			return SUCCESS;
636 		}
637 	} else {
638 		ZVAL_UNDEF(metadata);
639 	}
640 
641 	return SUCCESS;
642 }
643 /* }}}*/
644 
645 /**
646  * Size of fixed fields in the manifest.
647  * See: http://php.net/manual/en/phar.fileformat.phar.php
648  */
649 #define MANIFEST_FIXED_LEN	18
650 
651 #define SAFE_PHAR_GET_32(buffer, endbuffer, var) \
652 	if (UNEXPECTED(buffer + 4 > endbuffer)) { \
653 		MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)"); \
654 	} \
655 	PHAR_GET_32(buffer, var);
656 
657 /**
658  * Does not check for a previously opened phar in the cache.
659  *
660  * Parse a new one and add it to the cache, returning either SUCCESS or
661  * FAILURE, and setting pphar to the pointer to the manifest entry
662  *
663  * This is used by phar_open_from_filename to process the manifest, but can be called
664  * directly.
665  */
666 static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, int alias_len, zend_long halt_offset, phar_archive_data** pphar, uint32_t compression, char **error) /* {{{ */
667 {
668 	char b32[4], *buffer, *endbuffer, *savebuf;
669 	phar_archive_data *mydata = NULL;
670 	phar_entry_info entry;
671 	uint32_t manifest_len, manifest_count, manifest_flags, manifest_index, tmp_len, sig_flags;
672 	uint16_t manifest_ver;
673 	uint32_t len;
674 	zend_long offset;
675 	int sig_len, register_alias = 0, temp_alias = 0;
676 	char *signature = NULL;
677 
678 	if (pphar) {
679 		*pphar = NULL;
680 	}
681 
682 	if (error) {
683 		*error = NULL;
684 	}
685 
686 	/* check for ?>\n and increment accordingly */
687 	if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
688 		MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
689 	}
690 
691 	buffer = b32;
692 
693 	if (3 != php_stream_read(fp, buffer, 3)) {
694 		MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
695 	}
696 
697 	if ((*buffer == ' ' || *buffer == '\n') && *(buffer + 1) == '?' && *(buffer + 2) == '>') {
698 		int nextchar;
699 		halt_offset += 3;
700 		if (EOF == (nextchar = php_stream_getc(fp))) {
701 			MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
702 		}
703 
704 		if ((char) nextchar == '\r') {
705 			/* if we have an \r we require an \n as well */
706 			if (EOF == (nextchar = php_stream_getc(fp)) || (char)nextchar != '\n') {
707 				MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at stub end)")
708 			}
709 			++halt_offset;
710 		}
711 
712 		if ((char) nextchar == '\n') {
713 			++halt_offset;
714 		}
715 	}
716 
717 	/* make sure we are at the right location to read the manifest */
718 	if (-1 == php_stream_seek(fp, halt_offset, SEEK_SET)) {
719 		MAPPHAR_ALLOC_FAIL("cannot seek to __HALT_COMPILER(); location in phar \"%s\"")
720 	}
721 
722 	/* read in manifest */
723 	buffer = b32;
724 
725 	if (4 != php_stream_read(fp, buffer, 4)) {
726 		MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated manifest at manifest length)")
727 	}
728 
729 	PHAR_GET_32(buffer, manifest_len);
730 
731 	if (manifest_len > 1048576 * 100) {
732 		/* prevent serious memory issues by limiting manifest to at most 100 MB in length */
733 		MAPPHAR_ALLOC_FAIL("manifest cannot be larger than 100 MB in phar \"%s\"")
734 	}
735 
736 	buffer = (char *)emalloc(manifest_len);
737 	savebuf = buffer;
738 	endbuffer = buffer + manifest_len;
739 
740 	if (manifest_len < MANIFEST_FIXED_LEN || manifest_len != php_stream_read(fp, buffer, manifest_len)) {
741 		MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
742 	}
743 
744 	/* extract the number of entries */
745 	SAFE_PHAR_GET_32(buffer, endbuffer, manifest_count);
746 
747 	if (manifest_count == 0) {
748 		MAPPHAR_FAIL("in phar \"%s\", manifest claims to have zero entries.  Phars must have at least 1 entry");
749 	}
750 
751 	/* extract API version, lowest nibble currently unused */
752 	manifest_ver = (((unsigned char)buffer[0]) << 8)
753 				 + ((unsigned char)buffer[1]);
754 	buffer += 2;
755 
756 	if ((manifest_ver & PHAR_API_VER_MASK) < PHAR_API_MIN_READ) {
757 		efree(savebuf);
758 		php_stream_close(fp);
759 		if (error) {
760 			spprintf(error, 0, "phar \"%s\" is API version %1.u.%1.u.%1.u, and cannot be processed", fname, manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0x0F);
761 		}
762 		return FAILURE;
763 	}
764 
765 	SAFE_PHAR_GET_32(buffer, endbuffer, manifest_flags);
766 
767 	manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK;
768 	manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK;
769 	/* remember whether this entire phar was compressed with gz/bzip2 */
770 	manifest_flags |= compression;
771 
772 	/* The lowest nibble contains the phar wide flags. The compression flags can */
773 	/* be ignored on reading because it is being generated anyways. */
774 	if (manifest_flags & PHAR_HDR_SIGNATURE) {
775 		char sig_buf[8], *sig_ptr = sig_buf;
776 		zend_off_t read_len;
777 		size_t end_of_phar;
778 
779 		if (-1 == php_stream_seek(fp, -8, SEEK_END)
780 		|| (read_len = php_stream_tell(fp)) < 20
781 		|| 8 != php_stream_read(fp, sig_buf, 8)
782 		|| memcmp(sig_buf+4, "GBMB", 4)) {
783 			efree(savebuf);
784 			php_stream_close(fp);
785 			if (error) {
786 				spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
787 			}
788 			return FAILURE;
789 		}
790 
791 		PHAR_GET_32(sig_ptr, sig_flags);
792 
793 		switch(sig_flags) {
794 			case PHAR_SIG_OPENSSL: {
795 				uint32_t signature_len;
796 				char *sig;
797 				zend_off_t whence;
798 
799 				/* we store the signature followed by the signature length */
800 				if (-1 == php_stream_seek(fp, -12, SEEK_CUR)
801 				|| 4 != php_stream_read(fp, sig_buf, 4)) {
802 					efree(savebuf);
803 					php_stream_close(fp);
804 					if (error) {
805 						spprintf(error, 0, "phar \"%s\" openssl signature length could not be read", fname);
806 					}
807 					return FAILURE;
808 				}
809 
810 				sig_ptr = sig_buf;
811 				PHAR_GET_32(sig_ptr, signature_len);
812 				sig = (char *) emalloc(signature_len);
813 				whence = signature_len + 4;
814 				whence = -whence;
815 
816 				if (-1 == php_stream_seek(fp, whence, SEEK_CUR)
817 				|| !(end_of_phar = php_stream_tell(fp))
818 				|| signature_len != php_stream_read(fp, sig, signature_len)) {
819 					efree(savebuf);
820 					efree(sig);
821 					php_stream_close(fp);
822 					if (error) {
823 						spprintf(error, 0, "phar \"%s\" openssl signature could not be read", fname);
824 					}
825 					return FAILURE;
826 				}
827 
828 				if (FAILURE == phar_verify_signature(fp, end_of_phar, PHAR_SIG_OPENSSL, sig, signature_len, fname, &signature, &sig_len, error)) {
829 					efree(savebuf);
830 					efree(sig);
831 					php_stream_close(fp);
832 					if (error) {
833 						char *save = *error;
834 						spprintf(error, 0, "phar \"%s\" openssl signature could not be verified: %s", fname, *error);
835 						efree(save);
836 					}
837 					return FAILURE;
838 				}
839 				efree(sig);
840 			}
841 			break;
842 #if PHAR_HASH_OK
843 			case PHAR_SIG_SHA512: {
844 				unsigned char digest[64];
845 
846 				php_stream_seek(fp, -(8 + 64), SEEK_END);
847 				read_len = php_stream_tell(fp);
848 
849 				if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
850 					efree(savebuf);
851 					php_stream_close(fp);
852 					if (error) {
853 						spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
854 					}
855 					return FAILURE;
856 				}
857 
858 				if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA512, (char *)digest, 64, fname, &signature, &sig_len, error)) {
859 					efree(savebuf);
860 					php_stream_close(fp);
861 					if (error) {
862 						char *save = *error;
863 						spprintf(error, 0, "phar \"%s\" SHA512 signature could not be verified: %s", fname, *error);
864 						efree(save);
865 					}
866 					return FAILURE;
867 				}
868 				break;
869 			}
870 			case PHAR_SIG_SHA256: {
871 				unsigned char digest[32];
872 
873 				php_stream_seek(fp, -(8 + 32), SEEK_END);
874 				read_len = php_stream_tell(fp);
875 
876 				if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
877 					efree(savebuf);
878 					php_stream_close(fp);
879 					if (error) {
880 						spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
881 					}
882 					return FAILURE;
883 				}
884 
885 				if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA256, (char *)digest, 32, fname, &signature, &sig_len, error)) {
886 					efree(savebuf);
887 					php_stream_close(fp);
888 					if (error) {
889 						char *save = *error;
890 						spprintf(error, 0, "phar \"%s\" SHA256 signature could not be verified: %s", fname, *error);
891 						efree(save);
892 					}
893 					return FAILURE;
894 				}
895 				break;
896 			}
897 #else
898 			case PHAR_SIG_SHA512:
899 			case PHAR_SIG_SHA256:
900 				efree(savebuf);
901 				php_stream_close(fp);
902 
903 				if (error) {
904 					spprintf(error, 0, "phar \"%s\" has a unsupported signature", fname);
905 				}
906 				return FAILURE;
907 #endif
908 			case PHAR_SIG_SHA1: {
909 				unsigned char digest[20];
910 
911 				php_stream_seek(fp, -(8 + 20), SEEK_END);
912 				read_len = php_stream_tell(fp);
913 
914 				if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
915 					efree(savebuf);
916 					php_stream_close(fp);
917 					if (error) {
918 						spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
919 					}
920 					return FAILURE;
921 				}
922 
923 				if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_SHA1, (char *)digest, 20, fname, &signature, &sig_len, error)) {
924 					efree(savebuf);
925 					php_stream_close(fp);
926 					if (error) {
927 						char *save = *error;
928 						spprintf(error, 0, "phar \"%s\" SHA1 signature could not be verified: %s", fname, *error);
929 						efree(save);
930 					}
931 					return FAILURE;
932 				}
933 				break;
934 			}
935 			case PHAR_SIG_MD5: {
936 				unsigned char digest[16];
937 
938 				php_stream_seek(fp, -(8 + 16), SEEK_END);
939 				read_len = php_stream_tell(fp);
940 
941 				if (php_stream_read(fp, (char*)digest, sizeof(digest)) != sizeof(digest)) {
942 					efree(savebuf);
943 					php_stream_close(fp);
944 					if (error) {
945 						spprintf(error, 0, "phar \"%s\" has a broken signature", fname);
946 					}
947 					return FAILURE;
948 				}
949 
950 				if (FAILURE == phar_verify_signature(fp, read_len, PHAR_SIG_MD5, (char *)digest, 16, fname, &signature, &sig_len, error)) {
951 					efree(savebuf);
952 					php_stream_close(fp);
953 					if (error) {
954 						char *save = *error;
955 						spprintf(error, 0, "phar \"%s\" MD5 signature could not be verified: %s", fname, *error);
956 						efree(save);
957 					}
958 					return FAILURE;
959 				}
960 				break;
961 			}
962 			default:
963 				efree(savebuf);
964 				php_stream_close(fp);
965 
966 				if (error) {
967 					spprintf(error, 0, "phar \"%s\" has a broken or unsupported signature", fname);
968 				}
969 				return FAILURE;
970 		}
971 	} else if (PHAR_G(require_hash)) {
972 		efree(savebuf);
973 		php_stream_close(fp);
974 
975 		if (error) {
976 			spprintf(error, 0, "phar \"%s\" does not have a signature", fname);
977 		}
978 		return FAILURE;
979 	} else {
980 		sig_flags = 0;
981 		sig_len = 0;
982 	}
983 
984 	/* extract alias */
985 	SAFE_PHAR_GET_32(buffer, endbuffer, tmp_len);
986 
987 	if (buffer + tmp_len > endbuffer) {
988 		MAPPHAR_FAIL("internal corruption of phar \"%s\" (buffer overrun)");
989 	}
990 
991 	if (manifest_len < MANIFEST_FIXED_LEN + tmp_len) {
992 		MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)")
993 	}
994 
995 	/* tmp_len = 0 says alias length is 0, which means the alias is not stored in the phar */
996 	if (tmp_len) {
997 		/* if the alias is stored we enforce it (implicit overrides explicit) */
998 		if (alias && alias_len && (alias_len != (int)tmp_len || strncmp(alias, buffer, tmp_len)))
999 		{
1000 			php_stream_close(fp);
1001 
1002 			if (signature) {
1003 				efree(signature);
1004 			}
1005 
1006 			if (error) {
1007 				spprintf(error, 0, "cannot load phar \"%s\" with implicit alias \"%.*s\" under different alias \"%s\"", fname, tmp_len, buffer, alias);
1008 			}
1009 
1010 			efree(savebuf);
1011 			return FAILURE;
1012 		}
1013 
1014 		alias_len = tmp_len;
1015 		alias = buffer;
1016 		buffer += tmp_len;
1017 		register_alias = 1;
1018 	} else if (!alias_len || !alias) {
1019 		/* if we neither have an explicit nor an implicit alias, we use the filename */
1020 		alias = NULL;
1021 		alias_len = 0;
1022 		register_alias = 0;
1023 	} else if (alias_len) {
1024 		register_alias = 1;
1025 		temp_alias = 1;
1026 	}
1027 
1028 	/* we have 5 32-bit items plus 1 byte at least */
1029 	if (manifest_count > ((manifest_len - MANIFEST_FIXED_LEN - tmp_len) / (5 * 4 + 1))) {
1030 		/* prevent serious memory issues */
1031 		MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)")
1032 	}
1033 
1034 	mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
1035 	mydata->is_persistent = PHAR_G(persist);
1036 
1037 	/* check whether we have meta data, zero check works regardless of byte order */
1038 	SAFE_PHAR_GET_32(buffer, endbuffer, len);
1039 	if (mydata->is_persistent) {
1040 		mydata->metadata_len = len;
1041 		if (!len) {
1042 			/* FIXME: not sure why this is needed but removing it breaks tests */
1043 			SAFE_PHAR_GET_32(buffer, endbuffer, len);
1044 		}
1045 	}
1046 	if(len > (size_t)(endbuffer - buffer)) {
1047 		MAPPHAR_FAIL("internal corruption of phar \"%s\" (trying to read past buffer end)");
1048 	}
1049 	if (phar_parse_metadata(&buffer, &mydata->metadata, len) == FAILURE) {
1050 		MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\"");
1051 	}
1052 	buffer += len;
1053 
1054 	/* set up our manifest */
1055 	zend_hash_init(&mydata->manifest, manifest_count,
1056 		zend_get_hash_value, destroy_phar_manifest_entry, (zend_bool)mydata->is_persistent);
1057 	zend_hash_init(&mydata->mounted_dirs, 5,
1058 		zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
1059 	zend_hash_init(&mydata->virtual_dirs, manifest_count * 2,
1060 		zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
1061 	mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
1062 #ifdef PHP_WIN32
1063 	phar_unixify_path_separators(mydata->fname, fname_len);
1064 #endif
1065 	mydata->fname_len = fname_len;
1066 	offset = halt_offset + manifest_len + 4;
1067 	memset(&entry, 0, sizeof(phar_entry_info));
1068 	entry.phar = mydata;
1069 	entry.fp_type = PHAR_FP;
1070 	entry.is_persistent = mydata->is_persistent;
1071 
1072 	for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) {
1073 		if (buffer + 28 > endbuffer) {
1074 			MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)")
1075 		}
1076 
1077 		PHAR_GET_32(buffer, entry.filename_len);
1078 
1079 		if (entry.filename_len == 0) {
1080 			MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\"");
1081 		}
1082 
1083 		if (entry.is_persistent) {
1084 			entry.manifest_pos = manifest_index;
1085 		}
1086 
1087 		if (entry.filename_len > (size_t)(endbuffer - buffer - 24)) {
1088 			MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
1089 		}
1090 
1091 		if ((manifest_ver & PHAR_API_VER_MASK) >= PHAR_API_MIN_DIR && buffer[entry.filename_len - 1] == '/') {
1092 			entry.is_dir = 1;
1093 		} else {
1094 			entry.is_dir = 0;
1095 		}
1096 
1097 		phar_add_virtual_dirs(mydata, buffer, entry.filename_len);
1098 		entry.filename = pestrndup(buffer, entry.filename_len, entry.is_persistent);
1099 		buffer += entry.filename_len;
1100 		PHAR_GET_32(buffer, entry.uncompressed_filesize);
1101 		PHAR_GET_32(buffer, entry.timestamp);
1102 
1103 		if (offset == halt_offset + (int)manifest_len + 4) {
1104 			mydata->min_timestamp = entry.timestamp;
1105 			mydata->max_timestamp = entry.timestamp;
1106 		} else {
1107 			if (mydata->min_timestamp > entry.timestamp) {
1108 				mydata->min_timestamp = entry.timestamp;
1109 			} else if (mydata->max_timestamp < entry.timestamp) {
1110 				mydata->max_timestamp = entry.timestamp;
1111 			}
1112 		}
1113 
1114 		PHAR_GET_32(buffer, entry.compressed_filesize);
1115 		PHAR_GET_32(buffer, entry.crc32);
1116 		PHAR_GET_32(buffer, entry.flags);
1117 
1118 		if (entry.is_dir) {
1119 			entry.filename_len--;
1120 			entry.flags |= PHAR_ENT_PERM_DEF_DIR;
1121 		}
1122 
1123 		PHAR_GET_32(buffer, len);
1124 		if (entry.is_persistent) {
1125 			entry.metadata_len = len;
1126 		} else {
1127 			entry.metadata_len = 0;
1128 		}
1129 		if (len > (size_t)(endbuffer - buffer)) {
1130 			pefree(entry.filename, entry.is_persistent);
1131 			MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
1132 		}
1133 		if (phar_parse_metadata(&buffer, &entry.metadata, len) == FAILURE) {
1134 			pefree(entry.filename, entry.is_persistent);
1135 			MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\"");
1136 		}
1137 		buffer += len;
1138 
1139 		entry.offset = entry.offset_abs = offset;
1140 		offset += entry.compressed_filesize;
1141 
1142 		switch (entry.flags & PHAR_ENT_COMPRESSION_MASK) {
1143 			case PHAR_ENT_COMPRESSED_GZ:
1144 				if (!PHAR_G(has_zlib)) {
1145 					if (Z_TYPE(entry.metadata) != IS_UNDEF) {
1146 						if (entry.is_persistent) {
1147 							free(Z_PTR(entry.metadata));
1148 						} else {
1149 							zval_ptr_dtor(&entry.metadata);
1150 						}
1151 					}
1152 					pefree(entry.filename, entry.is_persistent);
1153 					MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\"");
1154 				}
1155 				break;
1156 			case PHAR_ENT_COMPRESSED_BZ2:
1157 				if (!PHAR_G(has_bz2)) {
1158 					if (Z_TYPE(entry.metadata) != IS_UNDEF) {
1159 						if (entry.is_persistent) {
1160 							free(Z_PTR(entry.metadata));
1161 						} else {
1162 							zval_ptr_dtor(&entry.metadata);
1163 						}
1164 					}
1165 					pefree(entry.filename, entry.is_persistent);
1166 					MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\"");
1167 				}
1168 				break;
1169 			default:
1170 				if (entry.uncompressed_filesize != entry.compressed_filesize) {
1171 					if (Z_TYPE(entry.metadata) != IS_UNDEF) {
1172 						if (entry.is_persistent) {
1173 							free(Z_PTR(entry.metadata));
1174 						} else {
1175 							zval_ptr_dtor(&entry.metadata);
1176 						}
1177 					}
1178 					pefree(entry.filename, entry.is_persistent);
1179 					MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)");
1180 				}
1181 				break;
1182 		}
1183 
1184 		manifest_flags |= (entry.flags & PHAR_ENT_COMPRESSION_MASK);
1185 		/* if signature matched, no need to check CRC32 for each file */
1186 		entry.is_crc_checked = (manifest_flags & PHAR_HDR_SIGNATURE ? 1 : 0);
1187 		phar_set_inode(&entry);
1188 		zend_hash_str_add_mem(&mydata->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info));
1189 	}
1190 
1191 	snprintf(mydata->version, sizeof(mydata->version), "%u.%u.%u", manifest_ver >> 12, (manifest_ver >> 8) & 0xF, (manifest_ver >> 4) & 0xF);
1192 	mydata->internal_file_start = halt_offset + manifest_len + 4;
1193 	mydata->halt_offset = halt_offset;
1194 	mydata->flags = manifest_flags;
1195 	endbuffer = strrchr(mydata->fname, '/');
1196 
1197 	if (endbuffer) {
1198 		mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer);
1199 		if (mydata->ext == endbuffer) {
1200 			mydata->ext = memchr(endbuffer + 1, '.', (mydata->fname + fname_len) - endbuffer - 1);
1201 		}
1202 		if (mydata->ext) {
1203 			mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext;
1204 		}
1205 	}
1206 
1207 	mydata->alias = alias ?
1208 		pestrndup(alias, alias_len, mydata->is_persistent) :
1209 		pestrndup(mydata->fname, fname_len, mydata->is_persistent);
1210 	mydata->alias_len = alias ? alias_len : fname_len;
1211 	mydata->sig_flags = sig_flags;
1212 	mydata->fp = fp;
1213 	mydata->sig_len = sig_len;
1214 	mydata->signature = signature;
1215 	phar_request_initialize();
1216 
1217 	if (register_alias) {
1218 		phar_archive_data *fd_ptr;
1219 
1220 		mydata->is_temporary_alias = temp_alias;
1221 
1222 		if (!phar_validate_alias(mydata->alias, mydata->alias_len)) {
1223 			signature = NULL;
1224 			fp = NULL;
1225 			MAPPHAR_FAIL("Cannot open archive \"%s\", invalid alias");
1226 		}
1227 
1228 		if (NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
1229 			if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len)) {
1230 				signature = NULL;
1231 				fp = NULL;
1232 				MAPPHAR_FAIL("Cannot open archive \"%s\", alias is already in use by existing archive");
1233 			}
1234 		}
1235 
1236 		zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, mydata);
1237 	} else {
1238 		mydata->is_temporary_alias = 1;
1239 	}
1240 
1241 	zend_hash_str_add_ptr(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len, mydata);
1242 	efree(savebuf);
1243 
1244 	if (pphar) {
1245 		*pphar = mydata;
1246 	}
1247 
1248 	return SUCCESS;
1249 }
1250 /* }}} */
1251 
1252 /**
1253  * Create or open a phar for writing
1254  */
1255 int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error) /* {{{ */
1256 {
1257 	const char *ext_str, *z;
1258 	char *my_error;
1259 	int ext_len;
1260 	phar_archive_data **test, *unused = NULL;
1261 
1262 	test = &unused;
1263 
1264 	if (error) {
1265 		*error = NULL;
1266 	}
1267 
1268 	/* first try to open an existing file */
1269 	if (phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 0, 1) == SUCCESS) {
1270 		goto check_file;
1271 	}
1272 
1273 	/* next try to create a new file */
1274 	if (FAILURE == phar_detect_phar_fname_ext(fname, fname_len, &ext_str, &ext_len, !is_data, 1, 1)) {
1275 		if (error) {
1276 			if (ext_len == -2) {
1277 				spprintf(error, 0, "Cannot create a phar archive from a URL like \"%s\". Phar objects can only be created from local files", fname);
1278 			} else {
1279 				spprintf(error, 0, "Cannot create phar '%s', file extension (or combination) not recognised or the directory does not exist", fname);
1280 			}
1281 		}
1282 		return FAILURE;
1283 	}
1284 check_file:
1285 	if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, test, &my_error) == SUCCESS) {
1286 		if (pphar) {
1287 			*pphar = *test;
1288 		}
1289 
1290 		if ((*test)->is_data && !(*test)->is_tar && !(*test)->is_zip) {
1291 			if (error) {
1292 				spprintf(error, 0, "Cannot open '%s' as a PharData object. Use Phar::__construct() for executable archives", fname);
1293 			}
1294 			return FAILURE;
1295 		}
1296 
1297 		if (PHAR_G(readonly) && !(*test)->is_data && ((*test)->is_tar || (*test)->is_zip)) {
1298 			phar_entry_info *stub;
1299 			if (NULL == (stub = zend_hash_str_find_ptr(&((*test)->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1))) {
1300 				spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname);
1301 				return FAILURE;
1302 			}
1303 		}
1304 
1305 		if (!PHAR_G(readonly) || (*test)->is_data) {
1306 			(*test)->is_writeable = 1;
1307 		}
1308 		return SUCCESS;
1309 	} else if (my_error) {
1310 		if (error) {
1311 			*error = my_error;
1312 		} else {
1313 			efree(my_error);
1314 		}
1315 		return FAILURE;
1316 	}
1317 
1318 	if (ext_len > 3 && (z = memchr(ext_str, 'z', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ip", 2)) {
1319 		/* assume zip-based phar */
1320 		return phar_open_or_create_zip(fname, fname_len, alias, alias_len, is_data, options, pphar, error);
1321 	}
1322 
1323 	if (ext_len > 3 && (z = memchr(ext_str, 't', ext_len)) && ((ext_str + ext_len) - z >= 2) && !memcmp(z + 1, "ar", 2)) {
1324 		/* assume tar-based phar */
1325 		return phar_open_or_create_tar(fname, fname_len, alias, alias_len, is_data, options, pphar, error);
1326 	}
1327 
1328 	return phar_create_or_parse_filename(fname, fname_len, alias, alias_len, is_data, options, pphar, error);
1329 }
1330 /* }}} */
1331 
1332 int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error) /* {{{ */
1333 {
1334 	phar_archive_data *mydata;
1335 	php_stream *fp;
1336 	zend_string *actual = NULL;
1337 	char *p;
1338 
1339 	if (!pphar) {
1340 		pphar = &mydata;
1341 	}
1342 	if (php_check_open_basedir(fname)) {
1343 		return FAILURE;
1344 	}
1345 
1346 	/* first open readonly so it won't be created if not present */
1347 	fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, &actual);
1348 
1349 	if (actual) {
1350 		fname = ZSTR_VAL(actual);
1351 		fname_len = ZSTR_LEN(actual);
1352 	}
1353 
1354 	if (fp) {
1355 		if (phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error) == SUCCESS) {
1356 			if ((*pphar)->is_data || !PHAR_G(readonly)) {
1357 				(*pphar)->is_writeable = 1;
1358 			}
1359 			if (actual) {
1360 				zend_string_release(actual);
1361 			}
1362 			return SUCCESS;
1363 		} else {
1364 			/* file exists, but is either corrupt or not a phar archive */
1365 			if (actual) {
1366 				zend_string_release(actual);
1367 			}
1368 			return FAILURE;
1369 		}
1370 	}
1371 
1372 	if (actual) {
1373 		zend_string_release(actual);
1374 	}
1375 
1376 	if (PHAR_G(readonly) && !is_data) {
1377 		if (options & REPORT_ERRORS) {
1378 			if (error) {
1379 				spprintf(error, 0, "creating archive \"%s\" disabled by the php.ini setting phar.readonly", fname);
1380 			}
1381 		}
1382 		return FAILURE;
1383 	}
1384 
1385 	/* set up our manifest */
1386 	mydata = ecalloc(1, sizeof(phar_archive_data));
1387 	mydata->fname = expand_filepath(fname, NULL);
1388 	if (mydata->fname == NULL) {
1389 		efree(mydata);
1390 		return FAILURE;
1391 	}
1392 	fname_len = strlen(mydata->fname);
1393 #ifdef PHP_WIN32
1394 	phar_unixify_path_separators(mydata->fname, fname_len);
1395 #endif
1396 	p = strrchr(mydata->fname, '/');
1397 
1398 	if (p) {
1399 		mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p);
1400 		if (mydata->ext == p) {
1401 			mydata->ext = memchr(p + 1, '.', (mydata->fname + fname_len) - p - 1);
1402 		}
1403 		if (mydata->ext) {
1404 			mydata->ext_len = (mydata->fname + fname_len) - mydata->ext;
1405 		}
1406 	}
1407 
1408 	if (pphar) {
1409 		*pphar = mydata;
1410 	}
1411 
1412 	zend_hash_init(&mydata->manifest, sizeof(phar_entry_info),
1413 		zend_get_hash_value, destroy_phar_manifest_entry, 0);
1414 	zend_hash_init(&mydata->mounted_dirs, sizeof(char *),
1415 		zend_get_hash_value, NULL, 0);
1416 	zend_hash_init(&mydata->virtual_dirs, sizeof(char *),
1417 		zend_get_hash_value, NULL, (zend_bool)mydata->is_persistent);
1418 	mydata->fname_len = fname_len;
1419 	snprintf(mydata->version, sizeof(mydata->version), "%s", PHP_PHAR_API_VERSION);
1420 	mydata->is_temporary_alias = alias ? 0 : 1;
1421 	mydata->internal_file_start = -1;
1422 	mydata->fp = NULL;
1423 	mydata->is_writeable = 1;
1424 	mydata->is_brandnew = 1;
1425 	phar_request_initialize();
1426 	zend_hash_str_add_ptr(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len, mydata);
1427 
1428 	if (is_data) {
1429 		alias = NULL;
1430 		alias_len = 0;
1431 		mydata->is_data = 1;
1432 		/* assume tar format, PharData can specify other */
1433 		mydata->is_tar = 1;
1434 	} else {
1435 		phar_archive_data *fd_ptr;
1436 
1437 		if (alias && NULL != (fd_ptr = zend_hash_str_find_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len))) {
1438 			if (SUCCESS != phar_free_alias(fd_ptr, alias, alias_len)) {
1439 				if (error) {
1440 					spprintf(error, 4096, "phar error: phar \"%s\" cannot set alias \"%s\", already in use by another phar archive", mydata->fname, alias);
1441 				}
1442 
1443 				zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
1444 
1445 				if (pphar) {
1446 					*pphar = NULL;
1447 				}
1448 
1449 				return FAILURE;
1450 			}
1451 		}
1452 
1453 		mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
1454 		mydata->alias_len = alias ? alias_len : fname_len;
1455 	}
1456 
1457 	if (alias_len && alias) {
1458 		if (NULL == zend_hash_str_add_ptr(&(PHAR_G(phar_alias_map)), alias, alias_len, mydata)) {
1459 			if (options & REPORT_ERRORS) {
1460 				if (error) {
1461 					spprintf(error, 0, "archive \"%s\" cannot be associated with alias \"%s\", already in use", fname, alias);
1462 				}
1463 			}
1464 
1465 			zend_hash_str_del(&(PHAR_G(phar_fname_map)), mydata->fname, fname_len);
1466 
1467 			if (pphar) {
1468 				*pphar = NULL;
1469 			}
1470 
1471 			return FAILURE;
1472 		}
1473 	}
1474 
1475 	return SUCCESS;
1476 }
1477 /* }}}*/
1478 
1479 /**
1480  * Return an already opened filename.
1481  *
1482  * Or scan a phar file for the required __HALT_COMPILER(); ?> token and verify
1483  * that the manifest is proper, then pass it to phar_parse_pharfile().  SUCCESS
1484  * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
1485  */
1486 int phar_open_from_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error) /* {{{ */
1487 {
1488 	php_stream *fp;
1489 	zend_string *actual;
1490 	int ret, is_data = 0;
1491 
1492 	if (error) {
1493 		*error = NULL;
1494 	}
1495 
1496 	if (!strstr(fname, ".phar")) {
1497 		is_data = 1;
1498 	}
1499 
1500 	if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, is_data, options, pphar, error) == SUCCESS) {
1501 		return SUCCESS;
1502 	} else if (error && *error) {
1503 		return FAILURE;
1504 	}
1505 	if (php_check_open_basedir(fname)) {
1506 		return FAILURE;
1507 	}
1508 
1509 	fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);
1510 
1511 	if (!fp) {
1512 		if (options & REPORT_ERRORS) {
1513 			if (error) {
1514 				spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
1515 			}
1516 		}
1517 		if (actual) {
1518 			zend_string_release(actual);
1519 		}
1520 		return FAILURE;
1521 	}
1522 
1523 	if (actual) {
1524 		fname = ZSTR_VAL(actual);
1525 		fname_len = ZSTR_LEN(actual);
1526 	}
1527 
1528 	ret =  phar_open_from_fp(fp, fname, fname_len, alias, alias_len, options, pphar, is_data, error);
1529 
1530 	if (actual) {
1531 		zend_string_release(actual);
1532 	}
1533 
1534 	return ret;
1535 }
1536 /* }}}*/
1537 
1538 static inline char *phar_strnstr(const char *buf, int buf_len, const char *search, int search_len) /* {{{ */
1539 {
1540 	const char *c;
1541 	ptrdiff_t so_far = 0;
1542 
1543 	if (buf_len < search_len) {
1544 		return NULL;
1545 	}
1546 
1547 	c = buf - 1;
1548 
1549 	do {
1550 		if (!(c = memchr(c + 1, search[0], buf_len - search_len - so_far))) {
1551 			return (char *) NULL;
1552 		}
1553 
1554 		so_far = c - buf;
1555 
1556 		if (so_far >= (buf_len - search_len)) {
1557 			return (char *) NULL;
1558 		}
1559 
1560 		if (!memcmp(c, search, search_len)) {
1561 			return (char *) c;
1562 		}
1563 	} while (1);
1564 }
1565 /* }}} */
1566 
1567 /**
1568  * Scan an open fp for the required __HALT_COMPILER(); ?> token and verify
1569  * that the manifest is proper, then pass it to phar_parse_pharfile().  SUCCESS
1570  * or FAILURE is returned and pphar is set to a pointer to the phar's manifest
1571  */
1572 static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, int is_data, char **error) /* {{{ */
1573 {
1574 	const char token[] = "__HALT_COMPILER();";
1575 	const char zip_magic[] = "PK\x03\x04";
1576 	const char gz_magic[] = "\x1f\x8b\x08";
1577 	const char bz_magic[] = "BZh";
1578 	char *pos, test = '\0';
1579 	const int window_size = 1024;
1580 	char buffer[1024 + sizeof(token)]; /* a 1024 byte window + the size of the halt_compiler token (moving window) */
1581 	const zend_long readsize = sizeof(buffer) - sizeof(token);
1582 	const zend_long tokenlen = sizeof(token) - 1;
1583 	zend_long halt_offset;
1584 	size_t got;
1585 	uint32_t compression = PHAR_FILE_COMPRESSED_NONE;
1586 
1587 	if (error) {
1588 		*error = NULL;
1589 	}
1590 
1591 	if (-1 == php_stream_rewind(fp)) {
1592 		MAPPHAR_ALLOC_FAIL("cannot rewind phar \"%s\"")
1593 	}
1594 
1595 	buffer[sizeof(buffer)-1] = '\0';
1596 	memset(buffer, 32, sizeof(token));
1597 	halt_offset = 0;
1598 
1599 	/* Maybe it's better to compile the file instead of just searching,  */
1600 	/* but we only want the offset. So we want a .re scanner to find it. */
1601 	while(!php_stream_eof(fp)) {
1602 		if ((got = php_stream_read(fp, buffer+tokenlen, readsize)) < (size_t) tokenlen) {
1603 			MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (truncated entry)")
1604 		}
1605 
1606 		if (!test) {
1607 			test = '\1';
1608 			pos = buffer+tokenlen;
1609 			if (!memcmp(pos, gz_magic, 3)) {
1610 				char err = 0;
1611 				php_stream_filter *filter;
1612 				php_stream *temp;
1613 				/* to properly decompress, we have to tell zlib to look for a zlib or gzip header */
1614 				zval filterparams;
1615 
1616 				if (!PHAR_G(has_zlib)) {
1617 					MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file, enable zlib extension in php.ini")
1618 				}
1619 				array_init(&filterparams);
1620 /* this is defined in zlib's zconf.h */
1621 #ifndef MAX_WBITS
1622 #define MAX_WBITS 15
1623 #endif
1624 				add_assoc_long_ex(&filterparams, "window", sizeof("window") - 1, MAX_WBITS + 32);
1625 
1626 				/* entire file is gzip-compressed, uncompress to temporary file */
1627 				if (!(temp = php_stream_fopen_tmpfile())) {
1628 					MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of gzipped phar archive \"%s\"")
1629 				}
1630 
1631 				php_stream_rewind(fp);
1632 				filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp));
1633 
1634 				if (!filter) {
1635 					err = 1;
1636 					add_assoc_long_ex(&filterparams, "window", sizeof("window") - 1, MAX_WBITS);
1637 					filter = php_stream_filter_create("zlib.inflate", &filterparams, php_stream_is_persistent(fp));
1638 					zval_dtor(&filterparams);
1639 
1640 					if (!filter) {
1641 						php_stream_close(temp);
1642 						MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
1643 					}
1644 				} else {
1645 					zval_dtor(&filterparams);
1646 				}
1647 
1648 				php_stream_filter_append(&temp->writefilters, filter);
1649 
1650 				if (SUCCESS != php_stream_copy_to_stream_ex(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
1651 					if (err) {
1652 						php_stream_close(temp);
1653 						MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\", ext/zlib is buggy in PHP versions older than 5.2.6")
1654 					}
1655 					php_stream_close(temp);
1656 					MAPPHAR_ALLOC_FAIL("unable to decompress gzipped phar archive \"%s\" to temporary file")
1657 				}
1658 
1659 				php_stream_filter_flush(filter, 1);
1660 				php_stream_filter_remove(filter, 1);
1661 				php_stream_close(fp);
1662 				fp = temp;
1663 				php_stream_rewind(fp);
1664 				compression = PHAR_FILE_COMPRESSED_GZ;
1665 
1666 				/* now, start over */
1667 				test = '\0';
1668 				continue;
1669 			} else if (!memcmp(pos, bz_magic, 3)) {
1670 				php_stream_filter *filter;
1671 				php_stream *temp;
1672 
1673 				if (!PHAR_G(has_bz2)) {
1674 					MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file, enable bz2 extension in php.ini")
1675 				}
1676 
1677 				/* entire file is bzip-compressed, uncompress to temporary file */
1678 				if (!(temp = php_stream_fopen_tmpfile())) {
1679 					MAPPHAR_ALLOC_FAIL("unable to create temporary file for decompression of bzipped phar archive \"%s\"")
1680 				}
1681 
1682 				php_stream_rewind(fp);
1683 				filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp));
1684 
1685 				if (!filter) {
1686 					php_stream_close(temp);
1687 					MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\", filter creation failed")
1688 				}
1689 
1690 				php_stream_filter_append(&temp->writefilters, filter);
1691 
1692 				if (SUCCESS != php_stream_copy_to_stream_ex(fp, temp, PHP_STREAM_COPY_ALL, NULL)) {
1693 					php_stream_close(temp);
1694 					MAPPHAR_ALLOC_FAIL("unable to decompress bzipped phar archive \"%s\" to temporary file")
1695 				}
1696 
1697 				php_stream_filter_flush(filter, 1);
1698 				php_stream_filter_remove(filter, 1);
1699 				php_stream_close(fp);
1700 				fp = temp;
1701 				php_stream_rewind(fp);
1702 				compression = PHAR_FILE_COMPRESSED_BZ2;
1703 
1704 				/* now, start over */
1705 				test = '\0';
1706 				continue;
1707 			}
1708 
1709 			if (!memcmp(pos, zip_magic, 4)) {
1710 				php_stream_seek(fp, 0, SEEK_END);
1711 				return phar_parse_zipfile(fp, fname, fname_len, alias, alias_len, pphar, error);
1712 			}
1713 
1714 			if (got > 512) {
1715 				if (phar_is_tar(pos, fname)) {
1716 					php_stream_rewind(fp);
1717 					return phar_parse_tarfile(fp, fname, fname_len, alias, alias_len, pphar, is_data, compression, error);
1718 				}
1719 			}
1720 		}
1721 
1722 		if (got > 0 && (pos = phar_strnstr(buffer, got + sizeof(token), token, sizeof(token)-1)) != NULL) {
1723 			halt_offset += (pos - buffer); /* no -tokenlen+tokenlen here */
1724 			return phar_parse_pharfile(fp, fname, fname_len, alias, alias_len, halt_offset, pphar, compression, error);
1725 		}
1726 
1727 		halt_offset += got;
1728 		memmove(buffer, buffer + window_size, tokenlen); /* move the memory buffer by the size of the window */
1729 	}
1730 
1731 	MAPPHAR_ALLOC_FAIL("internal corruption of phar \"%s\" (__HALT_COMPILER(); not found)")
1732 }
1733 /* }}} */
1734 
1735 /*
1736  * given the location of the file extension and the start of the file path,
1737  * determine the end of the portion of the path (i.e. /path/to/file.ext/blah
1738  * grabs "/path/to/file.ext" as does the straight /path/to/file.ext),
1739  * stat it to determine if it exists.
1740  * if so, check to see if it is a directory and fail if so
1741  * if not, check to see if its dirname() exists (i.e. "/path/to") and is a directory
1742  * succeed if we are creating the file, otherwise fail.
1743  */
1744 static int phar_analyze_path(const char *fname, const char *ext, int ext_len, int for_create) /* {{{ */
1745 {
1746 	php_stream_statbuf ssb;
1747 	char *realpath;
1748 	char *filename = estrndup(fname, (ext - fname) + ext_len);
1749 
1750 	if ((realpath = expand_filepath(filename, NULL))) {
1751 #ifdef PHP_WIN32
1752 		phar_unixify_path_separators(realpath, strlen(realpath));
1753 #endif
1754 		if (zend_hash_str_exists(&(PHAR_G(phar_fname_map)), realpath, strlen(realpath))) {
1755 			efree(realpath);
1756 			efree(filename);
1757 			return SUCCESS;
1758 		}
1759 
1760 		if (PHAR_G(manifest_cached) && zend_hash_str_exists(&cached_phars, realpath, strlen(realpath))) {
1761 			efree(realpath);
1762 			efree(filename);
1763 			return SUCCESS;
1764 		}
1765 		efree(realpath);
1766 	}
1767 
1768 	if (SUCCESS == php_stream_stat_path((char *) filename, &ssb)) {
1769 
1770 		efree(filename);
1771 
1772 		if (ssb.sb.st_mode & S_IFDIR) {
1773 			return FAILURE;
1774 		}
1775 
1776 		if (for_create == 1) {
1777 			return FAILURE;
1778 		}
1779 
1780 		return SUCCESS;
1781 	} else {
1782 		char *slash;
1783 
1784 		if (!for_create) {
1785 			efree(filename);
1786 			return FAILURE;
1787 		}
1788 
1789 		slash = (char *) strrchr(filename, '/');
1790 
1791 		if (slash) {
1792 			*slash = '\0';
1793 		}
1794 
1795 		if (SUCCESS != php_stream_stat_path((char *) filename, &ssb)) {
1796 			if (!slash) {
1797 				if (!(realpath = expand_filepath(filename, NULL))) {
1798 					efree(filename);
1799 					return FAILURE;
1800 				}
1801 #ifdef PHP_WIN32
1802 				phar_unixify_path_separators(realpath, strlen(realpath));
1803 #endif
1804 				slash = strstr(realpath, filename);
1805 				if (slash) {
1806 					slash += ((ext - fname) + ext_len);
1807 					*slash = '\0';
1808 				}
1809 				slash = strrchr(realpath, '/');
1810 
1811 				if (slash) {
1812 					*slash = '\0';
1813 				} else {
1814 					efree(realpath);
1815 					efree(filename);
1816 					return FAILURE;
1817 				}
1818 
1819 				if (SUCCESS != php_stream_stat_path(realpath, &ssb)) {
1820 					efree(realpath);
1821 					efree(filename);
1822 					return FAILURE;
1823 				}
1824 
1825 				efree(realpath);
1826 
1827 				if (ssb.sb.st_mode & S_IFDIR) {
1828 					efree(filename);
1829 					return SUCCESS;
1830 				}
1831 			}
1832 
1833 			efree(filename);
1834 			return FAILURE;
1835 		}
1836 
1837 		efree(filename);
1838 
1839 		if (ssb.sb.st_mode & S_IFDIR) {
1840 			return SUCCESS;
1841 		}
1842 
1843 		return FAILURE;
1844 	}
1845 }
1846 /* }}} */
1847 
1848 /* check for ".phar" in extension */
1849 static int phar_check_str(const char *fname, const char *ext_str, int ext_len, int executable, int for_create) /* {{{ */
1850 {
1851 	const char *pos;
1852 
1853 	if (ext_len < 0 || ext_len >= 50) {
1854 		return FAILURE;
1855 	}
1856 	if (executable == 1) {
1857 		/* executable phars must contain ".phar" as a valid extension (phar://.pharmy/oops is invalid) */
1858 		/* (phar://hi/there/.phar/oops is also invalid) */
1859 		pos = strstr(ext_str, ".phar");
1860 
1861 		if (!pos
1862 			|| (pos != ext_str && (*(pos - 1) == '/'))
1863 			|| (ext_len - (pos - ext_str)) < 5
1864 			|| !(pos += 5)
1865 			|| !(*pos == '\0' || *pos == '/' || *pos == '.')) {
1866 			return FAILURE;
1867 		}
1868 		return phar_analyze_path(fname, ext_str, ext_len, for_create);
1869 	}
1870 
1871 	/* data phars need only contain a single non-"." to be valid */
1872 	if (!executable) {
1873 		pos = strstr(ext_str, ".phar");
1874 		if (!(pos && (*(pos - 1) != '/')
1875 					&& (pos += 5) && (*pos == '\0' || *pos == '/' || *pos == '.')) && *(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
1876 			return phar_analyze_path(fname, ext_str, ext_len, for_create);
1877 		}
1878 	} else {
1879 		if (*(ext_str + 1) != '.' && *(ext_str + 1) != '/' && *(ext_str + 1) != '\0') {
1880 			return phar_analyze_path(fname, ext_str, ext_len, for_create);
1881 		}
1882 	}
1883 
1884 	return FAILURE;
1885 }
1886 /* }}} */
1887 
1888 /*
1889  * if executable is 1, only returns SUCCESS if the extension is one of the tar/zip .phar extensions
1890  * if executable is 0, it returns SUCCESS only if the filename does *not* contain ".phar" anywhere, and treats
1891  * the first extension as the filename extension
1892  *
1893  * if an extension is found, it sets ext_str to the location of the file extension in filename,
1894  * and ext_len to the length of the extension.
1895  * for urls like "phar://alias/oops" it instead sets ext_len to -1 and returns FAILURE, which tells
1896  * the calling function to use "alias" as the phar alias
1897  *
1898  * the last parameter should be set to tell the thing to assume that filename is the full path, and only to check the
1899  * extension rules, not to iterate.
1900  */
1901 int phar_detect_phar_fname_ext(const char *filename, int filename_len, const char **ext_str, int *ext_len, int executable, int for_create, int is_complete) /* {{{ */
1902 {
1903 	const char *pos, *slash;
1904 
1905 	*ext_str = NULL;
1906 	*ext_len = 0;
1907 
1908 	if (!filename_len || filename_len == 1) {
1909 		return FAILURE;
1910 	}
1911 
1912 	phar_request_initialize();
1913 	/* first check for alias in first segment */
1914 	pos = memchr(filename, '/', filename_len);
1915 
1916 	if (pos && pos != filename) {
1917 		/* check for url like http:// or phar:// */
1918 		if (*(pos - 1) == ':' && (pos - filename) < filename_len - 1 && *(pos + 1) == '/') {
1919 			*ext_len = -2;
1920 			*ext_str = NULL;
1921 			return FAILURE;
1922 		}
1923 		if (zend_hash_str_exists(&(PHAR_G(phar_alias_map)), (char *) filename, pos - filename)) {
1924 			*ext_str = pos;
1925 			*ext_len = -1;
1926 			return FAILURE;
1927 		}
1928 
1929 		if (PHAR_G(manifest_cached) && zend_hash_str_exists(&cached_alias, (char *) filename, pos - filename)) {
1930 			*ext_str = pos;
1931 			*ext_len = -1;
1932 			return FAILURE;
1933 		}
1934 	}
1935 
1936 	if (zend_hash_num_elements(&(PHAR_G(phar_fname_map))) || PHAR_G(manifest_cached)) {
1937 		phar_archive_data *pphar;
1938 
1939 		if (is_complete) {
1940 			if (NULL != (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), (char *) filename, filename_len))) {
1941 				*ext_str = filename + (filename_len - pphar->ext_len);
1942 woohoo:
1943 				*ext_len = pphar->ext_len;
1944 
1945 				if (executable == 2) {
1946 					return SUCCESS;
1947 				}
1948 
1949 				if (executable == 1 && !pphar->is_data) {
1950 					return SUCCESS;
1951 				}
1952 
1953 				if (!executable && pphar->is_data) {
1954 					return SUCCESS;
1955 				}
1956 
1957 				return FAILURE;
1958 			}
1959 
1960 			if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, (char *) filename, filename_len))) {
1961 				*ext_str = filename + (filename_len - pphar->ext_len);
1962 				goto woohoo;
1963 			}
1964 		} else {
1965 			zend_string *str_key;
1966 			zend_ulong unused;
1967 
1968 			for (zend_hash_internal_pointer_reset(&(PHAR_G(phar_fname_map)));
1969 				HASH_KEY_NON_EXISTENT != zend_hash_get_current_key(&(PHAR_G(phar_fname_map)), &str_key, &unused);
1970 				zend_hash_move_forward(&(PHAR_G(phar_fname_map)))
1971 			) {
1972 				if (ZSTR_LEN(str_key) > (uint32_t) filename_len) {
1973 					continue;
1974 				}
1975 
1976 				if (!memcmp(filename, ZSTR_VAL(str_key), ZSTR_LEN(str_key)) && ((uint32_t)filename_len == ZSTR_LEN(str_key)
1977 					|| filename[ZSTR_LEN(str_key)] == '/' || filename[ZSTR_LEN(str_key)] == '\0')) {
1978 					if (NULL == (pphar = zend_hash_get_current_data_ptr(&(PHAR_G(phar_fname_map))))) {
1979 						break;
1980 					}
1981 					*ext_str = filename + (ZSTR_LEN(str_key) - pphar->ext_len);
1982 					goto woohoo;
1983 				}
1984 			}
1985 
1986 			if (PHAR_G(manifest_cached)) {
1987 				for (zend_hash_internal_pointer_reset(&cached_phars);
1988 					HASH_KEY_NON_EXISTENT != zend_hash_get_current_key(&cached_phars, &str_key, &unused);
1989 					zend_hash_move_forward(&cached_phars)
1990 				) {
1991 					if (ZSTR_LEN(str_key) > (uint32_t) filename_len) {
1992 						continue;
1993 					}
1994 
1995 					if (!memcmp(filename, ZSTR_VAL(str_key), ZSTR_LEN(str_key)) && ((uint32_t)filename_len == ZSTR_LEN(str_key)
1996 						|| filename[ZSTR_LEN(str_key)] == '/' || filename[ZSTR_LEN(str_key)] == '\0')) {
1997 						if (NULL == (pphar = zend_hash_get_current_data_ptr(&cached_phars))) {
1998 							break;
1999 						}
2000 						*ext_str = filename + (ZSTR_LEN(str_key) - pphar->ext_len);
2001 						goto woohoo;
2002 					}
2003 				}
2004 			}
2005 		}
2006 	}
2007 
2008 	pos = memchr(filename + 1, '.', filename_len);
2009 next_extension:
2010 	if (!pos) {
2011 		return FAILURE;
2012 	}
2013 
2014 	while (pos != filename && (*(pos - 1) == '/' || *(pos - 1) == '\0')) {
2015 		pos = memchr(pos + 1, '.', filename_len - (pos - filename) - 1);
2016 		if (!pos) {
2017 			return FAILURE;
2018 		}
2019 	}
2020 
2021 	slash = memchr(pos, '/', filename_len - (pos - filename));
2022 
2023 	if (!slash) {
2024 		/* this is a url like "phar://blah.phar" with no directory */
2025 		*ext_str = pos;
2026 		*ext_len = strlen(pos);
2027 
2028 		/* file extension must contain "phar" */
2029 		switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create)) {
2030 			case SUCCESS:
2031 				return SUCCESS;
2032 			case FAILURE:
2033 				/* we are at the end of the string, so we fail */
2034 				return FAILURE;
2035 		}
2036 	}
2037 
2038 	/* we've found an extension that ends at a directory separator */
2039 	*ext_str = pos;
2040 	*ext_len = slash - pos;
2041 
2042 	switch (phar_check_str(filename, *ext_str, *ext_len, executable, for_create)) {
2043 		case SUCCESS:
2044 			return SUCCESS;
2045 		case FAILURE:
2046 			/* look for more extensions */
2047 			pos = strchr(pos + 1, '.');
2048 			if (pos) {
2049 				*ext_str = NULL;
2050 				*ext_len = 0;
2051 			}
2052 			goto next_extension;
2053 	}
2054 
2055 	return FAILURE;
2056 }
2057 /* }}} */
2058 
2059 static int php_check_dots(const char *element, int n) /* {{{ */
2060 {
2061 	for(n--; n >= 0; --n) {
2062 		if (element[n] != '.') {
2063 			return 1;
2064 		}
2065 	}
2066 	return 0;
2067 }
2068 /* }}} */
2069 
2070 #define IS_DIRECTORY_UP(element, len) \
2071 	(len >= 2 && !php_check_dots(element, len))
2072 
2073 #define IS_DIRECTORY_CURRENT(element, len) \
2074 	(len == 1 && element[0] == '.')
2075 
2076 #define IS_BACKSLASH(c) ((c) == '/')
2077 
2078 /**
2079  * Remove .. and . references within a phar filename
2080  */
2081 char *phar_fix_filepath(char *path, int *new_len, int use_cwd) /* {{{ */
2082 {
2083 	char *newpath;
2084 	int newpath_len;
2085 	char *ptr;
2086 	char *tok;
2087 	int ptr_length, path_length = *new_len;
2088 
2089 	if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
2090 		newpath_len = PHAR_G(cwd_len);
2091 		newpath = emalloc(strlen(path) + newpath_len + 1);
2092 		memcpy(newpath, PHAR_G(cwd), newpath_len);
2093 	} else {
2094 		newpath = emalloc(strlen(path) + 2);
2095 		newpath[0] = '/';
2096 		newpath_len = 1;
2097 	}
2098 
2099 	ptr = path;
2100 
2101 	if (*ptr == '/') {
2102 		++ptr;
2103 	}
2104 
2105 	tok = ptr;
2106 
2107 	do {
2108 		ptr = memchr(ptr, '/', path_length - (ptr - path));
2109 	} while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
2110 
2111 	if (!ptr && (path_length - (tok - path))) {
2112 		switch (path_length - (tok - path)) {
2113 			case 1:
2114 				if (*tok == '.') {
2115 					efree(path);
2116 					*new_len = 1;
2117 					efree(newpath);
2118 					return estrndup("/", 1);
2119 				}
2120 				break;
2121 			case 2:
2122 				if (tok[0] == '.' && tok[1] == '.') {
2123 					efree(path);
2124 					*new_len = 1;
2125 					efree(newpath);
2126 					return estrndup("/", 1);
2127 				}
2128 		}
2129 		efree(newpath);
2130 		return path;
2131 	}
2132 
2133 	while (ptr) {
2134 		ptr_length = ptr - tok;
2135 last_time:
2136 		if (IS_DIRECTORY_UP(tok, ptr_length)) {
2137 #define PREVIOUS newpath[newpath_len - 1]
2138 
2139 			while (newpath_len > 1 && !IS_BACKSLASH(PREVIOUS)) {
2140 				newpath_len--;
2141 			}
2142 
2143 			if (newpath[0] != '/') {
2144 				newpath[newpath_len] = '\0';
2145 			} else if (newpath_len > 1) {
2146 				--newpath_len;
2147 			}
2148 		} else if (!IS_DIRECTORY_CURRENT(tok, ptr_length)) {
2149 			if (newpath_len > 1) {
2150 				newpath[newpath_len++] = '/';
2151 				memcpy(newpath + newpath_len, tok, ptr_length+1);
2152 			} else {
2153 				memcpy(newpath + newpath_len, tok, ptr_length+1);
2154 			}
2155 
2156 			newpath_len += ptr_length;
2157 		}
2158 
2159 		if (ptr == path + path_length) {
2160 			break;
2161 		}
2162 
2163 		tok = ++ptr;
2164 
2165 		do {
2166 			ptr = memchr(ptr, '/', path_length - (ptr - path));
2167 		} while (ptr && ptr - tok == 0 && *ptr == '/' && ++ptr && ++tok);
2168 
2169 		if (!ptr && (path_length - (tok - path))) {
2170 			ptr_length = path_length - (tok - path);
2171 			ptr = path + path_length;
2172 			goto last_time;
2173 		}
2174 	}
2175 
2176 	efree(path);
2177 	*new_len = newpath_len;
2178 	newpath[newpath_len] = '\0';
2179 	return erealloc(newpath, newpath_len + 1);
2180 }
2181 /* }}} */
2182 
2183 /**
2184  * Process a phar stream name, ensuring we can handle any of:
2185  *
2186  * - whatever.phar
2187  * - whatever.phar.gz
2188  * - whatever.phar.bz2
2189  * - whatever.phar.php
2190  *
2191  * Optionally the name might start with 'phar://'
2192  *
2193  * This is used by phar_parse_url()
2194  */
2195 int phar_split_fname(const char *filename, int filename_len, char **arch, int *arch_len, char **entry, int *entry_len, int executable, int for_create) /* {{{ */
2196 {
2197 	const char *ext_str;
2198 #ifdef PHP_WIN32
2199 	char *save;
2200 #endif
2201 	int ext_len;
2202 
2203 	if (CHECK_NULL_PATH(filename, filename_len)) {
2204 		return FAILURE;
2205 	}
2206 
2207 	if (CHECK_NULL_PATH(filename, filename_len)) {
2208 		return FAILURE;
2209 	}
2210 
2211 	if (!strncasecmp(filename, "phar://", 7)) {
2212 		filename += 7;
2213 		filename_len -= 7;
2214 	}
2215 
2216 	ext_len = 0;
2217 #ifdef PHP_WIN32
2218 	save = filename;
2219 	filename = estrndup(filename, filename_len);
2220 	phar_unixify_path_separators(filename, filename_len);
2221 #endif
2222 	if (phar_detect_phar_fname_ext(filename, filename_len, &ext_str, &ext_len, executable, for_create, 0) == FAILURE) {
2223 		if (ext_len != -1) {
2224 			if (!ext_str) {
2225 				/* no / detected, restore arch for error message */
2226 #ifdef PHP_WIN32
2227 				*arch = save;
2228 #else
2229 				*arch = (char*)filename;
2230 #endif
2231 			}
2232 
2233 #ifdef PHP_WIN32
2234 			efree(filename);
2235 #endif
2236 			return FAILURE;
2237 		}
2238 
2239 		ext_len = 0;
2240 		/* no extension detected - instead we are dealing with an alias */
2241 	}
2242 
2243 	*arch_len = ext_str - filename + ext_len;
2244 	*arch = estrndup(filename, *arch_len);
2245 
2246 	if (ext_str[ext_len]) {
2247 		*entry_len = filename_len - *arch_len;
2248 		*entry = estrndup(ext_str+ext_len, *entry_len);
2249 #ifdef PHP_WIN32
2250 		phar_unixify_path_separators(*entry, *entry_len);
2251 #endif
2252 		*entry = phar_fix_filepath(*entry, entry_len, 0);
2253 	} else {
2254 		*entry_len = 1;
2255 		*entry = estrndup("/", 1);
2256 	}
2257 
2258 #ifdef PHP_WIN32
2259 	efree(filename);
2260 #endif
2261 
2262 	return SUCCESS;
2263 }
2264 /* }}} */
2265 
2266 /**
2267  * Invoked when a user calls Phar::mapPhar() from within an executing .phar
2268  * to set up its manifest directly
2269  */
2270 int phar_open_executed_filename(char *alias, int alias_len, char **error) /* {{{ */
2271 {
2272 	char *fname;
2273 	php_stream *fp;
2274 	int fname_len;
2275 	zend_string *actual = NULL;
2276 	int ret;
2277 
2278 	if (error) {
2279 		*error = NULL;
2280 	}
2281 
2282 	fname = (char*)zend_get_executed_filename();
2283 	fname_len = strlen(fname);
2284 
2285 	if (phar_open_parsed_phar(fname, fname_len, alias, alias_len, 0, REPORT_ERRORS, NULL, 0) == SUCCESS) {
2286 		return SUCCESS;
2287 	}
2288 
2289 	if (!strcmp(fname, "[no active file]")) {
2290 		if (error) {
2291 			spprintf(error, 0, "cannot initialize a phar outside of PHP execution");
2292 		}
2293 		return FAILURE;
2294 	}
2295 
2296 	if (0 == zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) {
2297 		if (error) {
2298 			spprintf(error, 0, "__HALT_COMPILER(); must be declared in a phar");
2299 		}
2300 		return FAILURE;
2301 	}
2302 
2303 	if (php_check_open_basedir(fname)) {
2304 		return FAILURE;
2305 	}
2306 
2307 	fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, &actual);
2308 
2309 	if (!fp) {
2310 		if (error) {
2311 			spprintf(error, 0, "unable to open phar for reading \"%s\"", fname);
2312 		}
2313 		if (actual) {
2314 			zend_string_release(actual);
2315 		}
2316 		return FAILURE;
2317 	}
2318 
2319 	if (actual) {
2320 		fname = ZSTR_VAL(actual);
2321 		fname_len = ZSTR_LEN(actual);
2322 	}
2323 
2324 	ret = phar_open_from_fp(fp, fname, fname_len, alias, alias_len, REPORT_ERRORS, NULL, 0, error);
2325 
2326 	if (actual) {
2327 		zend_string_release(actual);
2328 	}
2329 
2330 	return ret;
2331 }
2332 /* }}} */
2333 
2334 /**
2335  * Validate the CRC32 of a file opened from within the phar
2336  */
2337 int phar_postprocess_file(phar_entry_data *idata, uint32_t crc32, char **error, int process_zip) /* {{{ */
2338 {
2339 	uint32_t crc = ~0;
2340 	int len = idata->internal_file->uncompressed_filesize;
2341 	php_stream *fp = idata->fp;
2342 	phar_entry_info *entry = idata->internal_file;
2343 
2344 	if (error) {
2345 		*error = NULL;
2346 	}
2347 
2348 	if (entry->is_zip && process_zip > 0) {
2349 		/* verify local file header */
2350 		phar_zip_file_header local;
2351 		phar_zip_data_desc desc;
2352 
2353 		if (SUCCESS != phar_open_archive_fp(idata->phar)) {
2354 			spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", idata->phar->fname, entry->filename);
2355 			return FAILURE;
2356 		}
2357 		php_stream_seek(phar_get_entrypfp(idata->internal_file), entry->header_offset, SEEK_SET);
2358 
2359 		if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file), (char *) &local, sizeof(local))) {
2360 
2361 			spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", idata->phar->fname, entry->filename);
2362 			return FAILURE;
2363 		}
2364 
2365 		/* check for data descriptor */
2366 		if (((PHAR_ZIP_16(local.flags)) & 0x8) == 0x8) {
2367 			php_stream_seek(phar_get_entrypfp(idata->internal_file),
2368 					entry->header_offset + sizeof(local) +
2369 					PHAR_ZIP_16(local.filename_len) +
2370 					PHAR_ZIP_16(local.extra_len) +
2371 					entry->compressed_filesize, SEEK_SET);
2372 			if (sizeof(desc) != php_stream_read(phar_get_entrypfp(idata->internal_file),
2373 							    (char *) &desc, sizeof(desc))) {
2374 				spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local data descriptor for file \"%s\")", idata->phar->fname, entry->filename);
2375 				return FAILURE;
2376 			}
2377 			if (desc.signature[0] == 'P' && desc.signature[1] == 'K') {
2378 				memcpy(&(local.crc32), &(desc.crc32), 12);
2379 			} else {
2380 				/* old data descriptors have no signature */
2381 				memcpy(&(local.crc32), &desc, 12);
2382 			}
2383 		}
2384 		/* verify local header */
2385 		if (entry->filename_len != PHAR_ZIP_16(local.filename_len) || entry->crc32 != PHAR_ZIP_32(local.crc32) || entry->uncompressed_filesize != PHAR_ZIP_32(local.uncompsize) || entry->compressed_filesize != PHAR_ZIP_32(local.compsize)) {
2386 			spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local header of file \"%s\" does not match central directory)", idata->phar->fname, entry->filename);
2387 			return FAILURE;
2388 		}
2389 
2390 		/* construct actual offset to file start - local extra_len can be different from central extra_len */
2391 		entry->offset = entry->offset_abs =
2392 			sizeof(local) + entry->header_offset + PHAR_ZIP_16(local.filename_len) + PHAR_ZIP_16(local.extra_len);
2393 
2394 		if (idata->zero && idata->zero != entry->offset_abs) {
2395 			idata->zero = entry->offset_abs;
2396 		}
2397 	}
2398 
2399 	if (process_zip == 1) {
2400 		return SUCCESS;
2401 	}
2402 
2403 	php_stream_seek(fp, idata->zero, SEEK_SET);
2404 
2405 	while (len--) {
2406 		CRC32(crc, php_stream_getc(fp));
2407 	}
2408 
2409 	php_stream_seek(fp, idata->zero, SEEK_SET);
2410 
2411 	if (~crc == crc32) {
2412 		entry->is_crc_checked = 1;
2413 		return SUCCESS;
2414 	} else {
2415 		spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
2416 		return FAILURE;
2417 	}
2418 }
2419 /* }}} */
2420 
2421 static inline void phar_set_32(char *buffer, int var) /* {{{ */
2422 {
2423 #ifdef WORDS_BIGENDIAN
2424 	*((buffer) + 3) = (unsigned char) (((var) >> 24) & 0xFF);
2425 	*((buffer) + 2) = (unsigned char) (((var) >> 16) & 0xFF);
2426 	*((buffer) + 1) = (unsigned char) (((var) >> 8) & 0xFF);
2427 	*((buffer) + 0) = (unsigned char) ((var) & 0xFF);
2428 #else
2429 	 memcpy(buffer, &var, sizeof(var));
2430 #endif
2431 } /* }}} */
2432 
2433 static int phar_flush_clean_deleted_apply(zval *zv) /* {{{ */
2434 {
2435 	phar_entry_info *entry = (phar_entry_info *)Z_PTR_P(zv);
2436 
2437 	if (entry->fp_refcount <= 0 && entry->is_deleted) {
2438 		return ZEND_HASH_APPLY_REMOVE;
2439 	} else {
2440 		return ZEND_HASH_APPLY_KEEP;
2441 	}
2442 }
2443 /* }}} */
2444 
2445 #include "stub.h"
2446 
2447 zend_string *phar_create_default_stub(const char *index_php, const char *web_index, char **error) /* {{{ */
2448 {
2449 	int index_len, web_len;
2450 
2451 	if (error) {
2452 		*error = NULL;
2453 	}
2454 
2455 	if (!index_php) {
2456 		index_php = "index.php";
2457 	}
2458 
2459 	if (!web_index) {
2460 		web_index = "index.php";
2461 	}
2462 
2463 	index_len = strlen(index_php);
2464 	web_len = strlen(web_index);
2465 
2466 	if (index_len > 400) {
2467 		/* ridiculous size not allowed for index.php startup filename */
2468 		if (error) {
2469 			spprintf(error, 0, "Illegal filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", index_len);
2470 			return NULL;
2471 		}
2472 	}
2473 
2474 	if (web_len > 400) {
2475 		/* ridiculous size not allowed for index.php startup filename */
2476 		if (error) {
2477 			spprintf(error, 0, "Illegal web filename passed in for stub creation, was %d characters long, and only 400 or less is allowed", web_len);
2478 			return NULL;
2479 		}
2480 	}
2481 
2482 	return phar_get_stub(index_php, web_index, index_len+1, web_len+1);
2483 }
2484 /* }}} */
2485 
2486 /**
2487  * Save phar contents to disk
2488  *
2489  * user_stub contains either a string, or a resource pointer, if len is a negative length.
2490  * user_stub and len should be both 0 if the default or existing stub should be used
2491  */
2492 int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int convert, char **error) /* {{{ */
2493 {
2494 	char halt_stub[] = "__HALT_COMPILER();";
2495 	zend_string *newstub;
2496 	char *tmp;
2497 	phar_entry_info *entry, *newentry;
2498 	int halt_offset, restore_alias_len, global_flags = 0, closeoldfile;
2499 	char *pos, has_dirs = 0;
2500 	char manifest[18], entry_buffer[24];
2501 	zend_off_t manifest_ftell;
2502 	zend_long offset;
2503 	size_t wrote;
2504 	uint32_t manifest_len, mytime, loc, new_manifest_count;
2505 	uint32_t newcrc32;
2506 	php_stream *file, *oldfile, *newfile, *stubfile;
2507 	php_stream_filter *filter;
2508 	php_serialize_data_t metadata_hash;
2509 	smart_str main_metadata_str = {0};
2510 	int free_user_stub, free_fp = 1, free_ufp = 1;
2511 	int manifest_hack = 0;
2512 
2513 	if (phar->is_persistent) {
2514 		if (error) {
2515 			spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
2516 		}
2517 		return EOF;
2518 	}
2519 
2520 	if (error) {
2521 		*error = NULL;
2522 	}
2523 
2524 	if (!zend_hash_num_elements(&phar->manifest) && !user_stub) {
2525 		return EOF;
2526 	}
2527 
2528 	zend_hash_clean(&phar->virtual_dirs);
2529 
2530 	if (phar->is_zip) {
2531 		return phar_zip_flush(phar, user_stub, len, convert, error);
2532 	}
2533 
2534 	if (phar->is_tar) {
2535 		return phar_tar_flush(phar, user_stub, len, convert, error);
2536 	}
2537 
2538 	if (PHAR_G(readonly)) {
2539 		return EOF;
2540 	}
2541 
2542 	if (phar->fp && !phar->is_brandnew) {
2543 		oldfile = phar->fp;
2544 		closeoldfile = 0;
2545 		php_stream_rewind(oldfile);
2546 	} else {
2547 		oldfile = php_stream_open_wrapper(phar->fname, "rb", 0, NULL);
2548 		closeoldfile = oldfile != NULL;
2549 	}
2550 	newfile = php_stream_fopen_tmpfile();
2551 	if (!newfile) {
2552 		if (error) {
2553 			spprintf(error, 0, "unable to create temporary file");
2554 		}
2555 		if (closeoldfile) {
2556 			php_stream_close(oldfile);
2557 		}
2558 		return EOF;
2559 	}
2560 
2561 	if (user_stub) {
2562 		zend_string *suser_stub;
2563 		if (len < 0) {
2564 			/* resource passed in */
2565 			if (!(php_stream_from_zval_no_verify(stubfile, (zval *)user_stub))) {
2566 				if (closeoldfile) {
2567 					php_stream_close(oldfile);
2568 				}
2569 				php_stream_close(newfile);
2570 				if (error) {
2571 					spprintf(error, 0, "unable to access resource to copy stub to new phar \"%s\"", phar->fname);
2572 				}
2573 				return EOF;
2574 			}
2575 			if (len == -1) {
2576 				len = PHP_STREAM_COPY_ALL;
2577 			} else {
2578 				len = -len;
2579 			}
2580 			user_stub = 0;
2581 
2582 			if (!(suser_stub = php_stream_copy_to_mem(stubfile, len, 0))) {
2583 				if (closeoldfile) {
2584 					php_stream_close(oldfile);
2585 				}
2586 				php_stream_close(newfile);
2587 				if (error) {
2588 					spprintf(error, 0, "unable to read resource to copy stub to new phar \"%s\"", phar->fname);
2589 				}
2590 				return EOF;
2591 			}
2592 			free_user_stub = 1;
2593 			user_stub = ZSTR_VAL(suser_stub);
2594 			len = ZSTR_LEN(suser_stub);
2595 		} else {
2596 			free_user_stub = 0;
2597 		}
2598 		tmp = estrndup(user_stub, len);
2599 		if ((pos = php_stristr(tmp, halt_stub, len, sizeof(halt_stub) - 1)) == NULL) {
2600 			efree(tmp);
2601 			if (closeoldfile) {
2602 				php_stream_close(oldfile);
2603 			}
2604 			php_stream_close(newfile);
2605 			if (error) {
2606 				spprintf(error, 0, "illegal stub for phar \"%s\"", phar->fname);
2607 			}
2608 			if (free_user_stub) {
2609 				zend_string_free(suser_stub);
2610 			}
2611 			return EOF;
2612 		}
2613 		pos = user_stub + (pos - tmp);
2614 		efree(tmp);
2615 		len = pos - user_stub + 18;
2616 		if ((size_t)len != php_stream_write(newfile, user_stub, len)
2617 		||			  5 != php_stream_write(newfile, " ?>\r\n", 5)) {
2618 			if (closeoldfile) {
2619 				php_stream_close(oldfile);
2620 			}
2621 			php_stream_close(newfile);
2622 			if (error) {
2623 				spprintf(error, 0, "unable to create stub from string in new phar \"%s\"", phar->fname);
2624 			}
2625 			if (free_user_stub) {
2626 				zend_string_free(suser_stub);
2627 			}
2628 			return EOF;
2629 		}
2630 		phar->halt_offset = len + 5;
2631 		if (free_user_stub) {
2632 			zend_string_free(suser_stub);
2633 		}
2634 	} else {
2635 		size_t written;
2636 
2637 		if (!user_stub && phar->halt_offset && oldfile && !phar->is_brandnew) {
2638 			php_stream_copy_to_stream_ex(oldfile, newfile, phar->halt_offset, &written);
2639 			newstub = NULL;
2640 		} else {
2641 			/* this is either a brand new phar or a default stub overwrite */
2642 			newstub = phar_create_default_stub(NULL, NULL, NULL);
2643 			phar->halt_offset = ZSTR_LEN(newstub);
2644 			written = php_stream_write(newfile, ZSTR_VAL(newstub), phar->halt_offset);
2645 		}
2646 		if (phar->halt_offset != written) {
2647 			if (closeoldfile) {
2648 				php_stream_close(oldfile);
2649 			}
2650 			php_stream_close(newfile);
2651 			if (error) {
2652 				if (newstub) {
2653 					spprintf(error, 0, "unable to create stub in new phar \"%s\"", phar->fname);
2654 				} else {
2655 					spprintf(error, 0, "unable to copy stub of old phar to new phar \"%s\"", phar->fname);
2656 				}
2657 			}
2658 			if (newstub) {
2659 				zend_string_free(newstub);
2660 			}
2661 			return EOF;
2662 		}
2663 		if (newstub) {
2664 			zend_string_free(newstub);
2665 		}
2666 	}
2667 	manifest_ftell = php_stream_tell(newfile);
2668 	halt_offset = manifest_ftell;
2669 
2670 	/* Check whether we can get rid of some of the deleted entries which are
2671 	 * unused. However some might still be in use so even after this clean-up
2672 	 * we need to skip entries marked is_deleted. */
2673 	zend_hash_apply(&phar->manifest, phar_flush_clean_deleted_apply);
2674 
2675 	/* compress as necessary, calculate crcs, serialize meta-data, manifest size, and file sizes */
2676 	main_metadata_str.s = NULL;
2677 	if (Z_TYPE(phar->metadata) != IS_UNDEF) {
2678 		PHP_VAR_SERIALIZE_INIT(metadata_hash);
2679 		php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash);
2680 		PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
2681 	}
2682 	new_manifest_count = 0;
2683 	offset = 0;
2684 	for (zend_hash_internal_pointer_reset(&phar->manifest);
2685 		zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
2686 		zend_hash_move_forward(&phar->manifest)) {
2687 		if ((entry = zend_hash_get_current_data_ptr(&phar->manifest)) == NULL) {
2688 			continue;
2689 		}
2690 		if (entry->cfp) {
2691 			/* did we forget to get rid of cfp last time? */
2692 			php_stream_close(entry->cfp);
2693 			entry->cfp = 0;
2694 		}
2695 		if (entry->is_deleted || entry->is_mounted) {
2696 			/* remove this from the new phar */
2697 			continue;
2698 		}
2699 		if (!entry->is_modified && entry->fp_refcount) {
2700 			/* open file pointers refer to this fp, do not free the stream */
2701 			switch (entry->fp_type) {
2702 				case PHAR_FP:
2703 					free_fp = 0;
2704 					break;
2705 				case PHAR_UFP:
2706 					free_ufp = 0;
2707 				default:
2708 					break;
2709 			}
2710 		}
2711 		/* after excluding deleted files, calculate manifest size in bytes and number of entries */
2712 		++new_manifest_count;
2713 		phar_add_virtual_dirs(phar, entry->filename, entry->filename_len);
2714 
2715 		if (entry->is_dir) {
2716 			/* we use this to calculate API version, 1.1.1 is used for phars with directories */
2717 			has_dirs = 1;
2718 		}
2719 		if (Z_TYPE(entry->metadata) != IS_UNDEF) {
2720 			if (entry->metadata_str.s) {
2721 				smart_str_free(&entry->metadata_str);
2722 			}
2723 			entry->metadata_str.s = NULL;
2724 			PHP_VAR_SERIALIZE_INIT(metadata_hash);
2725 			php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash);
2726 			PHP_VAR_SERIALIZE_DESTROY(metadata_hash);
2727 		} else {
2728 			if (entry->metadata_str.s) {
2729 				smart_str_free(&entry->metadata_str);
2730 			}
2731 			entry->metadata_str.s = NULL;
2732 		}
2733 
2734 		/* 32 bits for filename length, length of filename, manifest + metadata, and add 1 for trailing / if a directory */
2735 		offset += 4 + entry->filename_len + sizeof(entry_buffer) + (entry->metadata_str.s ? ZSTR_LEN(entry->metadata_str.s) : 0) + (entry->is_dir ? 1 : 0);
2736 
2737 		/* compress and rehash as necessary */
2738 		if ((oldfile && !entry->is_modified) || entry->is_dir) {
2739 			if (entry->fp_type == PHAR_UFP) {
2740 				/* reset so we can copy the compressed data over */
2741 				entry->fp_type = PHAR_FP;
2742 			}
2743 			continue;
2744 		}
2745 		if (!phar_get_efp(entry, 0)) {
2746 			/* re-open internal file pointer just-in-time */
2747 			newentry = phar_open_jit(phar, entry, error);
2748 			if (!newentry) {
2749 				/* major problem re-opening, so we ignore this file and the error */
2750 				efree(*error);
2751 				*error = NULL;
2752 				continue;
2753 			}
2754 			entry = newentry;
2755 		}
2756 		file = phar_get_efp(entry, 0);
2757 		if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1)) {
2758 			if (closeoldfile) {
2759 				php_stream_close(oldfile);
2760 			}
2761 			php_stream_close(newfile);
2762 			if (error) {
2763 				spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
2764 			}
2765 			return EOF;
2766 		}
2767 		newcrc32 = ~0;
2768 		mytime = entry->uncompressed_filesize;
2769 		for (loc = 0;loc < mytime; ++loc) {
2770 			CRC32(newcrc32, php_stream_getc(file));
2771 		}
2772 		entry->crc32 = ~newcrc32;
2773 		entry->is_crc_checked = 1;
2774 		if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
2775 			/* not compressed */
2776 			entry->compressed_filesize = entry->uncompressed_filesize;
2777 			continue;
2778 		}
2779 		filter = php_stream_filter_create(phar_compress_filter(entry, 0), NULL, 0);
2780 		if (!filter) {
2781 			if (closeoldfile) {
2782 				php_stream_close(oldfile);
2783 			}
2784 			php_stream_close(newfile);
2785 			if (entry->flags & PHAR_ENT_COMPRESSED_GZ) {
2786 				if (error) {
2787 					spprintf(error, 0, "unable to gzip compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
2788 				}
2789 			} else {
2790 				if (error) {
2791 					spprintf(error, 0, "unable to bzip2 compress file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
2792 				}
2793 			}
2794 			return EOF;
2795 		}
2796 
2797 		/* create new file that holds the compressed version */
2798 		/* work around inability to specify freedom in write and strictness
2799 		in read count */
2800 		entry->cfp = php_stream_fopen_tmpfile();
2801 		if (!entry->cfp) {
2802 			if (error) {
2803 				spprintf(error, 0, "unable to create temporary file");
2804 			}
2805 			if (closeoldfile) {
2806 				php_stream_close(oldfile);
2807 			}
2808 			php_stream_close(newfile);
2809 			return EOF;
2810 		}
2811 		php_stream_flush(file);
2812 		if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
2813 			if (closeoldfile) {
2814 				php_stream_close(oldfile);
2815 			}
2816 			php_stream_close(newfile);
2817 			if (error) {
2818 				spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
2819 			}
2820 			return EOF;
2821 		}
2822 		php_stream_filter_append((&entry->cfp->writefilters), filter);
2823 		if (SUCCESS != php_stream_copy_to_stream_ex(file, entry->cfp, entry->uncompressed_filesize, NULL)) {
2824 			if (closeoldfile) {
2825 				php_stream_close(oldfile);
2826 			}
2827 			php_stream_close(newfile);
2828 			if (error) {
2829 				spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
2830 			}
2831 			return EOF;
2832 		}
2833 		php_stream_filter_flush(filter, 1);
2834 		php_stream_flush(entry->cfp);
2835 		php_stream_filter_remove(filter, 1);
2836 		php_stream_seek(entry->cfp, 0, SEEK_END);
2837 		entry->compressed_filesize = (uint32_t) php_stream_tell(entry->cfp);
2838 		/* generate crc on compressed file */
2839 		php_stream_rewind(entry->cfp);
2840 		entry->old_flags = entry->flags;
2841 		entry->is_modified = 1;
2842 		global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK);
2843 	}
2844 	global_flags |= PHAR_HDR_SIGNATURE;
2845 
2846 	/* write out manifest pre-header */
2847 	/*  4: manifest length
2848 	 *  4: manifest entry count
2849 	 *  2: phar version
2850 	 *  4: phar global flags
2851 	 *  4: alias length
2852 	 *  ?: the alias itself
2853 	 *  4: phar metadata length
2854 	 *  ?: phar metadata
2855 	 */
2856 	restore_alias_len = phar->alias_len;
2857 	if (phar->is_temporary_alias) {
2858 		phar->alias_len = 0;
2859 	}
2860 
2861 	manifest_len = offset + phar->alias_len + sizeof(manifest) + (main_metadata_str.s ? ZSTR_LEN(main_metadata_str.s) : 0);
2862 	phar_set_32(manifest, manifest_len);
2863 	/* Hack - see bug #65028, add padding byte to the end of the manifest */
2864 	if(manifest[0] == '\r' || manifest[0] == '\n') {
2865 		manifest_len++;
2866 		phar_set_32(manifest, manifest_len);
2867 		manifest_hack = 1;
2868 	}
2869 	phar_set_32(manifest+4, new_manifest_count);
2870 	if (has_dirs) {
2871 		*(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
2872 		*(manifest + 9) = (unsigned char) (((PHAR_API_VERSION) & 0xF0));
2873 	} else {
2874 		*(manifest + 8) = (unsigned char) (((PHAR_API_VERSION_NODIR) >> 8) & 0xFF);
2875 		*(manifest + 9) = (unsigned char) (((PHAR_API_VERSION_NODIR) & 0xF0));
2876 	}
2877 	phar_set_32(manifest+10, global_flags);
2878 	phar_set_32(manifest+14, phar->alias_len);
2879 
2880 	/* write the manifest header */
2881 	if (sizeof(manifest) != php_stream_write(newfile, manifest, sizeof(manifest))
2882 	|| (size_t)phar->alias_len != php_stream_write(newfile, phar->alias, phar->alias_len)) {
2883 
2884 		if (closeoldfile) {
2885 			php_stream_close(oldfile);
2886 		}
2887 
2888 		php_stream_close(newfile);
2889 		phar->alias_len = restore_alias_len;
2890 
2891 		if (error) {
2892 			spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
2893 		}
2894 
2895 		return EOF;
2896 	}
2897 
2898 	phar->alias_len = restore_alias_len;
2899 
2900 	phar_set_32(manifest, main_metadata_str.s ? ZSTR_LEN(main_metadata_str.s) : 0);
2901 	if (4 != php_stream_write(newfile, manifest, 4) || ((main_metadata_str.s ? ZSTR_LEN(main_metadata_str.s) : 0)
2902 	&& ZSTR_LEN(main_metadata_str.s) != php_stream_write(newfile, ZSTR_VAL(main_metadata_str.s), ZSTR_LEN(main_metadata_str.s)))) {
2903 		smart_str_free(&main_metadata_str);
2904 
2905 		if (closeoldfile) {
2906 			php_stream_close(oldfile);
2907 		}
2908 
2909 		php_stream_close(newfile);
2910 		phar->alias_len = restore_alias_len;
2911 
2912 		if (error) {
2913 			spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
2914 		}
2915 
2916 		return EOF;
2917 	}
2918 	smart_str_free(&main_metadata_str);
2919 
2920 	/* re-calculate the manifest location to simplify later code */
2921 	manifest_ftell = php_stream_tell(newfile);
2922 
2923 	/* now write the manifest */
2924 	for (zend_hash_internal_pointer_reset(&phar->manifest);
2925 		zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
2926 		zend_hash_move_forward(&phar->manifest)) {
2927 
2928 		if ((entry = zend_hash_get_current_data_ptr(&phar->manifest)) == NULL) {
2929 			continue;
2930 		}
2931 
2932 		if (entry->is_deleted || entry->is_mounted) {
2933 			/* remove this from the new phar if deleted, ignore if mounted */
2934 			continue;
2935 		}
2936 
2937 		if (entry->is_dir) {
2938 			/* add 1 for trailing slash */
2939 			phar_set_32(entry_buffer, entry->filename_len + 1);
2940 		} else {
2941 			phar_set_32(entry_buffer, entry->filename_len);
2942 		}
2943 
2944 		if (4 != php_stream_write(newfile, entry_buffer, 4)
2945 		|| entry->filename_len != php_stream_write(newfile, entry->filename, entry->filename_len)
2946 		|| (entry->is_dir && 1 != php_stream_write(newfile, "/", 1))) {
2947 			if (closeoldfile) {
2948 				php_stream_close(oldfile);
2949 			}
2950 			php_stream_close(newfile);
2951 			if (error) {
2952 				if (entry->is_dir) {
2953 					spprintf(error, 0, "unable to write filename of directory \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
2954 				} else {
2955 					spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
2956 				}
2957 			}
2958 			return EOF;
2959 		}
2960 
2961 		/* set the manifest meta-data:
2962 			4: uncompressed filesize
2963 			4: creation timestamp
2964 			4: compressed filesize
2965 			4: crc32
2966 			4: flags
2967 			4: metadata-len
2968 			+: metadata
2969 		*/
2970 		mytime = time(NULL);
2971 		phar_set_32(entry_buffer, entry->uncompressed_filesize);
2972 		phar_set_32(entry_buffer+4, mytime);
2973 		phar_set_32(entry_buffer+8, entry->compressed_filesize);
2974 		phar_set_32(entry_buffer+12, entry->crc32);
2975 		phar_set_32(entry_buffer+16, entry->flags);
2976 		phar_set_32(entry_buffer+20, entry->metadata_str.s ? ZSTR_LEN(entry->metadata_str.s) : 0);
2977 
2978 		if (sizeof(entry_buffer) != php_stream_write(newfile, entry_buffer, sizeof(entry_buffer))
2979 		|| (entry->metadata_str.s &&
2980 		    ZSTR_LEN(entry->metadata_str.s) != php_stream_write(newfile, ZSTR_VAL(entry->metadata_str.s), ZSTR_LEN(entry->metadata_str.s)))) {
2981 			if (closeoldfile) {
2982 				php_stream_close(oldfile);
2983 			}
2984 
2985 			php_stream_close(newfile);
2986 
2987 			if (error) {
2988 				spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
2989 			}
2990 
2991 			return EOF;
2992 		}
2993 	}
2994 	/* Hack - see bug #65028, add padding byte to the end of the manifest */
2995 	if(manifest_hack) {
2996 		if(1 != php_stream_write(newfile, manifest, 1)) {
2997 			if (closeoldfile) {
2998 				php_stream_close(oldfile);
2999 			}
3000 
3001 			php_stream_close(newfile);
3002 
3003 			if (error) {
3004 				spprintf(error, 0, "unable to write manifest padding byte");
3005 			}
3006 
3007 			return EOF;
3008 		}
3009 	}
3010 
3011 	/* now copy the actual file data to the new phar */
3012 	offset = php_stream_tell(newfile);
3013 	for (zend_hash_internal_pointer_reset(&phar->manifest);
3014 		zend_hash_has_more_elements(&phar->manifest) == SUCCESS;
3015 		zend_hash_move_forward(&phar->manifest)) {
3016 
3017 		if ((entry = zend_hash_get_current_data_ptr(&phar->manifest)) == NULL) {
3018 			continue;
3019 		}
3020 
3021 		if (entry->is_deleted || entry->is_dir || entry->is_mounted) {
3022 			continue;
3023 		}
3024 
3025 		if (entry->cfp) {
3026 			file = entry->cfp;
3027 			php_stream_rewind(file);
3028 		} else {
3029 			file = phar_get_efp(entry, 0);
3030 			if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
3031 				if (closeoldfile) {
3032 					php_stream_close(oldfile);
3033 				}
3034 				php_stream_close(newfile);
3035 				if (error) {
3036 					spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
3037 				}
3038 				return EOF;
3039 			}
3040 		}
3041 
3042 		if (!file) {
3043 			if (closeoldfile) {
3044 				php_stream_close(oldfile);
3045 			}
3046 			php_stream_close(newfile);
3047 			if (error) {
3048 				spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
3049 			}
3050 			return EOF;
3051 		}
3052 
3053 		/* this will have changed for all files that have either changed compression or been modified */
3054 		entry->offset = entry->offset_abs = offset;
3055 		offset += entry->compressed_filesize;
3056 		if (php_stream_copy_to_stream_ex(file, newfile, entry->compressed_filesize, &wrote) == FAILURE) {
3057 			if (closeoldfile) {
3058 				php_stream_close(oldfile);
3059 			}
3060 
3061 			php_stream_close(newfile);
3062 
3063 			if (error) {
3064 				spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
3065 			}
3066 
3067 			return EOF;
3068 		}
3069 
3070 		entry->is_modified = 0;
3071 
3072 		if (entry->cfp) {
3073 			php_stream_close(entry->cfp);
3074 			entry->cfp = NULL;
3075 		}
3076 
3077 		if (entry->fp_type == PHAR_MOD) {
3078 			/* this fp is in use by a phar_entry_data returned by phar_get_entry_data, it will be closed when the phar_entry_data is phar_entry_delref'ed */
3079 			if (entry->fp_refcount == 0 && entry->fp != phar->fp && entry->fp != phar->ufp) {
3080 				php_stream_close(entry->fp);
3081 			}
3082 
3083 			entry->fp = NULL;
3084 			entry->fp_type = PHAR_FP;
3085 		} else if (entry->fp_type == PHAR_UFP) {
3086 			entry->fp_type = PHAR_FP;
3087 		}
3088 	}
3089 
3090 	/* append signature */
3091 	if (global_flags & PHAR_HDR_SIGNATURE) {
3092 		char sig_buf[4];
3093 
3094 		php_stream_rewind(newfile);
3095 
3096 		if (phar->signature) {
3097 			efree(phar->signature);
3098 			phar->signature = NULL;
3099 		}
3100 
3101 		switch(phar->sig_flags) {
3102 #ifndef PHAR_HASH_OK
3103 			case PHAR_SIG_SHA512:
3104 			case PHAR_SIG_SHA256:
3105 				if (closeoldfile) {
3106 					php_stream_close(oldfile);
3107 				}
3108 				php_stream_close(newfile);
3109 				if (error) {
3110 					spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\" with requested hash type", entry->filename, phar->fname);
3111 				}
3112 				return EOF;
3113 #endif
3114 			default: {
3115 				char *digest = NULL;
3116 				int digest_len;
3117 
3118 				if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, error)) {
3119 					if (error) {
3120 						char *save = *error;
3121 						spprintf(error, 0, "phar error: unable to write signature: %s", save);
3122 						efree(save);
3123 					}
3124 					if (digest) {
3125 						efree(digest);
3126 					}
3127 					if (closeoldfile) {
3128 						php_stream_close(oldfile);
3129 					}
3130 					php_stream_close(newfile);
3131 					return EOF;
3132 				}
3133 
3134 				php_stream_write(newfile, digest, digest_len);
3135 				efree(digest);
3136 				if (phar->sig_flags == PHAR_SIG_OPENSSL) {
3137 					phar_set_32(sig_buf, digest_len);
3138 					php_stream_write(newfile, sig_buf, 4);
3139 				}
3140 				break;
3141 			}
3142 		}
3143 		phar_set_32(sig_buf, phar->sig_flags);
3144 		php_stream_write(newfile, sig_buf, 4);
3145 		php_stream_write(newfile, "GBMB", 4);
3146 	}
3147 
3148 	/* finally, close the temp file, rename the original phar,
3149 	   move the temp to the old phar, unlink the old phar, and reload it into memory
3150 	*/
3151 	if (phar->fp && free_fp) {
3152 		php_stream_close(phar->fp);
3153 	}
3154 
3155 	if (phar->ufp) {
3156 		if (free_ufp) {
3157 			php_stream_close(phar->ufp);
3158 		}
3159 		phar->ufp = NULL;
3160 	}
3161 
3162 	if (closeoldfile) {
3163 		php_stream_close(oldfile);
3164 	}
3165 
3166 	phar->internal_file_start = halt_offset + manifest_len + 4;
3167 	phar->halt_offset = halt_offset;
3168 	phar->is_brandnew = 0;
3169 
3170 	php_stream_rewind(newfile);
3171 
3172 	if (phar->donotflush) {
3173 		/* deferred flush */
3174 		phar->fp = newfile;
3175 	} else {
3176 		phar->fp = php_stream_open_wrapper(phar->fname, "w+b", IGNORE_URL|STREAM_MUST_SEEK|REPORT_ERRORS, NULL);
3177 		if (!phar->fp) {
3178 			phar->fp = newfile;
3179 			if (error) {
3180 				spprintf(error, 4096, "unable to open new phar \"%s\" for writing", phar->fname);
3181 			}
3182 			return EOF;
3183 		}
3184 
3185 		if (phar->flags & PHAR_FILE_COMPRESSED_GZ) {
3186 			/* to properly compress, we have to tell zlib to add a zlib header */
3187 			zval filterparams;
3188 
3189 			array_init(&filterparams);
3190 			add_assoc_long(&filterparams, "window", MAX_WBITS+16);
3191 			filter = php_stream_filter_create("zlib.deflate", &filterparams, php_stream_is_persistent(phar->fp));
3192 			zval_dtor(&filterparams);
3193 
3194 			if (!filter) {
3195 				if (error) {
3196 					spprintf(error, 4096, "unable to compress all contents of phar \"%s\" using zlib, PHP versions older than 5.2.6 have a buggy zlib", phar->fname);
3197 				}
3198 				return EOF;
3199 			}
3200 
3201 			php_stream_filter_append(&phar->fp->writefilters, filter);
3202 			php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
3203 			php_stream_filter_flush(filter, 1);
3204 			php_stream_filter_remove(filter, 1);
3205 			php_stream_close(phar->fp);
3206 			/* use the temp stream as our base */
3207 			phar->fp = newfile;
3208 		} else if (phar->flags & PHAR_FILE_COMPRESSED_BZ2) {
3209 			filter = php_stream_filter_create("bzip2.compress", NULL, php_stream_is_persistent(phar->fp));
3210 			php_stream_filter_append(&phar->fp->writefilters, filter);
3211 			php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
3212 			php_stream_filter_flush(filter, 1);
3213 			php_stream_filter_remove(filter, 1);
3214 			php_stream_close(phar->fp);
3215 			/* use the temp stream as our base */
3216 			phar->fp = newfile;
3217 		} else {
3218 			php_stream_copy_to_stream_ex(newfile, phar->fp, PHP_STREAM_COPY_ALL, NULL);
3219 			/* we could also reopen the file in "rb" mode but there is no need for that */
3220 			php_stream_close(newfile);
3221 		}
3222 	}
3223 
3224 	if (-1 == php_stream_seek(phar->fp, phar->halt_offset, SEEK_SET)) {
3225 		if (error) {
3226 			spprintf(error, 0, "unable to seek to __HALT_COMPILER(); in new phar \"%s\"", phar->fname);
3227 		}
3228 		return EOF;
3229 	}
3230 
3231 	return EOF;
3232 }
3233 /* }}} */
3234 
3235 #ifdef COMPILE_DL_PHAR
3236 #ifdef ZTS
3237 ZEND_TSRMLS_CACHE_DEFINE()
3238 #endif
3239 ZEND_GET_MODULE(phar)
3240 #endif
3241 
3242 /* {{{ phar_functions[]
3243  *
3244  * Every user visible function must have an entry in phar_functions[].
3245  */
3246 zend_function_entry phar_functions[] = {
3247 	PHP_FE_END
3248 };
3249 /* }}}*/
3250 
3251 static size_t phar_zend_stream_reader(void *handle, char *buf, size_t len) /* {{{ */
3252 {
3253 	return php_stream_read(phar_get_pharfp((phar_archive_data*)handle), buf, len);
3254 }
3255 /* }}} */
3256 
3257 static size_t phar_zend_stream_fsizer(void *handle) /* {{{ */
3258 {
3259 	return ((phar_archive_data*)handle)->halt_offset + 32;
3260 } /* }}} */
3261 
3262 zend_op_array *(*phar_orig_compile_file)(zend_file_handle *file_handle, int type);
3263 #define phar_orig_zend_open zend_stream_open_function
3264 
3265 static zend_string *phar_resolve_path(const char *filename, int filename_len)
3266 {
3267 	return phar_find_in_include_path((char *) filename, filename_len, NULL);
3268 }
3269 
3270 static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type) /* {{{ */
3271 {
3272 	zend_op_array *res;
3273 	char *name = NULL;
3274 	int failed;
3275 	phar_archive_data *phar;
3276 
3277 	if (!file_handle || !file_handle->filename) {
3278 		return phar_orig_compile_file(file_handle, type);
3279 	}
3280 	if (strstr(file_handle->filename, ".phar") && !strstr(file_handle->filename, "://")) {
3281 		if (SUCCESS == phar_open_from_filename((char*)file_handle->filename, strlen(file_handle->filename), NULL, 0, 0, &phar, NULL)) {
3282 			if (phar->is_zip || phar->is_tar) {
3283 				zend_file_handle f = *file_handle;
3284 
3285 				/* zip or tar-based phar */
3286 				spprintf(&name, 4096, "phar://%s/%s", file_handle->filename, ".phar/stub.php");
3287 				if (SUCCESS == phar_orig_zend_open((const char *)name, &f)) {
3288 
3289 					efree(name);
3290 					name = NULL;
3291 
3292 					f.filename = file_handle->filename;
3293 					if (f.opened_path) {
3294 						efree(f.opened_path);
3295 					}
3296 					f.opened_path = file_handle->opened_path;
3297 					f.free_filename = file_handle->free_filename;
3298 
3299 					switch (file_handle->type) {
3300 						case ZEND_HANDLE_STREAM:
3301 						case ZEND_HANDLE_MAPPED:
3302 							if (file_handle->handle.stream.closer && file_handle->handle.stream.handle) {
3303 								file_handle->handle.stream.closer(file_handle->handle.stream.handle);
3304 							}
3305 							file_handle->handle.stream.handle = NULL;
3306 							break;
3307 						default:
3308 							break;
3309 					}
3310 					*file_handle = f;
3311 				}
3312 			} else if (phar->flags & PHAR_FILE_COMPRESSION_MASK) {
3313 				zend_file_handle_dtor(file_handle);
3314 				/* compressed phar */
3315 				file_handle->type = ZEND_HANDLE_STREAM;
3316 				/* we do our own reading directly from the phar, don't change the next line */
3317 				file_handle->handle.stream.handle  = phar;
3318 				file_handle->handle.stream.reader  = phar_zend_stream_reader;
3319 				file_handle->handle.stream.closer  = NULL;
3320 				file_handle->handle.stream.fsizer  = phar_zend_stream_fsizer;
3321 				file_handle->handle.stream.isatty  = 0;
3322 				phar->is_persistent ?
3323 					php_stream_rewind(PHAR_G(cached_fp)[phar->phar_pos].fp) :
3324 					php_stream_rewind(phar->fp);
3325 				memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
3326 			}
3327 		}
3328 	}
3329 
3330 	zend_try {
3331 		failed = 0;
3332 		CG(zend_lineno) = 0;
3333 		res = phar_orig_compile_file(file_handle, type);
3334 	} zend_catch {
3335 		failed = 1;
3336 		res = NULL;
3337 	} zend_end_try();
3338 
3339 	if (name) {
3340 		efree(name);
3341 	}
3342 
3343 	if (failed) {
3344 		zend_bailout();
3345 	}
3346 
3347 	return res;
3348 }
3349 /* }}} */
3350 
3351 typedef zend_op_array* (zend_compile_t)(zend_file_handle*, int);
3352 typedef zend_compile_t* (compile_hook)(zend_compile_t *ptr);
3353 
3354 static void mime_type_dtor(zval *zv)
3355 {
3356 	free(Z_PTR_P(zv));
3357 }
3358 
3359 PHP_GINIT_FUNCTION(phar) /* {{{ */
3360 {
3361 #if defined(COMPILE_DL_PHAR) && defined(ZTS)
3362 	ZEND_TSRMLS_CACHE_UPDATE();
3363 #endif
3364 	phar_mime_type mime;
3365 
3366 	memset(phar_globals, 0, sizeof(zend_phar_globals));
3367 	phar_globals->readonly = 1;
3368 
3369 	zend_hash_init(&phar_globals->mime_types, 0, NULL, mime_type_dtor, 1);
3370 
3371 #define PHAR_SET_MIME(mimetype, ret, fileext) \
3372 		mime.mime = mimetype; \
3373 		mime.len = sizeof((mimetype))+1; \
3374 		mime.type = ret; \
3375 		zend_hash_str_add_mem(&phar_globals->mime_types, fileext, sizeof(fileext)-1, (void *)&mime, sizeof(phar_mime_type)); \
3376 
3377 	PHAR_SET_MIME("text/html", PHAR_MIME_PHPS, "phps")
3378 	PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c")
3379 	PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cc")
3380 	PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "cpp")
3381 	PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "c++")
3382 	PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "dtd")
3383 	PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "h")
3384 	PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "log")
3385 	PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "rng")
3386 	PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "txt")
3387 	PHAR_SET_MIME("text/plain", PHAR_MIME_OTHER, "xsd")
3388 	PHAR_SET_MIME("", PHAR_MIME_PHP, "php")
3389 	PHAR_SET_MIME("", PHAR_MIME_PHP, "inc")
3390 	PHAR_SET_MIME("video/avi", PHAR_MIME_OTHER, "avi")
3391 	PHAR_SET_MIME("image/bmp", PHAR_MIME_OTHER, "bmp")
3392 	PHAR_SET_MIME("text/css", PHAR_MIME_OTHER, "css")
3393 	PHAR_SET_MIME("image/gif", PHAR_MIME_OTHER, "gif")
3394 	PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htm")
3395 	PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "html")
3396 	PHAR_SET_MIME("text/html", PHAR_MIME_OTHER, "htmls")
3397 	PHAR_SET_MIME("image/x-ico", PHAR_MIME_OTHER, "ico")
3398 	PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpe")
3399 	PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpg")
3400 	PHAR_SET_MIME("image/jpeg", PHAR_MIME_OTHER, "jpeg")
3401 	PHAR_SET_MIME("application/x-javascript", PHAR_MIME_OTHER, "js")
3402 	PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "midi")
3403 	PHAR_SET_MIME("audio/midi", PHAR_MIME_OTHER, "mid")
3404 	PHAR_SET_MIME("audio/mod", PHAR_MIME_OTHER, "mod")
3405 	PHAR_SET_MIME("movie/quicktime", PHAR_MIME_OTHER, "mov")
3406 	PHAR_SET_MIME("audio/mp3", PHAR_MIME_OTHER, "mp3")
3407 	PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpg")
3408 	PHAR_SET_MIME("video/mpeg", PHAR_MIME_OTHER, "mpeg")
3409 	PHAR_SET_MIME("application/pdf", PHAR_MIME_OTHER, "pdf")
3410 	PHAR_SET_MIME("image/png", PHAR_MIME_OTHER, "png")
3411 	PHAR_SET_MIME("application/shockwave-flash", PHAR_MIME_OTHER, "swf")
3412 	PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tif")
3413 	PHAR_SET_MIME("image/tiff", PHAR_MIME_OTHER, "tiff")
3414 	PHAR_SET_MIME("audio/wav", PHAR_MIME_OTHER, "wav")
3415 	PHAR_SET_MIME("image/xbm", PHAR_MIME_OTHER, "xbm")
3416 	PHAR_SET_MIME("text/xml", PHAR_MIME_OTHER, "xml")
3417 
3418 	phar_restore_orig_functions();
3419 }
3420 /* }}} */
3421 
3422 PHP_GSHUTDOWN_FUNCTION(phar) /* {{{ */
3423 {
3424 	zend_hash_destroy(&phar_globals->mime_types);
3425 }
3426 /* }}} */
3427 
3428 PHP_MINIT_FUNCTION(phar) /* {{{ */
3429 {
3430 	REGISTER_INI_ENTRIES();
3431 
3432 	phar_orig_compile_file = zend_compile_file;
3433 	zend_compile_file = phar_compile_file;
3434 
3435 	phar_save_resolve_path = zend_resolve_path;
3436 	zend_resolve_path = phar_resolve_path;
3437 
3438 	phar_object_init();
3439 
3440 	phar_intercept_functions_init();
3441 	phar_save_orig_functions();
3442 
3443 	return php_register_url_stream_wrapper("phar", &php_stream_phar_wrapper);
3444 }
3445 /* }}} */
3446 
3447 PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */
3448 {
3449 	php_unregister_url_stream_wrapper("phar");
3450 
3451 	phar_intercept_functions_shutdown();
3452 
3453 	if (zend_compile_file == phar_compile_file) {
3454 		zend_compile_file = phar_orig_compile_file;
3455 	}
3456 
3457 	if (PHAR_G(manifest_cached)) {
3458 		zend_hash_destroy(&(cached_phars));
3459 		zend_hash_destroy(&(cached_alias));
3460 	}
3461 
3462 	return SUCCESS;
3463 }
3464 /* }}} */
3465 
3466 void phar_request_initialize(void) /* {{{ */
3467 {
3468 	if (!PHAR_G(request_init))
3469 	{
3470 		PHAR_G(last_phar) = NULL;
3471 		PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
3472 		PHAR_G(has_bz2) = zend_hash_str_exists(&module_registry, "bz2", sizeof("bz2")-1);
3473 		PHAR_G(has_zlib) = zend_hash_str_exists(&module_registry, "zlib", sizeof("zlib")-1);
3474 		PHAR_G(request_init) = 1;
3475 		PHAR_G(request_ends) = 0;
3476 		PHAR_G(request_done) = 0;
3477 		zend_hash_init(&(PHAR_G(phar_fname_map)), 5, zend_get_hash_value, destroy_phar_data,  0);
3478 		zend_hash_init(&(PHAR_G(phar_persist_map)), 5, zend_get_hash_value, NULL,  0);
3479 		zend_hash_init(&(PHAR_G(phar_alias_map)), 5, zend_get_hash_value, NULL, 0);
3480 
3481 		if (PHAR_G(manifest_cached)) {
3482 			phar_archive_data *pphar;
3483 			phar_entry_fp *stuff = (phar_entry_fp *) ecalloc(zend_hash_num_elements(&cached_phars), sizeof(phar_entry_fp));
3484 
3485 			for (zend_hash_internal_pointer_reset(&cached_phars);
3486 			(pphar = zend_hash_get_current_data_ptr(&cached_phars)) != NULL;
3487 			zend_hash_move_forward(&cached_phars)) {
3488 				stuff[pphar->phar_pos].manifest = (phar_entry_fp_info *) ecalloc( zend_hash_num_elements(&(pphar->manifest)), sizeof(phar_entry_fp_info));
3489 			}
3490 
3491 			PHAR_G(cached_fp) = stuff;
3492 		}
3493 
3494 		PHAR_G(phar_SERVER_mung_list) = 0;
3495 		PHAR_G(cwd) = NULL;
3496 		PHAR_G(cwd_len) = 0;
3497 		PHAR_G(cwd_init) = 0;
3498 	}
3499 }
3500 /* }}} */
3501 
3502 PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
3503 {
3504 	uint32_t i;
3505 
3506 	PHAR_G(request_ends) = 1;
3507 
3508 	if (PHAR_G(request_init))
3509 	{
3510 		phar_release_functions();
3511 		zend_hash_destroy(&(PHAR_G(phar_alias_map)));
3512 		PHAR_G(phar_alias_map.u.flags) = 0;
3513 		zend_hash_destroy(&(PHAR_G(phar_fname_map)));
3514 		PHAR_G(phar_fname_map.u.flags) = 0;
3515 		zend_hash_destroy(&(PHAR_G(phar_persist_map)));
3516 		PHAR_G(phar_persist_map.u.flags) = 0;
3517 		PHAR_G(phar_SERVER_mung_list) = 0;
3518 
3519 		if (PHAR_G(cached_fp)) {
3520 			for (i = 0; i < zend_hash_num_elements(&cached_phars); ++i) {
3521 				if (PHAR_G(cached_fp)[i].fp) {
3522 					php_stream_close(PHAR_G(cached_fp)[i].fp);
3523 				}
3524 				if (PHAR_G(cached_fp)[i].ufp) {
3525 					php_stream_close(PHAR_G(cached_fp)[i].ufp);
3526 				}
3527 				efree(PHAR_G(cached_fp)[i].manifest);
3528 			}
3529 			efree(PHAR_G(cached_fp));
3530 			PHAR_G(cached_fp) = 0;
3531 		}
3532 
3533 		PHAR_G(request_init) = 0;
3534 
3535 		if (PHAR_G(cwd)) {
3536 			efree(PHAR_G(cwd));
3537 		}
3538 
3539 		PHAR_G(cwd) = NULL;
3540 		PHAR_G(cwd_len) = 0;
3541 		PHAR_G(cwd_init) = 0;
3542 	}
3543 
3544 	PHAR_G(request_done) = 1;
3545 	return SUCCESS;
3546 }
3547 /* }}} */
3548 
3549 PHP_MINFO_FUNCTION(phar) /* {{{ */
3550 {
3551 	phar_request_initialize();
3552 	php_info_print_table_start();
3553 	php_info_print_table_header(2, "Phar: PHP Archive support", "enabled");
3554 	php_info_print_table_row(2, "Phar EXT version", PHP_PHAR_VERSION);
3555 	php_info_print_table_row(2, "Phar API version", PHP_PHAR_API_VERSION);
3556 	php_info_print_table_row(2, "SVN revision", "$Id: ba76a9b0e06d536a9b602c782e38e6826cb4ee02 $");
3557 	php_info_print_table_row(2, "Phar-based phar archives", "enabled");
3558 	php_info_print_table_row(2, "Tar-based phar archives", "enabled");
3559 	php_info_print_table_row(2, "ZIP-based phar archives", "enabled");
3560 
3561 	if (PHAR_G(has_zlib)) {
3562 		php_info_print_table_row(2, "gzip compression", "enabled");
3563 	} else {
3564 		php_info_print_table_row(2, "gzip compression", "disabled (install ext/zlib)");
3565 	}
3566 
3567 	if (PHAR_G(has_bz2)) {
3568 		php_info_print_table_row(2, "bzip2 compression", "enabled");
3569 	} else {
3570 		php_info_print_table_row(2, "bzip2 compression", "disabled (install pecl/bz2)");
3571 	}
3572 #ifdef PHAR_HAVE_OPENSSL
3573 	php_info_print_table_row(2, "Native OpenSSL support", "enabled");
3574 #else
3575 	if (zend_hash_str_exists(&module_registry, "openssl", sizeof("openssl")-1)) {
3576 		php_info_print_table_row(2, "OpenSSL support", "enabled");
3577 	} else {
3578 		php_info_print_table_row(2, "OpenSSL support", "disabled (install ext/openssl)");
3579 	}
3580 #endif
3581 	php_info_print_table_end();
3582 
3583 	php_info_print_box_start(0);
3584 	PUTS("Phar based on pear/PHP_Archive, original concept by Davey Shafik.");
3585 	PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
3586 	PUTS("Phar fully realized by Gregory Beaver and Marcus Boerger.");
3587 	PUTS(!sapi_module.phpinfo_as_text?"<br />":"\n");
3588 	PUTS("Portions of tar implementation Copyright (c) 2003-2009 Tim Kientzle.");
3589 	php_info_print_box_end();
3590 
3591 	DISPLAY_INI_ENTRIES();
3592 }
3593 /* }}} */
3594 
3595 /* {{{ phar_module_entry
3596  */
3597 static const zend_module_dep phar_deps[] = {
3598 	ZEND_MOD_OPTIONAL("apc")
3599 	ZEND_MOD_OPTIONAL("bz2")
3600 	ZEND_MOD_OPTIONAL("openssl")
3601 	ZEND_MOD_OPTIONAL("zlib")
3602 	ZEND_MOD_OPTIONAL("standard")
3603 #if defined(HAVE_HASH) && !defined(COMPILE_DL_HASH)
3604 	ZEND_MOD_REQUIRED("hash")
3605 #endif
3606 	ZEND_MOD_REQUIRED("spl")
3607 	ZEND_MOD_END
3608 };
3609 
3610 zend_module_entry phar_module_entry = {
3611 	STANDARD_MODULE_HEADER_EX, NULL,
3612 	phar_deps,
3613 	"Phar",
3614 	phar_functions,
3615 	PHP_MINIT(phar),
3616 	PHP_MSHUTDOWN(phar),
3617 	NULL,
3618 	PHP_RSHUTDOWN(phar),
3619 	PHP_MINFO(phar),
3620 	PHP_PHAR_VERSION,
3621 	PHP_MODULE_GLOBALS(phar),   /* globals descriptor */
3622 	PHP_GINIT(phar),            /* globals ctor */
3623 	PHP_GSHUTDOWN(phar),        /* globals dtor */
3624 	NULL,                       /* post deactivate */
3625 	STANDARD_MODULE_PROPERTIES_EX
3626 };
3627 /* }}} */
3628 
3629 /*
3630  * Local variables:
3631  * tab-width: 4
3632  * c-basic-offset: 4
3633  * End:
3634  * vim600: noet sw=4 ts=4 fdm=marker
3635  * vim<600: noet sw=4 ts=4
3636  */
3637