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

    1: /*
    2:   +----------------------------------------------------------------------+
    3:   | phar php single-file executable PHP extension                        |
    4:   | utility functions                                                    |
    5:   +----------------------------------------------------------------------+
    6:   | Copyright (c) 2005-2014 The PHP Group                                |
    7:   +----------------------------------------------------------------------+
    8:   | This source file is subject to version 3.01 of the PHP license,      |
    9:   | that is bundled with this package in the file LICENSE, and is        |
   10:   | available through the world-wide-web at the following url:           |
   11:   | http://www.php.net/license/3_01.txt.                                 |
   12:   | If you did not receive a copy of the PHP license and are unable to   |
   13:   | obtain it through the world-wide-web, please send a note to          |
   14:   | license@php.net so we can mail you a copy immediately.               |
   15:   +----------------------------------------------------------------------+
   16:   | Authors: Gregory Beaver <cellog@php.net>                             |
   17:   |          Marcus Boerger <helly@php.net>                              |
   18:   +----------------------------------------------------------------------+
   19: */
   20: 
   21: /* $Id: util.c,v 1.1.1.4 2014/06/15 20:03:54 misho Exp $ */
   22: 
   23: #include "phar_internal.h"
   24: #ifdef PHAR_HASH_OK
   25: #include "ext/hash/php_hash_sha.h"
   26: #endif
   27: 
   28: #ifdef PHAR_HAVE_OPENSSL
   29: /* OpenSSL includes */
   30: #include <openssl/evp.h>
   31: #include <openssl/x509.h>
   32: #include <openssl/x509v3.h>
   33: #include <openssl/crypto.h>
   34: #include <openssl/pem.h>
   35: #include <openssl/err.h>
   36: #include <openssl/conf.h>
   37: #include <openssl/rand.h>
   38: #include <openssl/ssl.h>
   39: #include <openssl/pkcs12.h>
   40: #else
   41: static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC);
   42: #endif
   43: 
   44: #if !defined(PHP_VERSION_ID) || PHP_VERSION_ID < 50300
   45: extern php_stream_wrapper php_stream_phar_wrapper;
   46: #endif
   47: 
   48: /* for links to relative location, prepend cwd of the entry */
   49: static char *phar_get_link_location(phar_entry_info *entry TSRMLS_DC) /* {{{ */
   50: {
   51: 	char *p, *ret = NULL;
   52: 	if (!entry->link) {
   53: 		return NULL;
   54: 	}
   55: 	if (entry->link[0] == '/') {
   56: 		return estrdup(entry->link + 1);
   57: 	}
   58: 	p = strrchr(entry->filename, '/');
   59: 	if (p) {
   60: 		*p = '\0';
   61: 		spprintf(&ret, 0, "%s/%s", entry->filename, entry->link);
   62: 		return ret;
   63: 	}
   64: 	return entry->link;
   65: }
   66: /* }}} */
   67: 
   68: phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC) /* {{{ */
   69: {
   70: 	phar_entry_info *link_entry;
   71: 	char *link;
   72: 
   73: 	if (!entry->link) {
   74: 		return entry;
   75: 	}
   76: 
   77: 	link = phar_get_link_location(entry TSRMLS_CC);
   78: 	if (SUCCESS == zend_hash_find(&(entry->phar->manifest), entry->link, strlen(entry->link), (void **)&link_entry) ||
   79: 		SUCCESS == zend_hash_find(&(entry->phar->manifest), link, strlen(link), (void **)&link_entry)) {
   80: 		if (link != entry->link) {
   81: 			efree(link);
   82: 		}
   83: 		return phar_get_link_source(link_entry TSRMLS_CC);
   84: 	} else {
   85: 		if (link != entry->link) {
   86: 			efree(link);
   87: 		}
   88: 		return NULL;
   89: 	}
   90: }
   91: /* }}} */
   92: 
   93: /* retrieve a phar_entry_info's current file pointer for reading contents */
   94: php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC) /* {{{ */
   95: {
   96: 	if (follow_links && entry->link) {
   97: 		phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
   98: 
   99: 		if (link_entry && link_entry != entry) {
  100: 			return phar_get_efp(link_entry, 1 TSRMLS_CC);
  101: 		}
  102: 	}
  103: 
  104: 	if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) {
  105: 		if (!phar_get_entrypfp(entry TSRMLS_CC)) {
  106: 			/* re-open just in time for cases where our refcount reached 0 on the phar archive */
  107: 			phar_open_archive_fp(entry->phar TSRMLS_CC);
  108: 		}
  109: 		return phar_get_entrypfp(entry TSRMLS_CC);
  110: 	} else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) {
  111: 		return phar_get_entrypufp(entry TSRMLS_CC);
  112: 	} else if (entry->fp_type == PHAR_MOD) {
  113: 		return entry->fp;
  114: 	} else {
  115: 		/* temporary manifest entry */
  116: 		if (!entry->fp) {
  117: 			entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
  118: 		}
  119: 		return entry->fp;
  120: 	}
  121: }
  122: /* }}} */
  123: 
  124: int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC) /* {{{ */
  125: {
  126: 	php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
  127: 	off_t temp, eoffset;
  128: 
  129: 	if (!fp) {
  130: 		return -1;
  131: 	}
  132: 
  133: 	if (follow_links) {
  134: 		phar_entry_info *t;
  135: 		t = phar_get_link_source(entry TSRMLS_CC);
  136: 		if (t) {
  137: 			entry = t;
  138: 		}
  139: 	}
  140: 
  141: 	if (entry->is_dir) {
  142: 		return 0;
  143: 	}
  144: 
  145: 	eoffset = phar_get_fp_offset(entry TSRMLS_CC);
  146: 
  147: 	switch (whence) {
  148: 		case SEEK_END:
  149: 			temp = eoffset + entry->uncompressed_filesize + offset;
  150: 			break;
  151: 		case SEEK_CUR:
  152: 			temp = eoffset + position + offset;
  153: 			break;
  154: 		case SEEK_SET:
  155: 			temp = eoffset + offset;
  156: 			break;
  157: 		default:
  158: 			temp = 0;
  159: 	}
  160: 
  161: 	if (temp > eoffset + (off_t) entry->uncompressed_filesize) {
  162: 		return -1;
  163: 	}
  164: 
  165: 	if (temp < eoffset) {
  166: 		return -1;
  167: 	}
  168: 
  169: 	return php_stream_seek(fp, temp, SEEK_SET);
  170: }
  171: /* }}} */
  172: 
  173: /* mount an absolute path or uri to a path internal to the phar archive */
  174: int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC) /* {{{ */
  175: {
  176: 	phar_entry_info entry = {0};
  177: 	php_stream_statbuf ssb;
  178: 	int is_phar;
  179: 	const char *err;
  180: 
  181: 	if (phar_path_check(&path, &path_len, &err) > pcr_is_ok) {
  182: 		return FAILURE;
  183: 	}
  184: 
  185: 	if (path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
  186: 		/* no creating magic phar files by mounting them */
  187: 		return FAILURE;
  188: 	}
  189: 
  190: 	is_phar = (filename_len > 7 && !memcmp(filename, "phar://", 7));
  191: 
  192: 	entry.phar = phar;
  193: 	entry.filename = estrndup(path, path_len);
  194: #ifdef PHP_WIN32
  195: 	phar_unixify_path_separators(entry.filename, path_len);
  196: #endif
  197: 	entry.filename_len = path_len;
  198: 	if (is_phar) {
  199: 		entry.tmp = estrndup(filename, filename_len);
  200: 	} else {
  201: 		entry.tmp = expand_filepath(filename, NULL TSRMLS_CC);
  202: 		if (!entry.tmp) {
  203: 			entry.tmp = estrndup(filename, filename_len);
  204: 		}
  205: 	}
  206: #if PHP_API_VERSION < 20100412
  207: 	if (PG(safe_mode) && !is_phar && (!php_checkuid(entry.tmp, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
  208: 		efree(entry.tmp);
  209: 		efree(entry.filename);
  210: 		return FAILURE;
  211: 	}
  212: #endif
  213: 	filename = entry.tmp;
  214: 
  215: 	/* only check openbasedir for files, not for phar streams */
  216: 	if (!is_phar && php_check_open_basedir(filename TSRMLS_CC)) {
  217: 		efree(entry.tmp);
  218: 		efree(entry.filename);
  219: 		return FAILURE;
  220: 	}
  221: 
  222: 	entry.is_mounted = 1;
  223: 	entry.is_crc_checked = 1;
  224: 	entry.fp_type = PHAR_TMP;
  225: 
  226: 	if (SUCCESS != php_stream_stat_path(filename, &ssb)) {
  227: 		efree(entry.tmp);
  228: 		efree(entry.filename);
  229: 		return FAILURE;
  230: 	}
  231: 
  232: 	if (ssb.sb.st_mode & S_IFDIR) {
  233: 		entry.is_dir = 1;
  234: 		if (SUCCESS != zend_hash_add(&phar->mounted_dirs, entry.filename, path_len, (void *)&(entry.filename), sizeof(char *), NULL)) {
  235: 			/* directory already mounted */
  236: 			efree(entry.tmp);
  237: 			efree(entry.filename);
  238: 			return FAILURE;
  239: 		}
  240: 	} else {
  241: 		entry.is_dir = 0;
  242: 		entry.uncompressed_filesize = entry.compressed_filesize = ssb.sb.st_size;
  243: 	}
  244: 
  245: 	entry.flags = ssb.sb.st_mode;
  246: 
  247: 	if (SUCCESS == zend_hash_add(&phar->manifest, entry.filename, path_len, (void*)&entry, sizeof(phar_entry_info), NULL)) {
  248: 		return SUCCESS;
  249: 	}
  250: 
  251: 	efree(entry.tmp);
  252: 	efree(entry.filename);
  253: 	return FAILURE;
  254: }
  255: /* }}} */
  256: 
  257: char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_data **pphar TSRMLS_DC) /* {{{ */
  258: {
  259: #if PHP_VERSION_ID >= 50300
  260: 	char *path, *fname, *arch, *entry, *ret, *test;
  261: 	int arch_len, entry_len, fname_len, ret_len;
  262: 	phar_archive_data *phar;
  263: 
  264: 	if (pphar) {
  265: 		*pphar = NULL;
  266: 	} else {
  267: 		pphar = &phar;
  268: 	}
  269: 
  270: 	if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
  271: 		return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
  272: 	}
  273: 
  274: 	fname = (char*)zend_get_executed_filename(TSRMLS_C);
  275: 	fname_len = strlen(fname);
  276: 
  277: 	if (PHAR_G(last_phar) && !memcmp(fname, "phar://", 7) && fname_len - 7 >= PHAR_G(last_phar_name_len) && !memcmp(fname + 7, PHAR_G(last_phar_name), PHAR_G(last_phar_name_len))) {
  278: 		arch = estrndup(PHAR_G(last_phar_name), PHAR_G(last_phar_name_len));
  279: 		arch_len = PHAR_G(last_phar_name_len);
  280: 		phar = PHAR_G(last_phar);
  281: 		goto splitted;
  282: 	}
  283: 
  284: 	if (fname_len < 7 || memcmp(fname, "phar://", 7) || SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
  285: 		return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
  286: 	}
  287: 
  288: 	efree(entry);
  289: 
  290: 	if (*filename == '.') {
  291: 		int try_len;
  292: 
  293: 		if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
  294: 			efree(arch);
  295: 			return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
  296: 		}
  297: splitted:
  298: 		if (pphar) {
  299: 			*pphar = phar;
  300: 		}
  301: 
  302: 		try_len = filename_len;
  303: 		test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
  304: 
  305: 		if (*test == '/') {
  306: 			if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
  307: 				spprintf(&ret, 0, "phar://%s%s", arch, test);
  308: 				efree(arch);
  309: 				efree(test);
  310: 				return ret;
  311: 			}
  312: 		} else {
  313: 			if (zend_hash_exists(&(phar->manifest), test, try_len)) {
  314: 				spprintf(&ret, 0, "phar://%s/%s", arch, test);
  315: 				efree(arch);
  316: 				efree(test);
  317: 				return ret;
  318: 			}
  319: 		}
  320: 		efree(test);
  321: 	}
  322: 
  323: 	spprintf(&path, MAXPATHLEN, "phar://%s/%s%c%s", arch, PHAR_G(cwd), DEFAULT_DIR_SEPARATOR, PG(include_path));
  324: 	efree(arch);
  325: 	ret = php_resolve_path(filename, filename_len, path TSRMLS_CC);
  326: 	efree(path);
  327: 
  328: 	if (ret && strlen(ret) > 8 && !strncmp(ret, "phar://", 7)) {
  329: 		ret_len = strlen(ret);
  330: 		/* found phar:// */
  331: 
  332: 		if (SUCCESS != phar_split_fname(ret, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
  333: 			return ret;
  334: 		}
  335: 
  336: 		zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
  337: 
  338: 		if (!pphar && PHAR_G(manifest_cached)) {
  339: 			zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
  340: 		}
  341: 
  342: 		efree(arch);
  343: 		efree(entry);
  344: 	}
  345: 
  346: 	return ret;
  347: #else /* PHP 5.2 */
  348: 	char resolved_path[MAXPATHLEN];
  349: 	char trypath[MAXPATHLEN];
  350: 	char *ptr, *end, *path = PG(include_path);
  351: 	php_stream_wrapper *wrapper;
  352: 	const char *p;
  353: 	int n = 0;
  354: 	char *fname, *arch, *entry, *ret, *test;
  355: 	int arch_len, entry_len;
  356: 	phar_archive_data *phar = NULL;
  357: 
  358: 	if (!filename) {
  359: 		return NULL;
  360: 	}
  361: 
  362: 	if (!zend_is_executing(TSRMLS_C) || !PHAR_G(cwd)) {
  363: 		goto doit;
  364: 	}
  365: 
  366: 	fname = (char*)zend_get_executed_filename(TSRMLS_C);
  367: 
  368: 	if (SUCCESS != phar_split_fname(fname, strlen(fname), &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
  369: 		goto doit;
  370: 	}
  371: 
  372: 	efree(entry);
  373: 
  374: 	if (*filename == '.') {
  375: 		int try_len;
  376: 
  377: 		if (FAILURE == phar_get_archive(&phar, arch, arch_len, NULL, 0, NULL TSRMLS_CC)) {
  378: 			efree(arch);
  379: 			goto doit;
  380: 		}
  381: 
  382: 		try_len = filename_len;
  383: 		test = phar_fix_filepath(estrndup(filename, filename_len), &try_len, 1 TSRMLS_CC);
  384: 
  385: 		if (*test == '/') {
  386: 			if (zend_hash_exists(&(phar->manifest), test + 1, try_len - 1)) {
  387: 				spprintf(&ret, 0, "phar://%s%s", arch, test);
  388: 				efree(arch);
  389: 				efree(test);
  390: 				return ret;
  391: 			}
  392: 		} else {
  393: 			if (zend_hash_exists(&(phar->manifest), test, try_len)) {
  394: 				spprintf(&ret, 0, "phar://%s/%s", arch, test);
  395: 				efree(arch);
  396: 				efree(test);
  397: 				return ret;
  398: 			}
  399: 		}
  400: 
  401: 		efree(test);
  402: 	}
  403: 
  404: 	efree(arch);
  405: doit:
  406: 	if (*filename == '.' || IS_ABSOLUTE_PATH(filename, filename_len) || !path || !*path) {
  407: 		if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
  408: 			return estrdup(resolved_path);
  409: 		} else {
  410: 			return NULL;
  411: 		}
  412: 	}
  413: 
  414: 	/* test for stream wrappers and return */
  415: 	for (p = filename; p - filename < filename_len && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
  416: 
  417: 	if (n < filename_len - 3 && (*p == ':') && (!strncmp("//", p+1, 2) || ( filename_len > 4 && !memcmp("data", filename, 4)))) {
  418: 		/* found stream wrapper, this is an absolute path until stream wrappers implement realpath */
  419: 		return estrndup(filename, filename_len);
  420: 	}
  421: 
  422: 	ptr = (char *) path;
  423: 	while (ptr && *ptr) {
  424: 		int len, is_stream_wrapper = 0, maybe_stream = 1;
  425: 
  426: 		end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
  427: #ifndef PHP_WIN32
  428: 		/* search for stream wrapper */
  429: 		if (end - ptr  <= 1) {
  430: 			maybe_stream = 0;
  431: 			goto not_stream;
  432: 		}
  433: 
  434: 		for (p = ptr, n = 0; p < end && (isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'); ++p, ++n);
  435: 
  436: 		if (n == end - ptr && *p && !strncmp("//", p+1, 2)) {
  437: 			is_stream_wrapper = 1;
  438: 			/* seek to real end of include_path portion */
  439: 			end = strchr(end + 1, DEFAULT_DIR_SEPARATOR);
  440: 		} else {
  441: 			maybe_stream = 0;
  442: 		}
  443: not_stream:
  444: #endif
  445: 		if (end) {
  446: 			if ((end-ptr) + 1 + filename_len + 1 >= MAXPATHLEN) {
  447: 				ptr = end + 1;
  448: 				continue;
  449: 			}
  450: 
  451: 			memcpy(trypath, ptr, end-ptr);
  452: 			len = end-ptr;
  453: 			trypath[end-ptr] = '/';
  454: 			memcpy(trypath+(end-ptr)+1, filename, filename_len+1);
  455: 			ptr = end+1;
  456: 		} else {
  457: 			len = strlen(ptr);
  458: 
  459: 			if (len + 1 + filename_len + 1 >= MAXPATHLEN) {
  460: 				break;
  461: 			}
  462: 
  463: 			memcpy(trypath, ptr, len);
  464: 			trypath[len] = '/';
  465: 			memcpy(trypath+len+1, filename, filename_len+1);
  466: 			ptr = NULL;
  467: 		}
  468: 
  469: 		if (!is_stream_wrapper && maybe_stream) {
  470: 			/* search for stream wrapper */
  471: 			for (p = trypath, n = 0; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
  472: 		}
  473: 
  474: 		if (is_stream_wrapper || (n < len - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4)))) {
  475: 			char *actual;
  476: 
  477: 			wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
  478: 			if (wrapper == &php_plain_files_wrapper) {
  479: 				strlcpy(trypath, actual, sizeof(trypath));
  480: 			} else if (!wrapper) {
  481: 				/* if wrapper is NULL, there was a mal-formed include_path stream wrapper, so skip this ptr */
  482: 				continue;
  483: 			} else {
  484: 				if (wrapper->wops->url_stat) {
  485: 					php_stream_statbuf ssb;
  486: 
  487: 					if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
  488: 						if (wrapper == &php_stream_phar_wrapper) {
  489: 							char *arch, *entry;
  490: 							int arch_len, entry_len, ret_len;
  491: 
  492: 							ret_len = strlen(trypath);
  493: 							/* found phar:// */
  494: 
  495: 							if (SUCCESS != phar_split_fname(trypath, ret_len, &arch, &arch_len, &entry, &entry_len, 1, 0 TSRMLS_CC)) {
  496: 								return estrndup(trypath, ret_len);
  497: 							}
  498: 
  499: 							zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar);
  500: 
  501: 							if (!pphar && PHAR_G(manifest_cached)) {
  502: 								zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar);
  503: 							}
  504: 
  505: 							efree(arch);
  506: 							efree(entry);
  507: 
  508: 							return estrndup(trypath, ret_len);
  509: 						}
  510: 						return estrdup(trypath);
  511: 					}
  512: 				}
  513: 				continue;
  514: 			}
  515: 		}
  516: 
  517: 		if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
  518: 			return estrdup(resolved_path);
  519: 		}
  520: 	} /* end provided path */
  521: 
  522: 	/* check in calling scripts' current working directory as a fall back case */
  523: 	if (zend_is_executing(TSRMLS_C)) {
  524: 		char *exec_fname = (char*)zend_get_executed_filename(TSRMLS_C);
  525: 		int exec_fname_length = strlen(exec_fname);
  526: 		const char *p;
  527: 		int n = 0;
  528: 
  529: 		while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
  530: 		if (exec_fname && exec_fname[0] != '[' && 
  531: 			exec_fname_length > 0 && 
  532: 			exec_fname_length + 1 + filename_len + 1 < MAXPATHLEN) {
  533: 			memcpy(trypath, exec_fname, exec_fname_length + 1);
  534: 			memcpy(trypath+exec_fname_length + 1, filename, filename_len+1);
  535: 
  536: 			/* search for stream wrapper */
  537: 			for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; ++p, ++n);
  538: 
  539: 			if (n < exec_fname_length - 3 && (*p == ':') && (n > 1) && (!strncmp("//", p+1, 2) || !memcmp("data", trypath, 4))) {
  540: 				char *actual;
  541: 
  542: 				wrapper = php_stream_locate_url_wrapper(trypath, &actual, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
  543: 
  544: 				if (wrapper == &php_plain_files_wrapper) {
  545: 					/* this should never technically happen, but we'll leave it here for completeness */
  546: 					strlcpy(trypath, actual, sizeof(trypath));
  547: 				} else if (!wrapper) {
  548: 					/* if wrapper is NULL, there was a malformed include_path stream wrapper
  549: 					   this also should be impossible */
  550: 					return NULL;
  551: 				} else {
  552: 					return estrdup(trypath);
  553: 				}
  554: 			}
  555: 
  556: 			if (tsrm_realpath(trypath, resolved_path TSRMLS_CC)) {
  557: 				return estrdup(resolved_path);
  558: 			}
  559: 		}
  560: 	}
  561: 
  562: 	return NULL;
  563: #endif /* PHP 5.2 */
  564: }
  565: /* }}} */
  566: 
  567: /**
  568:  * Retrieve a copy of the file information on a single file within a phar, or null.
  569:  * This also transfers the open file pointer, if any, to the entry.
  570:  *
  571:  * If the file does not already exist, this will fail.  Pre-existing files can be
  572:  * appended, truncated, or read.  For read, if the entry is marked unmodified, it is
  573:  * assumed that the file pointer, if present, is opened for reading
  574:  */
  575: int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */
  576: {
  577: 	phar_archive_data *phar;
  578: 	phar_entry_info *entry;
  579: 	int for_write  = mode[0] != 'r' || mode[1] == '+';
  580: 	int for_append = mode[0] == 'a';
  581: 	int for_create = mode[0] != 'r';
  582: 	int for_trunc  = mode[0] == 'w';
  583: 
  584: 	if (!ret) {
  585: 		return FAILURE;
  586: 	}
  587: 
  588: 	*ret = NULL;
  589: 
  590: 	if (error) {
  591: 		*error = NULL;
  592: 	}
  593: 
  594: 	if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
  595: 		return FAILURE;
  596: 	}
  597: 
  598: 	if (for_write && PHAR_G(readonly) && !phar->is_data) {
  599: 		if (error) {
  600: 			spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, disabled by ini setting", path, fname);
  601: 		}
  602: 		return FAILURE;
  603: 	}
  604: 
  605: 	if (!path_len) {
  606: 		if (error) {
  607: 			spprintf(error, 4096, "phar error: file \"\" in phar \"%s\" cannot be empty", fname);
  608: 		}
  609: 		return FAILURE;
  610: 	}
  611: really_get_entry:
  612: 	if (allow_dir) {
  613: 		if ((entry = phar_get_entry_info_dir(phar, path, path_len, allow_dir, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) {
  614: 			if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
  615: 				return SUCCESS;
  616: 			}
  617: 			return FAILURE;
  618: 		}
  619: 	} else {
  620: 		if ((entry = phar_get_entry_info(phar, path, path_len, for_create && !PHAR_G(readonly) && !phar->is_data ? NULL : error, security TSRMLS_CC)) == NULL) {
  621: 			if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
  622: 				return SUCCESS;
  623: 			}
  624: 			return FAILURE;
  625: 		}
  626: 	}
  627: 
  628: 	if (for_write && phar->is_persistent) {
  629: 		if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
  630: 			if (error) {
  631: 				spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname);
  632: 			}
  633: 			return FAILURE;
  634: 		} else {
  635: 			goto really_get_entry;
  636: 		}
  637: 	}
  638: 
  639: 	if (entry->is_modified && !for_write) {
  640: 		if (error) {
  641: 			spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname);
  642: 		}
  643: 		return FAILURE;
  644: 	}
  645: 
  646: 	if (entry->fp_refcount && for_write) {
  647: 		if (error) {
  648: 			spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, readable file pointers are open", path, fname);
  649: 		}
  650: 		return FAILURE;
  651: 	}
  652: 
  653: 	if (entry->is_deleted) {
  654: 		if (!for_create) {
  655: 			return FAILURE;
  656: 		}
  657: 		entry->is_deleted = 0;
  658: 	}
  659: 
  660: 	if (entry->is_dir) {
  661: 		*ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
  662: 		(*ret)->position = 0;
  663: 		(*ret)->fp = NULL;
  664: 		(*ret)->phar = phar;
  665: 		(*ret)->for_write = for_write;
  666: 		(*ret)->internal_file = entry;
  667: 		(*ret)->is_zip = entry->is_zip;
  668: 		(*ret)->is_tar = entry->is_tar;
  669: 
  670: 		if (!phar->is_persistent) {
  671: 			++(entry->phar->refcount);
  672: 			++(entry->fp_refcount);
  673: 		}
  674: 
  675: 		return SUCCESS;
  676: 	}
  677: 
  678: 	if (entry->fp_type == PHAR_MOD) {
  679: 		if (for_trunc) {
  680: 			if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
  681: 				return FAILURE;
  682: 			}
  683: 		} else if (for_append) {
  684: 			phar_seek_efp(entry, 0, SEEK_END, 0, 0 TSRMLS_CC);
  685: 		}
  686: 	} else {
  687: 		if (for_write) {
  688: 			if (entry->link) {
  689: 				efree(entry->link);
  690: 				entry->link = NULL;
  691: 				entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
  692: 			}
  693: 
  694: 			if (for_trunc) {
  695: 				if (FAILURE == phar_create_writeable_entry(phar, entry, error TSRMLS_CC)) {
  696: 					return FAILURE;
  697: 				}
  698: 			} else {
  699: 				if (FAILURE == phar_separate_entry_fp(entry, error TSRMLS_CC)) {
  700: 					return FAILURE;
  701: 				}
  702: 			}
  703: 		} else {
  704: 			if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
  705: 				return FAILURE;
  706: 			}
  707: 		}
  708: 	}
  709: 
  710: 	*ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
  711: 	(*ret)->position = 0;
  712: 	(*ret)->phar = phar;
  713: 	(*ret)->for_write = for_write;
  714: 	(*ret)->internal_file = entry;
  715: 	(*ret)->is_zip = entry->is_zip;
  716: 	(*ret)->is_tar = entry->is_tar;
  717: 	(*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
  718: 	if (entry->link) {
  719: 		(*ret)->zero = phar_get_fp_offset(phar_get_link_source(entry TSRMLS_CC) TSRMLS_CC);
  720: 	} else {
  721: 		(*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC);
  722: 	}
  723: 
  724: 	if (!phar->is_persistent) {
  725: 		++(entry->fp_refcount);
  726: 		++(entry->phar->refcount);
  727: 	}
  728: 
  729: 	return SUCCESS;
  730: }
  731: /* }}} */
  732: 
  733: /**
  734:  * Create a new dummy file slot within a writeable phar for a newly created file
  735:  */
  736: phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char *path, int path_len, char *mode, char allow_dir, char **error, int security TSRMLS_DC) /* {{{ */
  737: {
  738: 	phar_archive_data *phar;
  739: 	phar_entry_info *entry, etemp;
  740: 	phar_entry_data *ret;
  741: 	const char *pcr_error;
  742: 	char is_dir;
  743: 
  744: #ifdef PHP_WIN32
  745: 	phar_unixify_path_separators(path, path_len);
  746: #endif
  747: 
  748: 	is_dir = (path_len && path[path_len - 1] == '/') ? 1 : 0;
  749: 
  750: 	if (FAILURE == phar_get_archive(&phar, fname, fname_len, NULL, 0, error TSRMLS_CC)) {
  751: 		return NULL;
  752: 	}
  753: 
  754: 	if (FAILURE == phar_get_entry_data(&ret, fname, fname_len, path, path_len, mode, allow_dir, error, security TSRMLS_CC)) {
  755: 		return NULL;
  756: 	} else if (ret) {
  757: 		return ret;
  758: 	}
  759: 
  760: 	if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
  761: 		if (error) {
  762: 			spprintf(error, 0, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
  763: 		}
  764: 		return NULL;
  765: 	}
  766: 
  767: 	if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
  768: 		if (error) {
  769: 			spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname);
  770: 		}
  771: 		return NULL;
  772: 	}
  773: 
  774: 	/* create a new phar data holder */
  775: 	ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
  776: 
  777: 	/* create an entry, this is a new file */
  778: 	memset(&etemp, 0, sizeof(phar_entry_info));
  779: 	etemp.filename_len = path_len;
  780: 	etemp.fp_type = PHAR_MOD;
  781: 	etemp.fp = php_stream_fopen_tmpfile();
  782: 
  783: 	if (!etemp.fp) {
  784: 		if (error) {
  785: 			spprintf(error, 0, "phar error: unable to create temporary file");
  786: 		}
  787: 		efree(ret);
  788: 		return NULL;
  789: 	}
  790: 
  791: 	etemp.fp_refcount = 1;
  792: 
  793: 	if (allow_dir == 2) {
  794: 		etemp.is_dir = 1;
  795: 		etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_DIR;
  796: 	} else {
  797: 		etemp.flags = etemp.old_flags = PHAR_ENT_PERM_DEF_FILE;
  798: 	}
  799: 	if (is_dir) {
  800: 		etemp.filename_len--; /* strip trailing / */
  801: 		path_len--;
  802: 	}
  803: 
  804: 	phar_add_virtual_dirs(phar, path, path_len TSRMLS_CC);
  805: 	etemp.is_modified = 1;
  806: 	etemp.timestamp = time(0);
  807: 	etemp.is_crc_checked = 1;
  808: 	etemp.phar = phar;
  809: 	etemp.filename = estrndup(path, path_len);
  810: 	etemp.is_zip = phar->is_zip;
  811: 
  812: 	if (phar->is_tar) {
  813: 		etemp.is_tar = phar->is_tar;
  814: 		etemp.tar_type = etemp.is_dir ? TAR_DIR : TAR_FILE;
  815: 	}
  816: 
  817: 	if (FAILURE == zend_hash_add(&phar->manifest, etemp.filename, path_len, (void*)&etemp, sizeof(phar_entry_info), (void **) &entry)) {
  818: 		php_stream_close(etemp.fp);
  819: 		if (error) {
  820: 			spprintf(error, 0, "phar error: unable to add new entry \"%s\" to phar \"%s\"", etemp.filename, phar->fname);
  821: 		}
  822: 		efree(ret);
  823: 		efree(etemp.filename);
  824: 		return NULL;
  825: 	}
  826: 
  827: 	if (!entry) {
  828: 		php_stream_close(etemp.fp);
  829: 		efree(etemp.filename);
  830: 		efree(ret);
  831: 		return NULL;
  832: 	}
  833: 
  834: 	++(phar->refcount);
  835: 	ret->phar = phar;
  836: 	ret->fp = entry->fp;
  837: 	ret->position = ret->zero = 0;
  838: 	ret->for_write = 1;
  839: 	ret->is_zip = entry->is_zip;
  840: 	ret->is_tar = entry->is_tar;
  841: 	ret->internal_file = entry;
  842: 
  843: 	return ret;
  844: }
  845: /* }}} */
  846: 
  847: /* initialize a phar_archive_data's read-only fp for existing phar data */
  848: int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC) /* {{{ */
  849: {
  850: 	if (phar_get_pharfp(phar TSRMLS_CC)) {
  851: 		return SUCCESS;
  852: 	}
  853: #if PHP_API_VERSION < 20100412
  854: 	if (PG(safe_mode) && (!php_checkuid(phar->fname, NULL, CHECKUID_ALLOW_ONLY_FILE))) {
  855: 		return FAILURE;
  856: 	}
  857: #endif
  858: 
  859: 	if (php_check_open_basedir(phar->fname TSRMLS_CC)) {
  860: 		return FAILURE;
  861: 	}
  862: 
  863: 	phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC);
  864: 
  865: 	if (!phar_get_pharfp(phar TSRMLS_CC)) {
  866: 		return FAILURE;
  867: 	}
  868: 
  869: 	return SUCCESS;
  870: }
  871: /* }}} */
  872: 
  873: /* copy file data from an existing to a new phar_entry_info that is not in the manifest */
  874: int phar_copy_entry_fp(phar_entry_info *source, phar_entry_info *dest, char **error TSRMLS_DC) /* {{{ */
  875: {
  876: 	phar_entry_info *link;
  877: 
  878: 	if (FAILURE == phar_open_entry_fp(source, error, 1 TSRMLS_CC)) {
  879: 		return FAILURE;
  880: 	}
  881: 
  882: 	if (dest->link) {
  883: 		efree(dest->link);
  884: 		dest->link = NULL;
  885: 		dest->tar_type = (dest->is_tar ? TAR_FILE : '\0');
  886: 	}
  887: 
  888: 	dest->fp_type = PHAR_MOD;
  889: 	dest->offset = 0;
  890: 	dest->is_modified = 1;
  891: 	dest->fp = php_stream_fopen_tmpfile();
  892: 	if (dest->fp == NULL) {
  893: 		spprintf(error, 0, "phar error: unable to create temporary file");
  894: 		return EOF;
  895: 	}
  896: 	phar_seek_efp(source, 0, SEEK_SET, 0, 1 TSRMLS_CC);
  897: 	link = phar_get_link_source(source TSRMLS_CC);
  898: 
  899: 	if (!link) {
  900: 		link = source;
  901: 	}
  902: 
  903: 	if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), dest->fp, link->uncompressed_filesize, NULL)) {
  904: 		php_stream_close(dest->fp);
  905: 		dest->fp_type = PHAR_FP;
  906: 		if (error) {
  907: 			spprintf(error, 4096, "phar error: unable to copy contents of file \"%s\" to \"%s\" in phar archive \"%s\"", source->filename, dest->filename, source->phar->fname);
  908: 		}
  909: 		return FAILURE;
  910: 	}
  911: 
  912: 	return SUCCESS;
  913: }
  914: /* }}} */
  915: 
  916: /* open and decompress a compressed phar entry
  917:  */
  918: int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TSRMLS_DC) /* {{{ */
  919: {
  920: 	php_stream_filter *filter;
  921: 	phar_archive_data *phar = entry->phar;
  922: 	char *filtername;
  923: 	off_t loc;
  924: 	php_stream *ufp;
  925: 	phar_entry_data dummy;
  926: 
  927: 	if (follow_links && entry->link) {
  928: 		phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
  929: 		if (link_entry && link_entry != entry) {
  930: 			return phar_open_entry_fp(link_entry, error, 1 TSRMLS_CC);
  931: 		}
  932: 	}
  933: 
  934: 	if (entry->is_modified) {
  935: 		return SUCCESS;
  936: 	}
  937: 
  938: 	if (entry->fp_type == PHAR_TMP) {
  939: 		if (!entry->fp) {
  940: 			entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
  941: 		}
  942: 		return SUCCESS;
  943: 	}
  944: 
  945: 	if (entry->fp_type != PHAR_FP) {
  946: 		/* either newly created or already modified */
  947: 		return SUCCESS;
  948: 	}
  949: 
  950: 	if (!phar_get_pharfp(phar TSRMLS_CC)) {
  951: 		if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) {
  952: 			spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
  953: 			return FAILURE;
  954: 		}
  955: 	}
  956: 
  957: 	if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
  958: 		dummy.internal_file = entry;
  959: 		dummy.phar = phar;
  960: 		dummy.zero = entry->offset;
  961: 		dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
  962: 		if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
  963: 			return FAILURE;
  964: 		}
  965: 		return SUCCESS;
  966: 	}
  967: 
  968: 	if (!phar_get_entrypufp(entry TSRMLS_CC)) {
  969: 		phar_set_entrypufp(entry, php_stream_fopen_tmpfile() TSRMLS_CC);
  970: 		if (!phar_get_entrypufp(entry TSRMLS_CC)) {
  971: 			spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
  972: 			return FAILURE;
  973: 		}
  974: 	}
  975: 
  976: 	dummy.internal_file = entry;
  977: 	dummy.phar = phar;
  978: 	dummy.zero = entry->offset;
  979: 	dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
  980: 	if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
  981: 		return FAILURE;
  982: 	}
  983: 
  984: 	ufp = phar_get_entrypufp(entry TSRMLS_CC);
  985: 
  986: 	if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
  987: 		filter = php_stream_filter_create(filtername, NULL, 0 TSRMLS_CC);
  988: 	} else {
  989: 		filter = NULL;
  990: 	}
  991: 
  992: 	if (!filter) {
  993: 		spprintf(error, 4096, "phar error: unable to read phar \"%s\" (cannot create %s filter while decompressing file \"%s\")", phar->fname, phar_decompress_filter(entry, 1), entry->filename);
  994: 		return FAILURE;
  995: 	}
  996: 
  997: 	/* now we can safely use proper decompression */
  998: 	/* save the new offset location within ufp */
  999: 	php_stream_seek(ufp, 0, SEEK_END);
 1000: 	loc = php_stream_tell(ufp);
 1001: 	php_stream_filter_append(&ufp->writefilters, filter);
 1002: 	php_stream_seek(phar_get_entrypfp(entry TSRMLS_CC), phar_get_fp_offset(entry TSRMLS_CC), SEEK_SET);
 1003: 
 1004: 	if (entry->uncompressed_filesize) {
 1005: 		if (SUCCESS != phar_stream_copy_to_stream(phar_get_entrypfp(entry TSRMLS_CC), ufp, entry->compressed_filesize, NULL)) {
 1006: 			spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
 1007: 			php_stream_filter_remove(filter, 1 TSRMLS_CC);
 1008: 			return FAILURE;
 1009: 		}
 1010: 	}
 1011: 
 1012: 	php_stream_filter_flush(filter, 1);
 1013: 	php_stream_flush(ufp);
 1014: 	php_stream_filter_remove(filter, 1 TSRMLS_CC);
 1015: 
 1016: 	if (php_stream_tell(ufp) - loc != (off_t) entry->uncompressed_filesize) {
 1017: 		spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
 1018: 		return FAILURE;
 1019: 	}
 1020: 
 1021: 	entry->old_flags = entry->flags;
 1022: 
 1023: 	/* this is now the new location of the file contents within this fp */
 1024: 	phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
 1025: 	dummy.zero = entry->offset;
 1026: 	dummy.fp = ufp;
 1027: 	if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0 TSRMLS_CC)) {
 1028: 		return FAILURE;
 1029: 	}
 1030: 	return SUCCESS;
 1031: }
 1032: /* }}} */
 1033: 
 1034: #if defined(PHP_VERSION_ID) && PHP_VERSION_ID < 50202
 1035: typedef struct {
 1036: 	char        *data;
 1037: 	size_t      fpos;
 1038: 	size_t      fsize;
 1039: 	size_t      smax;
 1040: 	int         mode;
 1041: 	php_stream  **owner_ptr;
 1042: } php_stream_memory_data;
 1043: #endif
 1044: 
 1045: int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
 1046: {
 1047: 	if (entry->fp_type == PHAR_MOD) {
 1048: 		/* already newly created, truncate */
 1049: #if PHP_VERSION_ID >= 50202
 1050: 		php_stream_truncate_set_size(entry->fp, 0);
 1051: #else
 1052: 		if (php_stream_is(entry->fp, PHP_STREAM_IS_TEMP)) {
 1053: 			if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_MEMORY)) {
 1054: 				php_stream *inner = *(php_stream**)entry->fp->abstract;
 1055: 				php_stream_memory_data *memfp = (php_stream_memory_data*)inner->abstract;
 1056: 				memfp->fpos = 0;
 1057: 				memfp->fsize = 0;
 1058: 			} else if (php_stream_is(*(php_stream**)entry->fp->abstract, PHP_STREAM_IS_STDIO)) {
 1059: 				php_stream_truncate_set_size(*(php_stream**)entry->fp->abstract, 0);
 1060: 			} else {
 1061: 				if (error) {
 1062: 					spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
 1063: 				}
 1064: 				return FAILURE;
 1065: 			}
 1066: 		} else if (php_stream_is(entry->fp, PHP_STREAM_IS_STDIO)) {
 1067: 			php_stream_truncate_set_size(entry->fp, 0);
 1068: 		} else {
 1069: 			if (error) {
 1070: 				spprintf(error, 0, "phar error: file \"%s\" cannot be opened for writing, no truncate support", phar->fname);
 1071: 			}
 1072: 			return FAILURE;
 1073: 		}
 1074: #endif
 1075: 		entry->old_flags = entry->flags;
 1076: 		entry->is_modified = 1;
 1077: 		phar->is_modified = 1;
 1078: 		/* reset file size */
 1079: 		entry->uncompressed_filesize = 0;
 1080: 		entry->compressed_filesize = 0;
 1081: 		entry->crc32 = 0;
 1082: 		entry->flags = PHAR_ENT_PERM_DEF_FILE;
 1083: 		entry->fp_type = PHAR_MOD;
 1084: 		entry->offset = 0;
 1085: 		return SUCCESS;
 1086: 	}
 1087: 
 1088: 	if (error) {
 1089: 		*error = NULL;
 1090: 	}
 1091: 
 1092: 	/* open a new temp file for writing */
 1093: 	if (entry->link) {
 1094: 		efree(entry->link);
 1095: 		entry->link = NULL;
 1096: 		entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
 1097: 	}
 1098: 
 1099: 	entry->fp = php_stream_fopen_tmpfile();
 1100: 
 1101: 	if (!entry->fp) {
 1102: 		if (error) {
 1103: 			spprintf(error, 0, "phar error: unable to create temporary file");
 1104: 		}
 1105: 		return FAILURE;
 1106: 	}
 1107: 
 1108: 	entry->old_flags = entry->flags;
 1109: 	entry->is_modified = 1;
 1110: 	phar->is_modified = 1;
 1111: 	/* reset file size */
 1112: 	entry->uncompressed_filesize = 0;
 1113: 	entry->compressed_filesize = 0;
 1114: 	entry->crc32 = 0;
 1115: 	entry->flags = PHAR_ENT_PERM_DEF_FILE;
 1116: 	entry->fp_type = PHAR_MOD;
 1117: 	entry->offset = 0;
 1118: 	return SUCCESS;
 1119: }
 1120: /* }}} */
 1121: 
 1122: int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
 1123: {
 1124: 	php_stream *fp;
 1125: 	phar_entry_info *link;
 1126: 
 1127: 	if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
 1128: 		return FAILURE;
 1129: 	}
 1130: 
 1131: 	if (entry->fp_type == PHAR_MOD) {
 1132: 		return SUCCESS;
 1133: 	}
 1134: 
 1135: 	fp = php_stream_fopen_tmpfile();
 1136: 	if (fp == NULL) {
 1137: 		spprintf(error, 0, "phar error: unable to create temporary file");
 1138: 		return FAILURE;
 1139: 	}
 1140: 	phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC);
 1141: 	link = phar_get_link_source(entry TSRMLS_CC);
 1142: 
 1143: 	if (!link) {
 1144: 		link = entry;
 1145: 	}
 1146: 
 1147: 	if (SUCCESS != phar_stream_copy_to_stream(phar_get_efp(link, 0 TSRMLS_CC), fp, link->uncompressed_filesize, NULL)) {
 1148: 		if (error) {
 1149: 			spprintf(error, 4096, "phar error: cannot separate entry file \"%s\" contents in phar archive \"%s\" for write access", entry->filename, entry->phar->fname);
 1150: 		}
 1151: 		return FAILURE;
 1152: 	}
 1153: 
 1154: 	if (entry->link) {
 1155: 		efree(entry->link);
 1156: 		entry->link = NULL;
 1157: 		entry->tar_type = (entry->is_tar ? TAR_FILE : '\0');
 1158: 	}
 1159: 
 1160: 	entry->offset = 0;
 1161: 	entry->fp = fp;
 1162: 	entry->fp_type = PHAR_MOD;
 1163: 	entry->is_modified = 1;
 1164: 	return SUCCESS;
 1165: }
 1166: /* }}} */
 1167: 
 1168: /**
 1169:  * helper function to open an internal file's fp just-in-time
 1170:  */
 1171: phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC) /* {{{ */
 1172: {
 1173: 	if (error) {
 1174: 		*error = NULL;
 1175: 	}
 1176: 	/* seek to start of internal file and read it */
 1177: 	if (FAILURE == phar_open_entry_fp(entry, error, 1 TSRMLS_CC)) {
 1178: 		return NULL;
 1179: 	}
 1180: 	if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 1 TSRMLS_CC)) {
 1181: 		spprintf(error, 4096, "phar error: cannot seek to start of file \"%s\" in phar \"%s\"", entry->filename, phar->fname);
 1182: 		return NULL;
 1183: 	}
 1184: 	return entry;
 1185: }
 1186: /* }}} */
 1187: 
 1188: int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
 1189: {
 1190: 	if (phar->refcount || phar->is_persistent) {
 1191: 		return FAILURE;
 1192: 	}
 1193: 
 1194: 	/* this archive has no open references, so emit an E_STRICT and remove it */
 1195: 	if (zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
 1196: 		return FAILURE;
 1197: 	}
 1198: 
 1199: 	/* invalidate phar cache */
 1200: 	PHAR_G(last_phar) = NULL;
 1201: 	PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
 1202: 
 1203: 	return SUCCESS;
 1204: }
 1205: /* }}} */
 1206: 
 1207: /**
 1208:  * Looks up a phar archive in the filename map, connecting it to the alias
 1209:  * (if any) or returns null
 1210:  */
 1211: int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, char *alias, int alias_len, char **error TSRMLS_DC) /* {{{ */
 1212: {
 1213: 	phar_archive_data *fd, **fd_ptr;
 1214: 	char *my_realpath, *save;
 1215: 	int save_len;
 1216: 	ulong fhash, ahash = 0;
 1217: 
 1218: 	phar_request_initialize(TSRMLS_C);
 1219: 
 1220: 	if (error) {
 1221: 		*error = NULL;
 1222: 	}
 1223: 
 1224: 	*archive = NULL;
 1225: 
 1226: 	if (PHAR_G(last_phar) && fname_len == PHAR_G(last_phar_name_len) && !memcmp(fname, PHAR_G(last_phar_name), fname_len)) {
 1227: 		*archive = PHAR_G(last_phar);
 1228: 		if (alias && alias_len) {
 1229: 
 1230: 			if (!PHAR_G(last_phar)->is_temporary_alias && (alias_len != PHAR_G(last_phar)->alias_len || memcmp(PHAR_G(last_phar)->alias, alias, alias_len))) {
 1231: 				if (error) {
 1232: 					spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, PHAR_G(last_phar)->fname, fname);
 1233: 				}
 1234: 				*archive = NULL;
 1235: 				return FAILURE;
 1236: 			}
 1237: 
 1238: 			if (PHAR_G(last_phar)->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len, (void**)&fd_ptr)) {
 1239: 				zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), PHAR_G(last_phar)->alias, PHAR_G(last_phar)->alias_len);
 1240: 			}
 1241: 
 1242: 			zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&(*archive), sizeof(phar_archive_data*), NULL);
 1243: 			PHAR_G(last_alias) = alias;
 1244: 			PHAR_G(last_alias_len) = alias_len;
 1245: 		}
 1246: 
 1247: 		return SUCCESS;
 1248: 	}
 1249: 
 1250: 	if (alias && alias_len && PHAR_G(last_phar) && alias_len == PHAR_G(last_alias_len) && !memcmp(alias, PHAR_G(last_alias), alias_len)) {
 1251: 		fd = PHAR_G(last_phar);
 1252: 		fd_ptr = &fd;
 1253: 		goto alias_success;
 1254: 	}
 1255: 
 1256: 	if (alias && alias_len) {
 1257: 		ahash = zend_inline_hash_func(alias, alias_len);
 1258: 		if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) {
 1259: alias_success:
 1260: 			if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) {
 1261: 				if (error) {
 1262: 					spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
 1263: 				}
 1264: 				if (SUCCESS == phar_free_alias(*fd_ptr, alias, alias_len TSRMLS_CC)) {
 1265: 					if (error) {
 1266: 						efree(*error);
 1267: 						*error = NULL;
 1268: 					}
 1269: 				}
 1270: 				return FAILURE;
 1271: 			}
 1272: 
 1273: 			*archive = *fd_ptr;
 1274: 			fd = *fd_ptr;
 1275: 			PHAR_G(last_phar) = fd;
 1276: 			PHAR_G(last_phar_name) = fd->fname;
 1277: 			PHAR_G(last_phar_name_len) = fd->fname_len;
 1278: 			PHAR_G(last_alias) = alias;
 1279: 			PHAR_G(last_alias_len) = alias_len;
 1280: 
 1281: 			return SUCCESS;
 1282: 		}
 1283: 
 1284: 		if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
 1285: 			goto alias_success;
 1286: 		}
 1287: 	}
 1288: 
 1289: 	fhash = zend_inline_hash_func(fname, fname_len);
 1290: 	my_realpath = NULL;
 1291: 	save = fname;
 1292: 	save_len = fname_len;
 1293: 
 1294: 	if (fname && fname_len) {
 1295: 		if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
 1296: 			*archive = *fd_ptr;
 1297: 			fd = *fd_ptr;
 1298: 
 1299: 			if (alias && alias_len) {
 1300: 				if (!fd->is_temporary_alias && (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len))) {
 1301: 					if (error) {
 1302: 						spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
 1303: 					}
 1304: 					return FAILURE;
 1305: 				}
 1306: 
 1307: 				if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
 1308: 					zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
 1309: 				}
 1310: 
 1311: 				zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
 1312: 			}
 1313: 
 1314: 			PHAR_G(last_phar) = fd;
 1315: 			PHAR_G(last_phar_name) = fd->fname;
 1316: 			PHAR_G(last_phar_name_len) = fd->fname_len;
 1317: 			PHAR_G(last_alias) = fd->alias;
 1318: 			PHAR_G(last_alias_len) = fd->alias_len;
 1319: 
 1320: 			return SUCCESS;
 1321: 		}
 1322: 
 1323: 		if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
 1324: 			*archive = *fd_ptr;
 1325: 			fd = *fd_ptr;
 1326: 
 1327: 			/* this could be problematic - alias should never be different from manifest alias
 1328: 			   for cached phars */
 1329: 			if (!fd->is_temporary_alias && alias && alias_len) {
 1330: 				if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
 1331: 					if (error) {
 1332: 						spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
 1333: 					}
 1334: 					return FAILURE;
 1335: 				}
 1336: 			}
 1337: 
 1338: 			PHAR_G(last_phar) = fd;
 1339: 			PHAR_G(last_phar_name) = fd->fname;
 1340: 			PHAR_G(last_phar_name_len) = fd->fname_len;
 1341: 			PHAR_G(last_alias) = fd->alias;
 1342: 			PHAR_G(last_alias_len) = fd->alias_len;
 1343: 
 1344: 			return SUCCESS;
 1345: 		}
 1346: 
 1347: 		if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
 1348: 			fd = *archive = *fd_ptr;
 1349: 
 1350: 			PHAR_G(last_phar) = fd;
 1351: 			PHAR_G(last_phar_name) = fd->fname;
 1352: 			PHAR_G(last_phar_name_len) = fd->fname_len;
 1353: 			PHAR_G(last_alias) = fd->alias;
 1354: 			PHAR_G(last_alias_len) = fd->alias_len;
 1355: 
 1356: 			return SUCCESS;
 1357: 		}
 1358: 
 1359: 		if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
 1360: 			fd = *archive = *fd_ptr;
 1361: 
 1362: 			PHAR_G(last_phar) = fd;
 1363: 			PHAR_G(last_phar_name) = fd->fname;
 1364: 			PHAR_G(last_phar_name_len) = fd->fname_len;
 1365: 			PHAR_G(last_alias) = fd->alias;
 1366: 			PHAR_G(last_alias_len) = fd->alias_len;
 1367: 
 1368: 			return SUCCESS;
 1369: 		}
 1370: 
 1371: 		/* not found, try converting \ to / */
 1372: 		my_realpath = expand_filepath(fname, my_realpath TSRMLS_CC);
 1373: 
 1374: 		if (my_realpath) {
 1375: 			fname_len = strlen(my_realpath);
 1376: 			fname = my_realpath;
 1377: 		} else {
 1378: 			return FAILURE;
 1379: 		}
 1380: #ifdef PHP_WIN32
 1381: 		phar_unixify_path_separators(fname, fname_len);
 1382: #endif
 1383: 		fhash = zend_inline_hash_func(fname, fname_len);
 1384: 
 1385: 		if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
 1386: realpath_success:
 1387: 			*archive = *fd_ptr;
 1388: 			fd = *fd_ptr;
 1389: 
 1390: 			if (alias && alias_len) {
 1391: 				zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
 1392: 			}
 1393: 
 1394: 			efree(my_realpath);
 1395: 
 1396: 			PHAR_G(last_phar) = fd;
 1397: 			PHAR_G(last_phar_name) = fd->fname;
 1398: 			PHAR_G(last_phar_name_len) = fd->fname_len;
 1399: 			PHAR_G(last_alias) = fd->alias;
 1400: 			PHAR_G(last_alias_len) = fd->alias_len;
 1401: 
 1402: 			return SUCCESS;
 1403: 		}
 1404: 
 1405: 		if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
 1406: 			goto realpath_success;
 1407: 		}
 1408: 
 1409: 		efree(my_realpath);
 1410: 	}
 1411: 
 1412: 	return FAILURE;
 1413: }
 1414: /* }}} */
 1415: 
 1416: /**
 1417:  * Determine which stream compression filter (if any) we need to read this file
 1418:  */
 1419: char * phar_compress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
 1420: {
 1421: 	switch (entry->flags & PHAR_ENT_COMPRESSION_MASK) {
 1422: 	case PHAR_ENT_COMPRESSED_GZ:
 1423: 		return "zlib.deflate";
 1424: 	case PHAR_ENT_COMPRESSED_BZ2:
 1425: 		return "bzip2.compress";
 1426: 	default:
 1427: 		return return_unknown ? "unknown" : NULL;
 1428: 	}
 1429: }
 1430: /* }}} */
 1431: 
 1432: /**
 1433:  * Determine which stream decompression filter (if any) we need to read this file
 1434:  */
 1435: char * phar_decompress_filter(phar_entry_info * entry, int return_unknown) /* {{{ */
 1436: {
 1437: 	php_uint32 flags;
 1438: 
 1439: 	if (entry->is_modified) {
 1440: 		flags = entry->old_flags;
 1441: 	} else {
 1442: 		flags = entry->flags;
 1443: 	}
 1444: 
 1445: 	switch (flags & PHAR_ENT_COMPRESSION_MASK) {
 1446: 		case PHAR_ENT_COMPRESSED_GZ:
 1447: 			return "zlib.inflate";
 1448: 		case PHAR_ENT_COMPRESSED_BZ2:
 1449: 			return "bzip2.decompress";
 1450: 		default:
 1451: 			return return_unknown ? "unknown" : NULL;
 1452: 	}
 1453: }
 1454: /* }}} */
 1455: 
 1456: /**
 1457:  * retrieve information on a file contained within a phar, or null if it ain't there
 1458:  */
 1459: phar_entry_info *phar_get_entry_info(phar_archive_data *phar, char *path, int path_len, char **error, int security TSRMLS_DC) /* {{{ */
 1460: {
 1461: 	return phar_get_entry_info_dir(phar, path, path_len, 0, error, security TSRMLS_CC);
 1462: }
 1463: /* }}} */
 1464: /**
 1465:  * retrieve information on a file or directory contained within a phar, or null if none found
 1466:  * allow_dir is 0 for none, 1 for both empty directories in the phar and temp directories, and 2 for only
 1467:  * valid pre-existing empty directory entries
 1468:  */
 1469: phar_entry_info *phar_get_entry_info_dir(phar_archive_data *phar, char *path, int path_len, char dir, char **error, int security TSRMLS_DC) /* {{{ */
 1470: {
 1471: 	const char *pcr_error;
 1472: 	phar_entry_info *entry;
 1473: 	int is_dir;
 1474: 
 1475: #ifdef PHP_WIN32
 1476: 	phar_unixify_path_separators(path, path_len);
 1477: #endif
 1478: 
 1479: 	is_dir = (path_len && (path[path_len - 1] == '/')) ? 1 : 0;
 1480: 
 1481: 	if (error) {
 1482: 		*error = NULL;
 1483: 	}
 1484: 
 1485: 	if (security && path_len >= sizeof(".phar")-1 && !memcmp(path, ".phar", sizeof(".phar")-1)) {
 1486: 		if (error) {
 1487: 			spprintf(error, 4096, "phar error: cannot directly access magic \".phar\" directory or files within it");
 1488: 		}
 1489: 		return NULL;
 1490: 	}
 1491: 
 1492: 	if (!path_len && !dir) {
 1493: 		if (error) {
 1494: 			spprintf(error, 4096, "phar error: invalid path \"%s\" must not be empty", path);
 1495: 		}
 1496: 		return NULL;
 1497: 	}
 1498: 
 1499: 	if (phar_path_check(&path, &path_len, &pcr_error) > pcr_is_ok) {
 1500: 		if (error) {
 1501: 			spprintf(error, 4096, "phar error: invalid path \"%s\" contains %s", path, pcr_error);
 1502: 		}
 1503: 		return NULL;
 1504: 	}
 1505: 
 1506: 	if (!phar->manifest.arBuckets) {
 1507: 		return NULL;
 1508: 	}
 1509: 
 1510: 	if (is_dir) {
 1511: 		if (!path_len || path_len == 1) {
 1512: 			return NULL;
 1513: 		}
 1514: 		path_len--;
 1515: 	}
 1516: 
 1517: 	if (SUCCESS == zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
 1518: 		if (entry->is_deleted) {
 1519: 			/* entry is deleted, but has not been flushed to disk yet */
 1520: 			return NULL;
 1521: 		}
 1522: 		if (entry->is_dir && !dir) {
 1523: 			if (error) {
 1524: 				spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
 1525: 			}
 1526: 			return NULL;
 1527: 		}
 1528: 		if (!entry->is_dir && dir == 2) {
 1529: 			/* user requested a directory, we must return one */
 1530: 			if (error) {
 1531: 				spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
 1532: 			}
 1533: 			return NULL;
 1534: 		}
 1535: 		return entry;
 1536: 	}
 1537: 
 1538: 	if (dir) {
 1539: 		if (zend_hash_exists(&phar->virtual_dirs, path, path_len)) {
 1540: 			/* a file or directory exists in a sub-directory of this path */
 1541: 			entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
 1542: 			/* this next line tells PharFileInfo->__destruct() to efree the filename */
 1543: 			entry->is_temp_dir = entry->is_dir = 1;
 1544: 			entry->filename = (char *) estrndup(path, path_len + 1);
 1545: 			entry->filename_len = path_len;
 1546: 			entry->phar = phar;
 1547: 			return entry;
 1548: 		}
 1549: 	}
 1550: 
 1551: 	if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
 1552: 		phar_zstr key;
 1553: 		char *str_key;
 1554: 		ulong unused;
 1555: 		uint keylen;
 1556: 
 1557: 		zend_hash_internal_pointer_reset(&phar->mounted_dirs);
 1558: 		while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
 1559: 			if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
 1560: 				break;
 1561: 			}
 1562: 
 1563: 			PHAR_STR(key, str_key);
 1564: 
 1565: 			if ((int)keylen >= path_len || strncmp(str_key, path, keylen)) {
 1566: 				PHAR_STR_FREE(str_key);
 1567: 				continue;
 1568: 			} else {
 1569: 				char *test;
 1570: 				int test_len;
 1571: 				php_stream_statbuf ssb;
 1572: 
 1573: 				if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
 1574: 					if (error) {
 1575: 						spprintf(error, 4096, "phar internal error: mounted path \"%s\" could not be retrieved from manifest", str_key);
 1576: 					}
 1577: 					PHAR_STR_FREE(str_key);
 1578: 					return NULL;
 1579: 				}
 1580: 
 1581: 				if (!entry->tmp || !entry->is_mounted) {
 1582: 					if (error) {
 1583: 						spprintf(error, 4096, "phar internal error: mounted path \"%s\" is not properly initialized as a mounted path", str_key);
 1584: 					}
 1585: 					PHAR_STR_FREE(str_key);
 1586: 					return NULL;
 1587: 				}
 1588: 				PHAR_STR_FREE(str_key);
 1589: 
 1590: 				test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, path + keylen);
 1591: 
 1592: 				if (SUCCESS != php_stream_stat_path(test, &ssb)) {
 1593: 					efree(test);
 1594: 					return NULL;
 1595: 				}
 1596: 
 1597: 				if (ssb.sb.st_mode & S_IFDIR && !dir) {
 1598: 					efree(test);
 1599: 					if (error) {
 1600: 						spprintf(error, 4096, "phar error: path \"%s\" is a directory", path);
 1601: 					}
 1602: 					return NULL;
 1603: 				}
 1604: 
 1605: 				if ((ssb.sb.st_mode & S_IFDIR) == 0 && dir) {
 1606: 					efree(test);
 1607: 					/* user requested a directory, we must return one */
 1608: 					if (error) {
 1609: 						spprintf(error, 4096, "phar error: path \"%s\" exists and is a not a directory", path);
 1610: 					}
 1611: 					return NULL;
 1612: 				}
 1613: 
 1614: 				/* mount the file just in time */
 1615: 				if (SUCCESS != phar_mount_entry(phar, test, test_len, path, path_len TSRMLS_CC)) {
 1616: 					efree(test);
 1617: 					if (error) {
 1618: 						spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be mounted", path, test);
 1619: 					}
 1620: 					return NULL;
 1621: 				}
 1622: 
 1623: 				efree(test);
 1624: 
 1625: 				if (SUCCESS != zend_hash_find(&phar->manifest, path, path_len, (void**)&entry)) {
 1626: 					if (error) {
 1627: 						spprintf(error, 4096, "phar error: path \"%s\" exists as file \"%s\" and could not be retrieved after being mounted", path, test);
 1628: 					}
 1629: 					return NULL;
 1630: 				}
 1631: 				return entry;
 1632: 			}
 1633: 		}
 1634: 	}
 1635: 
 1636: 	return NULL;
 1637: }
 1638: /* }}} */
 1639: 
 1640: static const char hexChars[] = "0123456789ABCDEF";
 1641: 
 1642: static int phar_hex_str(const char *digest, size_t digest_len, char **signature TSRMLS_DC) /* {{{ */
 1643: {
 1644: 	int pos = -1;
 1645: 	size_t len = 0;
 1646: 
 1647: 	*signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist));
 1648: 
 1649: 	for (; len < digest_len; ++len) {
 1650: 		(*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4];
 1651: 		(*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] & 0x0F];
 1652: 	}
 1653: 	(*signature)[++pos] = '\0';
 1654: 	return pos;
 1655: }
 1656: /* }}} */
 1657: 
 1658: #ifndef PHAR_HAVE_OPENSSL
 1659: static int phar_call_openssl_signverify(int is_sign, php_stream *fp, off_t end, char *key, int key_len, char **signature, int *signature_len TSRMLS_DC) /* {{{ */
 1660: {
 1661: 	zend_fcall_info fci;
 1662: 	zend_fcall_info_cache fcc;
 1663: 	zval *zdata, *zsig, *zkey, *retval_ptr, **zp[3], *openssl;
 1664: 
 1665: 	MAKE_STD_ZVAL(zdata);
 1666: 	MAKE_STD_ZVAL(openssl);
 1667: 	ZVAL_STRINGL(openssl, is_sign ? "openssl_sign" : "openssl_verify", is_sign ? sizeof("openssl_sign")-1 : sizeof("openssl_verify")-1, 1);
 1668: 	MAKE_STD_ZVAL(zsig);
 1669: 	ZVAL_STRINGL(zsig, *signature, *signature_len, 1);
 1670: 	MAKE_STD_ZVAL(zkey);
 1671: 	ZVAL_STRINGL(zkey, key, key_len, 1);
 1672: 	zp[0] = &zdata;
 1673: 	zp[1] = &zsig;
 1674: 	zp[2] = &zkey;
 1675: 
 1676: 	php_stream_rewind(fp);
 1677: 	Z_TYPE_P(zdata) = IS_STRING;
 1678: 	Z_STRLEN_P(zdata) = end;
 1679: 
 1680: #if PHP_MAJOR_VERSION > 5
 1681: 	if (end != (off_t) php_stream_copy_to_mem(fp, (void **) &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
 1682: #else
 1683: 	if (end != (off_t) php_stream_copy_to_mem(fp, &(Z_STRVAL_P(zdata)), (size_t) end, 0)) {
 1684: #endif
 1685: 		zval_dtor(zdata);
 1686: 		zval_dtor(zsig);
 1687: 		zval_dtor(zkey);
 1688: 		zval_dtor(openssl);
 1689: 		efree(openssl);
 1690: 		efree(zdata);
 1691: 		efree(zkey);
 1692: 		efree(zsig);
 1693: 		return FAILURE;
 1694: 	}
 1695: 
 1696: #if PHP_VERSION_ID < 50300
 1697: 	if (FAILURE == zend_fcall_info_init(openssl, &fci, &fcc TSRMLS_CC)) {
 1698: #else
 1699: 	if (FAILURE == zend_fcall_info_init(openssl, 0, &fci, &fcc, NULL, NULL TSRMLS_CC)) {
 1700: #endif
 1701: 		zval_dtor(zdata);
 1702: 		zval_dtor(zsig);
 1703: 		zval_dtor(zkey);
 1704: 		zval_dtor(openssl);
 1705: 		efree(openssl);
 1706: 		efree(zdata);
 1707: 		efree(zkey);
 1708: 		efree(zsig);
 1709: 		return FAILURE;
 1710: 	}
 1711: 
 1712: 	fci.param_count = 3;
 1713: 	fci.params = zp;
 1714: #if PHP_VERSION_ID < 50300
 1715: 	++(zdata->refcount);
 1716: 	if (!is_sign) {
 1717: 		++(zsig->refcount);
 1718: 	}
 1719: 	++(zkey->refcount);
 1720: #else
 1721: 	Z_ADDREF_P(zdata);
 1722: 	if (is_sign) {
 1723: 		Z_SET_ISREF_P(zsig);
 1724: 	} else {
 1725: 		Z_ADDREF_P(zsig);
 1726: 	}
 1727: 	Z_ADDREF_P(zkey);
 1728: #endif
 1729: 	fci.retval_ptr_ptr = &retval_ptr;
 1730: 
 1731: 	if (FAILURE == zend_call_function(&fci, &fcc TSRMLS_CC)) {
 1732: 		zval_dtor(zdata);
 1733: 		zval_dtor(zsig);
 1734: 		zval_dtor(zkey);
 1735: 		zval_dtor(openssl);
 1736: 		efree(openssl);
 1737: 		efree(zdata);
 1738: 		efree(zkey);
 1739: 		efree(zsig);
 1740: 		return FAILURE;
 1741: 	}
 1742: 
 1743: 	zval_dtor(openssl);
 1744: 	efree(openssl);
 1745: #if PHP_VERSION_ID < 50300
 1746: 	--(zdata->refcount);
 1747: 	if (!is_sign) {
 1748: 		--(zsig->refcount);
 1749: 	}
 1750: 	--(zkey->refcount);
 1751: #else
 1752: 	Z_DELREF_P(zdata);
 1753: 	if (is_sign) {
 1754: 		Z_UNSET_ISREF_P(zsig);
 1755: 	} else {
 1756: 		Z_DELREF_P(zsig);
 1757: 	}
 1758: 	Z_DELREF_P(zkey);
 1759: #endif
 1760: 	zval_dtor(zdata);
 1761: 	efree(zdata);
 1762: 	zval_dtor(zkey);
 1763: 	efree(zkey);
 1764: 
 1765: 	switch (Z_TYPE_P(retval_ptr)) {
 1766: 		default:
 1767: 		case IS_LONG:
 1768: 			zval_dtor(zsig);
 1769: 			efree(zsig);
 1770: 			if (1 == Z_LVAL_P(retval_ptr)) {
 1771: 				efree(retval_ptr);
 1772: 				return SUCCESS;
 1773: 			}
 1774: 			efree(retval_ptr);
 1775: 			return FAILURE;
 1776: 		case IS_BOOL:
 1777: 			efree(retval_ptr);
 1778: 			if (Z_BVAL_P(retval_ptr)) {
 1779: 				*signature = estrndup(Z_STRVAL_P(zsig), Z_STRLEN_P(zsig));
 1780: 				*signature_len = Z_STRLEN_P(zsig);
 1781: 				zval_dtor(zsig);
 1782: 				efree(zsig);
 1783: 				return SUCCESS;
 1784: 			}
 1785: 			zval_dtor(zsig);
 1786: 			efree(zsig);
 1787: 			return FAILURE;
 1788: 	}
 1789: }
 1790: /* }}} */
 1791: #endif /* #ifndef PHAR_HAVE_OPENSSL */
 1792: 
 1793: int phar_verify_signature(php_stream *fp, size_t end_of_phar, php_uint32 sig_type, char *sig, int sig_len, char *fname, char **signature, int *signature_len, char **error TSRMLS_DC) /* {{{ */
 1794: {
 1795: 	int read_size, len;
 1796: 	off_t read_len;
 1797: 	unsigned char buf[1024];
 1798: 
 1799: 	php_stream_rewind(fp);
 1800: 
 1801: 	switch (sig_type) {
 1802: 		case PHAR_SIG_OPENSSL: {
 1803: #ifdef PHAR_HAVE_OPENSSL
 1804: 			BIO *in;
 1805: 			EVP_PKEY *key;
 1806: 			EVP_MD *mdtype = (EVP_MD *) EVP_sha1();
 1807: 			EVP_MD_CTX md_ctx;
 1808: #else
 1809: 			int tempsig;
 1810: #endif
 1811: 			php_uint32 pubkey_len;
 1812: 			char *pubkey = NULL, *pfile;
 1813: 			php_stream *pfp;
 1814: #ifndef PHAR_HAVE_OPENSSL
 1815: 			if (!zend_hash_exists(&module_registry, "openssl", sizeof("openssl"))) {
 1816: 				if (error) {
 1817: 					spprintf(error, 0, "openssl not loaded");
 1818: 				}
 1819: 				return FAILURE;
 1820: 			}
 1821: #endif
 1822: 			/* use __FILE__ . '.pubkey' for public key file */
 1823: 			spprintf(&pfile, 0, "%s.pubkey", fname);
 1824: 			pfp = php_stream_open_wrapper(pfile, "rb", 0, NULL);
 1825: 			efree(pfile);
 1826: 
 1827: #if PHP_MAJOR_VERSION > 5
 1828: 			if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, (void **) &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
 1829: #else
 1830: 			if (!pfp || !(pubkey_len = php_stream_copy_to_mem(pfp, &pubkey, PHP_STREAM_COPY_ALL, 0)) || !pubkey) {
 1831: #endif
 1832: 				if (pfp) {
 1833: 					php_stream_close(pfp);
 1834: 				}
 1835: 				if (error) {
 1836: 					spprintf(error, 0, "openssl public key could not be read");
 1837: 				}
 1838: 				return FAILURE;
 1839: 			}
 1840: 
 1841: 			php_stream_close(pfp);
 1842: #ifndef PHAR_HAVE_OPENSSL
 1843: 			tempsig = sig_len;
 1844: 
 1845: 			if (FAILURE == phar_call_openssl_signverify(0, fp, end_of_phar, pubkey, pubkey_len, &sig, &tempsig TSRMLS_CC)) {
 1846: 				if (pubkey) {
 1847: 					efree(pubkey);
 1848: 				}
 1849: 
 1850: 				if (error) {
 1851: 					spprintf(error, 0, "openssl signature could not be verified");
 1852: 				}
 1853: 
 1854: 				return FAILURE;
 1855: 			}
 1856: 
 1857: 			if (pubkey) {
 1858: 				efree(pubkey);
 1859: 			}
 1860: 
 1861: 			sig_len = tempsig;
 1862: #else
 1863: 			in = BIO_new_mem_buf(pubkey, pubkey_len);
 1864: 
 1865: 			if (NULL == in) {
 1866: 				efree(pubkey);
 1867: 				if (error) {
 1868: 					spprintf(error, 0, "openssl signature could not be processed");
 1869: 				}
 1870: 				return FAILURE;
 1871: 			}
 1872: 
 1873: 			key = PEM_read_bio_PUBKEY(in, NULL,NULL, NULL);
 1874: 			BIO_free(in);
 1875: 			efree(pubkey);
 1876: 
 1877: 			if (NULL == key) {
 1878: 				if (error) {
 1879: 					spprintf(error, 0, "openssl signature could not be processed");
 1880: 				}
 1881: 				return FAILURE;
 1882: 			}
 1883: 
 1884: 			EVP_VerifyInit(&md_ctx, mdtype);
 1885: 			read_len = end_of_phar;
 1886: 
 1887: 			if (read_len > sizeof(buf)) {
 1888: 				read_size = sizeof(buf);
 1889: 			} else {
 1890: 				read_size = (int)read_len;
 1891: 			}
 1892: 
 1893: 			php_stream_seek(fp, 0, SEEK_SET);
 1894: 
 1895: 			while (read_size && (len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
 1896: 				EVP_VerifyUpdate (&md_ctx, buf, len);
 1897: 				read_len -= (off_t)len;
 1898: 
 1899: 				if (read_len < read_size) {
 1900: 					read_size = (int)read_len;
 1901: 				}
 1902: 			}
 1903: 
 1904: 			if (EVP_VerifyFinal(&md_ctx, (unsigned char *)sig, sig_len, key) != 1) {
 1905: 				/* 1: signature verified, 0: signature does not match, -1: failed signature operation */
 1906: 				EVP_MD_CTX_cleanup(&md_ctx);
 1907: 
 1908: 				if (error) {
 1909: 					spprintf(error, 0, "broken openssl signature");
 1910: 				}
 1911: 
 1912: 				return FAILURE;
 1913: 			}
 1914: 
 1915: 			EVP_MD_CTX_cleanup(&md_ctx);
 1916: #endif
 1917: 
 1918: 			*signature_len = phar_hex_str((const char*)sig, sig_len, signature TSRMLS_CC);
 1919: 		}
 1920: 		break;
 1921: #ifdef PHAR_HASH_OK
 1922: 		case PHAR_SIG_SHA512: {
 1923: 			unsigned char digest[64];
 1924: 			PHP_SHA512_CTX context;
 1925: 
 1926: 			PHP_SHA512Init(&context);
 1927: 			read_len = end_of_phar;
 1928: 
 1929: 			if (read_len > sizeof(buf)) {
 1930: 				read_size = sizeof(buf);
 1931: 			} else {
 1932: 				read_size = (int)read_len;
 1933: 			}
 1934: 
 1935: 			while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
 1936: 				PHP_SHA512Update(&context, buf, len);
 1937: 				read_len -= (off_t)len;
 1938: 				if (read_len < read_size) {
 1939: 					read_size = (int)read_len;
 1940: 				}
 1941: 			}
 1942: 
 1943: 			PHP_SHA512Final(digest, &context);
 1944: 
 1945: 			if (memcmp(digest, sig, sizeof(digest))) {
 1946: 				if (error) {
 1947: 					spprintf(error, 0, "broken signature");
 1948: 				}
 1949: 				return FAILURE;
 1950: 			}
 1951: 
 1952: 			*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
 1953: 			break;
 1954: 		}
 1955: 		case PHAR_SIG_SHA256: {
 1956: 			unsigned char digest[32];
 1957: 			PHP_SHA256_CTX context;
 1958: 
 1959: 			PHP_SHA256Init(&context);
 1960: 			read_len = end_of_phar;
 1961: 
 1962: 			if (read_len > sizeof(buf)) {
 1963: 				read_size = sizeof(buf);
 1964: 			} else {
 1965: 				read_size = (int)read_len;
 1966: 			}
 1967: 
 1968: 			while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
 1969: 				PHP_SHA256Update(&context, buf, len);
 1970: 				read_len -= (off_t)len;
 1971: 				if (read_len < read_size) {
 1972: 					read_size = (int)read_len;
 1973: 				}
 1974: 			}
 1975: 
 1976: 			PHP_SHA256Final(digest, &context);
 1977: 
 1978: 			if (memcmp(digest, sig, sizeof(digest))) {
 1979: 				if (error) {
 1980: 					spprintf(error, 0, "broken signature");
 1981: 				}
 1982: 				return FAILURE;
 1983: 			}
 1984: 
 1985: 			*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
 1986: 			break;
 1987: 		}
 1988: #else
 1989: 		case PHAR_SIG_SHA512:
 1990: 		case PHAR_SIG_SHA256:
 1991: 			if (error) {
 1992: 				spprintf(error, 0, "unsupported signature");
 1993: 			}
 1994: 			return FAILURE;
 1995: #endif
 1996: 		case PHAR_SIG_SHA1: {
 1997: 			unsigned char digest[20];
 1998: 			PHP_SHA1_CTX  context;
 1999: 
 2000: 			PHP_SHA1Init(&context);
 2001: 			read_len = end_of_phar;
 2002: 
 2003: 			if (read_len > sizeof(buf)) {
 2004: 				read_size = sizeof(buf);
 2005: 			} else {
 2006: 				read_size = (int)read_len;
 2007: 			}
 2008: 
 2009: 			while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
 2010: 				PHP_SHA1Update(&context, buf, len);
 2011: 				read_len -= (off_t)len;
 2012: 				if (read_len < read_size) {
 2013: 					read_size = (int)read_len;
 2014: 				}
 2015: 			}
 2016: 
 2017: 			PHP_SHA1Final(digest, &context);
 2018: 
 2019: 			if (memcmp(digest, sig, sizeof(digest))) {
 2020: 				if (error) {
 2021: 					spprintf(error, 0, "broken signature");
 2022: 				}
 2023: 				return FAILURE;
 2024: 			}
 2025: 
 2026: 			*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
 2027: 			break;
 2028: 		}
 2029: 		case PHAR_SIG_MD5: {
 2030: 			unsigned char digest[16];
 2031: 			PHP_MD5_CTX   context;
 2032: 
 2033: 			PHP_MD5Init(&context);
 2034: 			read_len = end_of_phar;
 2035: 
 2036: 			if (read_len > sizeof(buf)) {
 2037: 				read_size = sizeof(buf);
 2038: 			} else {
 2039: 				read_size = (int)read_len;
 2040: 			}
 2041: 
 2042: 			while ((len = php_stream_read(fp, (char*)buf, read_size)) > 0) {
 2043: 				PHP_MD5Update(&context, buf, len);
 2044: 				read_len -= (off_t)len;
 2045: 				if (read_len < read_size) {
 2046: 					read_size = (int)read_len;
 2047: 				}
 2048: 			}
 2049: 
 2050: 			PHP_MD5Final(digest, &context);
 2051: 
 2052: 			if (memcmp(digest, sig, sizeof(digest))) {
 2053: 				if (error) {
 2054: 					spprintf(error, 0, "broken signature");
 2055: 				}
 2056: 				return FAILURE;
 2057: 			}
 2058: 
 2059: 			*signature_len = phar_hex_str((const char*)digest, sizeof(digest), signature TSRMLS_CC);
 2060: 			break;
 2061: 		}
 2062: 		default:
 2063: 			if (error) {
 2064: 				spprintf(error, 0, "broken or unsupported signature");
 2065: 			}
 2066: 			return FAILURE;
 2067: 	}
 2068: 	return SUCCESS;
 2069: }
 2070: /* }}} */
 2071: 
 2072: int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, int *signature_length, char **error TSRMLS_DC) /* {{{ */
 2073: {
 2074: 	unsigned char buf[1024];
 2075: 	int sig_len;
 2076: 
 2077: 	php_stream_rewind(fp);
 2078: 
 2079: 	if (phar->signature) {
 2080: 		efree(phar->signature);
 2081: 		phar->signature = NULL;
 2082: 	}
 2083: 
 2084: 	switch(phar->sig_flags) {
 2085: #ifdef PHAR_HASH_OK
 2086: 		case PHAR_SIG_SHA512: {
 2087: 			unsigned char digest[64];
 2088: 			PHP_SHA512_CTX context;
 2089: 
 2090: 			PHP_SHA512Init(&context);
 2091: 
 2092: 			while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
 2093: 				PHP_SHA512Update(&context, buf, sig_len);
 2094: 			}
 2095: 
 2096: 			PHP_SHA512Final(digest, &context);
 2097: 			*signature = estrndup((char *) digest, 64);
 2098: 			*signature_length = 64;
 2099: 			break;
 2100: 		}
 2101: 		case PHAR_SIG_SHA256: {
 2102: 			unsigned char digest[32];
 2103: 			PHP_SHA256_CTX  context;
 2104: 
 2105: 			PHP_SHA256Init(&context);
 2106: 
 2107: 			while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
 2108: 				PHP_SHA256Update(&context, buf, sig_len);
 2109: 			}
 2110: 
 2111: 			PHP_SHA256Final(digest, &context);
 2112: 			*signature = estrndup((char *) digest, 32);
 2113: 			*signature_length = 32;
 2114: 			break;
 2115: 		}
 2116: #else
 2117: 		case PHAR_SIG_SHA512:
 2118: 		case PHAR_SIG_SHA256:
 2119: 			if (error) {
 2120: 				spprintf(error, 0, "unable to write to phar \"%s\" with requested hash type", phar->fname);
 2121: 			}
 2122: 
 2123: 			return FAILURE;
 2124: #endif
 2125: 		case PHAR_SIG_OPENSSL: {
 2126: 			int siglen;
 2127: 			unsigned char *sigbuf;
 2128: #ifdef PHAR_HAVE_OPENSSL
 2129: 			BIO *in;
 2130: 			EVP_PKEY *key;
 2131: 			EVP_MD_CTX *md_ctx;
 2132: 
 2133: 			in = BIO_new_mem_buf(PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len));
 2134: 
 2135: 			if (in == NULL) {
 2136: 				if (error) {
 2137: 					spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", phar->fname);
 2138: 				}
 2139: 				return FAILURE;
 2140: 			}
 2141: 
 2142: 			key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
 2143: 			BIO_free(in);
 2144: 
 2145: 			if (!key) {
 2146: 				if (error) {
 2147: 					spprintf(error, 0, "unable to process private key");
 2148: 				}
 2149: 				return FAILURE;
 2150: 			}
 2151: 
 2152: 			md_ctx = EVP_MD_CTX_create();
 2153: 
 2154: 			siglen = EVP_PKEY_size(key);
 2155: 			sigbuf = emalloc(siglen + 1);
 2156: 
 2157: 			if (!EVP_SignInit(md_ctx, EVP_sha1())) {
 2158: 				efree(sigbuf);
 2159: 				if (error) {
 2160: 					spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", phar->fname);
 2161: 				}
 2162: 				return FAILURE;
 2163: 			}
 2164: 
 2165: 			while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
 2166: 				if (!EVP_SignUpdate(md_ctx, buf, sig_len)) {
 2167: 					efree(sigbuf);
 2168: 					if (error) {
 2169: 						spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", phar->fname);
 2170: 					}
 2171: 					return FAILURE;
 2172: 				}
 2173: 			}
 2174: 
 2175: 			if (!EVP_SignFinal (md_ctx, sigbuf,(unsigned int *)&siglen, key)) {
 2176: 				efree(sigbuf);
 2177: 				if (error) {
 2178: 					spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
 2179: 				}
 2180: 				return FAILURE;
 2181: 			}
 2182: 
 2183: 			sigbuf[siglen] = '\0';
 2184: 			EVP_MD_CTX_destroy(md_ctx);
 2185: #else
 2186: 			sigbuf = NULL;
 2187: 			siglen = 0;
 2188: 			php_stream_seek(fp, 0, SEEK_END);
 2189: 
 2190: 			if (FAILURE == phar_call_openssl_signverify(1, fp, php_stream_tell(fp), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen TSRMLS_CC)) {
 2191: 				if (error) {
 2192: 					spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", phar->fname);
 2193: 				}
 2194: 				return FAILURE;
 2195: 			}
 2196: #endif
 2197: 			*signature = (char *) sigbuf;
 2198: 			*signature_length = siglen;
 2199: 		}
 2200: 		break;
 2201: 		default:
 2202: 			phar->sig_flags = PHAR_SIG_SHA1;
 2203: 		case PHAR_SIG_SHA1: {
 2204: 			unsigned char digest[20];
 2205: 			PHP_SHA1_CTX  context;
 2206: 
 2207: 			PHP_SHA1Init(&context);
 2208: 
 2209: 			while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
 2210: 				PHP_SHA1Update(&context, buf, sig_len);
 2211: 			}
 2212: 
 2213: 			PHP_SHA1Final(digest, &context);
 2214: 			*signature = estrndup((char *) digest, 20);
 2215: 			*signature_length = 20;
 2216: 			break;
 2217: 		}
 2218: 		case PHAR_SIG_MD5: {
 2219: 			unsigned char digest[16];
 2220: 			PHP_MD5_CTX   context;
 2221: 
 2222: 			PHP_MD5Init(&context);
 2223: 
 2224: 			while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
 2225: 				PHP_MD5Update(&context, buf, sig_len);
 2226: 			}
 2227: 
 2228: 			PHP_MD5Final(digest, &context);
 2229: 			*signature = estrndup((char *) digest, 16);
 2230: 			*signature_length = 16;
 2231: 			break;
 2232: 		}
 2233: 	}
 2234: 
 2235: 	phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature TSRMLS_CC);
 2236: 	return SUCCESS;
 2237: }
 2238: /* }}} */
 2239: 
 2240: void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC) /* {{{ */
 2241: {
 2242: 	const char *s;
 2243: 
 2244: 	while ((s = zend_memrchr(filename, '/', filename_len))) {
 2245: 		filename_len = s - filename;
 2246: 		if (FAILURE == zend_hash_add_empty_element(&phar->virtual_dirs, filename, filename_len)) {
 2247: 			break;
 2248: 		}
 2249: 	}
 2250: }
 2251: /* }}} */
 2252: 
 2253: static int phar_update_cached_entry(void *data, void *argument) /* {{{ */
 2254: {
 2255: 	phar_entry_info *entry = (phar_entry_info *)data;
 2256: 	TSRMLS_FETCH();
 2257: 
 2258: 	entry->phar = (phar_archive_data *)argument;
 2259: 
 2260: 	if (entry->link) {
 2261: 		entry->link = estrdup(entry->link);
 2262: 	}
 2263: 
 2264: 	if (entry->tmp) {
 2265: 		entry->tmp = estrdup(entry->tmp);
 2266: 	}
 2267: 
 2268: 	entry->metadata_str.c = 0;
 2269: 	entry->filename = estrndup(entry->filename, entry->filename_len);
 2270: 	entry->is_persistent = 0;
 2271: 
 2272: 	if (entry->metadata) {
 2273: 		if (entry->metadata_len) {
 2274: 			char *buf = estrndup((char *) entry->metadata, entry->metadata_len);
 2275: 			/* assume success, we would have failed before */
 2276: 			phar_parse_metadata((char **) &buf, &entry->metadata, entry->metadata_len TSRMLS_CC);
 2277: 			efree(buf);
 2278: 		} else {
 2279: 			zval *t;
 2280: 
 2281: 			t = entry->metadata;
 2282: 			ALLOC_ZVAL(entry->metadata);
 2283: 			*entry->metadata = *t;
 2284: 			zval_copy_ctor(entry->metadata);
 2285: #if PHP_VERSION_ID < 50300
 2286: 			entry->metadata->refcount = 1;
 2287: #else
 2288: 			Z_SET_REFCOUNT_P(entry->metadata, 1);
 2289: #endif
 2290: 			entry->metadata_str.c = NULL;
 2291: 			entry->metadata_str.len = 0;
 2292: 		}
 2293: 	}
 2294: 	return ZEND_HASH_APPLY_KEEP;
 2295: }
 2296: /* }}} */
 2297: 
 2298: static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
 2299: {
 2300: 	phar_archive_data *phar;
 2301: 	HashTable newmanifest;
 2302: 	char *fname;
 2303: 	phar_archive_object **objphar;
 2304: 
 2305: 	phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
 2306: 	*phar = **pphar;
 2307: 	phar->is_persistent = 0;
 2308: 	fname = phar->fname;
 2309: 	phar->fname = estrndup(phar->fname, phar->fname_len);
 2310: 	phar->ext = phar->fname + (phar->ext - fname);
 2311: 
 2312: 	if (phar->alias) {
 2313: 		phar->alias = estrndup(phar->alias, phar->alias_len);
 2314: 	}
 2315: 
 2316: 	if (phar->signature) {
 2317: 		phar->signature = estrdup(phar->signature);
 2318: 	}
 2319: 
 2320: 	if (phar->metadata) {
 2321: 		/* assume success, we would have failed before */
 2322: 		if (phar->metadata_len) {
 2323: 			char *buf = estrndup((char *) phar->metadata, phar->metadata_len);
 2324: 			phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC);
 2325: 			efree(buf);
 2326: 		} else {
 2327: 			zval *t;
 2328: 
 2329: 			t = phar->metadata;
 2330: 			ALLOC_ZVAL(phar->metadata);
 2331: 			*phar->metadata = *t;
 2332: 			zval_copy_ctor(phar->metadata);
 2333: #if PHP_VERSION_ID < 50300
 2334: 			phar->metadata->refcount = 1;
 2335: #else
 2336: 			Z_SET_REFCOUNT_P(phar->metadata, 1);
 2337: #endif
 2338: 		}
 2339: 	}
 2340: 
 2341: 	zend_hash_init(&newmanifest, sizeof(phar_entry_info),
 2342: 		zend_get_hash_value, destroy_phar_manifest_entry, 0);
 2343: 	zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info));
 2344: 	zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC);
 2345: 	phar->manifest = newmanifest;
 2346: 	zend_hash_init(&phar->mounted_dirs, sizeof(char *),
 2347: 		zend_get_hash_value, NULL, 0);
 2348: 	zend_hash_init(&phar->virtual_dirs, sizeof(char *),
 2349: 		zend_get_hash_value, NULL, 0);
 2350: 	zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
 2351: 	*pphar = phar;
 2352: 
 2353: 	/* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
 2354: 	for (zend_hash_internal_pointer_reset(&PHAR_GLOBALS->phar_persist_map);
 2355: 	SUCCESS == zend_hash_get_current_data(&PHAR_GLOBALS->phar_persist_map, (void **) &objphar);
 2356: 	zend_hash_move_forward(&PHAR_GLOBALS->phar_persist_map)) {
 2357: 		if (objphar[0]->arc.archive->fname_len == phar->fname_len && !memcmp(objphar[0]->arc.archive->fname, phar->fname, phar->fname_len)) {
 2358: 			objphar[0]->arc.archive = phar;
 2359: 		}
 2360: 	}
 2361: }
 2362: /* }}} */
 2363: 
 2364: int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
 2365: {
 2366: 	phar_archive_data **newpphar, *newphar = NULL;
 2367: 
 2368: 	if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) {
 2369: 		return FAILURE;
 2370: 	}
 2371: 
 2372: 	*newpphar = *pphar;
 2373: 	phar_copy_cached_phar(newpphar TSRMLS_CC);
 2374: 	/* invalidate phar cache */
 2375: 	PHAR_G(last_phar) = NULL;
 2376: 	PHAR_G(last_phar_name) = PHAR_G(last_alias) = NULL;
 2377: 
 2378: 	if (newpphar[0]->alias_len && FAILURE == zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), newpphar[0]->alias, newpphar[0]->alias_len, (void*)newpphar, sizeof(phar_archive_data*), NULL)) {
 2379: 		zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
 2380: 		return FAILURE;
 2381: 	}
 2382: 
 2383: 	*pphar = *newpphar;
 2384: 	return SUCCESS;
 2385: }
 2386: /* }}} */
 2387: 
 2388: /*
 2389:  * Local variables:
 2390:  * tab-width: 4
 2391:  * c-basic-offset: 4
 2392:  * End:
 2393:  * vim600: noet sw=4 ts=4 fdm=marker
 2394:  * vim<600: noet sw=4 ts=4
 2395:  */

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