]> granicus.if.org Git - php/commitdiff
fix bug #45792: bz2 compressed files in zip failure
authorGreg Beaver <cellog@php.net>
Thu, 21 Aug 2008 05:17:28 +0000 (05:17 +0000)
committerGreg Beaver <cellog@php.net>
Thu, 21 Aug 2008 05:17:28 +0000 (05:17 +0000)
ext/phar/phar.c
ext/phar/phar.phar
ext/phar/phar_internal.h
ext/phar/stream.c
ext/phar/stream.h
ext/phar/tests/zip/bzip2.phpt [new file with mode: 0644]
ext/phar/tests/zip/files/bzip2.zip [new file with mode: 0644]
ext/phar/util.c
ext/phar/zip.c

index 36ec247b17be82576b90c8057966eaa7c4f967a2..2da7a948ff7ad4c924b1d87ab779a4e325ff4dca 100644 (file)
@@ -2383,7 +2383,7 @@ int phar_open_executed_filename(char *alias, int alias_len, char **error TSRMLS_
 /**
  * Validate the CRC32 of a file opened from within the phar
  */
-int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_data *idata, php_uint32 crc32, char **error TSRMLS_DC) /* {{{ */
+int phar_postprocess_file(phar_entry_data *idata, php_uint32 crc32, char **error, int process_zip TSRMLS_DC) /* {{{ */
 {
        php_uint32 crc = ~0;
        int len = idata->internal_file->uncompressed_filesize;
@@ -2394,7 +2394,7 @@ int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_d
                *error = NULL;
        }
 
-       if (entry->is_zip) {
+       if (entry->is_zip && process_zip > 0) {
                /* verify local file header */
                phar_zip_file_header local;
 
@@ -2424,6 +2424,7 @@ int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_d
                        idata->zero = entry->offset_abs;
                }
        }
+       if (process_zip == 1) return SUCCESS;
 
        php_stream_seek(fp, idata->zero, SEEK_SET);
 
@@ -2437,7 +2438,7 @@ int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_d
                entry->is_crc_checked = 1;
                return SUCCESS;
        } else {
-               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
+               spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
                return FAILURE;
        }
 }
index f509a85158347fcb3f6dbaf8d1ab02238dc2ad9a..09088ef30cb39f3edd1c269a5e1e96e62607eb9e 100755 (executable)
Binary files a/ext/phar/phar.phar and b/ext/phar/phar.phar differ
index d97dee0adbf98d42d06bf670d8f2210700b7858f..38b1e8816e55a18df23c68fbd9ae8e263a376cd6 100755 (executable)
@@ -576,6 +576,7 @@ void phar_object_init(TSRMLS_D);
 void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC);
 
 int phar_open_entry_file(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC);
+int phar_postprocess_file(phar_entry_data *idata, php_uint32 crc32, char **error, int process_zip TSRMLS_DC);
 int phar_open_from_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
 int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
 int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
index 229f1b99b5e11b061fee5f6d0b550da2e57a88bf..b432790d6559650d037f0a6de2039f25f7b64322 100644 (file)
@@ -307,8 +307,9 @@ idata_error:
 #endif
 
        /* check length, crc32 */
-       if (!idata->internal_file->is_crc_checked && phar_postprocess_file(wrapper, options, idata, idata->internal_file->crc32, &error TSRMLS_CC) != SUCCESS) {
-               /* already issued the error */
+       if (!idata->internal_file->is_crc_checked && phar_postprocess_file(idata, idata->internal_file->crc32, &error, 2 TSRMLS_CC) != SUCCESS) {
+               php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
+               efree(error);
                phar_entry_delref(idata TSRMLS_CC);
                efree(internal_file);
                return NULL;
index c69202bfcf0e75d599890e6f549d4372b1c8a689..4029025cbda86ad5cf009d1a087c776bf6f10ea0 100644 (file)
@@ -20,7 +20,6 @@
 /* $Id$ */
 
 BEGIN_EXTERN_C()
-int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_data *idata, php_uint32 crc32, char **error TSRMLS_DC);
 
 php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC);
 void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC);
diff --git a/ext/phar/tests/zip/bzip2.phpt b/ext/phar/tests/zip/bzip2.phpt
new file mode 100644 (file)
index 0000000..f34f185
--- /dev/null
@@ -0,0 +1,80 @@
+--TEST--
+Phar: process bzip2-compressed zip entry
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
+<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?>
+--FILE--
+<?php
+try {
+       $a = new PharData(dirname(__FILE__) . '/files/bzip2.zip');
+       foreach ($a as $entry => $file) {
+               echo $file->getContent();
+       }
+} catch (Exception $e) {
+       echo $e->getMessage() . "\n";
+}
+?>
+===DONE===
+--EXPECT--
+<?php
+include dirname(__FILE__) . '/corrupt_zipmaker.php.inc';
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii');
+$a->addFile('hi2', null, 'hii2', null, null, 'encrypt', 'encrypt');
+$a->writeZip(dirname(__FILE__) . '/encrypted.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii');
+$a->addFile('', null, 'stdin');
+$a->writeZip(dirname(__FILE__) . '/stdin.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hii', null, 'hii', null, null, 'filename_len', 'filename_len');
+$a->addFile('hi', null, 'hii');
+$a->writeZip(dirname(__FILE__) . '/truncfilename.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress');
+$a->writeZip(dirname(__FILE__) . '/compress_unsup1.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 2);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup2.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 3);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup3.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 4);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup4.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 5);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup5.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 6);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup6.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 7);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup7.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 9);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup9.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 10);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup10.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 14);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup14.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 18);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup18.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 19);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup19.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 97);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup97.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 98);
+$a->writeZip(dirname(__FILE__) . '/compress_unsup98.zip');
+$a = new corrupt_zipmaker;
+$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 11);
+$a->writeZip(dirname(__FILE__) . '/compress_unsupunknown.zip');
+?>
+===DONE===
diff --git a/ext/phar/tests/zip/files/bzip2.zip b/ext/phar/tests/zip/files/bzip2.zip
new file mode 100644 (file)
index 0000000..2f27f02
Binary files /dev/null and b/ext/phar/tests/zip/files/bzip2.zip differ
index 008bd3f5ead835c4e584ef91c2d1115a2e73607c..ea5159840d68de3e91489c08bed636b528952f5e 100644 (file)
@@ -913,6 +913,7 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
        char *filtername;
        off_t loc;
        php_stream *ufp;
+       phar_entry_data dummy;
 
        if (follow_links && entry->link) {
                phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
@@ -921,6 +922,10 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
                }
        }
 
+       if (entry->is_modified) {
+               return SUCCESS;
+       }
+
        if (entry->fp_type == PHAR_TMP) {
                if (!entry->fp) {
                        entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
@@ -941,6 +946,13 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
        }
 
        if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
+               dummy.internal_file = entry;
+               dummy.phar = phar;
+               dummy.zero = entry->offset;
+               dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
+               if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
+                       return FAILURE;
+               }
                return SUCCESS;
        }
 
@@ -952,6 +964,14 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
                }
        }
 
+       dummy.internal_file = entry;
+       dummy.phar = phar;
+       dummy.zero = entry->offset;
+       dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
+       if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
+               return FAILURE;
+       }
+
        ufp = phar_get_entrypufp(entry TSRMLS_CC);
 
        if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
@@ -991,6 +1011,11 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
 
        /* this is now the new location of the file contents within this fp */
        phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
+       dummy.zero = entry->offset;
+       dummy.fp = ufp;
+       if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0 TSRMLS_CC)) {
+               return FAILURE;
+       }
        return SUCCESS;
 }
 /* }}} */
index 07725875f41563623d11386c723e45122b538bd4..cd40e22dc5bda3f8f112cdccd14dff1ddd2b5252 100644 (file)
@@ -655,6 +655,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
        struct _phar_zip_pass *p;
        php_uint32 newcrc32;
        off_t offset;
+       int not_really_modified = 0;
 
        entry = (phar_entry_info *)data;
        p = (struct _phar_zip_pass*) arg;
@@ -723,6 +724,12 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
                        return ZEND_HASH_APPLY_STOP;
                }
 
+               /* we can be modified and already be compressed, such as when chmod() is executed */
+               if (entry->flags & PHAR_ENT_COMPRESSION_MASK && (entry->old_flags == entry->flags || !entry->old_flags)) {
+                       not_really_modified = 1;
+                       goto is_compressed;
+               }
+
                if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
                        spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
                        return ZEND_HASH_APPLY_STOP;
@@ -791,6 +798,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
                entry->old_flags = entry->flags;
                entry->is_modified = 1;
        } else {
+is_compressed:
                central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize);
                central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize);
 
@@ -872,7 +880,7 @@ continue_dir:
                return ZEND_HASH_APPLY_STOP;
        }
 
-       if (entry->is_modified) {
+       if (!not_really_modified && entry->is_modified) {
                if (entry->cfp) {
                        if (entry->compressed_filesize != php_stream_copy_to_stream(entry->cfp, p->filefp, entry->compressed_filesize)) {
                                spprintf(p->error, 0, "unable to write compressed contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
@@ -900,6 +908,7 @@ continue_dir:
 
                entry->is_modified = 0;
        } else {
+               entry->is_modified = 0;
                if (entry->fp_refcount) {
                        /* open file pointers refer to this fp, do not free the stream */
                        switch (entry->fp_type) {