2008-05-13 05:03:49 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| TAR archive support for Phar |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2019-02-04 05:47:49 +08:00
| Copyright ( c ) The PHP Group |
2008-05-13 05:03:49 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| This source file is subject to version 3.01 of the PHP license , |
| that is bundled with this package in the file LICENSE , and is |
| available through the world - wide - web at the following url : |
| http : //www.php.net/license/3_01.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ php . net so we can mail you a copy immediately . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2018-11-02 00:30:28 +08:00
| Authors : Dmitry Stogov < dmitry @ php . net > |
2008-05-13 05:03:49 +08:00
| Gregory Beaver < cellog @ php . net > |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
# include "phar_internal.h"
2018-04-17 21:09:31 +08:00
static uint32_t phar_tar_number ( char * buf , size_t len ) /* { { { */
2008-05-13 05:03:49 +08:00
{
2016-01-29 00:11:53 +08:00
uint32_t num = 0 ;
2019-01-09 05:08:40 +08:00
size_t i = 0 ;
2008-05-13 05:03:49 +08:00
while ( i < len & & buf [ i ] = = ' ' ) {
+ + i ;
}
2008-08-01 21:48:45 +08:00
while ( i < len & & buf [ i ] > = ' 0 ' & & buf [ i ] < = ' 7 ' ) {
2008-05-13 05:03:49 +08:00
num = num * 8 + ( buf [ i ] - ' 0 ' ) ;
+ + i ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
return num ;
}
/* }}} */
/* adapted from format_octal() in libarchive
2012-05-29 09:54:15 +08:00
*
2008-12-31 19:15:49 +08:00
* Copyright ( c ) 2003 - 2009 Tim Kientzle
2008-05-13 05:03:49 +08:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ( S ) ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR ( S ) BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2016-01-29 00:11:53 +08:00
static int phar_tar_octal ( char * buf , uint32_t val , int len ) /* { { { */
2008-05-13 05:03:49 +08:00
{
char * p = buf ;
int s = len ;
p + = len ; /* Start at the end and work backwards. */
while ( s - - > 0 ) {
* - - p = ( char ) ( ' 0 ' + ( val & 7 ) ) ;
val > > = 3 ;
}
if ( val = = 0 )
return SUCCESS ;
/* If it overflowed, fill field with max value. */
while ( len - - > 0 )
* p + + = ' 7 ' ;
return FAILURE ;
}
/* }}} */
2018-04-17 21:09:31 +08:00
static uint32_t phar_tar_checksum ( char * buf , size_t len ) /* { { { */
2008-05-13 05:03:49 +08:00
{
2016-01-29 00:11:53 +08:00
uint32_t sum = 0 ;
2008-05-13 05:03:49 +08:00
char * end = buf + len ;
while ( buf ! = end ) {
sum + = ( unsigned char ) * buf ;
+ + buf ;
}
return sum ;
}
/* }}} */
2008-07-29 18:52:08 +08:00
int phar_is_tar ( char * buf , char * fname ) /* { { { */
2008-05-13 05:03:49 +08:00
{
tar_header * header = ( tar_header * ) buf ;
2016-01-29 00:11:53 +08:00
uint32_t checksum = phar_tar_number ( header - > checksum , sizeof ( header - > checksum ) ) ;
uint32_t ret ;
2015-03-30 20:41:30 +08:00
char save [ sizeof ( header - > checksum ) ] , * bname ;
2008-05-13 05:03:49 +08:00
/* assume that the first filename in a tar won't begin with <?php */
if ( ! strncmp ( buf , " <?php " , sizeof ( " <?php " ) - 1 ) ) {
return 0 ;
}
memcpy ( save , header - > checksum , sizeof ( header - > checksum ) ) ;
memset ( header - > checksum , ' ' , sizeof ( header - > checksum ) ) ;
ret = ( checksum = = phar_tar_checksum ( buf , 512 ) ) ;
memcpy ( header - > checksum , save , sizeof ( header - > checksum ) ) ;
2015-03-30 20:41:30 +08:00
if ( ( bname = strrchr ( fname , PHP_DIR_SEPARATOR ) ) ) {
fname = bname ;
}
if ( ! ret & & ( bname = strstr ( fname , " .tar " ) ) & & ( bname [ 4 ] = = ' \0 ' | | bname [ 4 ] = = ' . ' ) ) {
2008-05-13 05:03:49 +08:00
/* probably a corrupted tar - so we will pretend it is one */
return 1 ;
}
return ret ;
}
2008-07-29 18:52:08 +08:00
/* }}} */
2008-05-13 05:03:49 +08:00
2018-04-17 21:09:31 +08:00
int phar_open_or_create_tar ( char * fname , size_t fname_len , char * alias , size_t alias_len , int is_data , uint32_t options , phar_archive_data * * pphar , char * * error ) /* { { { */
2008-05-13 05:03:49 +08:00
{
phar_archive_data * phar ;
2014-12-14 06:06:14 +08:00
int ret = phar_create_or_parse_filename ( fname , fname_len , alias , alias_len , is_data , options , & phar , error ) ;
2008-05-13 05:03:49 +08:00
if ( FAILURE = = ret ) {
return FAILURE ;
}
if ( pphar ) {
* pphar = phar ;
}
phar - > is_data = is_data ;
if ( phar - > is_tar ) {
return ret ;
}
if ( phar - > is_brandnew ) {
phar - > is_tar = 1 ;
2008-05-22 14:33:09 +08:00
phar - > is_zip = 0 ;
2008-05-13 05:03:49 +08:00
phar - > internal_file_start = 0 ;
return SUCCESS ;
}
/* we've reached here - the phar exists and is a regular phar */
if ( error ) {
spprintf ( error , 4096 , " phar tar error: \" %s \" already exists as a regular phar and must be deleted from disk prior to creating as a tar-based phar " , fname ) ;
}
return FAILURE ;
}
2008-07-29 18:52:08 +08:00
/* }}} */
2008-05-13 05:03:49 +08:00
2014-12-14 06:06:14 +08:00
static int phar_tar_process_metadata ( phar_entry_info * entry , php_stream * fp ) /* { { { */
2008-05-16 07:46:29 +08:00
{
char * metadata ;
size_t save = php_stream_tell ( fp ) , read ;
phar_entry_info * mentry ;
2012-05-29 09:54:15 +08:00
metadata = ( char * ) safe_emalloc ( 1 , entry - > uncompressed_filesize , 1 ) ;
2008-05-16 07:46:29 +08:00
read = php_stream_read ( fp , metadata , entry - > uncompressed_filesize ) ;
if ( read ! = entry - > uncompressed_filesize ) {
efree ( metadata ) ;
php_stream_seek ( fp , save , SEEK_SET ) ;
return FAILURE ;
}
2014-12-14 06:06:14 +08:00
if ( phar_parse_metadata ( & metadata , & entry - > metadata , entry - > uncompressed_filesize ) = = FAILURE ) {
2008-05-16 07:46:29 +08:00
/* if not valid serialized data, it is a regular string */
efree ( metadata ) ;
php_stream_seek ( fp , save , SEEK_SET ) ;
return FAILURE ;
}
2008-08-01 21:48:45 +08:00
2008-05-16 07:46:29 +08:00
if ( entry - > filename_len = = sizeof ( " .phar/.metadata.bin " ) - 1 & & ! memcmp ( entry - > filename , " .phar/.metadata.bin " , sizeof ( " .phar/.metadata.bin " ) - 1 ) ) {
2020-04-22 20:11:13 +08:00
if ( Z_TYPE ( entry - > phar - > metadata ) ! = IS_UNDEF ) {
efree ( metadata ) ;
return FAILURE ;
}
2008-05-16 07:46:29 +08:00
entry - > phar - > metadata = entry - > metadata ;
2014-05-08 22:30:07 +08:00
ZVAL_UNDEF ( & entry - > metadata ) ;
} else if ( entry - > filename_len > = sizeof ( " .phar/.metadata/ " ) + sizeof ( " /.metadata.bin " ) - 1 & & NULL ! = ( mentry = zend_hash_str_find_ptr ( & ( entry - > phar - > manifest ) , entry - > filename + sizeof ( " .phar/.metadata/ " ) - 1 , entry - > filename_len - ( sizeof ( " /.metadata.bin " ) - 1 + sizeof ( " .phar/.metadata/ " ) - 1 ) ) ) ) {
2020-04-22 20:11:13 +08:00
if ( Z_TYPE ( mentry - > metadata ) ! = IS_UNDEF ) {
efree ( metadata ) ;
return FAILURE ;
}
2008-05-16 07:46:29 +08:00
/* transfer this metadata to the entry it refers */
mentry - > metadata = entry - > metadata ;
2014-05-08 22:30:07 +08:00
ZVAL_UNDEF ( & entry - > metadata ) ;
2008-05-16 07:46:29 +08:00
}
2008-08-01 21:48:45 +08:00
2008-05-16 07:46:29 +08:00
efree ( metadata ) ;
php_stream_seek ( fp , save , SEEK_SET ) ;
return SUCCESS ;
}
2008-07-29 18:52:08 +08:00
/* }}} */
2008-05-16 07:46:29 +08:00
2016-02-01 11:37:56 +08:00
# if !HAVE_STRNLEN
static size_t strnlen ( const char * s , size_t maxlen ) {
char * r = ( char * ) memchr ( s , ' \0 ' , maxlen ) ;
return r ? r - s : maxlen ;
}
# endif
2018-04-17 21:09:31 +08:00
int phar_parse_tarfile ( php_stream * fp , char * fname , size_t fname_len , char * alias , size_t alias_len , phar_archive_data * * pphar , int is_data , uint32_t compression , char * * error ) /* { { { */
2008-05-13 05:03:49 +08:00
{
char buf [ 512 ] , * actual_alias = NULL , * p ;
phar_entry_info entry = { 0 } ;
size_t pos = 0 , read , totalsize ;
tar_header * hdr ;
2016-01-29 00:11:53 +08:00
uint32_t sum1 , sum2 , size , old ;
2014-05-09 01:18:59 +08:00
phar_archive_data * myphar , * actual ;
2009-11-12 05:02:59 +08:00
int last_was_longlink = 0 ;
2018-04-17 21:09:31 +08:00
size_t linkname_len ;
2008-05-13 05:03:49 +08:00
if ( error ) {
* error = NULL ;
}
php_stream_seek ( fp , 0 , SEEK_END ) ;
totalsize = php_stream_tell ( fp ) ;
php_stream_seek ( fp , 0 , SEEK_SET ) ;
read = php_stream_read ( fp , buf , sizeof ( buf ) ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( read ! = sizeof ( buf ) ) {
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" is not a tar file or is truncated " , fname ) ;
}
php_stream_close ( fp ) ;
return FAILURE ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
hdr = ( tar_header * ) buf ;
old = ( memcmp ( hdr - > magic , " ustar " , sizeof ( " ustar " ) - 1 ) ! = 0 ) ;
2008-06-13 02:56:23 +08:00
myphar = ( phar_archive_data * ) pecalloc ( 1 , sizeof ( phar_archive_data ) , PHAR_G ( persist ) ) ;
myphar - > is_persistent = PHAR_G ( persist ) ;
2008-06-16 12:09:20 +08:00
/* estimate number of entries, can't be certain with tar files */
zend_hash_init ( & myphar - > manifest , 2 + ( totalsize > > 12 ) ,
2008-06-18 23:06:50 +08:00
zend_get_hash_value , destroy_phar_manifest_entry , ( zend_bool ) myphar - > is_persistent ) ;
2008-06-16 12:09:20 +08:00
zend_hash_init ( & myphar - > mounted_dirs , 5 ,
2008-06-18 23:06:50 +08:00
zend_get_hash_value , NULL , ( zend_bool ) myphar - > is_persistent ) ;
2008-06-16 12:09:20 +08:00
zend_hash_init ( & myphar - > virtual_dirs , 4 + ( totalsize > > 11 ) ,
2008-06-18 23:06:50 +08:00
zend_get_hash_value , NULL , ( zend_bool ) myphar - > is_persistent ) ;
2008-05-13 05:03:49 +08:00
myphar - > is_tar = 1 ;
/* remember whether this entire phar was compressed with gz/bzip2 */
myphar - > flags = compression ;
entry . is_tar = 1 ;
entry . is_crc_checked = 1 ;
entry . phar = myphar ;
2008-05-22 06:00:43 +08:00
pos + = sizeof ( buf ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
do {
2008-05-16 07:46:29 +08:00
phar_entry_info * newentry ;
2008-05-22 06:00:43 +08:00
pos = php_stream_tell ( fp ) ;
2008-05-13 05:03:49 +08:00
hdr = ( tar_header * ) buf ;
sum1 = phar_tar_number ( hdr - > checksum , sizeof ( hdr - > checksum ) ) ;
if ( sum1 = = 0 & & phar_tar_checksum ( buf , sizeof ( buf ) ) = = 0 ) {
break ;
}
memset ( hdr - > checksum , ' ' , sizeof ( hdr - > checksum ) ) ;
sum2 = phar_tar_checksum ( buf , old ? sizeof ( old_tar_header ) : sizeof ( tar_header ) ) ;
2020-12-02 21:49:43 +08:00
if ( old & & sum2 ! = sum1 ) {
uint32_t sum3 = phar_tar_checksum ( buf , sizeof ( tar_header ) ) ;
if ( sum3 = = sum1 ) {
/* apparently a broken tar which is in ustar format w/o setting the ustar marker */
sum2 = sum3 ;
old = 0 ;
}
}
2008-05-13 05:03:49 +08:00
size = entry . uncompressed_filesize = entry . compressed_filesize =
phar_tar_number ( hdr - > size , sizeof ( hdr - > size ) ) ;
2015-03-30 19:09:32 +08:00
/* skip global/file headers (pax) */
if ( ! old & & ( hdr - > typeflag = = TAR_GLOBAL_HDR | | hdr - > typeflag = = TAR_FILE_HDR ) ) {
size = ( size + 511 ) & ~ 511 ;
goto next ;
}
2016-02-01 11:37:56 +08:00
if ( ( ( ! old & & hdr - > prefix [ 0 ] = = 0 ) | | old ) & & strnlen ( hdr - > name , 100 ) = = sizeof ( " .phar/signature.bin " ) - 1 & & ! strncmp ( hdr - > name , " .phar/signature.bin " , sizeof ( " .phar/signature.bin " ) - 1 ) ) {
2014-08-26 02:22:49 +08:00
zend_off_t curloc ;
2018-04-17 21:09:31 +08:00
size_t sig_len ;
2009-06-30 22:49:12 +08:00
2008-06-14 06:07:44 +08:00
if ( size > 511 ) {
if ( error ) {
spprintf ( error , 4096 , " phar error: tar-based phar \" %s \" has signature that is larger than 511 bytes, cannot process " , fname ) ;
}
bail :
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-06-14 06:07:44 +08:00
return FAILURE ;
}
2009-06-30 22:49:12 +08:00
curloc = php_stream_tell ( fp ) ;
2008-06-14 06:07:44 +08:00
read = php_stream_read ( fp , buf , size ) ;
2016-09-12 12:37:44 +08:00
if ( read ! = size | | read < = 8 ) {
2008-06-14 06:07:44 +08:00
if ( error ) {
spprintf ( error , 4096 , " phar error: tar-based phar \" %s \" signature cannot be read " , fname ) ;
}
goto bail ;
}
# ifdef WORDS_BIGENDIAN
# define PHAR_GET_32(buffer) \
( ( ( ( ( unsigned char * ) ( buffer ) ) [ 3 ] ) < < 24 ) \
| ( ( ( ( unsigned char * ) ( buffer ) ) [ 2 ] ) < < 16 ) \
| ( ( ( ( unsigned char * ) ( buffer ) ) [ 1 ] ) < < 8 ) \
| ( ( ( unsigned char * ) ( buffer ) ) [ 0 ] ) )
# else
2016-01-29 00:11:53 +08:00
# define PHAR_GET_32(buffer) (uint32_t) *(buffer)
2008-06-14 06:07:44 +08:00
# endif
2009-07-23 04:21:39 +08:00
myphar - > sig_flags = PHAR_GET_32 ( buf ) ;
2018-04-17 21:09:31 +08:00
if ( FAILURE = = phar_verify_signature ( fp , php_stream_tell ( fp ) - size - 512 , myphar - > sig_flags , buf + 8 , size - 8 , fname , & myphar - > signature , & sig_len , error ) ) {
2008-06-14 06:07:44 +08:00
if ( error ) {
char * save = * error ;
spprintf ( error , 4096 , " phar error: tar-based phar \" %s \" signature cannot be verified: %s " , fname , save ) ;
efree ( save ) ;
}
goto bail ;
}
2018-04-17 21:09:31 +08:00
myphar - > sig_len = sig_len ;
2009-06-30 22:49:12 +08:00
php_stream_seek ( fp , curloc + 512 , SEEK_SET ) ;
2008-06-14 06:07:44 +08:00
/* signature checked out, let's ensure this is the last file in the phar */
2008-09-01 03:47:31 +08:00
if ( ( ( hdr - > typeflag = = ' \0 ' ) | | ( hdr - > typeflag = = TAR_FILE ) ) & & size > 0 ) {
2008-06-14 06:07:44 +08:00
/* this is not good enough - seek succeeds even on truncated tars */
2009-06-30 22:49:12 +08:00
php_stream_seek ( fp , 512 , SEEK_CUR ) ;
2016-11-26 22:18:42 +08:00
if ( ( uint32_t ) php_stream_tell ( fp ) > totalsize ) {
2008-06-14 06:07:44 +08:00
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" is a corrupted tar file (truncated) " , fname ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-06-14 06:07:44 +08:00
return FAILURE ;
}
}
2008-08-01 21:48:45 +08:00
2008-06-14 06:07:44 +08:00
read = php_stream_read ( fp , buf , sizeof ( buf ) ) ;
2008-08-01 21:48:45 +08:00
2008-06-14 06:07:44 +08:00
if ( read ! = sizeof ( buf ) ) {
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" is a corrupted tar file (truncated) " , fname ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-06-14 06:07:44 +08:00
return FAILURE ;
}
2008-08-01 21:48:45 +08:00
2008-06-14 06:07:44 +08:00
hdr = ( tar_header * ) buf ;
sum1 = phar_tar_number ( hdr - > checksum , sizeof ( hdr - > checksum ) ) ;
2008-08-01 21:48:45 +08:00
2008-06-14 06:07:44 +08:00
if ( sum1 = = 0 & & phar_tar_checksum ( buf , sizeof ( buf ) ) = = 0 ) {
break ;
}
2008-08-01 21:48:45 +08:00
2008-06-14 06:07:44 +08:00
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" has entries after signature, invalid phar " , fname ) ;
}
2008-08-01 21:48:45 +08:00
2008-06-14 06:07:44 +08:00
goto bail ;
}
2008-08-01 21:48:45 +08:00
2009-11-12 05:02:59 +08:00
if ( ! last_was_longlink & & hdr - > typeflag = = ' L ' ) {
last_was_longlink = 1 ;
/* support the ././@LongLink system for storing long filenames */
entry . filename_len = entry . uncompressed_filesize ;
2012-05-16 13:34:34 +08:00
/* Check for overflow - bug 61065 */
2016-01-15 14:58:40 +08:00
if ( entry . filename_len = = UINT_MAX | | entry . filename_len = = 0 ) {
2012-05-16 13:34:34 +08:00
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" is a corrupted tar file (invalid entry size) " , fname ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2012-05-16 13:34:34 +08:00
return FAILURE ;
}
2009-11-12 05:02:59 +08:00
entry . filename = pemalloc ( entry . filename_len + 1 , myphar - > is_persistent ) ;
read = php_stream_read ( fp , entry . filename , entry . filename_len ) ;
if ( read ! = entry . filename_len ) {
efree ( entry . filename ) ;
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" is a corrupted tar file (truncated) " , fname ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2009-11-12 05:02:59 +08:00
return FAILURE ;
}
entry . filename [ entry . filename_len ] = ' \0 ' ;
/* skip blank stuff */
size = ( ( size + 511 ) & ~ 511 ) - size ;
/* this is not good enough - seek succeeds even on truncated tars */
php_stream_seek ( fp , size , SEEK_CUR ) ;
2016-11-26 22:18:42 +08:00
if ( ( uint32_t ) php_stream_tell ( fp ) > totalsize ) {
2009-11-12 05:02:59 +08:00
efree ( entry . filename ) ;
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" is a corrupted tar file (truncated) " , fname ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2009-11-12 05:02:59 +08:00
return FAILURE ;
}
read = php_stream_read ( fp , buf , sizeof ( buf ) ) ;
2012-05-29 09:54:15 +08:00
2009-11-12 05:02:59 +08:00
if ( read ! = sizeof ( buf ) ) {
efree ( entry . filename ) ;
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" is a corrupted tar file (truncated) " , fname ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2009-11-12 05:02:59 +08:00
return FAILURE ;
}
continue ;
} else if ( ! last_was_longlink & & ! old & & hdr - > prefix [ 0 ] ! = 0 ) {
2008-05-13 05:03:49 +08:00
char name [ 256 ] ;
2009-06-05 03:59:09 +08:00
int i , j ;
2008-05-13 05:03:49 +08:00
2009-06-05 03:59:09 +08:00
for ( i = 0 ; i < 155 ; i + + ) {
name [ i ] = hdr - > prefix [ i ] ;
if ( name [ i ] = = ' \0 ' ) {
break ;
}
}
2009-07-23 03:51:37 +08:00
name [ i + + ] = ' / ' ;
2009-06-05 03:59:09 +08:00
for ( j = 0 ; j < 100 ; j + + ) {
name [ i + j ] = hdr - > name [ j ] ;
2009-07-23 02:13:38 +08:00
if ( name [ i + j ] = = ' \0 ' ) {
break ;
}
2008-05-13 05:03:49 +08:00
}
2008-08-01 21:48:45 +08:00
2009-06-05 03:59:09 +08:00
entry . filename_len = i + j ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( name [ entry . filename_len - 1 ] = = ' / ' ) {
/* some tar programs store directories with trailing slash */
entry . filename_len - - ;
}
2008-06-13 02:56:23 +08:00
entry . filename = pestrndup ( name , entry . filename_len , myphar - > is_persistent ) ;
2009-11-12 05:02:59 +08:00
} else if ( ! last_was_longlink ) {
2009-06-05 03:59:09 +08:00
int i ;
/* calculate strlen, which can be no longer than 100 */
for ( i = 0 ; i < 100 ; i + + ) {
if ( hdr - > name [ i ] = = ' \0 ' ) {
break ;
}
}
entry . filename_len = i ;
entry . filename = pestrndup ( hdr - > name , i , myphar - > is_persistent ) ;
2008-08-01 21:48:45 +08:00
2015-04-30 13:04:20 +08:00
if ( i > 0 & & entry . filename [ entry . filename_len - 1 ] = = ' / ' ) {
2008-05-13 05:03:49 +08:00
/* some tar programs store directories with trailing slash */
entry . filename [ entry . filename_len - 1 ] = ' \0 ' ;
entry . filename_len - - ;
}
}
2009-11-12 05:02:59 +08:00
last_was_longlink = 0 ;
2008-08-01 21:48:45 +08:00
2014-12-14 06:06:14 +08:00
phar_add_virtual_dirs ( myphar , entry . filename , entry . filename_len ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( sum1 ! = sum2 ) {
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" is a corrupted tar file (checksum mismatch of file \" %s \" ) " , fname , entry . filename ) ;
}
2008-06-13 02:56:23 +08:00
pefree ( entry . filename , myphar - > is_persistent ) ;
2008-05-13 05:03:49 +08:00
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-05-13 05:03:49 +08:00
return FAILURE ;
}
2008-09-01 04:24:04 +08:00
entry . tar_type = ( ( old & ( hdr - > typeflag = = ' \0 ' ) ) ? TAR_FILE : hdr - > typeflag ) ;
2008-05-13 05:03:49 +08:00
entry . offset = entry . offset_abs = pos ; /* header_offset unused in tar */
entry . fp_type = PHAR_FP ;
entry . flags = phar_tar_number ( hdr - > mode , sizeof ( hdr - > mode ) ) & PHAR_ENT_PERM_MASK ;
entry . timestamp = phar_tar_number ( hdr - > mtime , sizeof ( hdr - > mtime ) ) ;
2008-06-13 02:56:23 +08:00
entry . is_persistent = myphar - > is_persistent ;
2015-05-25 19:21:01 +08:00
2008-05-13 05:03:49 +08:00
if ( old & & entry . tar_type = = TAR_FILE & & S_ISDIR ( entry . flags ) ) {
entry . tar_type = TAR_DIR ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( entry . tar_type = = TAR_DIR ) {
entry . is_dir = 1 ;
} else {
entry . is_dir = 0 ;
}
entry . link = NULL ;
2016-02-01 11:37:56 +08:00
/* link field is null-terminated unless it has 100 non-null chars.
* Thus we can not use strlen . */
linkname_len = strnlen ( hdr - > linkname , 100 ) ;
2008-05-13 05:03:49 +08:00
if ( entry . tar_type = = TAR_LINK ) {
2016-02-02 11:55:09 +08:00
if ( ! zend_hash_str_exists ( & myphar - > manifest , hdr - > linkname , linkname_len ) ) {
2008-05-13 05:03:49 +08:00
if ( error ) {
2018-04-17 21:09:31 +08:00
spprintf ( error , 4096 , " phar error: \" %s \" is a corrupted tar file - hard link to non-existent file \" %.*s \" " , fname , ( int ) linkname_len , hdr - > linkname ) ;
2008-05-13 05:03:49 +08:00
}
2008-06-13 02:56:23 +08:00
pefree ( entry . filename , entry . is_persistent ) ;
2008-05-13 05:03:49 +08:00
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-05-13 05:03:49 +08:00
return FAILURE ;
}
2016-02-01 11:37:56 +08:00
entry . link = estrndup ( hdr - > linkname , linkname_len ) ;
2008-05-13 05:03:49 +08:00
} else if ( entry . tar_type = = TAR_SYMLINK ) {
2016-02-01 11:37:56 +08:00
entry . link = estrndup ( hdr - > linkname , linkname_len ) ;
2008-05-13 05:03:49 +08:00
}
2014-12-14 06:06:14 +08:00
phar_set_inode ( & entry ) ;
2016-02-03 07:24:06 +08:00
2016-03-01 05:44:06 +08:00
newentry = zend_hash_str_update_mem ( & myphar - > manifest , entry . filename , entry . filename_len , ( void * ) & entry , sizeof ( phar_entry_info ) ) ;
2016-02-03 07:24:06 +08:00
ZEND_ASSERT ( newentry ! = NULL ) ;
2008-08-01 21:48:45 +08:00
if ( entry . is_persistent ) {
+ + entry . manifest_pos ;
}
2008-05-16 07:46:29 +08:00
if ( entry . filename_len > = sizeof ( " .phar/.metadata " ) - 1 & & ! memcmp ( entry . filename , " .phar/.metadata " , sizeof ( " .phar/.metadata " ) - 1 ) ) {
2014-12-14 06:06:14 +08:00
if ( FAILURE = = phar_tar_process_metadata ( newentry , fp ) ) {
2008-05-16 07:46:29 +08:00
if ( error ) {
spprintf ( error , 4096 , " phar error: tar-based phar \" %s \" has invalid metadata in magic file \" %s \" " , fname , entry . filename ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-05-16 07:46:29 +08:00
return FAILURE ;
}
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( ! actual_alias & & entry . filename_len = = sizeof ( " .phar/alias.txt " ) - 1 & & ! strncmp ( entry . filename , " .phar/alias.txt " , sizeof ( " .phar/alias.txt " ) - 1 ) ) {
/* found explicit alias */
if ( size > 511 ) {
if ( error ) {
spprintf ( error , 4096 , " phar error: tar-based phar \" %s \" has alias that is larger than 511 bytes, cannot process " , fname ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-05-13 05:03:49 +08:00
return FAILURE ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
read = php_stream_read ( fp , buf , size ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( read = = size ) {
buf [ size ] = ' \0 ' ;
if ( ! phar_validate_alias ( buf , size ) ) {
if ( size > 50 ) {
buf [ 50 ] = ' . ' ;
buf [ 51 ] = ' . ' ;
buf [ 52 ] = ' . ' ;
buf [ 53 ] = ' \0 ' ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( error ) {
spprintf ( error , 4096 , " phar error: invalid alias \" %s \" in tar-based phar \" %s \" " , buf , fname ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-05-13 05:03:49 +08:00
return FAILURE ;
}
2008-08-01 21:48:45 +08:00
2008-06-13 02:56:23 +08:00
actual_alias = pestrndup ( buf , size , myphar - > is_persistent ) ;
2008-05-13 05:03:49 +08:00
myphar - > alias = actual_alias ;
myphar - > alias_len = size ;
php_stream_seek ( fp , pos , SEEK_SET ) ;
} else {
if ( error ) {
spprintf ( error , 4096 , " phar error: Unable to read alias from tar-based phar \" %s \" " , fname ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-05-13 05:03:49 +08:00
return FAILURE ;
}
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
size = ( size + 511 ) & ~ 511 ;
2008-08-01 21:48:45 +08:00
2008-09-01 03:47:31 +08:00
if ( ( ( hdr - > typeflag = = ' \0 ' ) | | ( hdr - > typeflag = = TAR_FILE ) ) & & size > 0 ) {
2015-03-30 19:09:32 +08:00
next :
2008-05-13 05:03:49 +08:00
/* this is not good enough - seek succeeds even on truncated tars */
php_stream_seek ( fp , size , SEEK_CUR ) ;
2016-11-26 22:18:42 +08:00
if ( ( uint32_t ) php_stream_tell ( fp ) > totalsize ) {
2008-05-13 05:03:49 +08:00
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" is a corrupted tar file (truncated) " , fname ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-05-13 05:03:49 +08:00
return FAILURE ;
}
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
read = php_stream_read ( fp , buf , sizeof ( buf ) ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( read ! = sizeof ( buf ) ) {
if ( error ) {
spprintf ( error , 4096 , " phar error: \" %s \" is a corrupted tar file (truncated) " , fname ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-05-13 05:03:49 +08:00
return FAILURE ;
}
2014-09-19 17:42:44 +08:00
} while ( ! php_stream_eof ( fp ) ) ;
2008-06-14 06:07:44 +08:00
2014-05-08 22:30:07 +08:00
if ( zend_hash_str_exists ( & ( myphar - > manifest ) , " .phar/stub.php " , sizeof ( " .phar/stub.php " ) - 1 ) ) {
2009-05-14 04:25:43 +08:00
myphar - > is_data = 0 ;
} else {
myphar - > is_data = 1 ;
}
2008-06-14 06:07:44 +08:00
/* ensure signature set */
2009-05-14 04:25:43 +08:00
if ( ! myphar - > is_data & & PHAR_G ( require_hash ) & & ! myphar - > signature ) {
2008-06-14 06:07:44 +08:00
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-06-14 06:07:44 +08:00
if ( error ) {
spprintf ( error , 0 , " tar-based phar \" %s \" does not have a signature " , fname ) ;
}
return FAILURE ;
}
2008-06-22 22:46:10 +08:00
myphar - > fname = pestrndup ( fname , fname_len , myphar - > is_persistent ) ;
# ifdef PHP_WIN32
phar_unixify_path_separators ( myphar - > fname , fname_len ) ;
# endif
myphar - > fname_len = fname_len ;
2008-06-18 14:38:47 +08:00
myphar - > fp = fp ;
2008-05-13 05:03:49 +08:00
p = strrchr ( myphar - > fname , ' / ' ) ;
2008-05-22 14:33:09 +08:00
2008-05-13 05:03:49 +08:00
if ( p ) {
myphar - > ext = memchr ( p , ' . ' , ( myphar - > fname + fname_len ) - p ) ;
if ( myphar - > ext = = p ) {
myphar - > ext = memchr ( p + 1 , ' . ' , ( myphar - > fname + fname_len ) - p - 1 ) ;
}
if ( myphar - > ext ) {
myphar - > ext_len = ( myphar - > fname + fname_len ) - myphar - > ext ;
}
}
2008-08-01 21:48:45 +08:00
2014-12-14 06:06:14 +08:00
phar_request_initialize ( ) ;
2008-08-01 21:48:45 +08:00
2015-03-09 22:58:53 +08:00
if ( NULL = = ( actual = zend_hash_str_add_ptr ( & ( PHAR_G ( phar_fname_map ) ) , myphar - > fname , fname_len , myphar ) ) ) {
2008-05-13 05:03:49 +08:00
if ( error ) {
spprintf ( error , 4096 , " phar error: Unable to add tar-based phar \" %s \" to phar registry " , fname ) ;
}
php_stream_close ( fp ) ;
2014-12-14 06:06:14 +08:00
phar_destroy_phar_data ( myphar ) ;
2008-05-13 05:03:49 +08:00
return FAILURE ;
}
2008-08-01 21:48:45 +08:00
2014-05-09 01:18:59 +08:00
myphar = actual ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( actual_alias ) {
2014-05-08 22:30:07 +08:00
phar_archive_data * fd_ptr ;
2008-05-13 05:03:49 +08:00
myphar - > is_temporary_alias = 0 ;
2008-08-01 21:48:45 +08:00
2015-03-09 22:58:53 +08:00
if ( NULL ! = ( fd_ptr = zend_hash_str_find_ptr ( & ( PHAR_G ( phar_alias_map ) ) , actual_alias , myphar - > alias_len ) ) ) {
2014-12-14 06:06:14 +08:00
if ( SUCCESS ! = phar_free_alias ( fd_ptr , actual_alias , myphar - > alias_len ) ) {
2008-05-13 05:03:49 +08:00
if ( error ) {
spprintf ( error , 4096 , " phar error: Unable to add tar-based phar \" %s \" , alias is already in use " , fname ) ;
}
2015-03-09 22:58:53 +08:00
zend_hash_str_del ( & ( PHAR_G ( phar_fname_map ) ) , myphar - > fname , fname_len ) ;
2008-05-13 05:03:49 +08:00
return FAILURE ;
}
}
2008-08-01 21:48:45 +08:00
2015-03-09 22:58:53 +08:00
zend_hash_str_add_ptr ( & ( PHAR_G ( phar_alias_map ) ) , actual_alias , myphar - > alias_len , myphar ) ;
2008-05-13 05:03:49 +08:00
} else {
2014-05-08 22:30:07 +08:00
phar_archive_data * fd_ptr ;
2008-05-13 05:03:49 +08:00
if ( alias_len ) {
2015-03-09 22:58:53 +08:00
if ( NULL ! = ( fd_ptr = zend_hash_str_find_ptr ( & ( PHAR_G ( phar_alias_map ) ) , alias , alias_len ) ) ) {
2014-12-14 06:06:14 +08:00
if ( SUCCESS ! = phar_free_alias ( fd_ptr , alias , alias_len ) ) {
2008-05-13 05:03:49 +08:00
if ( error ) {
spprintf ( error , 4096 , " phar error: Unable to add tar-based phar \" %s \" , alias is already in use " , fname ) ;
}
2015-03-09 22:58:53 +08:00
zend_hash_str_del ( & ( PHAR_G ( phar_fname_map ) ) , myphar - > fname , fname_len ) ;
2008-05-13 05:03:49 +08:00
return FAILURE ;
}
}
2015-03-09 22:58:53 +08:00
zend_hash_str_add_ptr ( & ( PHAR_G ( phar_alias_map ) ) , alias , alias_len , myphar ) ;
2008-06-13 02:56:23 +08:00
myphar - > alias = pestrndup ( alias , alias_len , myphar - > is_persistent ) ;
2008-05-13 05:03:49 +08:00
myphar - > alias_len = alias_len ;
} else {
2008-06-13 02:56:23 +08:00
myphar - > alias = pestrndup ( myphar - > fname , fname_len , myphar - > is_persistent ) ;
2008-05-13 05:03:49 +08:00
myphar - > alias_len = fname_len ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
myphar - > is_temporary_alias = 1 ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( pphar ) {
* pphar = myphar ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
return SUCCESS ;
}
/* }}} */
struct _phar_pass_tar_info {
php_stream * old ;
php_stream * new ;
int free_fp ;
int free_ufp ;
char * * error ;
} ;
2014-12-14 06:06:14 +08:00
static int phar_tar_writeheaders_int ( phar_entry_info * entry , void * argument ) /* { { { */
2008-05-13 05:03:49 +08:00
{
tar_header header ;
size_t pos ;
struct _phar_pass_tar_info * fp = ( struct _phar_pass_tar_info * ) argument ;
char padding [ 512 ] ;
if ( entry - > is_mounted ) {
return ZEND_HASH_APPLY_KEEP ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( entry - > is_deleted ) {
if ( entry - > fp_refcount < = 0 ) {
return ZEND_HASH_APPLY_REMOVE ;
} else {
/* we can't delete this in-memory until it is closed */
return ZEND_HASH_APPLY_KEEP ;
}
}
2014-12-14 06:06:14 +08:00
phar_add_virtual_dirs ( entry - > phar , entry - > filename , entry - > filename_len ) ;
2008-05-13 05:03:49 +08:00
memset ( ( char * ) & header , 0 , sizeof ( header ) ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( entry - > filename_len > 100 ) {
2009-07-23 03:51:37 +08:00
char * boundary ;
if ( entry - > filename_len > 256 ) {
2008-05-13 05:03:49 +08:00
if ( fp - > error ) {
spprintf ( fp - > error , 4096 , " tar-based phar \" %s \" cannot be created, filename \" %s \" is too long for tar file format " , entry - > phar - > fname , entry - > filename ) ;
}
return ZEND_HASH_APPLY_STOP ;
}
2009-07-23 03:51:37 +08:00
boundary = entry - > filename + entry - > filename_len - 101 ;
while ( * boundary & & * boundary ! = ' / ' ) {
+ + boundary ;
}
if ( ! * boundary | | ( ( boundary - entry - > filename ) > 155 ) ) {
if ( fp - > error ) {
spprintf ( fp - > error , 4096 , " tar-based phar \" %s \" cannot be created, filename \" %s \" is too long for tar file format " , entry - > phar - > fname , entry - > filename ) ;
}
return ZEND_HASH_APPLY_STOP ;
}
memcpy ( header . prefix , entry - > filename , boundary - entry - > filename ) ;
memcpy ( header . name , boundary + 1 , entry - > filename_len - ( boundary + 1 - entry - > filename ) ) ;
2008-05-13 05:03:49 +08:00
} else {
memcpy ( header . name , entry - > filename , entry - > filename_len ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
phar_tar_octal ( header . mode , entry - > flags & PHAR_ENT_PERM_MASK , sizeof ( header . mode ) - 1 ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( FAILURE = = phar_tar_octal ( header . size , entry - > uncompressed_filesize , sizeof ( header . size ) - 1 ) ) {
if ( fp - > error ) {
spprintf ( fp - > error , 4096 , " tar-based phar \" %s \" cannot be created, filename \" %s \" is too large for tar file format " , entry - > phar - > fname , entry - > filename ) ;
}
return ZEND_HASH_APPLY_STOP ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( FAILURE = = phar_tar_octal ( header . mtime , entry - > timestamp , sizeof ( header . mtime ) - 1 ) ) {
if ( fp - > error ) {
spprintf ( fp - > error , 4096 , " tar-based phar \" %s \" cannot be created, file modification time of file \" %s \" is too large for tar file format " , entry - > phar - > fname , entry - > filename ) ;
}
return ZEND_HASH_APPLY_STOP ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
/* calc checksum */
header . typeflag = entry - > tar_type ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( entry - > link ) {
2019-03-04 14:33:38 +08:00
if ( strlcpy ( header . linkname , entry - > link , sizeof ( header . linkname ) ) > = sizeof ( header . linkname ) ) {
if ( fp - > error ) {
spprintf ( fp - > error , 4096 , " tar-based phar \" %s \" cannot be created, link \" %s \" is too long for format " , entry - > phar - > fname , entry - > link ) ;
}
return ZEND_HASH_APPLY_STOP ;
}
2008-05-13 05:03:49 +08:00
}
2008-08-01 21:48:45 +08:00
2019-07-24 22:06:07 +08:00
memcpy ( header . magic , " ustar " , sizeof ( " ustar " ) - 1 ) ;
memcpy ( header . version , " 00 " , sizeof ( " 00 " ) - 1 ) ;
memcpy ( header . checksum , " " , sizeof ( " " ) - 1 ) ;
2008-05-13 05:03:49 +08:00
entry - > crc32 = phar_tar_checksum ( ( char * ) & header , sizeof ( header ) ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( FAILURE = = phar_tar_octal ( header . checksum , entry - > crc32 , sizeof ( header . checksum ) - 1 ) ) {
if ( fp - > error ) {
spprintf ( fp - > error , 4096 , " tar-based phar \" %s \" cannot be created, checksum of file \" %s \" is too large for tar file format " , entry - > phar - > fname , entry - > filename ) ;
}
return ZEND_HASH_APPLY_STOP ;
}
/* write header */
entry - > header_offset = php_stream_tell ( fp - > new ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( sizeof ( header ) ! = php_stream_write ( fp - > new , ( char * ) & header , sizeof ( header ) ) ) {
if ( fp - > error ) {
spprintf ( fp - > error , 4096 , " tar-based phar \" %s \" cannot be created, header for file \" %s \" could not be written " , entry - > phar - > fname , entry - > filename ) ;
}
return ZEND_HASH_APPLY_STOP ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
pos = php_stream_tell ( fp - > new ) ; /* save start of file within tar */
/* write contents */
if ( entry - > uncompressed_filesize ) {
2014-12-14 06:06:14 +08:00
if ( FAILURE = = phar_open_entry_fp ( entry , fp - > error , 0 ) ) {
2008-05-13 05:03:49 +08:00
return ZEND_HASH_APPLY_STOP ;
}
2008-08-01 21:48:45 +08:00
2014-12-14 06:06:14 +08:00
if ( - 1 = = phar_seek_efp ( entry , 0 , SEEK_SET , 0 , 0 ) ) {
2008-05-13 05:03:49 +08:00
if ( fp - > error ) {
spprintf ( fp - > error , 4096 , " tar-based phar \" %s \" cannot be created, contents of file \" %s \" could not be written, seek failed " , entry - > phar - > fname , entry - > filename ) ;
}
return ZEND_HASH_APPLY_STOP ;
}
2008-08-01 21:48:45 +08:00
2014-12-14 06:06:14 +08:00
if ( SUCCESS ! = php_stream_copy_to_stream_ex ( phar_get_efp ( entry , 0 ) , fp - > new , entry - > uncompressed_filesize , NULL ) ) {
2008-05-13 05:03:49 +08:00
if ( fp - > error ) {
spprintf ( fp - > error , 4096 , " tar-based phar \" %s \" cannot be created, contents of file \" %s \" could not be written " , entry - > phar - > fname , entry - > filename ) ;
}
return ZEND_HASH_APPLY_STOP ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
memset ( padding , 0 , 512 ) ;
php_stream_write ( fp - > new , padding , ( ( entry - > uncompressed_filesize + 511 ) & ~ 511 ) - entry - > uncompressed_filesize ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( ! entry - > is_modified & & entry - > fp_refcount ) {
/* open file pointers refer to this fp, do not free the stream */
switch ( entry - > fp_type ) {
case PHAR_FP :
fp - > free_fp = 0 ;
break ;
case PHAR_UFP :
fp - > free_ufp = 0 ;
default :
break ;
}
}
entry - > is_modified = 0 ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( entry - > fp_type = = PHAR_MOD & & entry - > fp ! = entry - > phar - > fp & & entry - > fp ! = entry - > phar - > ufp ) {
if ( ! entry - > fp_refcount ) {
php_stream_close ( entry - > fp ) ;
}
entry - > fp = NULL ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
entry - > fp_type = PHAR_FP ;
/* note new location within tar */
entry - > offset = entry - > offset_abs = pos ;
return ZEND_HASH_APPLY_KEEP ;
}
2008-07-29 18:52:08 +08:00
/* }}} */
2008-05-13 05:03:49 +08:00
2014-12-14 06:06:14 +08:00
static int phar_tar_writeheaders ( zval * zv , void * argument ) /* { { { */
2014-05-09 01:18:59 +08:00
{
2014-12-14 06:06:14 +08:00
return phar_tar_writeheaders_int ( Z_PTR_P ( zv ) , argument ) ;
2014-05-09 01:18:59 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
int phar_tar_setmetadata ( zval * metadata , phar_entry_info * entry , char * * error ) /* { { { */
2008-05-16 07:46:29 +08:00
{
php_serialize_data_t metadata_hash ;
2014-05-08 22:30:07 +08:00
if ( entry - > metadata_str . s ) {
2008-05-16 07:46:29 +08:00
smart_str_free ( & entry - > metadata_str ) ;
}
2008-08-01 21:48:45 +08:00
2014-05-08 22:30:07 +08:00
entry - > metadata_str . s = NULL ;
2008-05-16 07:46:29 +08:00
PHP_VAR_SERIALIZE_INIT ( metadata_hash ) ;
2014-12-14 06:06:14 +08:00
php_var_serialize ( & entry - > metadata_str , metadata , & metadata_hash ) ;
2008-05-16 07:46:29 +08:00
PHP_VAR_SERIALIZE_DESTROY ( metadata_hash ) ;
2015-06-30 09:05:24 +08:00
entry - > uncompressed_filesize = entry - > compressed_filesize = entry - > metadata_str . s ? ZSTR_LEN ( entry - > metadata_str . s ) : 0 ;
2008-08-01 21:48:45 +08:00
2008-05-16 07:46:29 +08:00
if ( entry - > fp & & entry - > fp_type = = PHAR_MOD ) {
php_stream_close ( entry - > fp ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-16 07:46:29 +08:00
entry - > fp_type = PHAR_MOD ;
entry - > is_modified = 1 ;
entry - > fp = php_stream_fopen_tmpfile ( ) ;
entry - > offset = entry - > offset_abs = 0 ;
2013-05-14 22:45:11 +08:00
if ( entry - > fp = = NULL ) {
spprintf ( error , 0 , " phar error: unable to create temporary file " ) ;
return - 1 ;
}
2015-06-30 09:05:24 +08:00
if ( ZSTR_LEN ( entry - > metadata_str . s ) ! = php_stream_write ( entry - > fp , ZSTR_VAL ( entry - > metadata_str . s ) , ZSTR_LEN ( entry - > metadata_str . s ) ) ) {
2008-05-16 07:46:29 +08:00
spprintf ( error , 0 , " phar tar error: unable to write metadata to magic metadata file \" %s \" " , entry - > filename ) ;
2014-05-08 22:30:07 +08:00
zend_hash_str_del ( & ( entry - > phar - > manifest ) , entry - > filename , entry - > filename_len ) ;
2008-05-16 07:46:29 +08:00
return ZEND_HASH_APPLY_STOP ;
}
2008-08-01 21:48:45 +08:00
2008-05-16 07:46:29 +08:00
return ZEND_HASH_APPLY_KEEP ;
}
2008-07-29 18:52:08 +08:00
/* }}} */
2008-05-16 07:46:29 +08:00
2014-12-14 06:06:14 +08:00
static int phar_tar_setupmetadata ( zval * zv , void * argument ) /* { { { */
2008-05-16 07:46:29 +08:00
{
int lookfor_len ;
struct _phar_pass_tar_info * i = ( struct _phar_pass_tar_info * ) argument ;
char * lookfor , * * error = i - > error ;
2014-05-09 01:18:59 +08:00
phar_entry_info * entry = ( phar_entry_info * ) Z_PTR_P ( zv ) , * metadata , newentry = { 0 } ;
2008-05-16 07:46:29 +08:00
if ( entry - > filename_len > = sizeof ( " .phar/.metadata " ) & & ! memcmp ( entry - > filename , " .phar/.metadata " , sizeof ( " .phar/.metadata " ) - 1 ) ) {
if ( entry - > filename_len = = sizeof ( " .phar/.metadata.bin " ) - 1 & & ! memcmp ( entry - > filename , " .phar/.metadata.bin " , sizeof ( " .phar/.metadata.bin " ) - 1 ) ) {
2014-12-14 06:06:14 +08:00
return phar_tar_setmetadata ( & entry - > phar - > metadata , entry , error ) ;
2008-05-16 07:46:29 +08:00
}
/* search for the file this metadata entry references */
2014-05-08 22:30:07 +08:00
if ( entry - > filename_len > = sizeof ( " .phar/.metadata/ " ) + sizeof ( " /.metadata.bin " ) - 1 & & ! zend_hash_str_exists ( & ( entry - > phar - > manifest ) , entry - > filename + sizeof ( " .phar/.metadata/ " ) - 1 , entry - > filename_len - ( sizeof ( " /.metadata.bin " ) - 1 + sizeof ( " .phar/.metadata/ " ) - 1 ) ) ) {
2008-05-16 07:46:29 +08:00
/* this is orphaned metadata, erase it */
return ZEND_HASH_APPLY_REMOVE ;
}
/* we can keep this entry, the file that refers to it exists */
return ZEND_HASH_APPLY_KEEP ;
}
if ( ! entry - > is_modified ) {
return ZEND_HASH_APPLY_KEEP ;
}
2008-08-01 21:48:45 +08:00
2008-05-16 07:46:29 +08:00
/* now we are dealing with regular files, so look for metadata */
lookfor_len = spprintf ( & lookfor , 0 , " .phar/.metadata/%s/.metadata.bin " , entry - > filename ) ;
2008-08-01 21:48:45 +08:00
2014-05-08 22:30:07 +08:00
if ( Z_TYPE ( entry - > metadata ) = = IS_UNDEF ) {
zend_hash_str_del ( & ( entry - > phar - > manifest ) , lookfor , lookfor_len ) ;
2008-05-16 07:46:29 +08:00
efree ( lookfor ) ;
return ZEND_HASH_APPLY_KEEP ;
}
2008-08-01 21:48:45 +08:00
2014-05-08 22:30:07 +08:00
if ( NULL ! = ( metadata = zend_hash_str_find_ptr ( & ( entry - > phar - > manifest ) , lookfor , lookfor_len ) ) ) {
2008-05-16 07:46:29 +08:00
int ret ;
2014-12-14 06:06:14 +08:00
ret = phar_tar_setmetadata ( & entry - > metadata , metadata , error ) ;
2008-05-16 07:46:29 +08:00
efree ( lookfor ) ;
return ret ;
}
newentry . filename = lookfor ;
newentry . filename_len = lookfor_len ;
newentry . phar = entry - > phar ;
newentry . tar_type = TAR_FILE ;
newentry . is_tar = 1 ;
2014-05-08 22:30:07 +08:00
if ( NULL = = ( metadata = zend_hash_str_add_mem ( & ( entry - > phar - > manifest ) , lookfor , lookfor_len , ( void * ) & newentry , sizeof ( phar_entry_info ) ) ) ) {
2008-05-16 07:46:29 +08:00
efree ( lookfor ) ;
spprintf ( error , 0 , " phar tar error: unable to add magic metadata file to manifest for file \" %s \" " , entry - > filename ) ;
return ZEND_HASH_APPLY_STOP ;
}
2014-12-14 06:06:14 +08:00
return phar_tar_setmetadata ( & entry - > metadata , metadata , error ) ;
2008-05-16 07:46:29 +08:00
}
2008-07-29 18:52:08 +08:00
/* }}} */
2008-05-16 07:46:29 +08:00
2014-12-14 06:06:14 +08:00
int phar_tar_flush ( phar_archive_data * phar , char * user_stub , zend_long len , int defaultstub , char * * error ) /* { { { */
2008-05-13 05:03:49 +08:00
{
phar_entry_info entry = { 0 } ;
static const char newstub [ ] = " <?php // tar-based phar archive stub file \n __HALT_COMPILER(); " ;
php_stream * oldfile , * newfile , * stubfile ;
2018-04-17 21:09:31 +08:00
int closeoldfile , free_user_stub ;
size_t signature_length ;
2008-05-13 05:03:49 +08:00
struct _phar_pass_tar_info pass ;
2010-05-03 22:41:40 +08:00
char * buf , * signature , * tmp , sigbuf [ 8 ] ;
char halt_stub [ ] = " __HALT_COMPILER(); " ;
2008-05-13 05:03:49 +08:00
entry . flags = PHAR_ENT_PERM_DEF_FILE ;
entry . timestamp = time ( NULL ) ;
entry . is_modified = 1 ;
entry . is_crc_checked = 1 ;
entry . is_tar = 1 ;
entry . tar_type = ' 0 ' ;
entry . phar = phar ;
entry . fp_type = PHAR_MOD ;
2016-09-03 05:31:26 +08:00
entry . fp = NULL ;
entry . filename = NULL ;
2008-05-13 05:03:49 +08:00
2008-06-18 14:38:47 +08:00
if ( phar - > is_persistent ) {
if ( error ) {
spprintf ( error , 0 , " internal error: attempt to flush cached tar-based phar \" %s \" " , phar - > fname ) ;
}
return EOF ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( phar - > is_data ) {
goto nostub ;
}
/* set alias */
if ( ! phar - > is_temporary_alias & & phar - > alias_len ) {
entry . filename = estrndup ( " .phar/alias.txt " , sizeof ( " .phar/alias.txt " ) - 1 ) ;
entry . filename_len = sizeof ( " .phar/alias.txt " ) - 1 ;
entry . fp = php_stream_fopen_tmpfile ( ) ;
2013-05-14 22:45:11 +08:00
if ( entry . fp = = NULL ) {
2016-09-03 05:31:26 +08:00
efree ( entry . filename ) ;
2013-05-14 22:45:11 +08:00
spprintf ( error , 0 , " phar error: unable to create temporary file " ) ;
return - 1 ;
}
2018-04-17 21:09:31 +08:00
if ( phar - > alias_len ! = php_stream_write ( entry . fp , phar - > alias , phar - > alias_len ) ) {
2008-05-13 05:03:49 +08:00
if ( error ) {
spprintf ( error , 0 , " unable to set alias in tar-based phar \" %s \" " , phar - > fname ) ;
}
2016-09-03 05:31:26 +08:00
php_stream_close ( entry . fp ) ;
efree ( entry . filename ) ;
2008-05-13 05:03:49 +08:00
return EOF ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
entry . uncompressed_filesize = phar - > alias_len ;
2008-08-01 21:48:45 +08:00
2018-06-01 16:58:57 +08:00
zend_hash_str_update_mem ( & phar - > manifest , entry . filename , entry . filename_len , ( void * ) & entry , sizeof ( phar_entry_info ) ) ;
2016-09-14 18:07:38 +08:00
/* At this point the entry is saved into the manifest. The manifest destroy
routine will care about any resources to be freed . */
2008-05-13 05:03:49 +08:00
} else {
2014-05-08 22:30:07 +08:00
zend_hash_str_del ( & phar - > manifest , " .phar/alias.txt " , sizeof ( " .phar/alias.txt " ) - 1 ) ;
2008-05-13 05:03:49 +08:00
}
/* set stub */
if ( user_stub & & ! defaultstub ) {
char * pos ;
if ( len < 0 ) {
/* resource passed in */
2014-05-08 22:30:07 +08:00
if ( ! ( php_stream_from_zval_no_verify ( stubfile , ( zval * ) user_stub ) ) ) {
2008-05-13 05:03:49 +08:00
if ( error ) {
spprintf ( error , 0 , " unable to access resource to copy stub to new tar-based phar \" %s \" " , phar - > fname ) ;
}
return EOF ;
}
if ( len = = - 1 ) {
len = PHP_STREAM_COPY_ALL ;
} else {
len = - len ;
}
user_stub = 0 ;
2012-08-22 07:15:34 +08:00
2014-05-08 22:30:07 +08:00
// TODO: refactor to avoid reallocation ???
//??? len = php_stream_copy_to_mem(stubfile, &user_stub, len, 0)
{
zend_string * str = php_stream_copy_to_mem ( stubfile , len , 0 ) ;
if ( str ) {
2015-06-30 09:05:24 +08:00
len = ZSTR_LEN ( str ) ;
user_stub = estrndup ( ZSTR_VAL ( str ) , ZSTR_LEN ( str ) ) ;
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( str , 0 ) ;
2014-05-08 22:30:07 +08:00
} else {
user_stub = NULL ;
len = 0 ;
}
}
if ( ! len | | ! user_stub ) {
2008-05-13 05:03:49 +08:00
if ( error ) {
spprintf ( error , 0 , " unable to read resource to copy stub to new tar-based phar \" %s \" " , phar - > fname ) ;
}
return EOF ;
}
free_user_stub = 1 ;
} else {
free_user_stub = 0 ;
}
2008-08-01 21:48:45 +08:00
2010-05-03 22:41:40 +08:00
tmp = estrndup ( user_stub , len ) ;
if ( ( pos = php_stristr ( tmp , halt_stub , len , sizeof ( halt_stub ) - 1 ) ) = = NULL ) {
efree ( tmp ) ;
2008-05-13 05:03:49 +08:00
if ( error ) {
spprintf ( error , 0 , " illegal stub for tar-based phar \" %s \" " , phar - > fname ) ;
}
if ( free_user_stub ) {
efree ( user_stub ) ;
}
return EOF ;
}
2010-05-03 22:41:40 +08:00
pos = user_stub + ( pos - tmp ) ;
efree ( tmp ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
len = pos - user_stub + 18 ;
entry . fp = php_stream_fopen_tmpfile ( ) ;
2013-05-14 22:45:11 +08:00
if ( entry . fp = = NULL ) {
spprintf ( error , 0 , " phar error: unable to create temporary file " ) ;
return EOF ;
}
2008-05-13 05:03:49 +08:00
entry . uncompressed_filesize = len + 5 ;
if ( ( size_t ) len ! = php_stream_write ( entry . fp , user_stub , len )
| | 5 ! = php_stream_write ( entry . fp , " ?> \r \n " , 5 ) ) {
if ( error ) {
spprintf ( error , 0 , " unable to create stub from string in new tar-based phar \" %s \" " , phar - > fname ) ;
}
if ( free_user_stub ) {
efree ( user_stub ) ;
}
php_stream_close ( entry . fp ) ;
return EOF ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
entry . filename = estrndup ( " .phar/stub.php " , sizeof ( " .phar/stub.php " ) - 1 ) ;
entry . filename_len = sizeof ( " .phar/stub.php " ) - 1 ;
2014-05-08 22:30:07 +08:00
zend_hash_str_update_mem ( & phar - > manifest , entry . filename , entry . filename_len , ( void * ) & entry , sizeof ( phar_entry_info ) ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( free_user_stub ) {
efree ( user_stub ) ;
}
} else {
/* Either this is a brand new phar (add the stub), or the default stub is required (overwrite the stub) */
entry . fp = php_stream_fopen_tmpfile ( ) ;
2013-05-14 22:45:11 +08:00
if ( entry . fp = = NULL ) {
spprintf ( error , 0 , " phar error: unable to create temporary file " ) ;
return EOF ;
}
2008-05-13 05:03:49 +08:00
if ( sizeof ( newstub ) - 1 ! = php_stream_write ( entry . fp , newstub , sizeof ( newstub ) - 1 ) ) {
php_stream_close ( entry . fp ) ;
if ( error ) {
spprintf ( error , 0 , " unable to %s stub in%star-based phar \" %s \" , failed " , user_stub ? " overwrite " : " create " , user_stub ? " " : " new " , phar - > fname ) ;
}
return EOF ;
}
entry . uncompressed_filesize = entry . compressed_filesize = sizeof ( newstub ) - 1 ;
entry . filename = estrndup ( " .phar/stub.php " , sizeof ( " .phar/stub.php " ) - 1 ) ;
entry . filename_len = sizeof ( " .phar/stub.php " ) - 1 ;
if ( ! defaultstub ) {
2014-05-08 22:30:07 +08:00
if ( ! zend_hash_str_exists ( & phar - > manifest , " .phar/stub.php " , sizeof ( " .phar/stub.php " ) - 1 ) ) {
if ( NULL = = zend_hash_str_add_mem ( & phar - > manifest , entry . filename , entry . filename_len , ( void * ) & entry , sizeof ( phar_entry_info ) ) ) {
2008-05-13 05:03:49 +08:00
php_stream_close ( entry . fp ) ;
efree ( entry . filename ) ;
if ( error ) {
spprintf ( error , 0 , " unable to create stub in tar-based phar \" %s \" " , phar - > fname ) ;
}
return EOF ;
}
} else {
php_stream_close ( entry . fp ) ;
efree ( entry . filename ) ;
}
} else {
2018-06-01 16:58:57 +08:00
zend_hash_str_update_mem ( & phar - > manifest , entry . filename , entry . filename_len , ( void * ) & entry , sizeof ( phar_entry_info ) ) ;
2008-05-13 05:03:49 +08:00
}
}
nostub :
if ( phar - > fp & & ! phar - > is_brandnew ) {
oldfile = phar - > fp ;
closeoldfile = 0 ;
php_stream_rewind ( oldfile ) ;
} else {
oldfile = php_stream_open_wrapper ( phar - > fname , " rb " , 0 , NULL ) ;
closeoldfile = oldfile ! = NULL ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
newfile = php_stream_fopen_tmpfile ( ) ;
if ( ! newfile ) {
if ( error ) {
spprintf ( error , 0 , " unable to create temporary file " ) ;
}
if ( closeoldfile ) {
php_stream_close ( oldfile ) ;
}
return EOF ;
}
pass . old = oldfile ;
pass . new = newfile ;
pass . error = error ;
pass . free_fp = 1 ;
pass . free_ufp = 1 ;
2014-05-08 22:30:07 +08:00
if ( Z_TYPE ( phar - > metadata ) ! = IS_UNDEF ) {
2008-05-16 07:46:29 +08:00
phar_entry_info * mentry ;
2014-05-08 22:30:07 +08:00
if ( NULL ! = ( mentry = zend_hash_str_find_ptr ( & ( phar - > manifest ) , " .phar/.metadata.bin " , sizeof ( " .phar/.metadata.bin " ) - 1 ) ) ) {
2014-12-14 06:06:14 +08:00
if ( ZEND_HASH_APPLY_KEEP ! = phar_tar_setmetadata ( & phar - > metadata , mentry , error ) ) {
2008-05-16 07:46:29 +08:00
if ( closeoldfile ) {
php_stream_close ( oldfile ) ;
}
return EOF ;
}
} else {
phar_entry_info newentry = { 0 } ;
newentry . filename = estrndup ( " .phar/.metadata.bin " , sizeof ( " .phar/.metadata.bin " ) - 1 ) ;
newentry . filename_len = sizeof ( " .phar/.metadata.bin " ) - 1 ;
newentry . phar = phar ;
newentry . tar_type = TAR_FILE ;
newentry . is_tar = 1 ;
2014-05-08 22:30:07 +08:00
if ( NULL = = ( mentry = zend_hash_str_add_mem ( & ( phar - > manifest ) , " .phar/.metadata.bin " , sizeof ( " .phar/.metadata.bin " ) - 1 , ( void * ) & newentry , sizeof ( phar_entry_info ) ) ) ) {
2008-05-16 07:46:29 +08:00
spprintf ( error , 0 , " phar tar error: unable to add magic metadata file to manifest for phar archive \" %s \" " , phar - > fname ) ;
if ( closeoldfile ) {
php_stream_close ( oldfile ) ;
}
return EOF ;
}
2008-08-01 21:48:45 +08:00
2014-12-14 06:06:14 +08:00
if ( ZEND_HASH_APPLY_KEEP ! = phar_tar_setmetadata ( & phar - > metadata , mentry , error ) ) {
2014-05-08 22:30:07 +08:00
zend_hash_str_del ( & ( phar - > manifest ) , " .phar/.metadata.bin " , sizeof ( " .phar/.metadata.bin " ) - 1 ) ;
2008-05-16 07:46:29 +08:00
if ( closeoldfile ) {
php_stream_close ( oldfile ) ;
}
return EOF ;
}
}
}
2008-08-01 21:48:45 +08:00
2014-12-14 06:06:14 +08:00
zend_hash_apply_with_argument ( & phar - > manifest , phar_tar_setupmetadata , ( void * ) & pass ) ;
2008-05-16 07:46:29 +08:00
if ( error & & * error ) {
if ( closeoldfile ) {
php_stream_close ( oldfile ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-16 07:46:29 +08:00
/* on error in the hash iterator above, error is set */
php_stream_close ( newfile ) ;
return EOF ;
}
2014-12-14 06:06:14 +08:00
zend_hash_apply_with_argument ( & phar - > manifest , phar_tar_writeheaders , ( void * ) & pass ) ;
2008-05-13 05:03:49 +08:00
2008-06-14 06:07:44 +08:00
/* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */
if ( ! phar - > is_data | | phar - > sig_flags ) {
2014-12-14 06:06:14 +08:00
if ( FAILURE = = phar_create_signature ( phar , newfile , & signature , & signature_length , error ) ) {
2008-06-14 06:07:44 +08:00
if ( error ) {
char * save = * error ;
spprintf ( error , 0 , " phar error: unable to write signature to tar-based phar: %s " , save ) ;
efree ( save ) ;
}
2008-08-01 21:48:45 +08:00
2008-06-14 06:07:44 +08:00
if ( closeoldfile ) {
php_stream_close ( oldfile ) ;
}
2008-08-01 21:48:45 +08:00
2008-06-14 06:07:44 +08:00
php_stream_close ( newfile ) ;
return EOF ;
}
2008-08-01 21:48:45 +08:00
2008-06-14 06:07:44 +08:00
entry . filename = " .phar/signature.bin " ;
entry . filename_len = sizeof ( " .phar/signature.bin " ) - 1 ;
entry . fp = php_stream_fopen_tmpfile ( ) ;
2013-05-14 22:45:11 +08:00
if ( entry . fp = = NULL ) {
spprintf ( error , 0 , " phar error: unable to create temporary file " ) ;
return EOF ;
}
2008-06-14 06:07:44 +08:00
# ifdef WORDS_BIGENDIAN
# define PHAR_SET_32(var, buffer) \
2016-01-29 00:11:53 +08:00
* ( uint32_t * ) ( var ) = ( ( ( ( ( unsigned char * ) & ( buffer ) ) [ 3 ] ) < < 24 ) \
2009-02-16 02:51:46 +08:00
| ( ( ( ( unsigned char * ) & ( buffer ) ) [ 2 ] ) < < 16 ) \
| ( ( ( ( unsigned char * ) & ( buffer ) ) [ 1 ] ) < < 8 ) \
| ( ( ( unsigned char * ) & ( buffer ) ) [ 0 ] ) )
2008-06-14 06:07:44 +08:00
# else
2016-01-29 00:11:53 +08:00
# define PHAR_SET_32(var, buffer) *(uint32_t *)(var) = (uint32_t) (buffer)
2008-06-14 06:07:44 +08:00
# endif
PHAR_SET_32 ( sigbuf , phar - > sig_flags ) ;
PHAR_SET_32 ( sigbuf + 4 , signature_length ) ;
2008-08-01 21:48:45 +08:00
2018-04-17 21:09:31 +08:00
if ( 8 ! = php_stream_write ( entry . fp , sigbuf , 8 ) | | signature_length ! = php_stream_write ( entry . fp , signature , signature_length ) ) {
2008-06-14 06:07:44 +08:00
efree ( signature ) ;
if ( error ) {
spprintf ( error , 0 , " phar error: unable to write signature to tar-based phar %s " , phar - > fname ) ;
}
2008-08-01 21:48:45 +08:00
2008-06-14 06:07:44 +08:00
if ( closeoldfile ) {
php_stream_close ( oldfile ) ;
}
php_stream_close ( newfile ) ;
return EOF ;
}
2008-08-01 21:48:45 +08:00
efree ( signature ) ;
2008-06-14 06:07:44 +08:00
entry . uncompressed_filesize = entry . compressed_filesize = signature_length + 8 ;
/* throw out return value and write the signature */
2014-12-14 06:06:14 +08:00
entry . filename_len = phar_tar_writeheaders_int ( & entry , ( void * ) & pass ) ;
2008-06-14 06:07:44 +08:00
if ( error & & * error ) {
if ( closeoldfile ) {
php_stream_close ( oldfile ) ;
}
/* error is set by writeheaders */
php_stream_close ( newfile ) ;
return EOF ;
}
} /* signature */
2008-05-13 05:03:49 +08:00
/* add final zero blocks */
buf = ( char * ) ecalloc ( 1024 , 1 ) ;
php_stream_write ( newfile , buf , 1024 ) ;
efree ( buf ) ;
if ( closeoldfile ) {
php_stream_close ( oldfile ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
/* on error in the hash iterator above, error is set */
if ( error & & * error ) {
php_stream_close ( newfile ) ;
return EOF ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( phar - > fp & & pass . free_fp ) {
php_stream_close ( phar - > fp ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( phar - > ufp ) {
if ( pass . free_ufp ) {
php_stream_close ( phar - > ufp ) ;
}
phar - > ufp = NULL ;
}
phar - > is_brandnew = 0 ;
php_stream_rewind ( newfile ) ;
if ( phar - > donotflush ) {
/* deferred flush */
phar - > fp = newfile ;
} else {
phar - > fp = php_stream_open_wrapper ( phar - > fname , " w+b " , IGNORE_URL | STREAM_MUST_SEEK | REPORT_ERRORS , NULL ) ;
if ( ! phar - > fp ) {
phar - > fp = newfile ;
if ( error ) {
spprintf ( error , 0 , " unable to open new phar \" %s \" for writing " , phar - > fname ) ;
}
return EOF ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( phar - > flags & PHAR_FILE_COMPRESSED_GZ ) {
php_stream_filter * filter ;
/* to properly compress, we have to tell zlib to add a zlib header */
zval filterparams ;
array_init ( & filterparams ) ;
/* this is defined in zlib's zconf.h */
# ifndef MAX_WBITS
# define MAX_WBITS 15
# endif
2014-08-26 01:24:55 +08:00
add_assoc_long ( & filterparams , " window " , MAX_WBITS + 16 ) ;
2014-12-14 06:06:14 +08:00
filter = php_stream_filter_create ( " zlib.deflate " , & filterparams , php_stream_is_persistent ( phar - > fp ) ) ;
2018-07-05 18:32:39 +08:00
zend_array_destroy ( Z_ARR ( filterparams ) ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( ! filter ) {
/* copy contents uncompressed rather than lose them */
2013-09-14 03:40:32 +08:00
php_stream_copy_to_stream_ex ( newfile , phar - > fp , PHP_STREAM_COPY_ALL , NULL ) ;
2008-05-13 05:03:49 +08:00
php_stream_close ( newfile ) ;
if ( error ) {
spprintf ( error , 4096 , " unable to compress all contents of phar \" %s \" using zlib, PHP versions older than 5.2.6 have a buggy zlib " , phar - > fname ) ;
}
return EOF ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
php_stream_filter_append ( & phar - > fp - > writefilters , filter ) ;
2013-09-14 03:40:32 +08:00
php_stream_copy_to_stream_ex ( newfile , phar - > fp , PHP_STREAM_COPY_ALL , NULL ) ;
2008-05-13 05:03:49 +08:00
php_stream_filter_flush ( filter , 1 ) ;
2014-12-14 06:06:14 +08:00
php_stream_filter_remove ( filter , 1 ) ;
2008-05-13 05:03:49 +08:00
php_stream_close ( phar - > fp ) ;
/* use the temp stream as our base */
phar - > fp = newfile ;
} else if ( phar - > flags & PHAR_FILE_COMPRESSED_BZ2 ) {
php_stream_filter * filter ;
2014-12-14 06:06:14 +08:00
filter = php_stream_filter_create ( " bzip2.compress " , NULL , php_stream_is_persistent ( phar - > fp ) ) ;
2008-05-13 05:03:49 +08:00
php_stream_filter_append ( & phar - > fp - > writefilters , filter ) ;
2013-09-14 03:40:32 +08:00
php_stream_copy_to_stream_ex ( newfile , phar - > fp , PHP_STREAM_COPY_ALL , NULL ) ;
2008-05-13 05:03:49 +08:00
php_stream_filter_flush ( filter , 1 ) ;
2014-12-14 06:06:14 +08:00
php_stream_filter_remove ( filter , 1 ) ;
2008-05-13 05:03:49 +08:00
php_stream_close ( phar - > fp ) ;
/* use the temp stream as our base */
phar - > fp = newfile ;
} else {
2013-09-14 03:40:32 +08:00
php_stream_copy_to_stream_ex ( newfile , phar - > fp , PHP_STREAM_COPY_ALL , NULL ) ;
2008-05-13 05:03:49 +08:00
/* we could also reopen the file in "rb" mode but there is no need for that */
php_stream_close ( newfile ) ;
}
}
return EOF ;
}
/* }}} */