From: Greg Beaver Date: Wed, 7 May 2008 17:24:22 +0000 (+0000) Subject: optimize phar filename extension detection to first search through known phars. ... X-Git-Tag: RELEASE_2_0_0b1~62 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f134a909c3199ae0a1b23b53c8cd66703ea62bb8;p=php optimize phar filename extension detection to first search through known phars. This eliminates several stat/realpath calls for archives with lots of files --- diff --git a/ext/phar/phar.c b/ext/phar/phar.c index d31bb71e6e..b668e043e4 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -380,7 +380,9 @@ int phar_open_loaded(char *fname, int fname_len, char *alias, int alias_len, int /* prevent any ".phar" without a stub getting through */ if (!phar->halt_offset && !phar->is_brandnew) { if (PHAR_G(readonly) && FAILURE == zend_hash_find(&(phar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&stub)) { - spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname); + if (error) { + spprintf(error, 0, "'%s' is not a phar archive. Use PharData::__construct() for a standard zip or tar archive", fname); + } return FAILURE; } } @@ -908,6 +910,16 @@ int phar_open_file(php_stream *fp, char *fname, int fname_len, char *alias, int phar_unixify_path_separators(mydata->fname, fname_len); #endif mydata->fname_len = fname_len; + endbuffer = strrchr(mydata->fname, '/'); + if (endbuffer) { + mydata->ext = memchr(endbuffer, '.', (mydata->fname + fname_len) - endbuffer); + if (mydata->ext == endbuffer) { + mydata->ext = memchr(endbuffer + 1, '.', (mydata->fname + fname_len) - endbuffer - 1); + } + if (mydata->ext) { + mydata->ext_len = (mydata->fname + mydata->fname_len) - mydata->ext; + } + } mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len); mydata->alias_len = alias ? alias_len : fname_len; mydata->sig_flags = sig_flags; @@ -1008,7 +1020,7 @@ int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int a phar_archive_data *mydata; int register_alias; php_stream *fp; - char *actual = NULL; + char *actual = NULL, *p; if (!pphar) { pphar = &mydata; @@ -1068,7 +1080,17 @@ int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int a #ifdef PHP_WIN32 phar_unixify_path_separators(mydata->fname, fname_len); #endif - + p = strrchr(mydata->fname, '/'); + if (p) { + mydata->ext = memchr(p, '.', (mydata->fname + fname_len) - p); + if (mydata->ext == p) { + mydata->ext = memchr(p + 1, '.', (mydata->fname + fname_len) - p - 1); + } + if (mydata->ext) { + mydata->ext_len = (mydata->fname + fname_len) - mydata->ext; + } + } + if (pphar) { *pphar = mydata; } @@ -1508,6 +1530,53 @@ int phar_detect_phar_fname_ext(const char *filename, int check_length, const cha } } + if (zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) { + phar_archive_data **pphar; + + if (is_complete) { + if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), filename, filename_len, (void **)&pphar)) { + *ext_str = filename + (filename_len - (*pphar)->ext_len); +woohoo: + *ext_len = (*pphar)->ext_len; + if (executable == 2) { + return SUCCESS; + } + if (executable == 1 && !(*pphar)->is_data) { + return SUCCESS; + } + if (!executable && (*pphar)->is_data) { + return SUCCESS; + } + return FAILURE; + } + } else { + char *key; + uint keylen; + ulong unused; + + zend_hash_internal_pointer_reset(&(PHAR_GLOBALS->phar_fname_map)); + while (FAILURE != zend_hash_has_more_elements(&(PHAR_GLOBALS->phar_fname_map))) { + if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&(PHAR_GLOBALS->phar_fname_map), &key, &keylen, &unused, 0, NULL)) { + break; + } + + if (keylen > filename_len) { + zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map)); + continue; + } + if (!memcmp(filename, key, keylen) && (filename_len == keylen + || filename[keylen] == '/' || filename[keylen] == '\0')) { + if (FAILURE == zend_hash_get_current_data(&(PHAR_GLOBALS->phar_fname_map), (void **) &pphar)) { + break; + } + *ext_str = filename + (keylen - (*pphar)->ext_len); + goto woohoo; + } + zend_hash_move_forward(&(PHAR_GLOBALS->phar_fname_map)); + } + } + } + pos = strchr(filename + 1, '.'); next_extension: if (!pos) { diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index d6a7eaa7ea..1aa5425125 100755 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -260,6 +260,9 @@ typedef struct _phar_entry_info { struct _phar_archive_data { char *fname; int fname_len; + /* for phar_detect_fname_ext, this stores the location of the file extension within fname */ + char *ext; + int ext_len; char *alias; int alias_len; char version[12]; diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 485b84ec9d..ef59ba5e5e 100755 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1837,7 +1837,7 @@ static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool c } if (!phar->is_data) { - if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &ext, &ext_len, 1, 1, 1 TSRMLS_CC)) { + if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 1, 1, 1 TSRMLS_CC)) { efree(oldpath); zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "phar \"%s\" has invalid extension %s", phar->fname, ext); return NULL; @@ -1854,7 +1854,7 @@ static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool c } } } else { - if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &ext, &ext_len, 0, 1, 1 TSRMLS_CC)) { + if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &(phar->ext_len), 0, 1, 1 TSRMLS_CC)) { efree(oldpath); zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "data phar \"%s\" has invalid extension %s", phar->fname, ext); return NULL; diff --git a/ext/phar/tar.c b/ext/phar/tar.c index eb0c9a058f..7288b3bbff 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -154,7 +154,7 @@ int phar_open_or_create_tar(char *fname, int fname_len, char *alias, int alias_l int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */ { - char buf[512], *actual_alias = NULL; + char buf[512], *actual_alias = NULL, *p; phar_entry_info entry = {0}; size_t pos = 0, read, totalsize; tar_header *hdr; @@ -371,6 +371,16 @@ int phar_open_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, i phar_unixify_path_separators(myphar->fname, fname_len); #endif myphar->fname_len = fname_len; + p = strrchr(myphar->fname, '/'); + if (p) { + myphar->ext = memchr(p, '.', (myphar->fname + fname_len) - p); + if (myphar->ext == p) { + myphar->ext = memchr(p + 1, '.', (myphar->fname + fname_len) - p - 1); + } + if (myphar->ext) { + myphar->ext_len = (myphar->fname + fname_len) - p; + } + } myphar->fp = fp; phar_request_initialize(TSRMLS_C); if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), myphar->fname, fname_len, (void*)&myphar, sizeof(phar_archive_data*), (void **)&actual)) { diff --git a/ext/phar/tests/phar_convert_again.phpt b/ext/phar/tests/phar_convert_again.phpt index c58a8df14d..4543a238d5 100644 --- a/ext/phar/tests/phar_convert_again.phpt +++ b/ext/phar/tests/phar_convert_again.phpt @@ -212,7 +212,7 @@ A Phar stub cannot be set in a plain tar archive A Phar alias cannot be set in a plain tar archive A Phar stub cannot be set in a plain tar archive Cannot set signature algorithm, not possible with tar-based phar archives -data phar "%sphar_convert_again2.phar.tgz.oops" has invalid extension .phar.tgz.oops -phar "%sphar_convert_again2.tgz.oops" has invalid extension .tgz.oops -data phar "%sphar_convert_again2.phar/.tgz.oops" has invalid extension .phar/.tgz.oops +data phar "%sphar_convert_again2.phar.tgz.oops" has invalid extension phar.tgz.oops +phar "%sphar_convert_again2.tgz.oops" has invalid extension tgz.oops +data phar "%sphar_convert_again2.phar/.tgz.oops" has invalid extension phar/.tgz.oops ===DONE=== diff --git a/ext/phar/zip.c b/ext/phar/zip.c index 888d135f51..816180f550 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -152,7 +152,7 @@ int phar_open_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, i php_uint16 i; phar_archive_data *mydata = NULL; phar_entry_info entry = {0}; - char *p = buf; + char *p = buf, *ext; size = php_stream_tell(fp); if (size > sizeof(locator) + 65536) { @@ -231,6 +231,16 @@ foundit: #endif mydata->is_zip = 1; mydata->fname_len = fname_len; + ext = strrchr(mydata->fname, '/'); + if (ext) { + mydata->ext = memchr(ext, '.', (mydata->fname + fname_len) - ext); + if (mydata->ext == ext) { + mydata->ext = memchr(ext + 1, '.', (mydata->fname + fname_len) - ext - 1); + } + if (mydata->ext) { + mydata->ext_len = (mydata->fname + fname_len) - mydata->ext; + } + } /* clean up on big-endian systems */ /* seek to central directory */ php_stream_seek(fp, PHAR_GET_32(locator.cdir_offset), SEEK_SET);