From d1eda9c8acbd6a231012f22b124fda6d7242018c Mon Sep 17 00:00:00 2001 From: Greg Beaver Date: Wed, 16 Jan 2008 07:24:39 +0000 Subject: [PATCH] add Phar::convertToTar(), Phar::convertToZip(), and Phar::convertToPhar() --- ext/phar/package.php | 1 + ext/phar/phar.c | 3 +- ext/phar/phar_internal.h | 1 + ext/phar/phar_object.c | 540 ++++++++++++++++++++++ ext/phar/tests/phar_convert_tar.phpt | 42 ++ ext/phar/tests/phar_convert_zip.phpt | 42 ++ ext/phar/tests/tar/phar_convert_phar.phpt | 37 ++ ext/phar/tests/zip/phar_convert_phar.phpt | 37 ++ ext/phar/zip.c | 7 +- 9 files changed, 706 insertions(+), 4 deletions(-) create mode 100644 ext/phar/tests/phar_convert_tar.phpt create mode 100644 ext/phar/tests/phar_convert_zip.phpt create mode 100644 ext/phar/tests/tar/phar_convert_phar.phpt create mode 100644 ext/phar/tests/zip/phar_convert_phar.phpt diff --git a/ext/phar/package.php b/ext/phar/package.php index 82d807e36a..4368edbb31 100644 --- a/ext/phar/package.php +++ b/ext/phar/package.php @@ -4,6 +4,7 @@ $notes = ' Major feature functionality release * add support for tar-based and zip-based phar archives [Greg] * add Phar::isTar(), Phar::isZip(), and Phar::isPhar() [Greg] + * add Phar::convertToTar(), Phar::convertToZip(), and Phar::convertToPhar() [Greg] * add Phar::webPhar() for running a web-based application unmodified directly from a phar archive [Greg] * file functions (fopen-based and stat-based) can be instructed to only look for diff --git a/ext/phar/phar.c b/ext/phar/phar.c index df70fc284b..b497710469 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -791,7 +791,7 @@ phar_entry_data *phar_get_or_create_entry_data(char *fname, int fname_len, char } etemp.is_modified = 1; etemp.timestamp = time(0); - etemp.offset_within_phar = -1; + etemp.offset_within_phar = (phar->is_zip ? 0 : -1); etemp.is_crc_checked = 1; etemp.phar = phar; #if HAVE_PHAR_ZIP @@ -2168,7 +2168,6 @@ phar_entry_info * phar_open_jit(phar_archive_data *phar, phar_entry_info *entry, # if HAVE_BZ2 char *filter_name; php_stream_filter *filter; - php_stream *fp; /* we have to decompress this by hand */ if (!phar_has_bz2) { diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h index 95b3d80e22..4973b5ab2f 100755 --- a/ext/phar/phar_internal.h +++ b/ext/phar/phar_internal.h @@ -43,6 +43,7 @@ #include "main/streams/php_stream_plain_wrapper.h" #include "main/SAPI.h" #include "main/php_main.h" +#include "main/php_open_temporary_file.h" #include "ext/standard/info.h" #include "ext/standard/basic_functions.h" #include "ext/standard/file.h" diff --git a/ext/phar/phar_object.c b/ext/phar/phar_object.c index 7e9d614297..f84e41e637 100755 --- a/ext/phar/phar_object.c +++ b/ext/phar/phar_object.c @@ -1304,6 +1304,543 @@ PHP_METHOD(Phar, isPhar) } /* }}} */ +static int phar_copy_file_contents(phar_entry_info *entry, php_stream *fp TSRMLS_DC) /* {{{ */ +{ + /* if not available, open the file for reading */ + if (!entry->fp) { + char *error; + if (!phar_open_jit(entry->phar, entry, entry->phar->fp, &error, 0 TSRMLS_CC)) { + if (error) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents: %s", entry->phar->fname, entry->filename, error); + efree(error); + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", unable to open entry \"%s\" contents", entry->phar->fname, entry->filename); + } + return FAILURE; + } + } + /* copy old contents in entirety */ + php_stream_seek(entry->fp, entry->phar->internal_file_start + entry->offset_within_phar, SEEK_SET); + if (entry->uncompressed_filesize != php_stream_copy_to_stream(entry->fp, fp, entry->uncompressed_filesize)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", unable to copy entry \"%s\" contents", entry->phar->fname, entry->filename); + return FAILURE; + } + if (entry->fp != entry->phar->fp) { + php_stream_close(entry->fp); + entry->fp = NULL; + } + return SUCCESS; +} +/* }}} */ + +static void phar_convert_to_other(phar_archive_data *source, int convert TSRMLS_DC) /* {{{ */ +{ + phar_archive_data phar = {0}; + long offset = 0; + char *error, *opened_path = NULL; + int fd, ziperror; + + switch (convert) { + case 1 : + phar.is_tar = 1; + break; + case 2 : + phar.is_zip = 1; +#if HAVE_PHAR_ZIP + if (!((fd = php_open_temporary_fd(NULL, "pharzip", &opened_path TSRMLS_CC)) >= 0)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", unable to open temporary zip archive", source->fname); + return; + } + close(fd); + unlink(opened_path); + phar.zip = zip_open(opened_path, ZIP_CREATE, &ziperror); + if (!phar.zip) { + /* now for the stupid hoops libzip forces... */ + char *tmp; + int tmp_len; + + efree(opened_path); + tmp_len = zip_error_to_str(NULL, 0, ziperror, ziperror); + if (!(tmp = emalloc((tmp_len + 1) * sizeof(char)))) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", unable to open temporary zip archive", source->fname); + } else { + if (!zip_error_to_str(tmp, tmp_len + 1, ziperror, ziperror)) { + efree(tmp); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", unable to open temporary zip archive", source->fname); + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", unable to open temporary zip archive: %s", source->fname, tmp); + efree(tmp); + } + } + return; + } +#endif + break; + } + + zend_hash_init(&(phar.manifest), sizeof(phar_entry_info), + zend_get_hash_value, destroy_phar_manifest_entry, 0); + + phar.fp = php_stream_fopen_tmpfile(); + phar.fname = source->fname; + /* first copy each file's uncompressed contents to a temporary file and set per-file flags */ + for (zend_hash_internal_pointer_reset(&source->manifest); SUCCESS == zend_hash_has_more_elements(&source->manifest); zend_hash_move_forward(&source->manifest)) { + phar_entry_info *entry, newentry; + if (FAILURE == zend_hash_get_current_data(&source->manifest, (void **) &entry)) { + zend_hash_destroy(&(phar.manifest)); + php_stream_close(phar.fp); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\"", source->fname); + if (opened_path) { + efree(opened_path); + } +#if HAVE_PHAR_ZIP + if (phar.is_zip) { + _zip_free(phar.zip); + } +#endif + return; + } + if (entry->fp_refcount > 0) { + zend_hash_destroy(&(phar.manifest)); + php_stream_close(phar.fp); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\", open file pointers for entry \"%s\"", source->fname, entry->filename); +#if HAVE_PHAR_ZIP + if (phar.is_zip) { + _zip_free(phar.zip); + } +#endif + if (opened_path) { + efree(opened_path); + } + return; + } + newentry = *entry; + if (FAILURE == phar_copy_file_contents(entry, phar.fp TSRMLS_CC)) { + zend_hash_destroy(&(phar.manifest)); + php_stream_close(phar.fp); + /* exception already thrown */ +#if HAVE_PHAR_ZIP + if (phar.is_zip) { + _zip_free(phar.zip); + } +#endif + if (opened_path) { + efree(opened_path); + } + return; + } + newentry.filename = estrndup(newentry.filename, newentry.filename_len); + if (newentry.metadata) { + SEPARATE_ZVAL(&(newentry.metadata)); + } + newentry.offset_within_phar = offset; + offset += newentry.uncompressed_filesize; + newentry.is_zip = phar.is_zip; + newentry.is_tar = phar.is_tar; + if (newentry.is_tar) { + newentry.tar_type = (entry->is_dir ? TAR_DIR : TAR_FILE); + } + newentry.fp = phar.fp; +#if HAVE_PHAR_ZIP + newentry.index = -1; +#endif + newentry.is_modified = 1; + newentry.phar = &phar; + newentry.old_flags = newentry.flags & ~PHAR_ENT_COMPRESSION_MASK; /* remove compression from old_flags */ + zend_hash_add(&(phar.manifest), newentry.filename, newentry.filename_len, (void*)&newentry, sizeof(phar_entry_info), NULL); + } + + /* next copy the stub and flush */ + if (phar.is_zip) { + phar.fname = opened_path; + } + + if (source->is_zip) { + phar_entry_info *entry; + long tmp = 0; + zval *userz; + + if (FAILURE == (zend_hash_find(&source->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&entry))) { + /* use default stub - the existing one in the manifest will be used if present */ + phar_flush(&phar, NULL, 0, &error TSRMLS_CC); + goto finalize; + } + if (!entry->fp && !phar_open_jit(source, entry, NULL, &error, 0 TSRMLS_CC)) { + if (error) { + efree(error); + } + php_stream_close(phar.fp); + zend_hash_destroy(&(phar.manifest)); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\": unable to retrieve stub", source->fname, error); +#if HAVE_PHAR_ZIP + if (phar.is_zip) { + _zip_free(phar.zip); + } +#endif + if (opened_path) { + efree(opened_path); + } + return; + } + /* copy the other phar's stub */ + php_stream_seek(entry->fp, 0, SEEK_SET); + ALLOC_ZVAL(userz); + php_stream_to_zval(entry->fp, userz); + tmp = entry->uncompressed_filesize; + phar_flush(&phar, (char *) &userz, -tmp, &error TSRMLS_CC); + efree(userz); + php_stream_close(entry->fp); + if (error) { + zend_hash_destroy(&(phar.manifest)); + php_stream_close(phar.fp); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\": %s", source->fname, error); + efree(error); +#if HAVE_PHAR_ZIP + if (phar.is_zip) { + _zip_free(phar.zip); + } +#endif + if (opened_path) { + efree(opened_path); + } + return; + } + } else { + zval *userz; + + if (source->is_tar) { + phar_entry_info *entry; + + if (FAILURE == (zend_hash_find(&source->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1, (void **)&entry))) { + /* use default stub - the existing one in the manifest will be used if present */ + phar_flush(&phar, NULL, 0, &error TSRMLS_CC); + goto finalize; + } + php_stream_seek(source->fp, entry->offset_within_phar, SEEK_SET); + /* use this unused value to set the stub size */ + source->internal_file_start = entry->uncompressed_filesize; + } else { + php_stream_seek(source->fp, 0, SEEK_SET); + } + /* copy the other phar's stub */ + ALLOC_ZVAL(userz); + php_stream_to_zval(source->fp, userz); + phar_flush(&phar, (char *) &userz, -(source->internal_file_start), &error TSRMLS_CC); + efree(userz); + if (source->is_tar) { + source->internal_file_start = 0; + } + } + + if (error) { + zend_hash_destroy(&(phar.manifest)); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\": %s", source->fname, error); + efree(error); + php_stream_close(phar.fp); +#if HAVE_PHAR_ZIP + if (phar.is_zip) { + _zip_free(phar.zip); + } +#endif + if (opened_path) { + efree(opened_path); + } + return; + } + +finalize: + /* third, update the old phar's manifest */ + for (zend_hash_internal_pointer_reset(&(phar.manifest)); SUCCESS == zend_hash_has_more_elements(&(phar.manifest)); zend_hash_move_forward(&(phar.manifest))) { + phar_entry_info *entry, *mine; + if (FAILURE == zend_hash_get_current_data(&(phar.manifest), (void **) &entry)) { + zend_hash_destroy(&(phar.manifest)); + php_stream_close(phar.fp); + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot convert phar archive \"%s\"", source->fname); +#if HAVE_PHAR_ZIP + if (phar.is_zip) { + _zip_free(phar.zip); + } +#endif + if (opened_path) { + efree(opened_path); + } + /* we can't throw an exception or bad crap will happen */ + zend_error(E_ERROR, "Error: could not convert phar archive \"%s\", phar is in unstable state, shutting down", source->fname); + return; + } + if (FAILURE == zend_hash_find(&source->manifest, entry->filename, entry->filename_len, (void **) &mine)) { + if (phar.is_tar || phar.is_zip) { + if (entry->filename_len == sizeof(".phar/stub.php")-1 && !strncmp(entry->filename, ".phar/stub.php", sizeof(".phar/stub.php")-1)) { + /* a little hack to prevent destruction of data */ + dtor_func_t save; + + save = phar.manifest.pDestructor; + phar.manifest.pDestructor = NULL; + zend_hash_add(&source->manifest, ".phar/stub.php", sizeof(".phar/stub.php")-1, (void*)entry, sizeof(phar_entry_info), NULL); + zend_hash_del(&(phar.manifest), ".phar/stub.php", sizeof(".phar/stub.php")-1); + phar.manifest.pDestructor = save; + continue; + } + if (entry->filename_len == sizeof(".phar/alias.txt")-1 && !strncmp(entry->filename, ".phar/alias.txt", sizeof(".phar/alias.txt")-1)) { + /* a little hack to prevent destruction of data */ + dtor_func_t save; + + save = phar.manifest.pDestructor; + phar.manifest.pDestructor = NULL; + zend_hash_add(&source->manifest, ".phar/alias.txt", sizeof(".phar/alias.txt")-1, (void*)entry, sizeof(phar_entry_info), NULL); + zend_hash_del(&(phar.manifest), ".phar/alias.txt", sizeof(".phar/alias.txt")-1); + phar.manifest.pDestructor = save; + continue; + } + } + zend_hash_destroy(&(phar.manifest)); + php_stream_close(phar.fp); +#if HAVE_PHAR_ZIP + if (phar.is_zip) { + _zip_free(phar.zip); + } +#endif + if (opened_path) { + efree(opened_path); + } + /* we can't throw an exception or bad crap will happen */ + zend_error(E_ERROR, "Error: could not convert phar archive \"%s\", phar is in unstable state, shutting down", source->fname); + return; + } + /* now, replace the manifest entry with the new guy */ + efree(mine->filename); + if (mine->metadata) { + zval_dtor(mine->metadata); + efree(mine->metadata); + } + *mine = *entry; + mine->phar = source; + } + source->fp = phar.fp; + /* don't free stuff */ + phar.manifest.pDestructor = NULL; + zend_hash_destroy(&(phar.manifest)); + source->is_zip = phar.is_zip; + source->is_tar = phar.is_tar; + if (phar.signature) { + if (source->signature) { + efree(source->signature); + } + source->signature = phar.signature; + } +#if HAVE_PHAR_ZIP + if (phar.is_zip) { + _zip_free(phar.zip); + _zip_free(source->zip); + if (FAILURE == php_copy_file(opened_path, source->fname)) { + /* we can't throw an exception or bad crap will happen */ + zend_error(E_ERROR, "Error: could not copy newly created zip to \"%s\", phar is in unstable state, shutting down", source->fname); + } + source->zip = zip_open(source->fname, 0, &ziperror); + if (!source->zip) { + efree(opened_path); + /* now for the stupid hoops libzip forces... */ + char *tmp; + int tmp_len; + tmp_len = zip_error_to_str(NULL, 0, ziperror, ziperror); + if (!(tmp = emalloc((tmp_len + 1) * sizeof(char)))) { + zend_error(E_ERROR, "Error: could not re-open newly created zip \"%s\", phar is in unstable state, shutting down", source->fname); + } else { + if (!zip_error_to_str(tmp, tmp_len + 1, ziperror, ziperror)) { + efree(tmp); + zend_error(E_ERROR, "Error: could not re-open newly created zip \"%s\", phar is in unstable state, shutting down", source->fname); + } else { + zend_error(E_ERROR, "Error: could not re-open newly created zip \"%s\" (%s), phar is in unstable state, shutting down", source->fname, tmp); + efree(tmp); + } + } + return; + } + efree(opened_path); + } +#endif +} + +/* {{{ proto bool Phar::convertToTar() + * Convert the phar archive to the tar file format + */ +PHP_METHOD(Phar, convertToTar) +{ + char *error; + PHAR_ARCHIVE_OBJECT(); + + if (phar_obj->arc.archive->is_tar) { + RETURN_TRUE; + } + if (PHAR_G(readonly)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write out phar archive, phar is read-only"); + return; + } + + if (!zend_hash_num_elements(&phar_obj->arc.archive->manifest)) { + /* nothing need be done specially, this has no files in it */ + phar_obj->arc.archive->is_tar = 1; + phar_obj->arc.archive->is_modified = 1; + RETURN_TRUE; + } + + if (phar_obj->arc.archive->donotflush) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot convert phar archive to tar format, call stopBuffering() first"); + return; + } + + phar_flush(phar_obj->arc.archive, NULL, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + return; + } + phar_convert_to_other(phar_obj->arc.archive, 1); +} +/* }}} */ + + +/* {{{ proto bool Phar::convertToZip() + * Convert the phar archive to the zip file format + */ +PHP_METHOD(Phar, convertToZip) +{ + char *error; + PHAR_ARCHIVE_OBJECT(); + + if (phar_obj->arc.archive->is_zip) { + RETURN_TRUE; + } + if (PHAR_G(readonly)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write out phar archive, phar is read-only"); + return; + } + +#if HAVE_PHAR_ZIP + if (!phar_has_zip) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot convert phar archive to zip format, zip-based phar archives are disabled (enable ext/zip in php.ini)"); + return; + } +#else + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot convert phar archive to zip format, zip-based phar archives are unavailable"); + return; +#endif + + if (!zend_hash_num_elements(&phar_obj->arc.archive->manifest)) { + int ziperror; + /* nothing need be done specially, this has no files in it */ + phar_obj->arc.archive->is_zip = 1; + phar_obj->arc.archive->internal_file_start = 0; + phar_obj->arc.archive->is_modified = 1; + phar_obj->arc.archive->zip = zip_open(phar_obj->arc.archive->fname, ZIP_CREATE, &ziperror); + if (!phar_obj->arc.archive->zip) { + /* now for the stupid hoops libzip forces... */ + char *tmp; + int tmp_len; + tmp_len = zip_error_to_str(NULL, 0, ziperror, ziperror); + if (!(tmp = emalloc((tmp_len + 1) * sizeof(char)))) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot convert phar archive to zip format, unable to open", phar_obj->arc.archive->fname); + } else { + if (!zip_error_to_str(tmp, tmp_len + 1, ziperror, ziperror)) { + efree(tmp); + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot convert phar archive to zip format, unable to open", phar_obj->arc.archive->fname); + } else { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot convert phar archive to zip format, unable to open: %s", phar_obj->arc.archive->fname, tmp); + efree(tmp); + } + } + return; + } + RETURN_TRUE; + } + + if (phar_obj->arc.archive->donotflush) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot convert phar archive to zip format, call stopBuffering() first"); + return; + } + + phar_flush(phar_obj->arc.archive, NULL, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + return; + } + phar_convert_to_other(phar_obj->arc.archive, 2); +} +/* }}} */ + + +/* {{{ proto bool Phar::convertToPhar() + * Convert the phar archive to the phar file format + */ +PHP_METHOD(Phar, convertToPhar) +{ + char *error; + PHAR_ARCHIVE_OBJECT(); + + if (!phar_obj->arc.archive->is_tar && !phar_obj->arc.archive->is_zip) { + RETURN_TRUE; + } + if (PHAR_G(readonly)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, + "Cannot write out phar archive, phar is read-only"); + return; + } + + if (phar_obj->arc.archive->donotflush) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot convert phar archive to phar format, call stopBuffering() first"); + return; + } + + if (!zend_hash_num_elements(&phar_obj->arc.archive->manifest)) { + /* nothing need be done specially, this has no files in it */ + phar_obj->arc.archive->is_tar = 0; + phar_obj->arc.archive->is_zip = 0; + phar_obj->arc.archive->is_modified = 1; + RETURN_TRUE; + } + + if (phar_obj->arc.archive->donotflush) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, + "Cannot convert phar archive to zip format, call stopBuffering() first"); + return; + } + + phar_flush(phar_obj->arc.archive, NULL, 0, &error TSRMLS_CC); + if (error) { + zend_throw_exception_ex(phar_ce_PharException, 0 TSRMLS_CC, error); + efree(error); + return; + } + + phar_convert_to_other(phar_obj->arc.archive, 0); + RETURN_TRUE; +} +/* }}} */ + /* {{{ proto bool Phar::isCompressed() * Returns Phar::GZ or PHAR::BZ2 if the entire phar archive is compressed (.tar.gz/tar.bz and so on) */ @@ -2916,6 +3453,9 @@ zend_function_entry php_archive_methods[] = { PHP_ME(Phar, isTar, NULL, ZEND_ACC_PUBLIC) PHP_ME(Phar, isZip, NULL, ZEND_ACC_PUBLIC) PHP_ME(Phar, isPhar, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, convertToTar, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, convertToZip, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Phar, convertToPhar, NULL, ZEND_ACC_PUBLIC) PHP_ME(Phar, isCompressed, NULL, ZEND_ACC_PUBLIC) #endif /* static member functions */ diff --git a/ext/phar/tests/phar_convert_tar.phpt b/ext/phar/tests/phar_convert_tar.phpt new file mode 100644 index 0000000000..7eabb08100 --- /dev/null +++ b/ext/phar/tests/phar_convert_tar.phpt @@ -0,0 +1,42 @@ +--TEST-- +Phar::convertToTar() +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'phar_test.inc'; + +$phar = new Phar($fname); +$phar->convertToTar(); +var_dump($phar->isTar()); +copy($fname, $fname2); + +$phar = new Phar($fname2); +var_dump($phar->isTar()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +===DONE=== diff --git a/ext/phar/tests/phar_convert_zip.phpt b/ext/phar/tests/phar_convert_zip.phpt new file mode 100644 index 0000000000..0f02ccb474 --- /dev/null +++ b/ext/phar/tests/phar_convert_zip.phpt @@ -0,0 +1,42 @@ +--TEST-- +Phar::convertToZip() +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +'; +$file = $stub; + +$files = array(); +$files['a'] = 'a'; +$files['b'] = 'b'; +$files['c'] = 'c'; + +include 'phar_test.inc'; + +$phar = new Phar($fname); +$phar->convertToZip(); +var_dump($phar->isZip()); +copy($fname, $fname2); + +$phar = new Phar($fname2); +var_dump($phar->isZip()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +===DONE=== diff --git a/ext/phar/tests/tar/phar_convert_phar.phpt b/ext/phar/tests/tar/phar_convert_phar.phpt new file mode 100644 index 0000000000..7095f61956 --- /dev/null +++ b/ext/phar/tests/tar/phar_convert_phar.phpt @@ -0,0 +1,37 @@ +--TEST-- +Phar::convertToPhar() from tar +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +convertToTar(); +var_dump($phar->isTar()); +$phar['a'] = 'hi there'; +$phar->convertToPhar(); +var_dump($phar->isPhar()); +copy($fname, $fname2); + +$phar = new Phar($fname2); +var_dump($phar->isPhar()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +===DONE=== diff --git a/ext/phar/tests/zip/phar_convert_phar.phpt b/ext/phar/tests/zip/phar_convert_phar.phpt new file mode 100644 index 0000000000..337682e7d8 --- /dev/null +++ b/ext/phar/tests/zip/phar_convert_phar.phpt @@ -0,0 +1,37 @@ +--TEST-- +Phar::convertToPhar() from zip +--SKIPIF-- + +--INI-- +phar.require_hash=0 +phar.readonly=0 +--FILE-- +convertToZip(); +var_dump($phar->isZip()); +$phar['a'] = 'hi there'; +$phar->convertToPhar(); +var_dump($phar->isPhar()); +copy($fname, $fname2); + +$phar = new Phar($fname2); +var_dump($phar->isPhar()); +?> +===DONE=== +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +===DONE=== diff --git a/ext/phar/zip.c b/ext/phar/zip.c index 236509f739..d6dc7815a9 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -73,6 +73,7 @@ int phar_open_zipfile(char *fname, int fname_len, char *alias, int alias_len, ph spprintf(error, 4096, "phar zip error: cannot open zip-based phar \"%s\"", fname); } else { if (!zip_error_to_str(tmp, tmp_len + 1, ziperror, ziperror)) { + efree(tmp); spprintf(error, 4096, "phar zip error: cannot open zip-based phar \"%s\"", fname); } else { spprintf(error, 4096, "phar zip error: cannot open zip-based phar \"%s\": %s", fname, tmp); @@ -330,7 +331,8 @@ static ssize_t phar_zip_source(void *state, void *data, size_t len, enum zip_sou switch (cmd) { case ZIP_SOURCE_OPEN : - php_stream_seek(entry->fp, 0, SEEK_SET); + /* offset_within_phar is only non-zero when converting from tar/phar-based to zip-based */ + php_stream_seek(entry->fp, entry->offset_within_phar, SEEK_SET); return 0; case ZIP_SOURCE_READ : read = php_stream_read(entry->fp, buf, len); @@ -343,7 +345,8 @@ static ssize_t phar_zip_source(void *state, void *data, size_t len, enum zip_sou return sizeof(struct zip_stat); case ZIP_SOURCE_FREE: entry->is_modified = 0; - if (entry->fp && entry->fp_refcount == 0) { + /* phar->fp is set only if we're converting from a tar/phar-based archive */ + if (entry->fp && entry->fp_refcount == 0 && entry->fp != entry->phar->fp) { php_stream_close(entry->fp); entry->fp = NULL; } -- 2.50.1