File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / phar / phar.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:31:59 2013 UTC (11 years ago) by misho
Branches: php, MAIN
CVS tags: v5_4_17, HEAD
5.4.17

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

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