diff --git a/NEWS b/NEWS index 9ca7f5624b021..0ef6168f56599 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ PHP NEWS . Fixed bug #75850 (Unclear error message wrt. __halt_compiler() w/o semicolon) (cmb) . Fixed bug #70091 (Phar does not mark UTF-8 filenames in ZIP archives). (cmb) + . Fixed bug #53467 (Phar cannot compress large archives). (cmb, lserni) - Standard: . Fixed bug #80654 (file_get_contents() maxlen fails above (2**31)-1 bytes). diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 2749283ff5a37..7cb1b06363874 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -2508,6 +2508,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv smart_str main_metadata_str = {0}; int free_user_stub, free_fp = 1, free_ufp = 1; int manifest_hack = 0; + php_stream *shared_cfp = NULL; if (phar->is_persistent) { if (error) { @@ -2788,10 +2789,13 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv return EOF; } - /* create new file that holds the compressed version */ + /* create new file that holds the compressed versions */ /* work around inability to specify freedom in write and strictness in read count */ - entry->cfp = php_stream_fopen_tmpfile(); + if (shared_cfp == NULL) { + shared_cfp = php_stream_fopen_tmpfile(); + } + entry->cfp = shared_cfp; if (!entry->cfp) { if (error) { spprintf(error, 0, "unable to create temporary file"); @@ -2800,8 +2804,11 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv php_stream_close(oldfile); } php_stream_close(newfile); - return EOF; + goto cleanup; } + /* for real phars, header_offset is unused; we misuse it here to store the offset in the temp file */ + ZEND_ASSERT(entry->header_offset == 0); + entry->header_offset = php_stream_tell(entry->cfp); php_stream_flush(file); if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) { if (closeoldfile) { @@ -2811,7 +2818,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv if (error) { spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname); } - return EOF; + goto cleanup; } php_stream_filter_append((&entry->cfp->writefilters), filter); if (SUCCESS != php_stream_copy_to_stream_ex(file, entry->cfp, entry->uncompressed_filesize, NULL)) { @@ -2822,15 +2829,14 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv if (error) { spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname); } - return EOF; + goto cleanup; } php_stream_filter_flush(filter, 1); php_stream_flush(entry->cfp); php_stream_filter_remove(filter, 1); php_stream_seek(entry->cfp, 0, SEEK_END); - entry->compressed_filesize = (uint32_t) php_stream_tell(entry->cfp); + entry->compressed_filesize = ((uint32_t) php_stream_tell(entry->cfp)) - entry->header_offset; /* generate crc on compressed file */ - php_stream_rewind(entry->cfp); entry->old_flags = entry->flags; entry->is_modified = 1; global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK); @@ -2886,7 +2892,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname); } - return EOF; + goto cleanup; } phar->alias_len = restore_alias_len; @@ -2907,7 +2913,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname); } - return EOF; + goto cleanup; } smart_str_free(&main_metadata_str); @@ -2942,7 +2948,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname); } } - return EOF; + goto cleanup; } /* set the manifest meta-data: @@ -2975,7 +2981,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname); } - return EOF; + goto cleanup; } } ZEND_HASH_FOREACH_END(); /* Hack - see bug #65028, add padding byte to the end of the manifest */ @@ -2991,7 +2997,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv spprintf(error, 0, "unable to write manifest padding byte"); } - return EOF; + goto cleanup; } } @@ -3004,7 +3010,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv if (entry->cfp) { file = entry->cfp; - php_stream_rewind(file); + php_stream_seek(file, entry->header_offset, SEEK_SET); } else { file = phar_get_efp(entry, 0); if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) { @@ -3015,7 +3021,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv if (error) { spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname); } - return EOF; + goto cleanup; } } @@ -3027,7 +3033,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv if (error) { spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname); } - return EOF; + goto cleanup; } /* this will have changed for all files that have either changed compression or been modified */ @@ -3044,14 +3050,14 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname); } - return EOF; + goto cleanup; } entry->is_modified = 0; if (entry->cfp) { - php_stream_close(entry->cfp); entry->cfp = NULL; + entry->header_offset = 0; } if (entry->fp_type == PHAR_MOD) { @@ -3067,6 +3073,11 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv } } ZEND_HASH_FOREACH_END(); + if (shared_cfp != NULL) { + php_stream_close(shared_cfp); + shared_cfp = NULL; + } + /* append signature */ if (global_flags & PHAR_HDR_SIGNATURE) { char sig_buf[4]; @@ -3196,6 +3207,19 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv return EOF; } + return EOF; + +cleanup: + if (shared_cfp != NULL) { + php_stream_close(shared_cfp); + } + ZEND_HASH_FOREACH_PTR(&phar->manifest, entry) { + if (entry->cfp) { + entry->cfp = NULL; + entry->header_offset = 0; + } + } ZEND_HASH_FOREACH_END(); + return EOF; } /* }}} */