summaryrefslogtreecommitdiff
path: root/ext/phar
diff options
context:
space:
mode:
authorGreg Beaver <cellog@php.net>2008-10-12 19:40:30 +0000
committerGreg Beaver <cellog@php.net>2008-10-12 19:40:30 +0000
commitc448cb165cb2e8b9e353a9af78f81fac54809972 (patch)
treeec1f2fef9ec0c1b72817054d56fbeab01d7492ac /ext/phar
parent4bd8bacde70b3a3c3bbcc1549bf05c23f704b128 (diff)
downloadphp-git-c448cb165cb2e8b9e353a9af78f81fac54809972.tar.gz
MFB: add tests for copy-on-write support
- fix metadata handling with cached phars - fix virtual_dirs with rmdir - ensure that after copy-on-write, all existing Phar objects link to the newly copied phar data
Diffstat (limited to 'ext/phar')
-rw-r--r--ext/phar/dirstream.c71
-rw-r--r--ext/phar/phar.c12
-rwxr-xr-xext/phar/phar_internal.h4
-rwxr-xr-xext/phar/phar_object.c26
-rw-r--r--ext/phar/tar.c1
-rw-r--r--ext/phar/tests/cache_list/copyonwrite2.phar.phpt17
-rw-r--r--ext/phar/tests/cache_list/copyonwrite3.phar.phpt16
-rw-r--r--ext/phar/tests/cache_list/files/write2.pharbin0 -> 425 bytes
-rw-r--r--ext/phar/tests/cache_list/files/write3.pharbin0 -> 447 bytes
-rw-r--r--ext/phar/util.c16
-rw-r--r--ext/phar/zip.c1
11 files changed, 116 insertions, 48 deletions
diff --git a/ext/phar/dirstream.c b/ext/phar/dirstream.c
index fa22f4681b..c0e4b18e09 100644
--- a/ext/phar/dirstream.c
+++ b/ext/phar/dirstream.c
@@ -507,12 +507,6 @@ int phar_wrapper_mkdir(php_stream_wrapper *wrapper, char *url_from, int mode, in
return 0;
}
- 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 0;
- }
-
memset((void *) &entry, 0, sizeof(phar_entry_info));
/* strip leading "/" */
@@ -631,50 +625,43 @@ int phar_wrapper_rmdir(php_stream_wrapper *wrapper, char *url, int options, php_
return 0;
}
- /* 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 0;
- }
-
- for (zend_hash_internal_pointer_reset(&phar->manifest);
+ if (!entry->is_deleted) {
+ for (zend_hash_internal_pointer_reset(&phar->manifest);
HASH_KEY_NON_EXISTANT != zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL);
zend_hash_move_forward(&phar->manifest)) {
- PHAR_STR(key, str_key);
+ PHAR_STR(key, str_key);
- if (!entry->is_deleted &&
- key_len > path_len &&
- memcmp(str_key, resource->path+1, path_len) == 0 &&
- IS_SLASH(str_key[path_len])) {
- php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
- if (entry->is_temp_dir) {
- efree(entry->filename);
- efree(entry);
+ if (key_len > path_len &&
+ memcmp(str_key, resource->path+1, path_len) == 0 &&
+ IS_SLASH(str_key[path_len])) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
+ if (entry->is_temp_dir) {
+ efree(entry->filename);
+ efree(entry);
+ }
+ php_url_free(resource);
+ return 0;
}
- php_url_free(resource);
- return 0;
}
- }
- for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
- HASH_KEY_NON_EXISTANT != zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL);
- zend_hash_move_forward(&phar->virtual_dirs)) {
-
- PHAR_STR(key, str_key);
-
- if (!entry->is_deleted &&
- key_len > path_len &&
- memcmp(str_key, resource->path+1, path_len) == 0 &&
- IS_SLASH(str_key[path_len])) {
- php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
- if (entry->is_temp_dir) {
- efree(entry->filename);
- efree(entry);
+ for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
+ HASH_KEY_NON_EXISTANT != zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL);
+ zend_hash_move_forward(&phar->virtual_dirs)) {
+
+ PHAR_STR(key, str_key);
+
+ if (key_len > path_len &&
+ memcmp(str_key, resource->path+1, path_len) == 0 &&
+ IS_SLASH(str_key[path_len])) {
+ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: Directory not empty");
+ if (entry->is_temp_dir) {
+ efree(entry->filename);
+ efree(entry);
+ }
+ php_url_free(resource);
+ return 0;
}
- php_url_free(resource);
- return 0;
}
}
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
index ec608a84d3..183fec4487 100644
--- a/ext/phar/phar.c
+++ b/ext/phar/phar.c
@@ -637,9 +637,7 @@ int phar_parse_metadata(char **buffer, zval **metadata, int zip_metadata_len TSR
zval_ptr_dtor(metadata);
*metadata = (zval *) pemalloc(buf_len, 1);
memcpy(*metadata, *buffer, buf_len);
- if (!zip_metadata_len) {
- *buffer += buf_len;
- }
+ *buffer += buf_len;
return SUCCESS;
}
} else {
@@ -1036,9 +1034,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
/* check whether we have meta data, zero check works regardless of byte order */
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\"");
}
@@ -2562,6 +2558,8 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
return EOF;
}
+ zend_hash_clean(&phar->virtual_dirs);
+
if (phar->is_zip) {
return phar_zip_flush(phar, user_stub, len, convert, error TSRMLS_CC);
}
@@ -2739,6 +2737,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
}
/* after excluding deleted files, calculate manifest size in bytes and number of entries */
++new_manifest_count;
+ phar_add_virtual_dirs(phar, entry->filename, entry->filename_len);
if (entry->is_dir) {
/* we use this to calculate API version, 1.1.1 is used for phars with directories */
@@ -3545,6 +3544,7 @@ void phar_request_initialize(TSRMLS_D) /* {{{ */
PHAR_GLOBALS->request_ends = 0;
PHAR_GLOBALS->request_done = 0;
zend_hash_init(&(PHAR_GLOBALS->phar_fname_map), 5, zend_get_hash_value, destroy_phar_data, 0);
+ zend_hash_init(&(PHAR_GLOBALS->phar_persist_map), 5, zend_get_hash_value, NULL, 0);
zend_hash_init(&(PHAR_GLOBALS->phar_alias_map), 5, zend_get_hash_value, NULL, 0);
if (PHAR_G(manifest_cached)) {
@@ -3581,6 +3581,8 @@ PHP_RSHUTDOWN_FUNCTION(phar) /* {{{ */
PHAR_GLOBALS->phar_alias_map.arBuckets = NULL;
zend_hash_destroy(&(PHAR_GLOBALS->phar_fname_map));
PHAR_GLOBALS->phar_fname_map.arBuckets = NULL;
+ zend_hash_destroy(&(PHAR_GLOBALS->phar_persist_map));
+ PHAR_GLOBALS->phar_persist_map.arBuckets = NULL;
PHAR_GLOBALS->phar_SERVER_mung_list = 0;
if (PHAR_GLOBALS->cached_fp) {
diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
index 7e0a59c43b..efe28671fa 100755
--- a/ext/phar/phar_internal.h
+++ b/ext/phar/phar_internal.h
@@ -150,6 +150,9 @@ typedef struct _phar_entry_fp phar_entry_fp;
typedef struct _phar_archive_data phar_archive_data;
ZEND_BEGIN_MODULE_GLOBALS(phar)
+ /* a list of phar_archive_data objects that reference a cached phar, so
+ that if copy-on-write is performed, we can swap them out for the new value */
+ HashTable phar_persist_map;
HashTable phar_fname_map;
/* for cached phars, this is a per-process store of fp/ufp */
phar_entry_fp *cached_fp;
@@ -593,6 +596,7 @@ char *phar_create_default_stub(const char *index_php, const char *web_index, siz
char *phar_decompress_filter(phar_entry_info * entry, int return_unknown);
char *phar_compress_filter(phar_entry_info * entry, int return_unknown);
+void phar_remove_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC);
void phar_add_virtual_dirs(phar_archive_data *phar, char *filename, int filename_len TSRMLS_DC);
int phar_mount_entry(phar_archive_data *phar, char *filename, int filename_len, char *path, int path_len TSRMLS_DC);
char *phar_find_in_include_path(char *file, int file_len, phar_archive_data **pphar TSRMLS_DC);
diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c
index 043f2b4280..c85f39d79e 100755
--- a/ext/phar/phar_object.c
+++ b/ext/phar/phar_object.c
@@ -1254,6 +1254,9 @@ PHP_METHOD(Phar, __construct)
if (!phar_data->is_persistent) {
phar_obj->arc.archive->is_data = is_data;
+ } else if (!EG(exception)) {
+ /* register this guy so we can modify if necessary */
+ zend_hash_add(&PHAR_GLOBALS->phar_persist_map, (const char *) phar_obj->arc.archive, sizeof(phar_obj->arc.archive), (void *) &phar_obj, sizeof(phar_archive_object **), NULL);
}
phar_obj->spl.info_class = phar_ce_entry;
@@ -1378,6 +1381,19 @@ PHP_METHOD(Phar, unlinkArchive)
return; \
}
+/* {{{ proto void Phar::__destruct()
+ * if persistent, remove from the cache
+ */
+PHP_METHOD(Phar, __destruct)
+{
+ phar_archive_object *phar_obj = (phar_archive_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (phar_obj->arc.archive && phar_obj->arc.archive->is_persistent) {
+ zend_hash_del(&PHAR_GLOBALS->phar_persist_map, (const char *) &(phar_obj->arc.archive), sizeof(&(phar_obj->arc.archive)));
+ }
+}
+/* }}} */
+
struct _phar_t {
phar_archive_object *p;
zend_class_entry *c;
@@ -3923,6 +3939,15 @@ PHP_METHOD(Phar, getMetadata)
PHAR_ARCHIVE_OBJECT();
if (phar_obj->arc.archive->metadata) {
+ if (phar_obj->arc.archive->is_persistent) {
+ zval *ret;
+ char *buf = estrndup((char *) phar_obj->arc.archive->metadata, phar_obj->arc.archive->metadata_len);
+ /* assume success, we would have failed before */
+ phar_parse_metadata(&buf, &ret, phar_obj->arc.archive->metadata_len TSRMLS_CC);
+ efree(buf);
+ RETURN_ZVAL(ret, 0, 1);
+ return;
+ }
RETURN_ZVAL(phar_obj->arc.archive->metadata, 1, 0);
}
}
@@ -5098,6 +5123,7 @@ zend_function_entry php_archive_methods[] = {
PHP_ME(Phar, __construct, arginfo_phar___construct, ZEND_ACC_PRIVATE)
#else
PHP_ME(Phar, __construct, arginfo_phar___construct, ZEND_ACC_PUBLIC)
+ PHP_ME(Phar, __destruct, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Phar, addEmptyDir, arginfo_phar_emptydir, ZEND_ACC_PUBLIC)
PHP_ME(Phar, addFile, arginfo_phar_addfile, ZEND_ACC_PUBLIC)
PHP_ME(Phar, addFromString, arginfo_phar_fromstring, ZEND_ACC_PUBLIC)
diff --git a/ext/phar/tar.c b/ext/phar/tar.c
index 01dca9364c..bcd75c325a 100644
--- a/ext/phar/tar.c
+++ b/ext/phar/tar.c
@@ -620,6 +620,7 @@ static int phar_tar_writeheaders(void *pDest, void *argument TSRMLS_DC) /* {{{ *
}
}
+ phar_add_virtual_dirs(entry->phar, entry->filename, entry->filename_len);
memset((char *) &header, 0, sizeof(header));
if (entry->filename_len > 100) {
diff --git a/ext/phar/tests/cache_list/copyonwrite2.phar.phpt b/ext/phar/tests/cache_list/copyonwrite2.phar.phpt
new file mode 100644
index 0000000000..8d21c813a4
--- /dev/null
+++ b/ext/phar/tests/cache_list/copyonwrite2.phar.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Phar: copy-on-write test 2 [cache_list]
+--INI--
+default_charset=UTF-8
+phar.cache_list={PWD}/copyonwrite2.phar.php
+phar.readonly=0
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE_EXTERNAL--
+files/write2.phar
+--EXPECT--
+string(2) "hi"
+bool(true)
+string(2) "hi"
+bool(true)
+bool(true)
+ok \ No newline at end of file
diff --git a/ext/phar/tests/cache_list/copyonwrite3.phar.phpt b/ext/phar/tests/cache_list/copyonwrite3.phar.phpt
new file mode 100644
index 0000000000..7e2c94c5b2
--- /dev/null
+++ b/ext/phar/tests/cache_list/copyonwrite3.phar.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Phar: copy-on-write test 3 [cache_list]
+--INI--
+default_charset=UTF-8
+phar.cache_list={PWD}/copyonwrite3.phar.php
+phar.readonly=0
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE_EXTERNAL--
+files/write3.phar
+--EXPECT--
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+ok \ No newline at end of file
diff --git a/ext/phar/tests/cache_list/files/write2.phar b/ext/phar/tests/cache_list/files/write2.phar
new file mode 100644
index 0000000000..094102547a
--- /dev/null
+++ b/ext/phar/tests/cache_list/files/write2.phar
Binary files differ
diff --git a/ext/phar/tests/cache_list/files/write3.phar b/ext/phar/tests/cache_list/files/write3.phar
new file mode 100644
index 0000000000..c5be7daceb
--- /dev/null
+++ b/ext/phar/tests/cache_list/files/write3.phar
Binary files differ
diff --git a/ext/phar/util.c b/ext/phar/util.c
index 224b7e778b..c6d734981c 100644
--- a/ext/phar/util.c
+++ b/ext/phar/util.c
@@ -2219,8 +2219,10 @@ static void phar_update_cached_entry(void *data, void *argument) /* {{{ */
if (entry->metadata) {
if (entry->metadata_len) {
+ char *buf = estrndup((char *) entry->metadata, entry->metadata_len);
/* assume success, we would have failed before */
phar_parse_metadata((char **) &entry->metadata, &entry->metadata, entry->metadata_len TSRMLS_CC);
+ efree(buf);
} else {
zval *t;
@@ -2245,6 +2247,7 @@ static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
phar_archive_data *phar;
HashTable newmanifest;
char *fname;
+ phar_archive_object **objphar;
phar = (phar_archive_data *) emalloc(sizeof(phar_archive_data));
*phar = **pphar;
@@ -2264,7 +2267,9 @@ static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
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);
+ char *buf = estrndup((char *) phar->metadata, phar->metadata_len);
+ phar_parse_metadata(&buf, &phar->metadata, phar->metadata_len TSRMLS_CC);
+ efree(buf);
} else {
zval *t;
@@ -2291,6 +2296,15 @@ static void phar_copy_cached_phar(phar_archive_data **pphar TSRMLS_DC) /* {{{ */
zend_get_hash_value, NULL, 0);
zend_hash_copy(&phar->virtual_dirs, &(*pphar)->virtual_dirs, NULL, NULL, sizeof(void *));
*pphar = phar;
+
+ /* now, scan the list of persistent Phar objects referencing this phar and update the pointers */
+ for (zend_hash_internal_pointer_reset(&PHAR_GLOBALS->phar_persist_map);
+ SUCCESS == zend_hash_get_current_data(&PHAR_GLOBALS->phar_persist_map, (void **) &objphar);
+ zend_hash_move_forward(&PHAR_GLOBALS->phar_persist_map)) {
+ if (objphar[0]->arc.archive->fname_len == phar->fname_len && !memcmp(objphar[0]->arc.archive->fname, phar->fname, phar->fname_len)) {
+ objphar[0]->arc.archive = phar;
+ }
+ }
}
/* }}} */
diff --git a/ext/phar/zip.c b/ext/phar/zip.c
index 027fcdb665..891280eb6e 100644
--- a/ext/phar/zip.c
+++ b/ext/phar/zip.c
@@ -704,6 +704,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
}
}
+ phar_add_virtual_dirs(entry->phar, entry->filename, entry->filename_len);
memset(&local, 0, sizeof(local));
memset(&central, 0, sizeof(central));
memset(&perms, 0, sizeof(perms));