optimize phar filename extension detection to first search through known phars. This eliminates several stat/realpath calls for archives with lots of files

This commit is contained in:
Greg Beaver 2008-05-07 17:24:22 +00:00
parent ae26f18c73
commit f134a909c3
6 changed files with 102 additions and 10 deletions

View File

@ -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) {

View File

@ -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];

View File

@ -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;

View File

@ -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)) {

View File

@ -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===

View File

@ -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);