summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Beaver <cellog@php.net>2008-06-18 06:38:47 +0000
committerGreg Beaver <cellog@php.net>2008-06-18 06:38:47 +0000
commitcbe23b9f2041a6b37fbeadc49963baf6ffc5827a (patch)
tree2318f9bc03c9022fb2359ff27da66dc62fb7401b
parent31bfce6f19f7e484b0a901fe1d0e26a2f8439395 (diff)
downloadphp-git-cbe23b9f2041a6b37fbeadc49963baf6ffc5827a.tar.gz
fix windows build and more performance jumps (these are minor)
implement real copy-on-write use virtual_dirs for wrapper stat
-rw-r--r--ext/phar/dirstream.c18
-rw-r--r--ext/phar/func_interceptors.c36
-rw-r--r--ext/phar/phar.c204
-rwxr-xr-xext/phar/phar.pharbin15252 -> 15252 bytes
-rwxr-xr-xext/phar/phar_internal.h131
-rwxr-xr-xext/phar/phar_object.c59
-rw-r--r--ext/phar/stream.c132
-rw-r--r--ext/phar/tar.c11
-rw-r--r--ext/phar/tests/cached_manifest_1.phpt36
-rw-r--r--ext/phar/util.c249
-rw-r--r--ext/phar/zip.c8
11 files changed, 608 insertions, 276 deletions
diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c
index 19ac6f9cef..6c2bd7231c 100644
--- a/ext/phar/dirstream.c
+++ b/ext/phar/dirstream.c
@@ -145,9 +145,9 @@ static int phar_dir_flush(php_stream *stream TSRMLS_DC) /* {{{ */
*/
static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength) /* {{{ */
{
- void *dummy = (void *) 1;
+ void *dummy = (char *) 1;
- return zend_hash_update(ht, arKey, nKeyLength, &dummy, sizeof(void *), NULL);
+ return zend_hash_update(ht, arKey, nKeyLength, (void *) &dummy, sizeof(void *), NULL);
}
/* }}} */
@@ -445,7 +445,6 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
}
host_len = strlen(resource->host);
- phar_request_initialize(TSRMLS_C);
if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
@@ -483,6 +482,12 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
return FAILURE;
}
+ if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot create directory \"%s\" in phar \"%s\", unable to make cached phar writeable", resource->path+1, resource->host);
+ php_url_free(resource);
+ return FAILURE;
+ }
+
memset((void *) &entry, 0, sizeof(phar_entry_info));
/* strip leading "/" */
@@ -565,7 +570,6 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
}
host_len = strlen(resource->host);
- phar_request_initialize(TSRMLS_C);
if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", error retrieving phar information: %s", resource->path+1, resource->host, error);
@@ -586,6 +590,12 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
}
/* now for the easy part */
+ if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: cannot remove directory \"%s\" in phar \"%s\", unable to make cached phar writeable", resource->path+1, resource->host);
+ php_url_free(resource);
+ return FAILURE;
+ }
+
entry->is_deleted = 1;
entry->is_modified = 1;
phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
diff --git a/ext/phar/func_interceptors.c b/ext/phar/func_interceptors.c
index 621d87392a..0abc623963 100644
--- a/ext/phar/func_interceptors.c
+++ b/ext/phar/func_interceptors.c
@@ -29,7 +29,8 @@ PHAR_FUNC(phar_opendir) /* {{{ */
int filename_len;
zval *zcontext = NULL;
- if (!PHAR_GLOBALS->phar_fname_map.arBuckets || !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
+ && !cached_phars.arBuckets) {
goto skip_phar;
}
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &filename, &filename_len, &zcontext) == FAILURE) {
@@ -97,7 +98,8 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
long maxlen = PHP_STREAM_COPY_ALL;
zval *zcontext = NULL;
- if (!PHAR_GLOBALS->phar_fname_map.arBuckets || !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
+ && !cached_phars.arBuckets) {
goto skip_phar;
}
/* Parse arguments */
@@ -131,7 +133,8 @@ PHAR_FUNC(phar_file_get_contents) /* {{{ */
}
/* retrieving a file defaults to within the current directory, so use this if possible */
- if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
+ && (PHAR_G(manifest_cached) && FAILURE == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
efree(arch);
goto skip_phar;
}
@@ -222,7 +225,8 @@ PHAR_FUNC(phar_readfile) /* {{{ */
zval *zcontext = NULL;
php_stream *stream;
- if (!PHAR_GLOBALS->phar_fname_map.arBuckets || !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
+ && !cached_phars.arBuckets) {
goto skip_phar;
}
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s|br!", &filename, &filename_len, &use_include_path, &zcontext) == FAILURE) {
@@ -249,7 +253,8 @@ PHAR_FUNC(phar_readfile) /* {{{ */
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = filename_len;
/* retrieving a file defaults to within the current directory, so use this if possible */
- if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
+ && (PHAR_G(manifest_cached) && FAILURE == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
efree(arch);
goto skip_phar;
}
@@ -312,7 +317,8 @@ PHAR_FUNC(phar_fopen) /* {{{ */
zval *zcontext = NULL;
php_stream *stream;
- if (!PHAR_GLOBALS->phar_fname_map.arBuckets || !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
+ && !cached_phars.arBuckets) {
/* no need to check, include_path not even specified in fopen/ no active phars */
goto skip_phar;
}
@@ -340,7 +346,8 @@ PHAR_FUNC(phar_fopen) /* {{{ */
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = filename_len;
/* retrieving a file defaults to within the current directory, so use this if possible */
- if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
+ && (PHAR_G(manifest_cached) && FAILURE == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
efree(arch);
goto skip_phar;
}
@@ -614,7 +621,8 @@ void phar_file_stat(const char *filename, php_stat_len filename_length, int type
entry = estrndup(filename, filename_length);
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = (int) filename_length;
- if (FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
+ && (PHAR_G(manifest_cached) && FAILURE == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
efree(arch);
goto skip_phar;
}
@@ -876,7 +884,8 @@ PHAR_FUNC(phar_is_file) /* {{{ */
char *filename;
int filename_len;
- if (!PHAR_GLOBALS->phar_fname_map.arBuckets || !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
+ && !cached_phars.arBuckets) {
goto skip_phar;
}
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
@@ -902,7 +911,8 @@ PHAR_FUNC(phar_is_file) /* {{{ */
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = filename_len;
/* retrieving a file within the current directory, so use this if possible */
- if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
+ || (PHAR_G(manifest_cached) && SUCCESS == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
phar_entry_info *etemp;
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
@@ -936,7 +946,8 @@ PHAR_FUNC(phar_is_link) /* {{{ */
char *filename;
int filename_len;
- if (!PHAR_GLOBALS->phar_fname_map.arBuckets || !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && !zend_hash_num_elements(&(PHAR_GLOBALS->phar_fname_map)))
+ && !cached_phars.arBuckets) {
goto skip_phar;
}
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
@@ -962,7 +973,8 @@ PHAR_FUNC(phar_is_link) /* {{{ */
/* fopen within phar, if :// is not in the url, then prepend phar://<archive>/ */
entry_len = filename_len;
/* retrieving a file within the current directory, so use this if possible */
- if (SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ if ((PHAR_GLOBALS->phar_fname_map.arBuckets && SUCCESS == (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar)))
+ || (PHAR_G(manifest_cached) && SUCCESS == (zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)))) {
phar_entry_info *etemp;
entry = phar_fix_filepath(estrndup(entry, entry_len), &entry_len, 1 TSRMLS_CC);
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
index 3e19e3d4fc..e4f917cce9 100644
--- a/ext/phar/phar.c
+++ b/ext/phar/phar.c
@@ -95,8 +95,8 @@ ZEND_INI_MH(phar_ini_modify_handler) /* {{{ */
/* }}}*/
/* this global stores the global cached pre-parsed manifests */
-static HashTable cached_phars;
-static HashTable cached_alias;
+HashTable cached_phars;
+HashTable cached_alias;
static void phar_split_cache_list(TSRMLS_D)
{
@@ -104,19 +104,24 @@ static void phar_split_cache_list(TSRMLS_D)
char *key, *lasts, *end;
char ds[1];
phar_archive_data *phar;
+ uint i = 0;
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;
+ zend_init_rsrc_list(TSRMLS_C);
PHAR_G(has_bz2) = zend_hash_exists(&module_registry, "bz2", sizeof("bz2"));
PHAR_G(has_zlib) = zend_hash_exists(&module_registry, "zlib", sizeof("zlib"));
+ /* these two are dummies and will be destroyed later */
+ zend_hash_init(&cached_phars, sizeof(phar_archive_data*), zend_get_hash_value, destroy_phar_data, 1);
+ zend_hash_init(&cached_alias, sizeof(phar_archive_data*), zend_get_hash_value, NULL, 1);
+ /* these two are real and will be copied over cached_phars/cached_alias later */
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;
@@ -130,19 +135,22 @@ static void phar_split_cache_list(TSRMLS_D)
if (end) {
if (SUCCESS == phar_open_from_filename(key, end - key, NULL, 0, 0, &phar, NULL TSRMLS_CC)) {
finish_up:
+ phar->phar_pos = i++;
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);
- memset(&EG(regular_list), 0, sizeof(HashTable));
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;
+ zend_hash_destroy(&cached_phars);
+ zend_hash_destroy(&cached_alias);
+ zend_destroy_rsrc_list(&EG(regular_list) TSRMLS_CC);
+ memset(&EG(regular_list), 0, sizeof(HashTable));
/* free cached manifests */
PHAR_GLOBALS->request_init = 0;
return;
@@ -157,11 +165,13 @@ finish_error:
}
PHAR_GLOBALS->persist = 0;
PHAR_GLOBALS->request_init = 0;
+ /* destroy dummy values from before */
+ zend_hash_destroy(&cached_phars);
+ zend_hash_destroy(&cached_alias);
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);
memset(&EG(regular_list), 0, sizeof(HashTable));
efree(tmp);
@@ -236,7 +246,7 @@ void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */
}
if (phar->ufp) {
php_stream_close(phar->ufp);
- phar->fp = 0;
+ phar->ufp = 0;
}
pefree(phar, phar->is_persistent);
}
@@ -247,6 +257,7 @@ void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC) /* {{{ */
*/
int phar_archive_delref(phar_archive_data *phar TSRMLS_DC) /* {{{ */
{
+ if (phar->is_persistent) return 0;
if (--phar->refcount < 0) {
if (PHAR_GLOBALS->request_done
|| zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), phar->fname, phar->fname_len) != SUCCESS) {
@@ -388,7 +399,7 @@ int phar_entry_delref(phar_entry_data *idata TSRMLS_DC) /* {{{ */
{
int ret = 0;
- if (idata->internal_file) {
+ if (idata->internal_file && !idata->internal_file->is_persistent) {
if (--idata->internal_file->fp_refcount < 0) {
idata->internal_file->fp_refcount = 0;
}
@@ -984,6 +995,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
if (entry.filename_len == 0) {
MAPPHAR_FAIL("zero-length filename encountered in phar \"%s\"");
}
+ if (entry.is_persistent) entry.manifest_pos = manifest_index;
if (buffer + entry.filename_len + 20 > endbuffer) {
MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest entry)");
}
@@ -1079,7 +1091,6 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
mydata->internal_file_start = halt_offset + manifest_len + 4;
mydata->halt_offset = halt_offset;
mydata->flags = manifest_flags;
- mydata->fp = fp;
mydata->fname = pestrndup(fname, fname_len, mydata->is_persistent);
#ifdef PHP_WIN32
phar_unixify_path_separators(mydata->fname, fname_len);
@@ -1100,6 +1111,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
pestrndup(mydata->fname, fname_len, mydata->is_persistent);
mydata->alias_len = alias ? alias_len : fname_len;
mydata->sig_flags = sig_flags;
+ mydata->fp = fp;
mydata->sig_len = sig_len;
mydata->signature = signature;
phar_request_initialize(TSRMLS_C);
@@ -1125,7 +1137,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
}
zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), mydata->fname, fname_len, (void*)&mydata, sizeof(phar_archive_data*), NULL);
efree(savebuf);
-
+
if (pphar) {
*pphar = mydata;
}
@@ -2145,9 +2157,9 @@ int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_d
spprintf(error, 0, "phar error: unable to open zip-based phar archive \"%s\" to verify local file header for file \"%s\"", idata->phar->fname, entry->filename);
return FAILURE;
}
- php_stream_seek(idata->phar->fp, entry->header_offset, SEEK_SET);
+ php_stream_seek(phar_get_entrypfp(idata->internal_file TSRMLS_CC), entry->header_offset, SEEK_SET);
- if (sizeof(local) != php_stream_read(idata->phar->fp, (char *) &local, sizeof(local))) {
+ if (sizeof(local) != php_stream_read(phar_get_entrypfp(idata->internal_file TSRMLS_CC), (char *) &local, sizeof(local))) {
spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (cannot read local file header for file \"%s\")", idata->phar->fname, entry->filename);
return FAILURE;
@@ -2387,14 +2399,16 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
smart_str main_metadata_str = {0};
int free_user_stub, free_fp = 1, free_ufp = 1;
+ if (phar->is_persistent) {
+ if (error) {
+ spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
if (error) {
*error = NULL;
}
- if (PHAR_G(readonly) && !phar->is_data) {
- return EOF;
- }
-
if (!zend_hash_num_elements(&phar->manifest) && !user_stub) {
return EOF;
}
@@ -2406,6 +2420,10 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
return phar_tar_flush(phar, user_stub, len, convert, error TSRMLS_CC);
}
+ if (PHAR_G(readonly)) {
+ return EOF;
+ }
+
if (phar->fp && !phar->is_brandnew) {
oldfile = phar->fp;
closeoldfile = 0;
@@ -3065,7 +3083,7 @@ static void php_phar_init_globals_module(zend_phar_globals *phar_globals)
#if PHP_VERSION_ID >= 50300
static size_t phar_zend_stream_reader(void *handle, char *buf, size_t len TSRMLS_DC) /* {{{ */
{
- return php_stream_read(((phar_archive_data*)handle)->fp, buf, len);
+ return php_stream_read(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC), buf, len);
}
/* }}} */
@@ -3078,7 +3096,7 @@ static size_t phar_zend_stream_fsizer(void *handle TSRMLS_DC) /* {{{ */
static long stream_fteller_for_zend(void *handle TSRMLS_DC) /* {{{ */
{
- return (long)php_stream_tell((php_stream*)handle);
+ return (long)php_stream_tell(phar_get_pharfp((phar_archive_data*)handle TSRMLS_CC));
}
/* }}} */
#endif
@@ -3125,22 +3143,28 @@ static zend_op_array *phar_compile_file(zend_file_handle *file_handle, int type
#if PHP_VERSION_ID >= 50300
file_handle->type = ZEND_HANDLE_STREAM;
file_handle->free_filename = 0;
+ /* we do our own reading directly from the phar, don't change the next line */
file_handle->handle.stream.handle = phar;
file_handle->handle.stream.reader = phar_zend_stream_reader;
file_handle->handle.stream.closer = NULL;
file_handle->handle.stream.fsizer = phar_zend_stream_fsizer;
file_handle->handle.stream.isatty = 0;
- php_stream_rewind(phar->fp);
+ phar->is_persistent ?
+ php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
+ php_stream_rewind(phar->fp);
memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap));
#else /* PHP_VERSION_ID */
file_handle->type = ZEND_HANDLE_STREAM;
file_handle->free_filename = 0;
- file_handle->handle.stream.handle = phar->fp;
+ /* we do our own reading directly from the phar, don't change the next line */
+ file_handle->handle.stream.handle = phar;
file_handle->handle.stream.reader = (zend_stream_reader_t)_php_stream_read;
file_handle->handle.stream.closer = NULL; /* don't close - let phar handle this one */
file_handle->handle.stream.fteller = stream_fteller_for_zend;
file_handle->handle.stream.interactive = 0;
- php_stream_rewind(phar->fp);
+ phar->is_persistent ?
+ php_stream_rewind(PHAR_GLOBALS->cached_fp[phar->phar_pos].fp) :
+ php_stream_rewind(phar->fp);
#endif
}
}
@@ -3251,108 +3275,6 @@ PHP_MSHUTDOWN_FUNCTION(phar) /* {{{ */
}
/* }}} */
-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);
- entry->is_persistent = 0;
- 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);
- zend_hash_init(&phar->virtual_dirs, sizeof(char *),
- zend_get_hash_value, NULL, 0);
- zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
- *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;
-}
-/* }}} */
-
void phar_request_initialize(TSRMLS_D) /* {{{ */
{
if (!PHAR_GLOBALS->request_init)
@@ -3362,14 +3284,23 @@ void phar_request_initialize(TSRMLS_D) /* {{{ */
PHAR_GLOBALS->request_init = 1;
PHAR_GLOBALS->request_ends = 0;
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);
+ zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), 5, zend_get_hash_value, destroy_phar_data, 0);
+ zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), 5, 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);
+ phar_archive_data **pphar;
+ phar_entry_fp *stuff = (phar_entry_fp *) ecalloc(zend_hash_num_elements(&cached_phars), sizeof(phar_entry_fp));
+
+ for (zend_hash_internal_pointer_reset(&cached_phars);
+ zend_hash_has_more_elements(&cached_phars) == SUCCESS;
+ zend_hash_move_forward(&cached_phars)) {
+ if (zend_hash_get_current_data(&cached_phars, (void **)&pphar) == FAILURE) {
+ continue;
+ }
+ stuff[pphar[0]->phar_pos].manifest = (phar_entry_fp_info *) ecalloc( zend_hash_num_elements(&(pphar[0]->manifest)), sizeof(phar_entry_fp_info));
+ }
+ PHAR_GLOBALS->cached_fp = stuff;
}
- zend_hash_init(&(PHAR_GLOBALS->phar_SERVER_mung_list), sizeof(const char *), zend_get_hash_value, NULL, 0);
+ zend_hash_init(&(PHAR_GLOBALS->phar_SERVER_mung_list), 5, zend_get_hash_value, NULL, 0);
PHAR_G(cwd) = NULL;
PHAR_G(cwd_len) = 0;
PHAR_G(cwd_init) = 0;
@@ -3382,6 +3313,8 @@ void phar_request_initialize(TSRMLS_D) /* {{{ */
PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
{
+ int i;
+
PHAR_GLOBALS->request_ends = 1;
if (PHAR_GLOBALS->request_init)
{
@@ -3391,6 +3324,19 @@ PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
PHAR_GLOBALS->phar_fname_map.arBuckets = NULL;
zend_hash_destroy(&(PHAR_GLOBALS->phar_SERVER_mung_list));
+ if (PHAR_GLOBALS->cached_fp) {
+ for (i = 0; i < zend_hash_num_elements(&cached_phars); ++i) {
+ if (PHAR_GLOBALS->cached_fp[i].fp) {
+ php_stream_close(PHAR_GLOBALS->cached_fp[i].fp);
+ }
+ if (PHAR_GLOBALS->cached_fp[i].ufp) {
+ php_stream_close(PHAR_GLOBALS->cached_fp[i].ufp);
+ }
+ efree(PHAR_GLOBALS->cached_fp[i].manifest);
+ }
+ efree(PHAR_GLOBALS->cached_fp);
+ PHAR_GLOBALS->cached_fp = 0;
+ }
PHAR_GLOBALS->phar_SERVER_mung_list.arBuckets = NULL;
PHAR_GLOBALS->request_init = 0;
if (PHAR_G(cwd)) {
diff --git a/ext/phar/phar.phar b/ext/phar/phar.phar
index 730a2d311c..336c929e64 100755
--- a/ext/phar/phar.phar
+++ b/ext/phar/phar.phar
Binary files differ
diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
index 85a2b8551c..a14c707a9e 100755
--- a/ext/phar/phar_internal.h
+++ b/ext/phar/phar_internal.h
@@ -136,8 +136,12 @@
#define TAR_DIR '5'
#define TAR_NEW '8'
+typedef struct _phar_entry_fp phar_entry_fp;
+
ZEND_BEGIN_MODULE_GLOBALS(phar)
HashTable phar_fname_map;
+ /* for cached phars, this is a per-process store of fp/ufp */
+ phar_entry_fp *cached_fp;
HashTable phar_alias_map;
HashTable phar_SERVER_mung_list;
int readonly;
@@ -223,6 +227,7 @@ enum phar_fp_type {
};
typedef struct _phar_archive_data phar_archive_data;
+
/* entry for one file in a phar file */
typedef struct _phar_entry_info {
/* first bytes are exactly as in file */
@@ -268,6 +273,8 @@ typedef struct _phar_entry_info {
int is_zip:1;
/* for cached phar entries */
int is_persistent:1;
+ /* position in the manifest */
+ uint manifest_pos;
/* for stat */
unsigned short inode;
} phar_entry_info;
@@ -316,8 +323,128 @@ struct _phar_archive_data {
int is_data:1;
/* for cached phar manifests */
int is_persistent:1;
+ uint phar_pos;
+};
+
+typedef struct _phar_entry_fp_info {
+ enum phar_fp_type fp_type;
+ /* offset within fp of the file contents */
+ long offset;
+} phar_entry_fp_info;
+
+struct _phar_entry_fp {
+ php_stream *fp;
+ php_stream *ufp;
+ phar_entry_fp_info *manifest;
};
+static inline php_stream *phar_get_entrypfp(phar_entry_info *entry TSRMLS_DC)
+{
+ if (!entry->is_persistent) {
+ return entry->phar->fp;
+ }
+ return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].fp;
+}
+
+static inline php_stream *phar_get_entrypufp(phar_entry_info *entry TSRMLS_DC)
+{
+ if (!entry->is_persistent) {
+ return entry->phar->ufp;
+ }
+ return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].ufp;
+}
+
+static inline void phar_set_entrypfp(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
+{
+ if (!entry->phar->is_persistent) {
+ entry->phar->fp = fp;
+ return;
+ }
+
+ PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].fp = fp;
+}
+
+static inline void phar_set_entrypufp(phar_entry_info *entry, php_stream *fp TSRMLS_DC)
+{
+ if (!entry->phar->is_persistent) {
+ entry->phar->ufp = fp;
+ return;
+ }
+
+ PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].ufp = fp;
+}
+
+static inline php_stream *phar_get_pharfp(phar_archive_data *phar TSRMLS_CC)
+{
+ if (!phar->is_persistent) {
+ return phar->fp;
+ }
+ return PHAR_GLOBALS->cached_fp[phar->phar_pos].fp;
+}
+
+static inline php_stream *phar_get_pharufp(phar_archive_data *phar TSRMLS_CC)
+{
+ if (!phar->is_persistent) {
+ return phar->ufp;
+ }
+ return PHAR_GLOBALS->cached_fp[phar->phar_pos].ufp;
+}
+
+static inline void phar_set_pharfp(phar_archive_data *phar, php_stream *fp TSRMLS_DC)
+{
+ if (!phar->is_persistent) {
+ phar->fp = fp;
+ return;
+ }
+
+ PHAR_GLOBALS->cached_fp[phar->phar_pos].fp = fp;
+}
+
+static inline void phar_set_pharufp(phar_archive_data *phar, php_stream *fp TSRMLS_DC)
+{
+ if (!phar->is_persistent) {
+ phar->ufp = fp;
+ return;
+ }
+
+ PHAR_GLOBALS->cached_fp[phar->phar_pos].ufp = fp;
+}
+
+static inline void phar_set_fp_type(phar_entry_info *entry, enum phar_fp_type type, off_t offset TSRMLS_DC)
+{
+ phar_entry_fp_info *data;
+
+ if (!entry->is_persistent) {
+ entry->fp_type = type;
+ entry->offset = offset;
+ return;
+ }
+ data = &(PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos]);
+ data->fp_type = type;
+ data->offset = offset;
+}
+
+static inline enum phar_fp_type phar_get_fp_type(phar_entry_info *entry TSRMLS_DC)
+{
+ if (!entry->is_persistent) {
+ return entry->fp_type;
+ }
+ return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].fp_type;
+}
+
+static inline off_t phar_get_fp_offset(phar_entry_info *entry TSRMLS_DC)
+{
+ if (!entry->is_persistent) {
+ return entry->offset;
+ }
+ if (PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].fp_type == PHAR_FP) {
+ if (!PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].offset) {
+ PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].offset = entry->offset;
+ }
+ }
+ return PHAR_GLOBALS->cached_fp[entry->phar->phar_pos].manifest[entry->manifest_pos].offset;
+}
+
#define PHAR_MIME_PHP '\0'
#define PHAR_MIME_PHPS '\1'
#define PHAR_MIME_OTHER '\2'
@@ -460,6 +587,7 @@ phar_entry_info *phar_get_link_source(phar_entry_info *entry TSRMLS_DC);
int phar_create_writeable_entry(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC);
int phar_separate_entry_fp(phar_entry_info *entry, char **error TSRMLS_DC);
int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC);
+int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC);
/* tar functions in tar.c */
int phar_is_tar(char *buf, char *fname);
@@ -475,6 +603,9 @@ int phar_zip_flush(phar_archive_data *archive, char *user_stub, long len, int de
#ifdef PHAR_MAIN
static int phar_open_from_fp(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
extern php_stream_wrapper php_stream_phar_wrapper;
+#else
+extern HashTable cached_phars;
+extern HashTable cached_alias;
#endif
int phar_archive_delref(phar_archive_data *phar TSRMLS_DC);
diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c
index 0c76b876d9..2f5b1635db 100755
--- a/ext/phar/phar_object.c
+++ b/ext/phar/phar_object.c
@@ -161,7 +161,7 @@ static void phar_mung_server_vars(char *fname, char *entry, int entry_len, char
}
/* }}} */
-static int phar_file_action(phar_entry_data *phar, char *mime_type, int code, char *entry, int entry_len, char *arch, int arch_len, char *basename, int basename_len, char *ru, int ru_len TSRMLS_DC) /* {{{ */
+static int phar_file_action(phar_entry_data *idata, char *mime_type, int code, char *entry, int entry_len, char *arch, int arch_len, char *basename, int basename_len, char *ru, int ru_len TSRMLS_DC) /* {{{ */
{
char *name = NULL, buf[8192], *cwd;
zend_syntax_highlighter_ini syntax_highlighter_ini;
@@ -185,7 +185,7 @@ static int phar_file_action(phar_entry_data *phar, char *mime_type, int code, ch
highlight_file(name, &syntax_highlighter_ini TSRMLS_CC);
- phar_entry_delref(phar TSRMLS_CC);
+ phar_entry_delref(idata TSRMLS_CC);
efree(name);
#ifdef PHP_WIN32
efree(arch);
@@ -197,45 +197,45 @@ static int phar_file_action(phar_entry_data *phar, char *mime_type, int code, ch
ctr.line_len = spprintf(&(ctr.line), 0, "Content-type: %s", mime_type);
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
efree(ctr.line);
- ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %d", phar->internal_file->uncompressed_filesize);
+ ctr.line_len = spprintf(&(ctr.line), 0, "Content-length: %d", idata->internal_file->uncompressed_filesize);
sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
efree(ctr.line);
if (FAILURE == sapi_send_headers(TSRMLS_C)) {
- phar_entry_delref(phar TSRMLS_CC);
+ phar_entry_delref(idata TSRMLS_CC);
zend_bailout();
}
/* prepare to output */
- if (!phar_get_efp(phar->internal_file, 1 TSRMLS_CC)) {
+ if (!phar_get_efp(idata->internal_file, 1 TSRMLS_CC)) {
char *error;
- if (!phar_open_jit(phar->phar, phar->internal_file, phar->phar->fp, &error, 0 TSRMLS_CC)) {
+ if (!phar_open_jit(idata->phar, idata->internal_file, phar_get_pharfp(idata->phar TSRMLS_CC), &error, 0 TSRMLS_CC)) {
if (error) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error);
efree(error);
}
return -1;
}
- phar->fp = phar_get_efp(phar->internal_file, 1 TSRMLS_CC);
- phar->zero = phar->internal_file->offset;
+ idata->fp = phar_get_efp(idata->internal_file, 1 TSRMLS_CC);
+ idata->zero = phar_get_fp_offset(idata->internal_file TSRMLS_CC);
}
- phar_seek_efp(phar->internal_file, 0, SEEK_SET, 0, 1 TSRMLS_CC);
+ phar_seek_efp(idata->internal_file, 0, SEEK_SET, 0, 1 TSRMLS_CC);
do {
- got = php_stream_read(phar->fp, buf, MIN(8192, phar->internal_file->uncompressed_filesize - phar->position));
+ got = php_stream_read(idata->fp, buf, MIN(8192, idata->internal_file->uncompressed_filesize - idata->position));
PHPWRITE(buf, got);
- phar->position = php_stream_tell(phar->fp) - phar->zero;
- if (phar->position == (off_t) phar->internal_file->uncompressed_filesize) {
+ idata->position = php_stream_tell(idata->fp) - idata->zero;
+ if (idata->position == (off_t) idata->internal_file->uncompressed_filesize) {
break;
}
} while (1);
- phar_entry_delref(phar TSRMLS_CC);
+ phar_entry_delref(idata TSRMLS_CC);
zend_bailout();
case PHAR_MIME_PHP:
if (basename) {
phar_mung_server_vars(arch, entry, entry_len, basename, basename_len, ru, ru_len TSRMLS_CC);
efree(basename);
}
- phar_entry_delref(phar TSRMLS_CC);
+ phar_entry_delref(idata TSRMLS_CC);
if (entry[0] == '/') {
name_len = spprintf(&name, 4096, "phar://%s%s", arch, entry);
} else {
@@ -356,10 +356,13 @@ static void phar_postprocess_ru_web(char *fname, int fname_len, char **entry, in
{
char *e = *entry + 1, *u = NULL, *u1 = NULL, *saveu = NULL;
int e_len = *entry_len - 1, u_len = 0;
- phar_archive_data **pphar;
+ phar_archive_data **pphar = NULL;
/* we already know we can retrieve the phar if we reach here */
zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void **) &pphar);
+ if (!pphar && PHAR_G(manifest_cached)) {
+ zend_hash_find(&cached_phars, fname, fname_len, (void **) &pphar);
+ }
do {
if (zend_hash_exists(&((*pphar)->manifest), e, e_len)) {
@@ -1082,7 +1085,10 @@ PHP_METHOD(Phar, isValidPharFilename)
*/
static void phar_spl_foreign_dtor(spl_filesystem_object *object TSRMLS_DC) /* {{{ */
{
- phar_archive_delref((phar_archive_data *) object->oth TSRMLS_CC);
+ phar_archive_data *phar = (phar_archive_data *) object->oth;
+ if (!phar->is_persistent) {
+ phar_archive_delref(phar TSRMLS_CC);
+ }
object->oth = NULL;
}
/* }}} */
@@ -1094,7 +1100,9 @@ static void phar_spl_foreign_clone(spl_filesystem_object *src, spl_filesystem_ob
{
phar_archive_data *phar_data = (phar_archive_data *) dst->oth;
- ++(phar_data->refcount);
+ if (!phar_data->is_persistent) {
+ ++(phar_data->refcount);
+ }
}
/* }}} */
@@ -1199,7 +1207,9 @@ PHP_METHOD(Phar, __construct)
return;
}
is_data = phar_data->is_data;
- ++(phar_data->refcount);
+ if (!phar_data->is_persistent) {
+ ++(phar_data->refcount);
+ }
phar_obj->arc.archive = phar_data;
phar_obj->spl.oth_handler = &phar_spl_foreign_handler;
@@ -1223,7 +1233,9 @@ PHP_METHOD(Phar, __construct)
&spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1);
}
- phar_obj->arc.archive->is_data = is_data;
+ if (!phar_data->is_persistent) {
+ phar_obj->arc.archive->is_data = is_data;
+ }
phar_obj->spl.info_class = phar_ce_entry;
efree(fname);
@@ -1313,6 +1325,10 @@ PHP_METHOD(Phar, unlinkArchive)
efree(entry);
}
+ if (phar->is_persistent) {
+ zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" is in phar.cache_list, cannot unlinkArchive()", fname);
+ return;
+ }
if (phar->refcount) {
zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, "phar archive \"%s\" has open file handles or objects. fclose() all file handles, and unset() all objects prior to calling unlinkArchive()", fname);
return;
@@ -1930,6 +1946,11 @@ static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool c
efree(basepath);
efree(newname);
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_find(&cached_phars, newpath, phar->fname_len, (void **) &pphar)) {
+ efree(oldpath);
+ zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "Unable to add newly converted phar \"%s\" to the list of phars, new phar name is in phar.cache_list", phar->fname);
+ return NULL;
+ }
if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), newpath, phar->fname_len, (void **) &pphar)) {
if ((*pphar)->fname_len == phar->fname_len && !memcmp((*pphar)->fname, phar->fname, phar->fname_len)) {
if (!zend_hash_num_elements(&phar->manifest)) {
diff --git a/ext/phar/stream.c b/ext/phar/stream.c
index 4854aeb907..262c3f207b 100644
--- a/ext/phar/stream.c
+++ b/ext/phar/stream.c
@@ -101,7 +101,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode,
}
#endif
if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) {
- phar_archive_data **pphar = NULL;
+ phar_archive_data **pphar = NULL, *phar;
if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
pphar = NULL;
@@ -113,7 +113,7 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode,
php_url_free(resource);
return NULL;
}
- if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, 0, options, NULL, &error TSRMLS_CC) == FAILURE)
+ if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, 0, options, &phar, &error TSRMLS_CC) == FAILURE)
{
if (error) {
if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
@@ -124,6 +124,17 @@ php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode,
php_url_free(resource);
return NULL;
}
+ if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
+ if (error) {
+ spprintf(&error, 0, "Cannot open cached phar '%s' as writeable, copy on write failed", resource->host);
+ if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
+ }
+ efree(error);
+ }
+ php_url_free(resource);
+ return NULL;
+ }
} else {
if (phar_open_from_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE)
{
@@ -489,10 +500,7 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) /* {{{ */
{
php_url *resource = NULL;
- phar_zstr key;
- char *internal_file, *error, *str_key;
- uint keylen;
- ulong unused;
+ char *internal_file, *error;
phar_archive_data *phar;
phar_entry_info *entry;
uint host_len;
@@ -544,72 +552,56 @@ static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC);
php_url_free(resource);
return SUCCESS;
- } else {
- /* search for directory (partial match of a file) */
- zend_hash_internal_pointer_reset(&phar->manifest);
- while (FAILURE != zend_hash_has_more_elements(&phar->manifest)) {
- if (HASH_KEY_NON_EXISTANT !=
- zend_hash_get_current_key_ex(
- &phar->manifest, &key, &keylen, &unused, 0, NULL)) {
- PHAR_STR(key, str_key);
- if (keylen >= (uint)internal_file_len && 0 == memcmp(internal_file, str_key, internal_file_len)) {
- /* directory found, all dirs have the same stat */
- if (str_key[internal_file_len] == '/') {
- phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC);
- php_url_free(resource);
- return SUCCESS;
- }
- }
- }
- if (SUCCESS != zend_hash_move_forward(&phar->manifest)) {
+ }
+ if (SUCCESS == zend_hash_find(&(phar->virtual_dirs), internal_file, internal_file_len, (void **) &entry)) {
+ phar_dostat(phar, NULL, ssb, 1, phar->alias, phar->alias_len TSRMLS_CC);
+ php_url_free(resource);
+ return SUCCESS;
+ }
+ /* check for mounted directories */
+ if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
+ phar_zstr key;
+ char *str_key;
+ ulong unused;
+ uint keylen;
+
+ zend_hash_internal_pointer_reset(&phar->mounted_dirs);
+ while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
+ if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
break;
}
- }
- /* check for mounted directories */
- if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
- phar_zstr key;
- char *str_key;
- ulong unused;
- uint keylen;
-
- zend_hash_internal_pointer_reset(&phar->mounted_dirs);
- while (FAILURE != zend_hash_has_more_elements(&phar->mounted_dirs)) {
- if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, NULL)) {
- break;
+ PHAR_STR(key, str_key);
+ if ((int)keylen >= internal_file_len || strncmp(str_key, internal_file, keylen)) {
+ continue;
+ } else {
+ char *test;
+ int test_len;
+ phar_entry_info *entry;
+ php_stream_statbuf ssbi;
+
+ if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
+ goto free_resource;
+ }
+ if (!entry->tmp || !entry->is_mounted) {
+ goto free_resource;
}
- PHAR_STR(key, str_key);
- if ((int)keylen >= internal_file_len || strncmp(str_key, internal_file, keylen)) {
+ test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen);
+ if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
+ efree(test);
continue;
- } else {
- char *test;
- int test_len;
- phar_entry_info *entry;
- php_stream_statbuf ssbi;
-
- if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
- goto free_resource;
- }
- if (!entry->tmp || !entry->is_mounted) {
- goto free_resource;
- }
- test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen);
- if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
- efree(test);
- continue;
- }
- /* mount the file/directory just in time */
- if (SUCCESS != phar_mount_entry(phar, test, test_len, internal_file, internal_file_len TSRMLS_CC)) {
- efree(test);
- goto free_resource;
- }
+ }
+ /* mount the file/directory just in time */
+ if (SUCCESS != phar_mount_entry(phar, test, test_len, internal_file, internal_file_len TSRMLS_CC)) {
efree(test);
- if (SUCCESS != zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
- goto free_resource;
- }
- phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC);
- php_url_free(resource);
- return SUCCESS;
+ goto free_resource;
+ }
+ efree(test);
+ if (SUCCESS != zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
+ goto free_resource;
}
+ phar_dostat(phar, entry, ssb, 0, phar->alias, phar->alias_len TSRMLS_CC);
+ php_url_free(resource);
+ return SUCCESS;
}
}
}
@@ -777,7 +769,6 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
}
host_len = strlen(resource_from->host);
- phar_request_initialize(TSRMLS_C);
if (SUCCESS != phar_get_archive(&phar, resource_from->host, strlen(resource_from->host), NULL, 0, &error TSRMLS_CC)) {
php_url_free(resource_from);
@@ -787,6 +778,13 @@ static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char
return 0;
}
+ if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
+ php_url_free(resource_from);
+ php_url_free(resource_to);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": could not make cached phar writeable", url_from, url_to);
+ return 0;
+ }
+
if (SUCCESS == zend_hash_find(&(phar->manifest), resource_from->path+1, strlen(resource_from->path)-1, (void **)&entry)) {
phar_entry_info new, *source;
diff --git a/ext/phar/tar.c b/ext/phar/tar.c
index 92ecde46af..4537f024b4 100644
--- a/ext/phar/tar.c
+++ b/ext/phar/tar.c
@@ -416,6 +416,7 @@ bail:
}
phar_set_inode(&entry TSRMLS_CC);
zend_hash_add(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), (void **) &newentry);
+ if (entry.is_persistent) ++entry.manifest_pos;
if (entry.filename_len >= sizeof(".phar/.metadata")-1 && !memcmp(entry.filename, ".phar/.metadata", sizeof(".phar/.metadata")-1)) {
if (FAILURE == phar_tar_process_metadata(newentry, fp TSRMLS_CC)) {
if (error) {
@@ -548,6 +549,7 @@ bail:
phar_unixify_path_separators(myphar->fname, fname_len);
#endif
myphar->fname_len = fname_len;
+ myphar->fp = fp;
p = strrchr(myphar->fname, '/');
if (zend_hash_exists(&(myphar->manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
@@ -564,7 +566,6 @@ bail:
myphar->ext_len = (myphar->fname + fname_len) - myphar->ext;
}
}
- 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)) {
if (error) {
@@ -608,7 +609,7 @@ bail:
return FAILURE;
}
}
- zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), actual_alias, myphar->alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
+ zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&myphar, sizeof(phar_archive_data*), NULL);
myphar->alias = pestrndup(alias, alias_len, myphar->is_persistent);
myphar->alias_len = alias_len;
} else {
@@ -851,6 +852,12 @@ int phar_tar_flush(phar_archive_data *phar, char *user_stub, long len, int defau
entry.phar = phar;
entry.fp_type = PHAR_MOD;
+ if (phar->is_persistent) {
+ if (error) {
+ spprintf(error, 0, "internal error: attempt to flush cached tar-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
if (phar->is_data) {
goto nostub;
}
diff --git a/ext/phar/tests/cached_manifest_1.phpt b/ext/phar/tests/cached_manifest_1.phpt
new file mode 100644
index 0000000000..54ab6f0065
--- /dev/null
+++ b/ext/phar/tests/cached_manifest_1.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Phar: phar.cache_list basic read test
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--INI--
+phar.cache_list={PWD}/files/nophar.phar
+--FILE--
+<?php
+$pname = 'phar://' . dirname(__FILE__) . '/files/nophar.phar';
+var_dump(file_get_contents($pname . '/b/c.php'));
+$a = opendir($pname);
+while (false !== ($b = readdir($a))) {
+var_dump($b);
+}
+foreach (new RecursiveIteratorIterator(new Phar($pname)) as $f) {
+ var_dump($f->getPathName());
+}
+var_dump(is_dir($pname . '/b'));
+var_dump(is_dir($pname . '/d'));
+var_dump(is_dir($pname . '/b/c.php'));
+?>
+===DONE===
+--EXPECTF--
+string(131) "<?php echo "in b\n";$a = fopen("index.php", "r", true);echo stream_get_contents($a);fclose($a);include dirname(__FILE__) . "/../d";"
+string(1) "b"
+string(1) "d"
+string(9) "index.php"
+string(7) "web.php"
+string(%d) "phar://%snophar.phar%cb%cc.php"
+string(%d) "phar://%snophar.phar%cd"
+string(%d) "phar://%snophar.phar%cindex.php"
+string(%d) "phar://%snophar.phar%cweb.php"
+bool(true)
+bool(false)
+bool(false)
+===DONE===
diff --git a/ext/phar/util.c b/ext/phar/util.c
index cf789de898..de1eb34719 100644
--- a/ext/phar/util.c
+++ b/ext/phar/util.c
@@ -95,14 +95,14 @@ php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC)
return phar_get_efp(link_entry, 1 TSRMLS_CC);
}
}
- if (entry->fp_type == PHAR_FP) {
- if (!entry->phar->fp) {
+ if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_FP) {
+ if (!phar_get_entrypfp(entry TSRMLS_CC)) {
/* re-open just in time for cases where our refcount reached 0 on the phar archive */
phar_open_archive_fp(entry->phar TSRMLS_CC);
}
- return entry->phar->fp;
- } else if (entry->fp_type == PHAR_UFP) {
- return entry->phar->ufp;
+ return phar_get_entrypfp(entry TSRMLS_CC);
+ } else if (phar_get_fp_type(entry TSRMLS_CC) == PHAR_UFP) {
+ return phar_get_entrypufp(entry TSRMLS_CC);
} else if (entry->fp_type == PHAR_MOD) {
return entry->fp;
} else {
@@ -117,7 +117,7 @@ php_stream *phar_get_efp(phar_entry_info *entry, int follow_links TSRMLS_DC)
int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t position, int follow_links TSRMLS_DC)
{
php_stream *fp = phar_get_efp(entry, follow_links TSRMLS_CC);
- off_t temp;
+ off_t temp, eoffset;
if (!fp) {
return -1;
@@ -132,21 +132,22 @@ int phar_seek_efp(phar_entry_info *entry, off_t offset, int whence, off_t positi
if (entry->is_dir) {
return 0;
}
+ eoffset = phar_get_fp_offset(entry TSRMLS_CC);
switch (whence) {
case SEEK_END :
- temp = entry->offset + entry->uncompressed_filesize + offset;
+ temp = eoffset + entry->uncompressed_filesize + offset;
break;
case SEEK_CUR :
- temp = entry->offset + position + offset;
+ temp = eoffset + position + offset;
break;
case SEEK_SET :
- temp = entry->offset + offset;
+ temp = eoffset + offset;
break;
}
- if (temp > entry->offset + (off_t) entry->uncompressed_filesize) {
+ if (temp > eoffset + (off_t) entry->uncompressed_filesize) {
return -1;
}
- if (temp < entry->offset) {
+ if (temp < eoffset) {
return -1;
}
return php_stream_seek(fp, temp, SEEK_SET);
@@ -254,7 +255,8 @@ char *phar_find_in_include_path(char *filename, int filename_len, phar_archive_d
if (*filename == '.') {
int try_len;
- if (SUCCESS != (zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar))) {
+ if (SUCCESS != zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **) &pphar) &&
+ PHAR_G(manifest_cached) && SUCCESS != zend_hash_find(&cached_phars, arch, arch_len, (void **) &pphar)) {
efree(arch);
return phar_save_resolve_path(filename, filename_len TSRMLS_CC);
}
@@ -537,6 +539,7 @@ int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char
}
return FAILURE;
}
+really_get_entry:
if (allow_dir) {
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) {
if (for_create && (!PHAR_G(readonly) || phar->is_data)) {
@@ -552,6 +555,16 @@ int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char
return FAILURE;
}
}
+ if (for_write && phar->is_persistent) {
+ if (FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for writing, could not make cached phar writeable", path, fname);
+ }
+ return FAILURE;
+ } else {
+ goto really_get_entry;
+ }
+ }
if (entry->is_modified && !for_write) {
if (error) {
spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be opened for reading, writable file pointers are open", path, fname);
@@ -579,8 +592,10 @@ int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char
(*ret)->internal_file = entry;
(*ret)->is_zip = entry->is_zip;
(*ret)->is_tar = entry->is_tar;
- ++(entry->phar->refcount);
- ++(entry->fp_refcount);
+ if (!phar->is_persistent) {
+ ++(entry->phar->refcount);
+ ++(entry->fp_refcount);
+ }
return SUCCESS;
}
if (entry->fp_type == PHAR_MOD) {
@@ -621,9 +636,11 @@ int phar_get_entry_data(phar_entry_data **ret, char *fname, int fname_len, char
(*ret)->is_zip = entry->is_zip;
(*ret)->is_tar = entry->is_tar;
(*ret)->fp = phar_get_efp(entry, 1 TSRMLS_CC);
- (*ret)->zero = entry->offset;
- ++(entry->fp_refcount);
- ++(entry->phar->refcount);
+ (*ret)->zero = phar_get_fp_offset(entry TSRMLS_CC);
+ if (!phar->is_persistent) {
+ ++(entry->fp_refcount);
+ ++(entry->phar->refcount);
+ }
return SUCCESS;
}
/* }}} */
@@ -662,6 +679,13 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char
return NULL;
}
+ if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
+ if (error) {
+ spprintf(error, 4096, "phar error: file \"%s\" in phar \"%s\" cannot be created, could not make cached phar writeable", path, fname);
+ }
+ return NULL;
+ }
+
/* create a new phar data holder */
ret = (phar_entry_data *) emalloc(sizeof(phar_entry_data));
@@ -732,7 +756,7 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char
/* initialize a phar_archive_data's read-only fp for existing phar data */
int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC)
{
- if (phar->fp) {
+ if (phar_get_pharfp(phar TSRMLS_CC)) {
return SUCCESS;
}
@@ -746,8 +770,8 @@ int phar_open_archive_fp(phar_archive_data *phar TSRMLS_DC)
return FAILURE;
}
- phar->fp = php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL);
- if (!phar->fp) {
+ phar_set_pharfp(phar, php_stream_open_wrapper(phar->fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL) TSRMLS_CC);
+ if (!phar_get_pharfp(phar TSRMLS_CC)) {
return FAILURE;
}
return SUCCESS;
@@ -795,6 +819,7 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
phar_archive_data *phar = entry->phar;
char *filtername;
off_t loc;
+ php_stream *ufp;
if (follow_links && entry->link) {
phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
@@ -813,7 +838,7 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
/* either newly created or already modified */
return SUCCESS;
}
- if (!phar->fp) {
+ if (!phar_get_pharfp(phar TSRMLS_CC)) {
if (FAILURE == phar_open_archive_fp(phar TSRMLS_CC)) {
spprintf(error, 4096, "phar error: Cannot open phar archive \"%s\" for reading", phar->fname);
return FAILURE;
@@ -822,16 +847,17 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
return SUCCESS;
}
- if (!phar->ufp) {
- phar->ufp = php_stream_fopen_tmpfile();
- if (!phar->ufp) {
+ if (!phar_get_entrypufp(entry TSRMLS_CC)) {
+ phar_set_entrypufp(entry, php_stream_fopen_tmpfile() TSRMLS_CC);
+ if (!phar_get_entrypufp(entry TSRMLS_CC)) {
spprintf(error, 4096, "phar error: Cannot open temporary file for decompressing phar archive \"%s\" file \"%s\"", phar->fname, entry->filename);
return FAILURE;
}
}
+ ufp = phar_get_entrypufp(entry TSRMLS_CC);
if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
- filter = php_stream_filter_create(filtername, NULL, php_stream_is_persistent(phar->ufp) TSRMLS_CC);
+ filter = php_stream_filter_create(filtername, NULL, 0 TSRMLS_CC);
} else {
filter = NULL;
}
@@ -841,27 +867,26 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
}
/* now we can safely use proper decompression */
/* save the new offset location within ufp */
- php_stream_seek(phar->ufp, 0, SEEK_END);
- loc = php_stream_tell(phar->ufp);
- php_stream_filter_append(&phar->ufp->writefilters, filter);
- php_stream_seek(phar->fp, entry->offset, SEEK_SET);
- if (php_stream_copy_to_stream(phar->fp, phar->ufp, entry->compressed_filesize) != entry->compressed_filesize) {
+ php_stream_seek(ufp, 0, SEEK_END);
+ loc = php_stream_tell(ufp);
+ php_stream_filter_append(&ufp->writefilters, filter);
+ php_stream_seek(phar_get_entrypfp(entry TSRMLS_CC), phar_get_fp_offset(entry TSRMLS_CC), SEEK_SET);
+ if (php_stream_copy_to_stream(phar_get_entrypfp(entry TSRMLS_CC), ufp, entry->compressed_filesize) != entry->compressed_filesize) {
spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
return FAILURE;
}
php_stream_filter_flush(filter, 1);
- php_stream_flush(phar->ufp);
+ php_stream_flush(ufp);
php_stream_filter_remove(filter, 1 TSRMLS_CC);
- if (php_stream_tell(phar->ufp) - loc != (off_t) entry->uncompressed_filesize) {
+ if (php_stream_tell(ufp) - loc != (off_t) entry->uncompressed_filesize) {
spprintf(error, 4096, "phar error: internal corruption of phar \"%s\" (actual filesize mismatch on file \"%s\")", phar->fname, entry->filename);
return FAILURE;
}
entry->old_flags = entry->flags;
- entry->fp_type = PHAR_UFP;
/* this is now the new location of the file contents within this fp */
- entry->offset = loc;
+ phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
return SUCCESS;
}
@@ -1010,7 +1035,7 @@ phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry,
int phar_free_alias(phar_archive_data *phar, char *alias, int alias_len TSRMLS_DC) /* {{{ */
{
- if (phar->refcount) {
+ if (phar->refcount || phar->is_persistent) {
return FAILURE;
}
/* this archive has no open references, so emit an E_STRICT and remove it */
@@ -1030,6 +1055,7 @@ int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, ch
phar_archive_data *fd, **fd_ptr;
char *my_realpath, *save;
int save_len;
+ ulong fhash, ahash;
phar_request_initialize(TSRMLS_C);
@@ -1038,7 +1064,9 @@ int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, ch
}
*archive = NULL;
if (alias && alias_len) {
- if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void**)&fd_ptr)) {
+ ahash = zend_inline_hash_func(alias, alias_len);
+ if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void**)&fd_ptr)) {
+alias_success:
if (fname && (fname_len != (*fd_ptr)->fname_len || strncmp(fname, (*fd_ptr)->fname, fname_len))) {
if (error) {
spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
@@ -1052,12 +1080,16 @@ int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, ch
*archive = *fd_ptr;
return SUCCESS;
}
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, alias, alias_len, ahash, (void **)&fd_ptr)) {
+ goto alias_success;
+ }
}
+ fhash = zend_inline_hash_func(fname, fname_len);
my_realpath = NULL;
save = fname;
save_len = fname_len;
if (fname && fname_len) {
- if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void**)&fd_ptr)) {
+ if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
*archive = *fd_ptr;
fd = *fd_ptr;
if (alias && alias_len) {
@@ -1070,11 +1102,30 @@ int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, ch
if (fd->alias_len && SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len, (void**)&fd_ptr)) {
zend_hash_del(&(PHAR_GLOBALS->phar_alias_map), fd->alias, fd->alias_len);
}
- zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&fd, sizeof(phar_archive_data*), NULL);
+ zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
+ }
+ return SUCCESS;
+ }
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
+ *archive = *fd_ptr;
+ fd = *fd_ptr;
+ /* this could be problematic - alias should never be different from manifest alias
+ for cached phars */
+ if (!fd->is_temporary_alias && alias && alias_len) {
+ if (alias_len != fd->alias_len || memcmp(fd->alias, alias, alias_len)) {
+ if (error) {
+ spprintf(error, 0, "alias \"%s\" is already used for archive \"%s\" cannot be overloaded with \"%s\"", alias, (*fd_ptr)->fname, fname);
+ }
+ return FAILURE;
+ }
}
return SUCCESS;
}
- if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, (void**)&fd_ptr)) {
+ if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_alias_map), save, save_len, fhash, (void**)&fd_ptr)) {
+ *archive = *fd_ptr;
+ return SUCCESS;
+ }
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_alias, save, save_len, fhash, (void**)&fd_ptr)) {
*archive = *fd_ptr;
return SUCCESS;
}
@@ -1090,15 +1141,20 @@ int phar_get_archive(phar_archive_data **archive, char *fname, int fname_len, ch
#ifdef PHP_WIN32
phar_unixify_path_separators(fname, fname_len);
#endif
- if (SUCCESS == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, (void**)&fd_ptr)) {
+ fhash = zend_inline_hash_func(fname, fname_len);
+ if (SUCCESS == zend_hash_quick_find(&(PHAR_GLOBALS->phar_fname_map), fname, fname_len, fhash, (void**)&fd_ptr)) {
+realpath_success:
*archive = *fd_ptr;
fd = *fd_ptr;
if (alias && alias_len) {
- zend_hash_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, (void*)&fd, sizeof(phar_archive_data*), NULL);
+ zend_hash_quick_add(&(PHAR_GLOBALS->phar_alias_map), alias, alias_len, ahash, (void*)&fd, sizeof(phar_archive_data*), NULL);
}
efree(my_realpath);
return SUCCESS;
}
+ if (PHAR_G(manifest_cached) && SUCCESS == zend_hash_quick_find(&cached_phars, fname, fname_len, fhash, (void**)&fd_ptr)) {
+ goto realpath_success;
+ }
efree(my_realpath);
}
return FAILURE;
@@ -1827,12 +1883,12 @@ int phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signat
*/
static int phar_add_empty(HashTable *ht, char *arKey, uint nKeyLength) /* {{{ */
{
- void *dummy = (void *) 1;
+ void *dummy = (char *) 1;
if (SUCCESS == zend_hash_find(ht, arKey, nKeyLength, (void **)&dummy)) {
dummy++;
}
- return zend_hash_update(ht, arKey, nKeyLength, &dummy, sizeof(void *), NULL);
+ return zend_hash_update(ht, arKey, nKeyLength, (char *) &dummy, sizeof(void *), NULL);
}
/* }}} */
@@ -1870,3 +1926,110 @@ void phar_delete_virtual_dirs(phar_archive_data *phar, char *filename, int filen
}
}
/* }}} */
+
+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);
+ entry->is_persistent = 0;
+ 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(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data *phar;
+ HashTable newmanifest;
+ char *fname;
+
+ 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);
+ zend_hash_init(&phar->virtual_dirs, sizeof(char *),
+ zend_get_hash_value, NULL, 0);
+ zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
+ *pphar = phar;
+}
+/* }}} */
+
+int phar_copy_on_write(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
+{
+ phar_archive_data **newpphar, *newphar = NULL;
+
+ if (SUCCESS != zend_hash_add(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len, (void *)&newphar, sizeof(phar_archive_data *), (void **)&newpphar)) {
+ return FAILURE;
+ }
+
+ *newpphar = *pphar;
+ phar_copy_cached_phar(newpphar TSRMLS_CC);
+ 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)) {
+ zend_hash_del(&(PHAR_GLOBALS->phar_fname_map), (*pphar)->fname, (*pphar)->fname_len);
+ return FAILURE;
+ }
+ *pphar = *newpphar;
+ return SUCCESS;
+}
+/* }}} */
diff --git a/ext/phar/zip.c b/ext/phar/zip.c
index 3932c7c9af..a32576231f 100644
--- a/ext/phar/zip.c
+++ b/ext/phar/zip.c
@@ -297,6 +297,7 @@ foundit:
/* corrupted entry */
PHAR_ZIP_FAIL("corrupted central directory entry, no magic signature");
}
+ if (entry.is_persistent) entry.manifest_pos = i;
entry.compressed_filesize = PHAR_GET_32(zipentry.compsize);
entry.uncompressed_filesize = PHAR_GET_32(zipentry.uncompsize);
entry.crc32 = PHAR_GET_32(zipentry.crc32);
@@ -521,6 +522,7 @@ foundit:
}
mydata->is_temporary_alias = 1;
}
+
if (pphar) {
*pphar = mydata;
}
@@ -844,6 +846,12 @@ int phar_zip_flush(phar_archive_data *phar, char *user_stub, long len, int defau
entry.phar = phar;
entry.fp_type = PHAR_MOD;
+ if (phar->is_persistent) {
+ if (error) {
+ spprintf(error, 0, "internal error: attempt to flush cached zip-based phar \"%s\"", phar->fname);
+ }
+ return EOF;
+ }
if (phar->is_data) {
goto nostub;
}