From: Greg Beaver Date: Thu, 12 Jun 2008 18:56:23 +0000 (+0000) Subject: [DOC] add phar.cache_list, a PATH_SEPARATOR-separated list of full paths to phar... X-Git-Tag: BEFORE_NEW_PARAMETER_PARSE~26 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=98f2dc2aca9665985910dcb5585e7fab03943689;p=php [DOC] add phar.cache_list, a PATH_SEPARATOR-separated list of full paths to phar archives to cache at startup. This caches the manifest, so that on first access to a phar archive, no file manifest parsing occurs. This could use further tweaking. For instance, the full copy of the manifest into the current process may be unnecessary if refcounting could be external to the manifest. This would be another significant gain. With APC, I measure a slight perf increase to 19 req/sec up from 16 req/sec, without it approaches regular PHP at 3.8 req/sec (regular is 4 req/sec). This is benching phpMyAdmin --- diff --git a/ext/phar/phar.c b/ext/phar/phar.c index ded61ce31c..629741866e 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -43,6 +43,7 @@ #ifndef PHAR_HAVE_OPENSSL 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); #endif +static void destroy_phar_data(void *pDest); ZEND_DECLARE_MODULE_GLOBALS(phar) #if PHP_VERSION_ID >= 50300 @@ -112,9 +113,94 @@ ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */ } /* }}}*/ +/* this global stores the global cached pre-parsed manifests */ +static HashTable cached_phars; +static HashTable cached_alias; + +static void phar_split_cache_list(TSRMLS_D) +{ + char *tmp; + char *key, *lasts, *end; + char ds[1]; + phar_archive_data *phar; + + if (!PHAR_GLOBALS->cache_list || !(PHAR_GLOBALS->cache_list[0])) { + return; + } + + ds[0] = DEFAULT_DIR_SEPARATOR; + zend_init_rsrc_list(TSRMLS_C); + tmp = estrdup(PHAR_GLOBALS->cache_list); + + /* fake request startup */ + PHAR_GLOBALS->request_init = 1; + PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2")); + PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib")); + zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1); + zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1); + PHAR_GLOBALS->manifest_cached = 1; + PHAR_GLOBALS->persist = 1; + + for (key = php_strtok_r(tmp, ds, &lasts); + key; + key = php_strtok_r(NULL, ds, &lasts)) + { + end = strchr(key, DEFAULT_DIR_SEPARATOR); + if (end) { + if (SUCCESS == phar_open_from_filename(key, end - key, NULL, 0, 0, &phar, NULL TSRMLS_CC)) { +finish_up: + php_stream_close(phar->fp); + phar->fp = NULL; + } else { +finish_error: + PHAR_GLOBALS->persist = 0; + PHAR_GLOBALS->manifest_cached = 0; + zend_destroy_rsrc_list(&EG(regular_list) TSRMLS_CC); + efree(tmp); + zend_hash_destroy(&(PHAR_G(phar_fname_map))); + PHAR_GLOBALS->phar_fname_map.arBuckets = 0; + zend_hash_destroy(&(PHAR_G(phar_alias_map))); + PHAR_GLOBALS->phar_alias_map.arBuckets = 0; + /* free cached manifests */ + PHAR_GLOBALS->request_init = 0; + return; + } + } else { + if (SUCCESS == phar_open_from_filename(key, strlen(key), NULL, 0, 0, &phar, NULL TSRMLS_CC)) { + goto finish_up; + } else { + goto finish_error; + } + } + } + PHAR_GLOBALS->persist = 0; + PHAR_GLOBALS->request_init = 0; + cached_phars = PHAR_GLOBALS->phar_fname_map; + cached_alias = PHAR_GLOBALS->phar_alias_map; + PHAR_GLOBALS->phar_fname_map.arBuckets = 0; + PHAR_GLOBALS->phar_alias_map.arBuckets = 0; + + zend_destroy_rsrc_list(&EG(regular_list) TSRMLS_CC); + efree(tmp); +} +/* }}} */ + +ZEND_INI_MH(phar_ini_cache_list) /* {{{ */ +{ + PHAR_G(cache_list) = new_value; + + if (stage == ZEND_INI_STAGE_STARTUP) { + phar_split_cache_list(TSRMLS_C); + } + + return SUCCESS; +} +/* }}} */ + PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN( "phar.readonly", "1", PHP_INI_ALL, phar_ini_modify_handler, readonly, zend_phar_globals, phar_globals) STD_PHP_INI_BOOLEAN( "phar.require_hash", "1", PHP_INI_ALL, phar_ini_modify_handler, require_hash, zend_phar_globals, phar_globals) + STD_PHP_INI_ENTRY("phar.cache_list", "", PHP_INI_SYSTEM, phar_ini_cache_list, cache_list, zend_phar_globals, phar_globals) PHP_INI_END() /** @@ -124,15 +210,15 @@ PHP_INI_END() void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */ { if (phar->alias && phar->alias != phar->fname) { - efree(phar->alias); + pefree(phar->alias, phar->is_persistent); phar->alias = NULL; } if (phar->fname) { - efree(phar->fname); + pefree(phar->fname, phar->is_persistent); phar->fname = NULL; } if (phar->signature) { - efree(phar->signature); + pefree(phar->signature, phar->is_persistent); phar->signature = NULL; } if (phar->manifest.arBuckets) { @@ -144,7 +230,17 @@ void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */ phar->mounted_dirs.arBuckets = NULL; } if (phar->metadata) { - zval_ptr_dtor(&phar->metadata); + if (phar->is_persistent) { + if (phar->metadata_len) { + /* for zip comments that are strings */ + free(phar->metadata); + } else { + zval_internal_ptr_dtor(&phar->metadata); + } + } else { + zval_ptr_dtor(&phar->metadata); + } + phar->metadata_len = 0; phar->metadata = 0; } if (phar->fp) { @@ -155,7 +251,7 @@ void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */ php_stream_close(phar->ufp); phar->fp = 0; } - efree(phar); + pefree(phar, phar->is_persistent); } /* }}}*/ @@ -272,20 +368,30 @@ void destroy_phar_manifest_entry(void *pDest) /* {{{ */ entry->fp = 0; } if (entry->metadata) { - zval_ptr_dtor(&entry->metadata); + if (entry->is_persistent) { + if (entry->metadata_len) { + /* for zip comments that are strings */ + free(entry->metadata); + } else { + zval_internal_ptr_dtor(&entry->metadata); + } + } else { + zval_ptr_dtor(&entry->metadata); + } + entry->metadata_len = 0; entry->metadata = 0; } if (entry->metadata_str.c) { smart_str_free(&entry->metadata_str); entry->metadata_str.c = 0; } - efree(entry->filename); + pefree(entry->filename, entry->is_persistent); if (entry->link) { - efree(entry->link); + pefree(entry->link, entry->is_persistent); entry->link = 0; } if (entry->tmp) { - efree(entry->tmp); + pefree(entry->tmp, entry->is_persistent); entry->tmp = 0; } } @@ -349,7 +455,7 @@ void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC) /* {{{ */ phar_destroy_phar_data(mydata TSRMLS_CC);\ }\ if (signature) {\ - efree(signature);\ + pefree(signature, mydata->is_persistent);\ }\ MAPPHAR_ALLOC_FAIL(msg) @@ -465,9 +571,10 @@ int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSR } else { buf_len = zip_metadata_len; } - + if (buf_len) { - ALLOC_INIT_ZVAL(*metadata); + ALLOC_ZVAL(*metadata); + INIT_ZVAL(**metadata); p = (const unsigned char*) *buffer; PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(metadata, &p, p + buf_len, &var_hash TSRMLS_CC)) { @@ -477,6 +584,16 @@ int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSR return FAILURE; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + if (PHAR_G(persist)) { + /* lazy init metadata */ + zval_ptr_dtor(metadata); + *metadata = (zval *) pemalloc(buf_len, 1); + memcpy(*metadata, *buffer, buf_len); + if (!zip_metadata_len) { + *buffer += buf_len; + } + return SUCCESS; + } } else { *metadata = NULL; } @@ -494,7 +611,7 @@ static int phar_hex_str(const char *digest, size_t digest_len, char ** signature int pos = -1; size_t len = 0; - *signature = (char*)safe_emalloc(digest_len, 2, 1); + *signature = (char*)safe_pemalloc(digest_len, 2, 1, PHAR_G(persist)); for (; len < digest_len; ++len) { (*signature)[++pos] = hexChars[((const unsigned char *)digest)[len] >> 4]; @@ -513,7 +630,7 @@ static int phar_hex_str(const char *digest, size_t digest_len, char ** signature * This is used by phar_open_from_filename to process the manifest, but can be called * directly. */ -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) /* {{{ */ +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) /* {{{ */ { char b32[4], *buffer, *endbuffer, *savebuf; phar_archive_data *mydata = NULL; @@ -988,22 +1105,33 @@ int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, MAPPHAR_FAIL("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)") } - mydata = ecalloc(sizeof(phar_archive_data), 1); + mydata = pecalloc(sizeof(phar_archive_data), 1, PHAR_G(persist)); + mydata->is_persistent = PHAR_G(persist); /* check whether we have meta data, zero check works regardless of byte order */ - if (phar_parse_metadata(&buffer, &mydata->metadata, 0 TSRMLS_CC) == FAILURE) { - MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\""); + if (mydata->is_persistent) { + char *mysave = buffer; + PHAR_GET_32(buffer, mydata->metadata_len); + buffer = mysave; + if (phar_parse_metadata(&buffer, &mydata->metadata, mydata->metadata_len TSRMLS_CC) == FAILURE) { + MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\""); + } + } else { + if (phar_parse_metadata(&buffer, &mydata->metadata, 0 TSRMLS_CC) == FAILURE) { + MAPPHAR_FAIL("unable to read phar metadata in .phar file \"%s\""); + } } /* set up our manifest */ zend_hash_init(&mydata->manifest, sizeof(phar_entry_info), - zend_get_hash_value, destroy_phar_manifest_entry, 0); + zend_get_hash_value, destroy_phar_manifest_entry, mydata->is_persistent); zend_hash_init(&mydata->mounted_dirs, sizeof(char *), - zend_get_hash_value, NULL, 0); + zend_get_hash_value, NULL, mydata->is_persistent); offset = halt_offset + manifest_len + 4; memset(&entry, 0, sizeof(phar_entry_info)); entry.phar = mydata; entry.fp_type = PHAR_FP; + entry.is_persistent = mydata->is_persistent; for (manifest_index = 0; manifest_index < manifest_count; ++manifest_index) { if (buffer + 4 > endbuffer) { @@ -1021,7 +1149,7 @@ int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, } else { entry.is_dir = 0; } - entry.filename = estrndup(buffer, entry.filename_len); + entry.filename = pestrndup(buffer, entry.filename_len, entry.is_persistent); buffer += entry.filename_len; PHAR_GET_32(buffer, entry.uncompressed_filesize); PHAR_GET_32(buffer, entry.timestamp); @@ -1042,9 +1170,17 @@ int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, entry.filename_len--; entry.flags |= PHAR_ENT_PERM_DEF_DIR; } - if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) { - efree(entry.filename); - MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\""); + if (entry.is_persistent) { + PHAR_GET_32(buffer, entry.metadata_len); + if (phar_parse_metadata(&buffer, &entry.metadata, entry.metadata_len TSRMLS_CC) == FAILURE) { + pefree(entry.filename, entry.is_persistent); + MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\""); + } + } else { + if (phar_parse_metadata(&buffer, &entry.metadata, 0 TSRMLS_CC) == FAILURE) { + pefree(entry.filename, entry.is_persistent); + MAPPHAR_FAIL("unable to read file metadata in .phar file \"%s\""); + } } entry.offset = entry.offset_abs = offset; offset += entry.compressed_filesize; @@ -1052,27 +1188,39 @@ int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, case PHAR_ENT_COMPRESSED_GZ: if (!PHAR_G(has_zlib)) { if (entry.metadata) { - zval_ptr_dtor(&entry.metadata); + if (entry.is_persistent) { + free(entry.metadata); + } else { + zval_ptr_dtor(&entry.metadata); + } } - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); MAPPHAR_FAIL("zlib extension is required for gz compressed .phar file \"%s\""); } break; case PHAR_ENT_COMPRESSED_BZ2: if (!PHAR_G(has_bz2)) { if (entry.metadata) { - zval_ptr_dtor(&entry.metadata); + if (entry.is_persistent) { + free(entry.metadata); + } else { + zval_ptr_dtor(&entry.metadata); + } } - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); MAPPHAR_FAIL("bz2 extension is required for bzip2 compressed .phar file \"%s\""); } break; default: if (entry.uncompressed_filesize != entry.compressed_filesize) { if (entry.metadata) { - zval_ptr_dtor(&entry.metadata); + if (entry.is_persistent) { + free(entry.metadata); + } else { + zval_ptr_dtor(&entry.metadata); + } } - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); MAPPHAR_FAIL("internal corruption of phar \"%s\" (compressed and uncompressed size does not match for uncompressed entry)"); } break; @@ -1088,7 +1236,7 @@ int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, mydata->halt_offset = halt_offset; mydata->flags = manifest_flags; mydata->fp = fp; - mydata->fname = estrndup(fname, fname_len); + mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent); #ifdef PHP_WIN32 phar_unixify_path_separators(mydata->fname, fname_len); #endif @@ -1103,7 +1251,9 @@ int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char *alias, mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext; } } - mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len); + mydata->alias = alias ? + pestrndup(alias, alias_len, mydata->is_persistent) : + pestrndup(mydata->fname, fname_len, mydata->is_persistent); mydata->alias_len = alias ? alias_len : fname_len; mydata->sig_flags = sig_flags; mydata->sig_len = sig_len; @@ -3351,6 +3501,108 @@ PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */ zend_stream_open_function = phar_orig_zend_open; } #endif + if (PHAR_G(manifest_cached)) { + zend_hash_destroy(&(cached_phars)); + zend_hash_destroy(&(cached_alias)); + } +} +/* }}} */ + +static void phar_update_cached_entry(void *data, void *argument) /* {{{ */ +{ + phar_entry_info *entry = (phar_entry_info *)data; + TSRMLS_FETCH(); + + entry->phar = (phar_archive_data *)argument; + if (entry->link) { + entry->link = estrdup(entry->link); + } + if (entry->tmp) { + entry->tmp = estrdup(entry->tmp); + } + entry->metadata_str.c = 0; + entry->filename = estrndup(entry->filename, entry->filename_len); + if (entry->metadata) { + if (entry->metadata_len) { + /* assume success, we would have failed before */ + phar_parse_metadata((char **) &entry->metadata, &entry->metadata, entry->metadata_len TSRMLS_CC); + } else { + zval *t; + + t = entry->metadata; + ALLOC_ZVAL(entry->metadata); + *entry->metadata = *t; + zval_copy_ctor(entry->metadata); +#if PHP_VERSION_ID < 50300 + entry->metadata->refcount = 1; +#else + Z_SET_REFCOUNT_P(entry->metadata, 1); +#endif + + entry->metadata_str.c = NULL; + entry->metadata_str.len = 0; + } + } +} + +static void phar_copy_cached_phar(void *data) /* {{{ */ +{ + phar_archive_data *phar, **pphar = (phar_archive_data **)data; + HashTable newmanifest; + char *fname; + TSRMLS_FETCH(); + + phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data)); + *phar = **pphar; + phar->is_persistent = 0; + fname = phar->fname; + phar->fname = estrndup(phar->fname, phar->fname_len); + phar->ext = phar->fname + (phar->ext - fname); + if (phar->alias) { + phar->alias = estrndup(phar->alias, phar->alias_len); + } + if (phar->signature) { + phar->signature = estrdup(phar->signature); + } + if (phar->metadata) { + /* assume success, we would have failed before */ + if (phar->metadata_len) { + phar_parse_metadata((char **) &phar->metadata, &phar->metadata, phar->metadata_len TSRMLS_CC); + } else { + zval *t; + + t = phar->metadata; + ALLOC_ZVAL(phar->metadata); + *phar->metadata = *t; + zval_copy_ctor(phar->metadata); +#if PHP_VERSION_ID < 50300 + phar->metadata->refcount = 1; +#else + Z_SET_REFCOUNT_P(phar->metadata, 1); +#endif + } + } + zend_hash_init(&newmanifest, sizeof(phar_entry_info), + zend_get_hash_value, destroy_phar_manifest_entry, 0); + zend_hash_copy(&newmanifest, &(*pphar)->manifest, NULL, NULL, sizeof(phar_entry_info)); + zend_hash_apply_with_argument(&newmanifest, (apply_func_arg_t) phar_update_cached_entry, (void *)phar TSRMLS_CC); + phar->manifest = newmanifest; + zend_hash_init(&phar->mounted_dirs, sizeof(char *), + zend_get_hash_value, NULL, 0); + *pphar = phar; +} +/* }}} */ + +static int phar_update_alias_map(void *data) /* {{{ */ +{ + phar_archive_data **pphar, **old = (phar_archive_data **)data; + TSRMLS_FETCH(); + + zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), (*old)->fname, (*old)->fname_len, (void **) &pphar); + if (pphar) { + *old = *pphar; + } + return ZEND_HASH_APPLY_KEEP; } /* }}} */ @@ -3365,11 +3617,18 @@ void phar_request_initialize(TSRMLS_D) /* {{{ */ PHAR_GLOBALS->request_done = 0; zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 0); zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), sizeof(phar_archive_data*), zend_get_hash_value, NULL, 0); + if (PHAR_G(manifest_cached)) { + zend_hash_copy(&(PHAR_GLOBALS->phar_fname_map), &cached_phars, phar_copy_cached_phar, NULL, sizeof(phar_archive_data *)); + zend_hash_copy(&(PHAR_GLOBALS->phar_alias_map), &cached_alias, NULL, NULL, sizeof(phar_archive_data *)); + zend_hash_apply(&(PHAR_GLOBALS->phar_alias_map), (apply_func_t) phar_update_alias_map TSRMLS_CC); + } zend_hash_init(&(PHAR_GLOBALS->phar_SERVER_mung_list), sizeof(const char *), zend_get_hash_value, NULL, 0); PHAR_G(cwd) = NULL; PHAR_G(cwd_len) = 0; PHAR_G(cwd_init) = 0; - phar_intercept_functions(TSRMLS_C); + if (!PHAR_G(orig_fopen)) { + phar_intercept_functions(TSRMLS_C); + } } } /* }}} */ @@ -3439,6 +3698,8 @@ PHP_MINFO_FUNCTION(phar) /* {{{ */ static zend_module_dep phar_deps[] = { ZEND_MOD_OPTIONAL("apc") ZEND_MOD_OPTIONAL("openssl") + ZEND_MOD_OPTIONAL("zlib") + ZEND_MOD_OPTIONAL("bz2") #if HAVE_SPL ZEND_MOD_REQUIRED("spl") #endif diff --git a/ext/phar/phar.phar b/ext/phar/phar.phar index 20fea1786c..c68028875c 100755 Binary files a/ext/phar/phar.phar and b/ext/phar/phar.phar differ diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 4d8ba8475b..411411fb9d 100755 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -137,6 +137,9 @@ ZEND_BEGIN_MODULE_GLOBALS(phar) HashTable phar_alias_map; HashTable phar_SERVER_mung_list; int readonly; + char* cache_list; + int manifest_cached; + int persist; int has_zlib; int has_bz2; zend_bool readonly_orig; @@ -228,6 +231,7 @@ typedef struct _phar_entry_info { /* when changing compression, save old flags in case fp is NULL */ php_uint32 old_flags; zval *metadata; + int metadata_len; /* only used for cached manifests */ php_uint32 filename_len; char *filename; enum phar_fp_type fp_type; @@ -258,6 +262,8 @@ typedef struct _phar_entry_info { char tar_type; /* zip-based phar file stuff */ int is_zip:1; + /* for cached phar entries */ + int is_persistent:1; } phar_entry_info; /* information about a phar file (the archive itself) */ @@ -286,6 +292,7 @@ struct _phar_archive_data { int sig_len; char *signature; zval *metadata; + int metadata_len; /* only used for cached manifests */ /* if 1, then this alias was manually specified by the user and is not a permanent alias */ int is_temporary_alias:1; int is_modified:1; @@ -299,6 +306,8 @@ struct _phar_archive_data { int is_tar:1; /* PharData variables */ int is_data:1; + /* for cached phar manifests */ + int is_persistent:1; }; #define PHAR_MIME_PHP '\0' diff --git a/ext/phar/tar.c b/ext/phar/tar.c index b3d69cc88f..1cd5046aa0 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -214,11 +214,12 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, hdr = (tar_header*)buf; old = (memcmp(hdr->magic, "ustar", sizeof("ustar")-1) != 0); - myphar = (phar_archive_data *) ecalloc(1, sizeof(phar_archive_data)); + myphar = (phar_archive_data *) pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist)); + myphar->is_persistent = PHAR_G(persist); zend_hash_init(&myphar->manifest, sizeof(phar_entry_info), - zend_get_hash_value, destroy_phar_manifest_entry, 0); + zend_get_hash_value, destroy_phar_manifest_entry, myphar->is_persistent); zend_hash_init(&myphar->mounted_dirs, sizeof(char *), - zend_get_hash_value, NULL, 0); + zend_get_hash_value, NULL, myphar->is_persistent); myphar->is_tar = 1; /* remember whether this entire phar was compressed with gz/bzip2 */ myphar->flags = compression; @@ -257,9 +258,9 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, /* some tar programs store directories with trailing slash */ entry.filename_len--; } - entry.filename = estrndup(name, entry.filename_len); + entry.filename = pestrndup(name, entry.filename_len, myphar->is_persistent); } else { - entry.filename = estrdup(hdr->name); + entry.filename = pestrdup(hdr->name, myphar->is_persistent); entry.filename_len = strlen(entry.filename); if (entry.filename[entry.filename_len - 1] == '/') { /* some tar programs store directories with trailing slash */ @@ -271,13 +272,13 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (checksum mismatch of file \"%s\")", fname, entry.filename); } - efree(entry.filename); + pefree(entry.filename, myphar->is_persistent); php_stream_close(fp); zend_hash_destroy(&myphar->manifest); myphar->manifest.arBuckets = 0; zend_hash_destroy(&myphar->mounted_dirs); myphar->mounted_dirs.arBuckets = 0; - efree(myphar); + pefree(myphar, myphar->is_persistent); return FAILURE; } @@ -286,6 +287,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, entry.fp_type = PHAR_FP; entry.flags = phar_tar_number(hdr->mode, sizeof(hdr->mode)) & PHAR_ENT_PERM_MASK; entry.timestamp = phar_tar_number(hdr->mtime, sizeof(hdr->mtime)); + entry.is_persistent = myphar->is_persistent; #ifndef S_ISDIR #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) @@ -305,13 +307,13 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%s\"", fname, hdr->linkname); } - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); php_stream_close(fp); zend_hash_destroy(&myphar->manifest); myphar->manifest.arBuckets = 0; zend_hash_destroy(&myphar->mounted_dirs); myphar->mounted_dirs.arBuckets = 0; - efree(myphar); + pefree(myphar, entry.is_persistent); return FAILURE; } entry.link = estrdup(hdr->linkname); @@ -329,7 +331,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, myphar->manifest.arBuckets = 0; zend_hash_destroy(&myphar->mounted_dirs); myphar->mounted_dirs.arBuckets = 0; - efree(myphar); + pefree(myphar, myphar->is_persistent); return FAILURE; } } @@ -345,7 +347,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, myphar->manifest.arBuckets = 0; zend_hash_destroy(&myphar->mounted_dirs); myphar->mounted_dirs.arBuckets = 0; - efree(myphar); + pefree(myphar, myphar->is_persistent); return FAILURE; } read = php_stream_read(fp, buf, size); @@ -366,10 +368,10 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, myphar->manifest.arBuckets = 0; zend_hash_destroy(&myphar->mounted_dirs); myphar->mounted_dirs.arBuckets = 0; - efree(myphar); + pefree(myphar, myphar->is_persistent); return FAILURE; } - actual_alias = estrndup(buf, size); + actual_alias = pestrndup(buf, size, myphar->is_persistent); myphar->alias = actual_alias; myphar->alias_len = size; php_stream_seek(fp, pos, SEEK_SET); @@ -382,7 +384,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, myphar->manifest.arBuckets = 0; zend_hash_destroy(&myphar->mounted_dirs); myphar->mounted_dirs.arBuckets = 0; - efree(myphar); + pefree(myphar, myphar->is_persistent); return FAILURE; } } @@ -399,7 +401,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, myphar->manifest.arBuckets = 0; zend_hash_destroy(&myphar->mounted_dirs); myphar->mounted_dirs.arBuckets = 0; - efree(myphar); + pefree(myphar, myphar->is_persistent); return FAILURE; } } @@ -413,11 +415,11 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, myphar->manifest.arBuckets = 0; zend_hash_destroy(&myphar->mounted_dirs); myphar->mounted_dirs.arBuckets = 0; - efree(myphar); + pefree(myphar, myphar->is_persistent); return FAILURE; } } while (read != 0); - myphar->fname = estrndup(fname, fname_len); + myphar->fname = pestrndup(fname, fname_len, myphar->is_persistent); #ifdef PHP_WIN32 phar_unixify_path_separators(myphar->fname, fname_len); #endif @@ -449,7 +451,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, myphar->manifest.arBuckets = 0; zend_hash_destroy(&myphar->mounted_dirs); myphar->mounted_dirs.arBuckets = 0; - efree(myphar); + pefree(myphar, myphar->is_persistent); return FAILURE; } myphar = *actual; @@ -481,10 +483,10 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, } } zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL); - myphar->alias = estrndup(alias, alias_len); + myphar->alias = pestrndup(alias, alias_len, myphar->is_persistent); myphar->alias_len = alias_len; } else { - myphar->alias = estrndup(myphar->fname, fname_len); + myphar->alias = pestrndup(myphar->fname, fname_len, myphar->is_persistent); myphar->alias_len = fname_len; } myphar->is_temporary_alias = 1; diff --git a/ext/phar/tests/phpinfo_001.phpt b/ext/phar/tests/phpinfo_001.phpt index 7b31185827..400a553226 100644 --- a/ext/phar/tests/phpinfo_001.phpt +++ b/ext/phar/tests/phpinfo_001.phpt @@ -7,6 +7,7 @@ Phar: phpinfo display 1 --INI-- phar.readonly=0 phar.require_hash=0 +phar.cache_list= --FILE-- Local Value => Master Value +phar.cache_list => no value => no value phar.readonly => Off => Off phar.require_hash => Off => Off %a @@ -53,6 +55,7 @@ Phar based on pear/PHP_Archive, original concept by Davey Shafik. Phar fully realized by Gregory Beaver and Marcus Boerger. Portions of tar implementation Copyright (c) 2003-2007 Tim Kientzle. Directive => Local Value => Master Value +phar.cache_list => no value => no value phar.readonly => On => Off phar.require_hash => On => Off %a diff --git a/ext/phar/tests/phpinfo_002.phpt b/ext/phar/tests/phpinfo_002.phpt index 1e0e567aff..5fd0370d33 100644 --- a/ext/phar/tests/phpinfo_002.phpt +++ b/ext/phar/tests/phpinfo_002.phpt @@ -7,6 +7,7 @@ Phar: phpinfo display 2 --INI-- phar.readonly=1 phar.require_hash=1 +phar.cache_list= --FILE-- Local Value => Master Value +phar.cache_list => no value => no value phar.readonly => On => On phar.require_hash => On => On %a diff --git a/ext/phar/tests/phpinfo_003.phpt b/ext/phar/tests/phpinfo_003.phpt index 23bc0a773a..16690b476c 100644 --- a/ext/phar/tests/phpinfo_003.phpt +++ b/ext/phar/tests/phpinfo_003.phpt @@ -7,6 +7,7 @@ Phar: phpinfo display 3 --INI-- phar.readonly=1 phar.require_hash=1 +phar.cache_list= --FILE-- Local Value => Master Value +phar.cache_list => no value => no value phar.readonly => On => On phar.require_hash => On => On %a diff --git a/ext/phar/tests/phpinfo_004.phpt b/ext/phar/tests/phpinfo_004.phpt index 1dbccda889..b541c6f00a 100644 --- a/ext/phar/tests/phpinfo_004.phpt +++ b/ext/phar/tests/phpinfo_004.phpt @@ -7,6 +7,7 @@ Phar: phpinfo display 4 --INI-- phar.readonly=0 phar.require_hash=0 +phar.cache_list= --POST-- a=b --FILE-- @@ -37,6 +38,7 @@ Phar based on pear/PHP_Archive, original concept by Davey Shafik.
Phar full
+
DirectiveLocal ValueMaster Value
phar.cache_listno valueno value
phar.readonlyOffOff
phar.require_hashOffOff

@@ -59,6 +61,7 @@ Phar based on pear/PHP_Archive, original concept by Davey Shafik.
Phar full
+
DirectiveLocal ValueMaster Value
phar.cache_listno valueno value
phar.readonlyOnOff
phar.require_hashOnOff

diff --git a/ext/phar/zip.c b/ext/phar/zip.c index 046c2fd6eb..dbeddfb2f9 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -193,7 +193,8 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, php_stream_close(fp); return FAILURE; } - mydata = ecalloc(sizeof(phar_archive_data), 1); + mydata = pecalloc(sizeof(phar_archive_data), 1, PHAR_G(persist)); + mydata->is_persistent = PHAR_G(persist); /* read in archive comment, if any */ if (locator.comment_len) { @@ -205,13 +206,21 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname); } php_stream_close(fp); - efree(mydata); + pefree(mydata, mydata->is_persistent); return FAILURE; } + mydata->metadata_len = PHAR_GET_16(locator.comment_len); if (phar_parse_metadata(&metadata, &mydata->metadata, PHAR_GET_16(locator.comment_len) TSRMLS_CC) == FAILURE) { + mydata->metadata_len = 0; /* if not valid serialized data, it is a regular string */ - ALLOC_INIT_ZVAL(mydata->metadata); - ZVAL_STRINGL(mydata->metadata, metadata, PHAR_GET_16(locator.comment_len), 1); + if (entry.is_persistent) { + ALLOC_PERMANENT_ZVAL(mydata->metadata); + } else { + ALLOC_ZVAL(mydata->metadata); + } + INIT_ZVAL(*mydata->metadata); + metadata = pestrndup(metadata, PHAR_GET_16(locator.comment_len), mydata->is_persistent); + ZVAL_STRINGL(mydata->metadata, metadata, PHAR_GET_16(locator.comment_len), 0); } } else { mydata->metadata = NULL; @@ -225,7 +234,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, } return FAILURE; foundit: - mydata->fname = estrndup(fname, fname_len); + mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent); #ifdef PHP_WIN32 phar_unixify_path_separators(mydata->fname, fname_len); #endif @@ -246,12 +255,13 @@ foundit: php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET); /* read in central directory */ zend_hash_init(&mydata->manifest, sizeof(phar_entry_info), - zend_get_hash_value, destroy_phar_manifest_entry, 0); + zend_get_hash_value, destroy_phar_manifest_entry, mydata->is_persistent); zend_hash_init(&mydata->mounted_dirs, sizeof(char *), - zend_get_hash_value, NULL, 0); + zend_get_hash_value, NULL, mydata->is_persistent); entry.phar = mydata; entry.is_zip = 1; entry.fp_type = PHAR_FP; + entry.is_persistent = mydata->is_persistent; #define PHAR_ZIP_FAIL(errmsg) \ zend_hash_destroy(&mydata->manifest); \ mydata->manifest.arBuckets = 0; \ @@ -264,11 +274,11 @@ foundit: if (error) { \ spprintf(error, 4096, "phar error: %s in zip-based phar \"%s\"", errmsg, mydata->fname); \ } \ - efree(mydata->fname); \ + pefree(mydata->fname, mydata->is_persistent); \ if (mydata->alias) { \ - efree(mydata->alias); \ + pefree(mydata->alias, mydata->is_persistent); \ } \ - efree(mydata); \ + pefree(mydata, mydata->is_persistent); \ return FAILURE; /* add each central directory item to the manifest */ @@ -299,9 +309,9 @@ foundit: PHAR_ZIP_FAIL("Cannot process zips created from stdin (zero-length filename)"); } entry.filename_len = PHAR_GET_16(zipentry.filename_len); - entry.filename = (char *) emalloc(entry.filename_len + 1); + entry.filename = (char *) pemalloc(entry.filename_len + 1, entry.is_persistent); if (entry.filename_len != php_stream_read(fp, entry.filename, entry.filename_len)) { - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unable to read in filename from central directory, truncated"); } entry.filename[entry.filename_len] = '\0'; @@ -339,56 +349,63 @@ foundit: } break; case 1 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (Shrunk) used in this zip"); case 2 : case 3 : case 4 : case 5 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (Reduce) used in this zip"); case 6 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (Implode) used in this zip"); case 7 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (Tokenize) used in this zip"); case 9 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (Deflate64) used in this zip"); case 10 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (PKWare Implode/old IBM TERSE) used in this zip"); case 14 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (LZMA) used in this zip"); case 18 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (IBM TERSE) used in this zip"); case 19 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (IBM LZ77) used in this zip"); case 97 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (WavPack) used in this zip"); case 98 : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (PPMd) used in this zip"); default : - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unsupported compression method (unknown) used in this zip"); } /* get file metadata */ if (zipentry.comment_len) { if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) { - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unable to read in file comment, truncated"); } p = buf; + entry.metadata_len = zipentry.comment_len; if (phar_parse_metadata(&p, &(entry.metadata), PHAR_GET_16(zipentry.comment_len) TSRMLS_CC) == FAILURE) { + entry.metadata_len = 0; /* if not valid serialized data, it is a regular string */ - ALLOC_INIT_ZVAL(entry.metadata); - ZVAL_STRINGL(entry.metadata, buf, PHAR_GET_16(zipentry.comment_len), 1); + if (entry.is_persistent) { + ALLOC_PERMANENT_ZVAL(entry.metadata); + } else { + ALLOC_ZVAL(entry.metadata); + } + INIT_ZVAL(*entry.metadata); + ZVAL_STRINGL(entry.metadata, pestrndup(buf, PHAR_GET_16(zipentry.comment_len), entry.is_persistent), PHAR_GET_16(zipentry.comment_len), 0); } } else { entry.metadata = NULL; @@ -405,12 +422,12 @@ foundit: if (entry.flags & PHAR_ENT_COMPRESSED_GZ) { filter = php_stream_filter_create("zlib.inflate", NULL, php_stream_is_persistent(fp) TSRMLS_CC); if (!filter) { - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unable to decompress alias, zlib filter creation failed"); } php_stream_filter_append(&fp->readfilters, filter); if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unable to read in alias, truncated"); } php_stream_filter_flush(filter, 1); @@ -419,20 +436,20 @@ foundit: php_stream_filter *filter; filter = php_stream_filter_create("bzip2.decompress", NULL, php_stream_is_persistent(fp) TSRMLS_CC); if (!filter) { - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unable to read in alias, bzip2 filter creation failed"); } php_stream_filter_append(&fp->readfilters, filter); php_stream_filter_append(&fp->readfilters, filter); if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unable to read in alias, truncated"); } php_stream_filter_flush(filter, 1); php_stream_filter_remove(filter, 1 TSRMLS_CC); } else { if (!(entry.uncompressed_filesize = php_stream_copy_to_mem(fp, &actual_alias, entry.uncompressed_filesize, 0)) || !actual_alias) { - efree(entry.filename); + pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unable to read in alias, truncated"); } } @@ -471,7 +488,10 @@ foundit: return FAILURE; } } - mydata->alias = actual_alias; + mydata->alias = entry.is_persistent ? pestrndup(actual_alias, mydata->alias_len, 1) : actual_alias; + if (entry.is_persistent) { + efree(actual_alias); + } zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL); } else { phar_archive_data **fd_ptr; @@ -487,10 +507,10 @@ foundit: } } zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, mydata->alias_len, (void*)&mydata, sizeof(phar_archive_data*), NULL); - mydata->alias = estrndup(alias, alias_len); + mydata->alias = pestrndup(alias, alias_len, mydata->is_persistent); mydata->alias_len = alias_len; } else { - mydata->alias = estrndup(mydata->fname, fname_len); + mydata->alias = pestrndup(mydata->fname, fname_len, mydata->is_persistent); mydata->alias_len = fname_len; } mydata->is_temporary_alias = 1;