diff options
author | Greg Beaver <cellog@php.net> | 2008-10-12 19:40:11 +0000 |
---|---|---|
committer | Greg Beaver <cellog@php.net> | 2008-10-12 19:40:11 +0000 |
commit | e16636f06932d8cd30857bae33a0086b6da0332d (patch) | |
tree | 52b84ba51b8614a20d37d07cfbd568fe7c92cdf1 /ext/phar | |
parent | eaf5d4c8b3312cc5c78539b8ad054e2c834e2e39 (diff) | |
download | php-git-e16636f06932d8cd30857bae33a0086b6da0332d.tar.gz |
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.c | 71 | ||||
-rw-r--r-- | ext/phar/phar.c | 12 | ||||
-rwxr-xr-x | ext/phar/phar_internal.h | 4 | ||||
-rwxr-xr-x | ext/phar/phar_object.c | 26 | ||||
-rw-r--r-- | ext/phar/tar.c | 1 | ||||
-rw-r--r-- | ext/phar/tests/cache_list/copyonwrite2.phar.phpt | 17 | ||||
-rw-r--r-- | ext/phar/tests/cache_list/copyonwrite3.phar.phpt | 16 | ||||
-rw-r--r-- | ext/phar/tests/cache_list/files/write2.phar | bin | 0 -> 425 bytes | |||
-rw-r--r-- | ext/phar/tests/cache_list/files/write2.phar.inc | 23 | ||||
-rw-r--r-- | ext/phar/tests/cache_list/files/write3.phar | bin | 0 -> 447 bytes | |||
-rw-r--r-- | ext/phar/tests/cache_list/files/write3.phar.inc | 21 | ||||
-rw-r--r-- | ext/phar/util.c | 16 | ||||
-rw-r--r-- | ext/phar/zip.c | 1 |
13 files changed, 160 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 Binary files differnew file mode 100644 index 0000000000..094102547a --- /dev/null +++ b/ext/phar/tests/cache_list/files/write2.phar diff --git a/ext/phar/tests/cache_list/files/write2.phar.inc b/ext/phar/tests/cache_list/files/write2.phar.inc new file mode 100644 index 0000000000..7a4e2e39f8 --- /dev/null +++ b/ext/phar/tests/cache_list/files/write2.phar.inc @@ -0,0 +1,23 @@ +<?php + +$fname = dirname(__FILE__) . '/write2.phar'; +@unlink($fname); + +$phar = new Phar($fname); +$phar->setStub('<?php +$phar = new Phar(__FILE__); +var_dump($phar->getMetadata()); +mkdir("phar://" . __FILE__ . "/test"); +var_dump(is_dir("phar://" . __FILE__ . "/test")); +$phar2 = new Phar(__FILE__); +var_dump($phar2->getMetadata()); +var_dump(isset($phar["test"])); +var_dump(isset($phar2["test"])); +echo "ok\n"; +__HALT_COMPILER(); +?>'); +$phar->setMetadata('hi'); +$phar['test.txt'] = "hi +"; +$phar['test.txt']->setMetadata('hi'); +?> diff --git a/ext/phar/tests/cache_list/files/write3.phar b/ext/phar/tests/cache_list/files/write3.phar Binary files differnew file mode 100644 index 0000000000..c5be7daceb --- /dev/null +++ b/ext/phar/tests/cache_list/files/write3.phar diff --git a/ext/phar/tests/cache_list/files/write3.phar.inc b/ext/phar/tests/cache_list/files/write3.phar.inc new file mode 100644 index 0000000000..686c065bde --- /dev/null +++ b/ext/phar/tests/cache_list/files/write3.phar.inc @@ -0,0 +1,21 @@ +<?php + +$fname = dirname(__FILE__) . '/write3.phar'; +@unlink($fname); + +$phar = new Phar($fname); +$phar->setStub('<?php +clearstatcache(); +var_dump(file_exists("phar://" . __FILE__ . "/test"), is_dir("phar://" . __FILE__ . "/test")); +rmdir("phar://" . __FILE__ . "/test"); +clearstatcache(); +var_dump(file_exists("phar://" . __FILE__ . "/test"), is_dir("phar://" . __FILE__ . "/test")); +echo "ok\n"; +__HALT_COMPILER(); +?>'); +$phar->setMetadata('hi'); +$phar['test.txt'] = "hi +"; +$phar['test.txt']->setMetadata('hi'); +$phar->addEmptyDir('test'); +?> 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(¢ral, 0, sizeof(central)); memset(&perms, 0, sizeof(perms)); |