Skip to content

Commit 8b21e4e

Browse files
committed
Merge branch 'PHP-8.0'
* PHP-8.0: Fix #53467: Phar cannot compress large archives
2 parents 5f21062 + f4332a3 commit 8b21e4e

File tree

1 file changed

+41
-17
lines changed

1 file changed

+41
-17
lines changed

ext/phar/phar.c

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2558,6 +2558,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
25582558
smart_str main_metadata_str = {0};
25592559
int free_user_stub, free_fp = 1, free_ufp = 1;
25602560
int manifest_hack = 0;
2561+
php_stream *shared_cfp = NULL;
25612562

25622563
if (phar->is_persistent) {
25632564
if (error) {
@@ -2835,10 +2836,13 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
28352836
return EOF;
28362837
}
28372838

2838-
/* create new file that holds the compressed version */
2839+
/* create new file that holds the compressed versions */
28392840
/* work around inability to specify freedom in write and strictness
28402841
in read count */
2841-
entry->cfp = php_stream_fopen_tmpfile();
2842+
if (shared_cfp == NULL) {
2843+
shared_cfp = php_stream_fopen_tmpfile();
2844+
}
2845+
entry->cfp = shared_cfp;
28422846
if (!entry->cfp) {
28432847
if (error) {
28442848
spprintf(error, 0, "unable to create temporary file");
@@ -2847,8 +2851,11 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
28472851
php_stream_close(oldfile);
28482852
}
28492853
php_stream_close(newfile);
2850-
return EOF;
2854+
goto cleanup;
28512855
}
2856+
/* for real phars, header_offset is unused; we misuse it here to store the offset in the temp file */
2857+
ZEND_ASSERT(entry->header_offset == 0);
2858+
entry->header_offset = php_stream_tell(entry->cfp);
28522859
php_stream_flush(file);
28532860
if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
28542861
if (closeoldfile) {
@@ -2858,7 +2865,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
28582865
if (error) {
28592866
spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
28602867
}
2861-
return EOF;
2868+
goto cleanup;
28622869
}
28632870
php_stream_filter_append((&entry->cfp->writefilters), filter);
28642871
if (SUCCESS != php_stream_copy_to_stream_ex(file, entry->cfp, entry->uncompressed_filesize, NULL)) {
@@ -2869,15 +2876,14 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
28692876
if (error) {
28702877
spprintf(error, 0, "unable to copy compressed file contents of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
28712878
}
2872-
return EOF;
2879+
goto cleanup;
28732880
}
28742881
php_stream_filter_flush(filter, 1);
28752882
php_stream_flush(entry->cfp);
28762883
php_stream_filter_remove(filter, 1);
28772884
php_stream_seek(entry->cfp, 0, SEEK_END);
2878-
entry->compressed_filesize = (uint32_t) php_stream_tell(entry->cfp);
2885+
entry->compressed_filesize = ((uint32_t) php_stream_tell(entry->cfp)) - entry->header_offset;
28792886
/* generate crc on compressed file */
2880-
php_stream_rewind(entry->cfp);
28812887
entry->old_flags = entry->flags;
28822888
entry->is_modified = 1;
28832889
global_flags |= (entry->flags & PHAR_ENT_COMPRESSION_MASK);
@@ -2933,7 +2939,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
29332939
spprintf(error, 0, "unable to write manifest header of new phar \"%s\"", phar->fname);
29342940
}
29352941

2936-
return EOF;
2942+
goto cleanup;
29372943
}
29382944

29392945
phar->alias_len = restore_alias_len;
@@ -2954,7 +2960,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
29542960
spprintf(error, 0, "unable to write manifest meta-data of new phar \"%s\"", phar->fname);
29552961
}
29562962

2957-
return EOF;
2963+
goto cleanup;
29582964
}
29592965
smart_str_free(&main_metadata_str);
29602966

@@ -2990,7 +2996,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
29902996
spprintf(error, 0, "unable to write filename of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
29912997
}
29922998
}
2993-
return EOF;
2999+
goto cleanup;
29943000
}
29953001

29963002
/* set the manifest meta-data:
@@ -3024,7 +3030,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
30243030
spprintf(error, 0, "unable to write temporary manifest of file \"%s\" to manifest of new phar \"%s\"", entry->filename, phar->fname);
30253031
}
30263032

3027-
return EOF;
3033+
goto cleanup;
30283034
}
30293035
} ZEND_HASH_FOREACH_END();
30303036
/* Hack - see bug #65028, add padding byte to the end of the manifest */
@@ -3040,7 +3046,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
30403046
spprintf(error, 0, "unable to write manifest padding byte");
30413047
}
30423048

3043-
return EOF;
3049+
goto cleanup;
30443050
}
30453051
}
30463052

@@ -3053,7 +3059,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
30533059

30543060
if (entry->cfp) {
30553061
file = entry->cfp;
3056-
php_stream_rewind(file);
3062+
php_stream_seek(file, entry->header_offset, SEEK_SET);
30573063
} else {
30583064
file = phar_get_efp(entry, 0);
30593065
if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0)) {
@@ -3064,7 +3070,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
30643070
if (error) {
30653071
spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
30663072
}
3067-
return EOF;
3073+
goto cleanup;
30683074
}
30693075
}
30703076

@@ -3076,7 +3082,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
30763082
if (error) {
30773083
spprintf(error, 0, "unable to seek to start of file \"%s\" while creating new phar \"%s\"", entry->filename, phar->fname);
30783084
}
3079-
return EOF;
3085+
goto cleanup;
30803086
}
30813087

30823088
/* this will have changed for all files that have either changed compression or been modified */
@@ -3093,14 +3099,14 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
30933099
spprintf(error, 0, "unable to write contents of file \"%s\" to new phar \"%s\"", entry->filename, phar->fname);
30943100
}
30953101

3096-
return EOF;
3102+
goto cleanup;
30973103
}
30983104

30993105
entry->is_modified = 0;
31003106

31013107
if (entry->cfp) {
3102-
php_stream_close(entry->cfp);
31033108
entry->cfp = NULL;
3109+
entry->header_offset = 0;
31043110
}
31053111

31063112
if (entry->fp_type == PHAR_MOD) {
@@ -3116,6 +3122,11 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
31163122
}
31173123
} ZEND_HASH_FOREACH_END();
31183124

3125+
if (shared_cfp != NULL) {
3126+
php_stream_close(shared_cfp);
3127+
shared_cfp = NULL;
3128+
}
3129+
31193130
/* append signature */
31203131
if (global_flags & PHAR_HDR_SIGNATURE) {
31213132
char sig_buf[4];
@@ -3245,6 +3256,19 @@ int phar_flush(phar_archive_data *phar, char *user_stub, zend_long len, int conv
32453256
return EOF;
32463257
}
32473258

3259+
return EOF;
3260+
3261+
cleanup:
3262+
if (shared_cfp != NULL) {
3263+
php_stream_close(shared_cfp);
3264+
}
3265+
ZEND_HASH_FOREACH_PTR(&phar->manifest, entry) {
3266+
if (entry->cfp) {
3267+
entry->cfp = NULL;
3268+
entry->header_offset = 0;
3269+
}
3270+
} ZEND_HASH_FOREACH_END();
3271+
32483272
return EOF;
32493273
}
32503274
/* }}} */

0 commit comments

Comments
 (0)