From: Greg Beaver Date: Sat, 5 Jan 2008 22:46:54 +0000 (+0000) Subject: do not attempt to create a new phar if a file exists and is corrupted or is not a... X-Git-Tag: RELEASE_2_0_0a1~1014 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2fa568b7b00e2d3601c1cb8ef6afac6edd0b3b7c;p=php do not attempt to create a new phar if a file exists and is corrupted or is not a phar archive, i.e. require a clean slate - a non-existent file or a valid phar archive - to muck around with phar contents add the first tar-based phar test --- diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 5c9e95be20..ea04444113 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -1782,15 +1782,24 @@ int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int a return FAILURE; } - fp = php_stream_open_wrapper(fname, PHAR_G(readonly)?"rb":"r+b", IGNORE_URL|STREAM_MUST_SEEK|0, NULL); + /* first open readonly so it won't be created if not present */ + fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK|0, NULL); - if (fp && phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar, 0 TSRMLS_CC) == SUCCESS) { - if (!PHAR_G(readonly)) { - (*pphar)->is_writeable = 1; + if (fp) { + if (phar_open_fp(fp, fname, fname_len, alias, alias_len, options, pphar, error TSRMLS_CC) == SUCCESS) { + if (!PHAR_G(readonly)) { + (*pphar)->is_writeable = 1; + } + return SUCCESS; + } else { + /* file exists, but is either corrupt or not a phar archive */ + php_stream_close(fp); + return FAILURE; } - return SUCCESS; } + php_stream_close(fp); + if (PHAR_G(readonly)) { if (options & REPORT_ERRORS) { if (error) { @@ -1799,6 +1808,8 @@ int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int a } return FAILURE; } + /* re-open for writing */ + fp = php_stream_open_wrapper(fname, "r+b", IGNORE_URL|STREAM_MUST_SEEK|0, NULL); /* set up our manifest */ mydata = ecalloc(sizeof(phar_archive_data), 1); diff --git a/ext/phar/tests/tar/make_invalid_tar.php.inc b/ext/phar/tests/tar/make_invalid_tar.php.inc new file mode 100644 index 0000000000..c18bd199b3 --- /dev/null +++ b/ext/phar/tests/tar/make_invalid_tar.php.inc @@ -0,0 +1,9 @@ +tmp, 'oopsie'); + fclose($this->tmp); +} +} \ No newline at end of file diff --git a/ext/phar/tests/tar/tar_001.phpt b/ext/phar/tests/tar/tar_001.phpt new file mode 100644 index 0000000000..4e888c0d02 --- /dev/null +++ b/ext/phar/tests/tar/tar_001.phpt @@ -0,0 +1,33 @@ +--TEST-- +Phar: tar-based phar corrupted +--SKIPIF-- + + +--INI-- +phar.readonly=0 +phar.require_hash=0 +--FILE-- +init(); +$a->addFile('tar_001.phpt', __FILE__); +$a->close(); + +$a = fopen('phar://tar_001.phar/tar_001.phpt', 'rb'); +try { +$a = new Phar('tar_001.phar'); +echo "should not execute\n"; +} catch (Exception $e) { +echo $e->getMessage() . "\n"; +} +?> +===DONE=== +--CLEAN-- + +--EXPECTF-- +Warning: fopen(phar://tar_001.phar/tar_001.phpt): failed to open stream: phar error: "tar_001.phar" is a corrupted tar file in %s/tar_001.php on line %d +Cannot open phar file 'tar_001.phar' with alias '(null)': phar error: "tar_001.phar" is a corrupted tar file +===DONE=== \ No newline at end of file diff --git a/ext/phar/tests/tar/tarmaker.php.inc b/ext/phar/tests/tar/tarmaker.php.inc new file mode 100644 index 0000000000..9b75d9be12 --- /dev/null +++ b/ext/phar/tests/tar/tarmaker.php.inc @@ -0,0 +1,161 @@ +compress = $compress; + if ($compress === 'bz2' && !function_exists('bzopen')) { + throw new PEAR2_Pyrus_Developer_Creator_Exception( + 'bzip2 extension not available'); + } + if ($compress === 'zlib' && !function_exists('gzopen')) { + throw new PEAR2_Pyrus_Developer_Creator_Exception( + 'zlib extension not available'); + } + $this->path = $path; + } + + /** + * save a file inside this package + * + * This code is modified from Vincent Lascaux's File_Archive + * package, which is licensed under the LGPL license. + * @param string relative path within the package + * @param string|resource file contents or open file handle + */ + function addFile($path, $fileOrStream) + { + clearstatcache(); + if (is_resource($fileOrStream)) { + $stat = fstat($fileOrStream); + } else { + $stat = array( + 'mode' => 0x8000 + 0644, + 'uid' => 0, + 'gid' => 0, + 'size' => strlen($fileOrStream), + 'mtime' => time(), + ); + } + + $link = null; + if ($stat['mode'] & 0x4000) { + $type = 5; // Directory + } else if ($stat['mode'] & 0x8000) { + $type = 0; // Regular + } else if ($stat['mode'] & 0xA000) { + $type = 1; // Link + $link = @readlink($current); + } else { + $type = 9; // Unknown + } + + $filePrefix = ''; + if (strlen($path) > 255) { + throw new Exception( + "$path is too long, must be 255 characters or less" + ); + } else if (strlen($path) > 100) { + $filePrefix = substr($path, 0, strlen($path)-100); + $path = substr($path, -100); + } + + $block = pack('a100a8a8a8a12A12', + $path, + decoct($stat['mode']), + sprintf('%6s ',decoct($stat['uid'])), + sprintf('%6s ',decoct($stat['gid'])), + sprintf('%11s ',decoct($stat['size'])), + sprintf('%11s ',decoct($stat['mtime'])) + ); + + $blockend = pack('a1a100a6a2a32a32a8a8a155a12', + $type, + $link, + 'ustar', + '00', + 'Pyrus', + 'Pyrus', + '', + '', + $filePrefix, + ''); + + $checkheader = array_merge(str_split($block), str_split($blockend)); + if (!function_exists('_pear2tarchecksum')) { + function _pear2tarchecksum($a, $b) {return $a + ord($b);} + } + $checksum = 256; // 8 * ord(' '); + $checksum += array_reduce($checkheader, '_pear2tarchecksum'); + + $checksum = pack('a8', sprintf('%6s ', decoct($checksum))); + + fwrite($this->tmp, $block . $checksum . $blockend, 512); + if (is_resource($fileOrStream)) { + stream_copy_to_stream($fileOrStream, $this->tmp); + if ($stat['size'] % 512) { + fwrite($this->tmp, str_repeat("\0", 512 - $stat['size'] % 512)); + } + } else { + fwrite($this->tmp, $fileOrStream); + if (strlen($fileOrStream) % 512) { + fwrite($this->tmp, str_repeat("\0", 512 - strlen($fileOrStream) % 512)); + } + } + } + + /** + * Initialize the package creator + */ + function init() + { + switch ($this->compress) { + case 'zlib' : + $this->tmp = gzopen($this->path, 'wb'); + break; + case 'bz2' : + $this->tmp = bzopen($this->path, 'wb'); + break; + case 'none' : + $this->tmp = fopen($this->path, 'wb'); + break; + default : + throw new Exception( + 'unknown compression type ' . $this->compress); + } + } + + /** + * Create an internal directory, creating parent directories as needed + * + * This is a no-op for the tar creator + * @param string $dir + */ + function mkdir($dir) + { + } + + /** + * Finish saving the package + */ + function close() + { + fwrite($this->tmp, pack('a1024', '')); + fclose($this->tmp); + } +} \ No newline at end of file