Skip to content

Fix #53467: Phar cannot compress large archives #6643

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 41 additions & 17 deletions ext/phar/phar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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");
Expand All @@ -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) {
Expand All @@ -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)) {
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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);

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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 */
Expand All @@ -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;
}
}

Expand All @@ -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)) {
Expand All @@ -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;
}
}

Expand All @@ -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 */
Expand All @@ -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) {
Expand All @@ -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];
Expand Down Expand Up @@ -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;
}
/* }}} */
Expand Down