2008-05-13 05:03:49 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| phar : // stream wrapper support |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
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 . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Authors : Gregory Beaver < cellog @ php . net > |
| Marcus Boerger < helly @ php . net > |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
# define PHAR_DIRSTREAM 1
# include "phar_internal.h"
# include "dirstream.h"
BEGIN_EXTERN_C ( )
2014-12-14 06:06:14 +08:00
void phar_dostat ( phar_archive_data * phar , phar_entry_info * data , php_stream_statbuf * ssb , zend_bool is_dir ) ;
2008-05-13 05:03:49 +08:00
END_EXTERN_C ( )
2017-12-15 03:14:36 +08:00
const php_stream_ops phar_dir_ops = {
2008-05-13 05:03:49 +08:00
phar_dir_write , /* write */
phar_dir_read , /* read */
phar_dir_close , /* close */
phar_dir_flush , /* flush */
" phar dir " ,
phar_dir_seek , /* seek */
NULL , /* cast */
NULL , /* stat */
NULL , /* set option */
} ;
/**
* Used for closedir ( $ fp ) where $ fp is an opendir ( ' phar : //...') directory handle
*/
2014-12-14 06:06:14 +08:00
static int phar_dir_close ( php_stream * stream , int close_handle ) /* { { { */
2008-05-13 05:03:49 +08:00
{
HashTable * data = ( HashTable * ) stream - > abstract ;
2018-12-28 03:35:37 +08:00
if ( data ) {
2008-05-13 05:03:49 +08:00
zend_hash_destroy ( data ) ;
FREE_HASHTABLE ( data ) ;
stream - > abstract = NULL ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
return 0 ;
}
/* }}} */
/**
* Used for seeking on a phar directory handle
*/
2014-12-14 06:06:14 +08:00
static int phar_dir_seek ( php_stream * stream , zend_off_t offset , int whence , zend_off_t * newoffset ) /* { { { */
2008-05-13 05:03:49 +08:00
{
HashTable * data = ( HashTable * ) stream - > abstract ;
2008-08-01 21:48:45 +08:00
if ( ! data ) {
2008-05-13 05:03:49 +08:00
return - 1 ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( whence = = SEEK_END ) {
whence = SEEK_SET ;
offset = zend_hash_num_elements ( data ) + offset ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( whence = = SEEK_SET ) {
zend_hash_internal_pointer_reset ( data ) ;
}
if ( offset < 0 ) {
return - 1 ;
} else {
* newoffset = 0 ;
while ( * newoffset < offset & & zend_hash_move_forward ( data ) = = SUCCESS ) {
+ + ( * newoffset ) ;
}
return 0 ;
}
}
/* }}} */
/**
* Used for readdir ( ) on an opendir ( ) ed phar directory handle
*/
2019-07-18 21:25:59 +08:00
static ssize_t phar_dir_read ( php_stream * stream , char * buf , size_t count ) /* { { { */
2008-05-13 05:03:49 +08:00
{
size_t to_read ;
HashTable * data = ( HashTable * ) stream - > abstract ;
2014-05-08 22:30:07 +08:00
zend_string * str_key ;
2014-08-26 01:24:55 +08:00
zend_ulong unused ;
2008-05-13 05:03:49 +08:00
2014-12-24 05:00:18 +08:00
if ( HASH_KEY_NON_EXISTENT = = zend_hash_get_current_key ( data , & str_key , & unused ) ) {
2008-05-13 05:03:49 +08:00
return 0 ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
zend_hash_move_forward ( data ) ;
2015-06-30 09:05:24 +08:00
to_read = MIN ( ZSTR_LEN ( str_key ) , count ) ;
2008-08-01 21:48:45 +08:00
2015-06-30 09:05:24 +08:00
if ( to_read = = 0 | | count < ZSTR_LEN ( str_key ) ) {
2008-05-13 05:03:49 +08:00
return 0 ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
memset ( buf , 0 , sizeof ( php_stream_dirent ) ) ;
2015-06-30 09:05:24 +08:00
memcpy ( ( ( php_stream_dirent * ) buf ) - > d_name , ZSTR_VAL ( str_key ) , to_read ) ;
2008-05-13 05:03:49 +08:00
( ( php_stream_dirent * ) buf ) - > d_name [ to_read + 1 ] = ' \0 ' ;
return sizeof ( php_stream_dirent ) ;
}
/* }}} */
/**
* Dummy : Used for writing to a phar directory ( i . e . not used )
*/
2019-07-18 21:25:59 +08:00
static ssize_t phar_dir_write ( php_stream * stream , const char * buf , size_t count ) /* { { { */
2008-05-13 05:03:49 +08:00
{
2019-07-18 21:25:59 +08:00
return - 1 ;
2008-05-13 05:03:49 +08:00
}
/* }}} */
/**
* Dummy : Used for flushing writes to a phar directory ( i . e . not used )
*/
2014-12-14 06:06:14 +08:00
static int phar_dir_flush ( php_stream * stream ) /* { { { */
2008-05-13 05:03:49 +08:00
{
return EOF ;
}
/* }}} */
/**
* add an empty element with a char * key to a hash table , avoiding duplicates
*
* This is used to get a unique listing of virtual directories within a phar ,
* for iterating over opendir ( ) ed phar directories .
*/
2016-11-26 22:18:42 +08:00
static int phar_add_empty ( HashTable * ht , char * arKey , uint32_t nKeyLength ) /* { { { */
2008-05-13 05:03:49 +08:00
{
2014-05-08 22:30:07 +08:00
zval dummy ;
2008-05-13 05:03:49 +08:00
2014-05-08 22:30:07 +08:00
ZVAL_NULL ( & dummy ) ;
2018-06-01 16:58:57 +08:00
zend_hash_str_update ( ht , arKey , nKeyLength , & dummy ) ;
return SUCCESS ;
2008-05-13 05:03:49 +08:00
}
/* }}} */
/**
* Used for sorting directories alphabetically
*/
2020-03-04 19:35:49 +08:00
static int phar_compare_dir_name ( Bucket * f , Bucket * s ) /* { { { */
2008-05-13 05:03:49 +08:00
{
2020-03-04 19:35:49 +08:00
int result = zend_binary_strcmp (
ZSTR_VAL ( f - > key ) , ZSTR_LEN ( f - > key ) , ZSTR_VAL ( s - > key ) , ZSTR_LEN ( s - > key ) ) ;
return ZEND_NORMALIZE_BOOL ( result ) ;
2008-05-13 05:03:49 +08:00
}
/* }}} */
/**
* Create a opendir ( ) directory stream handle by iterating over each of the
* files in a phar and retrieving its relative path . From this , construct
* a list of files / directories that are " in " the directory represented by dir
*/
2014-12-14 06:06:14 +08:00
static php_stream * phar_make_dirstream ( char * dir , HashTable * manifest ) /* { { { */
2008-05-13 05:03:49 +08:00
{
HashTable * data ;
2016-06-22 05:40:50 +08:00
size_t dirlen = strlen ( dir ) ;
2014-05-08 22:30:07 +08:00
char * entry , * found , * save ;
zend_string * str_key ;
2018-04-17 21:09:31 +08:00
size_t keylen ;
2014-08-26 01:24:55 +08:00
zend_ulong unused ;
2008-05-15 05:29:51 +08:00
2008-05-13 05:03:49 +08:00
ALLOC_HASHTABLE ( data ) ;
2013-09-14 03:21:23 +08:00
zend_hash_init ( data , 64 , NULL , NULL , 0 ) ;
2008-05-13 05:03:49 +08:00
2008-05-16 00:09:01 +08:00
if ( ( * dir = = ' / ' & & dirlen = = 1 & & ( manifest - > nNumOfElements = = 0 ) ) | | ( dirlen > = sizeof ( " .phar " ) - 1 & & ! memcmp ( dir , " .phar " , sizeof ( " .phar " ) - 1 ) ) ) {
2008-05-13 05:03:49 +08:00
/* make empty root directory for empty phar */
2008-05-16 00:09:01 +08:00
/* make empty directory for .phar magic directory */
2008-05-13 05:03:49 +08:00
efree ( dir ) ;
return php_stream_alloc ( & phar_dir_ops , data , NULL , " r " ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
zend_hash_internal_pointer_reset ( manifest ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
while ( FAILURE ! = zend_hash_has_more_elements ( manifest ) ) {
2015-09-29 12:43:16 +08:00
if ( HASH_KEY_NON_EXISTENT = = zend_hash_get_current_key ( manifest , & str_key , & unused ) ) {
2008-05-13 05:03:49 +08:00
break ;
}
2008-08-01 21:48:45 +08:00
2015-06-30 09:05:24 +08:00
keylen = ZSTR_LEN ( str_key ) ;
2018-04-17 21:09:31 +08:00
if ( keylen < = dirlen ) {
if ( keylen = = 0 | | keylen < dirlen | | ! strncmp ( ZSTR_VAL ( str_key ) , dir , dirlen ) ) {
2008-05-13 05:03:49 +08:00
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
continue ;
}
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( * dir = = ' / ' ) {
/* root directory */
2015-06-30 09:05:24 +08:00
if ( keylen > = sizeof ( " .phar " ) - 1 & & ! memcmp ( ZSTR_VAL ( str_key ) , " .phar " , sizeof ( " .phar " ) - 1 ) ) {
2008-05-16 00:09:01 +08:00
/* do not add any magic entries to this directory */
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
continue ;
}
2008-08-01 21:48:45 +08:00
2015-06-30 09:05:24 +08:00
if ( NULL ! = ( found = ( char * ) memchr ( ZSTR_VAL ( str_key ) , ' / ' , keylen ) ) ) {
2008-05-13 05:03:49 +08:00
/* the entry has a path separator and is a subdirectory */
2015-06-30 09:05:24 +08:00
entry = ( char * ) safe_emalloc ( found - ZSTR_VAL ( str_key ) , 1 , 1 ) ;
memcpy ( entry , ZSTR_VAL ( str_key ) , found - ZSTR_VAL ( str_key ) ) ;
keylen = found - ZSTR_VAL ( str_key ) ;
2008-05-13 05:03:49 +08:00
entry [ keylen ] = ' \0 ' ;
} else {
entry = ( char * ) safe_emalloc ( keylen , 1 , 1 ) ;
2015-06-30 09:05:24 +08:00
memcpy ( entry , ZSTR_VAL ( str_key ) , keylen ) ;
2008-05-13 05:03:49 +08:00
entry [ keylen ] = ' \0 ' ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
goto PHAR_ADD_ENTRY ;
} else {
2015-06-30 09:05:24 +08:00
if ( 0 ! = memcmp ( ZSTR_VAL ( str_key ) , dir , dirlen ) ) {
2008-05-13 05:03:49 +08:00
/* entry in directory not found */
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
continue ;
} else {
2015-06-30 09:05:24 +08:00
if ( ZSTR_VAL ( str_key ) [ dirlen ] ! = ' / ' ) {
2008-05-13 05:03:49 +08:00
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
continue ;
}
}
}
2008-08-01 21:48:45 +08:00
2015-06-30 09:05:24 +08:00
save = ZSTR_VAL ( str_key ) ;
2008-05-13 05:03:49 +08:00
save + = dirlen + 1 ; /* seek to just past the path separator */
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( NULL ! = ( found = ( char * ) memchr ( save , ' / ' , keylen - dirlen - 1 ) ) ) {
/* is subdirectory */
save - = dirlen + 1 ;
entry = ( char * ) safe_emalloc ( found - save + dirlen , 1 , 1 ) ;
memcpy ( entry , save + dirlen + 1 , found - save - dirlen - 1 ) ;
keylen = found - save - dirlen - 1 ;
entry [ keylen ] = ' \0 ' ;
} else {
/* is file */
save - = dirlen + 1 ;
entry = ( char * ) safe_emalloc ( keylen - dirlen , 1 , 1 ) ;
memcpy ( entry , save + dirlen + 1 , keylen - dirlen - 1 ) ;
entry [ keylen - dirlen - 1 ] = ' \0 ' ;
keylen = keylen - dirlen - 1 ;
}
PHAR_ADD_ENTRY :
if ( keylen ) {
phar_add_empty ( data , entry , keylen ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
efree ( entry ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( FAILURE ! = zend_hash_has_more_elements ( data ) ) {
efree ( dir ) ;
2019-03-11 19:55:25 +08:00
zend_hash_sort ( data , phar_compare_dir_name , 0 ) ;
2008-05-13 05:03:49 +08:00
return php_stream_alloc ( & phar_dir_ops , data , NULL , " r " ) ;
} else {
efree ( dir ) ;
return php_stream_alloc ( & phar_dir_ops , data , NULL , " r " ) ;
}
}
/* }}}*/
/**
* Open a directory handle within a phar archive
*/
2015-03-04 07:05:28 +08:00
php_stream * phar_wrapper_open_dir ( php_stream_wrapper * wrapper , const char * path , const char * mode , int options , zend_string * * opened_path , php_stream_context * context STREAMS_DC ) /* { { { */
2008-05-13 05:03:49 +08:00
{
php_url * resource = NULL ;
php_stream * ret ;
2014-05-08 22:30:07 +08:00
char * internal_file , * error ;
zend_string * str_key ;
2014-08-26 01:24:55 +08:00
zend_ulong unused ;
2008-05-13 05:03:49 +08:00
phar_archive_data * phar ;
phar_entry_info * entry = NULL ;
2016-11-26 22:18:42 +08:00
uint32_t host_len ;
2008-05-13 05:03:49 +08:00
2014-12-14 06:06:14 +08:00
if ( ( resource = phar_parse_url ( wrapper , path , mode , options ) ) = = NULL ) {
php_stream_wrapper_log_error ( wrapper , options , " phar url \" %s \" is unknown " , path ) ;
2008-05-13 05:03:49 +08:00
return NULL ;
}
/* we must have at the very least phar://alias.phar/ */
if ( ! resource - > scheme | | ! resource - > host | | ! resource - > path ) {
if ( resource - > host & & ! resource - > path ) {
2017-08-06 17:48:05 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: no directory in \" %s \" , must have at least phar://%s/ for root directory (always use full path to a new phar) " , path , ZSTR_VAL ( resource - > host ) ) ;
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
return NULL ;
}
php_url_free ( resource ) ;
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: invalid url \" %s \" , must have at least phar://%s/ " , path , path ) ;
2008-05-13 05:03:49 +08:00
return NULL ;
}
2017-08-06 17:48:05 +08:00
if ( ! zend_string_equals_literal_ci ( resource - > scheme , " phar " ) ) {
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: not a phar url \" %s \" " , path ) ;
2008-05-13 05:03:49 +08:00
return NULL ;
}
2017-08-06 17:48:05 +08:00
host_len = ZSTR_LEN ( resource - > host ) ;
2014-12-14 06:06:14 +08:00
phar_request_initialize ( ) ;
2017-08-06 17:48:05 +08:00
internal_file = ZSTR_VAL ( resource - > path ) + 1 ; /* strip leading "/" */
2008-08-01 21:48:45 +08:00
2017-08-06 17:48:05 +08:00
if ( FAILURE = = phar_get_archive ( & phar , ZSTR_VAL ( resource - > host ) , host_len , NULL , 0 , & error ) ) {
2008-05-13 05:03:49 +08:00
if ( error ) {
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " %s " , error ) ;
2008-05-13 05:03:49 +08:00
efree ( error ) ;
} else {
2017-08-06 17:48:05 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar file \" %s \" is unknown " , ZSTR_VAL ( resource - > host ) ) ;
2008-05-13 05:03:49 +08:00
}
php_url_free ( resource ) ;
return NULL ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( error ) {
efree ( error ) ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( * internal_file = = ' \0 ' ) {
/* root directory requested */
internal_file = estrndup ( internal_file - 1 , 1 ) ;
2014-12-14 06:06:14 +08:00
ret = phar_make_dirstream ( internal_file , & phar - > manifest ) ;
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
return ret ;
}
2008-08-01 21:48:45 +08:00
2018-12-28 03:48:25 +08:00
if ( ! HT_IS_INITIALIZED ( & phar - > manifest ) ) {
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
return NULL ;
}
2008-08-01 21:48:45 +08:00
2014-05-08 22:30:07 +08:00
if ( NULL ! = ( entry = zend_hash_str_find_ptr ( & phar - > manifest , internal_file , strlen ( internal_file ) ) ) & & ! entry - > is_dir ) {
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
return NULL ;
} else if ( entry & & entry - > is_dir ) {
if ( entry - > is_mounted ) {
php_url_free ( resource ) ;
return php_stream_opendir ( entry - > tmp , options , context ) ;
}
internal_file = estrdup ( internal_file ) ;
php_url_free ( resource ) ;
2014-12-14 06:06:14 +08:00
return phar_make_dirstream ( internal_file , & phar - > manifest ) ;
2008-05-13 05:03:49 +08:00
} else {
2018-04-17 21:09:31 +08:00
size_t i_len = strlen ( internal_file ) ;
2008-05-13 05:03:49 +08:00
/* search for directory */
zend_hash_internal_pointer_reset ( & phar - > manifest ) ;
while ( FAILURE ! = zend_hash_has_more_elements ( & phar - > manifest ) ) {
2015-01-03 17:22:58 +08:00
if ( HASH_KEY_NON_EXISTENT ! =
2014-12-24 05:00:18 +08:00
zend_hash_get_current_key ( & phar - > manifest , & str_key , & unused ) ) {
2018-04-17 21:09:31 +08:00
if ( ZSTR_LEN ( str_key ) > i_len & & 0 = = memcmp ( ZSTR_VAL ( str_key ) , internal_file , i_len ) ) {
2008-05-13 05:03:49 +08:00
/* directory found */
internal_file = estrndup ( internal_file ,
i_len ) ;
php_url_free ( resource ) ;
2014-12-14 06:06:14 +08:00
return phar_make_dirstream ( internal_file , & phar - > manifest ) ;
2008-05-13 05:03:49 +08:00
}
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( SUCCESS ! = zend_hash_move_forward ( & phar - > manifest ) ) {
break ;
}
}
}
php_url_free ( resource ) ;
return NULL ;
}
/* }}} */
/**
* Make a new directory within a phar archive
*/
2014-12-14 06:06:14 +08:00
int phar_wrapper_mkdir ( php_stream_wrapper * wrapper , const char * url_from , int mode , int options , php_stream_context * context ) /* { { { */
2008-05-13 05:03:49 +08:00
{
phar_entry_info entry , * e ;
phar_archive_data * phar = NULL ;
char * error , * arch , * entry2 ;
2018-04-17 21:09:31 +08:00
size_t arch_len , entry_len ;
2008-05-13 05:03:49 +08:00
php_url * resource = NULL ;
2016-11-26 22:18:42 +08:00
uint32_t host_len ;
2008-05-13 05:03:49 +08:00
/* pre-readonly check, we need to know if this is a data phar */
2014-12-14 06:06:14 +08:00
if ( FAILURE = = phar_split_fname ( url_from , strlen ( url_from ) , & arch , & arch_len , & entry2 , & entry_len , 2 , 2 ) ) {
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot create directory \" %s \" , no phar archive specified " , url_from ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2008-08-01 21:48:45 +08:00
2014-12-14 06:06:14 +08:00
if ( FAILURE = = phar_get_archive ( & phar , arch , arch_len , NULL , 0 , NULL ) ) {
2008-05-13 05:03:49 +08:00
phar = NULL ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
efree ( arch ) ;
efree ( entry2 ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( PHAR_G ( readonly ) & & ( ! phar | | ! phar - > is_data ) ) {
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot create directory \" %s \" , write operations disabled " , url_from ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2014-12-14 06:06:14 +08:00
if ( ( resource = phar_parse_url ( wrapper , url_from , " w " , options ) ) = = NULL ) {
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
/* we must have at the very least phar://alias.phar/internalfile.php */
if ( ! resource - > scheme | | ! resource - > host | | ! resource - > path ) {
php_url_free ( resource ) ;
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: invalid url \" %s \" " , url_from ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2017-08-06 17:48:05 +08:00
if ( ! zend_string_equals_literal_ci ( resource - > scheme , " phar " ) ) {
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: not a phar stream url \" %s \" " , url_from ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2017-08-06 17:48:05 +08:00
host_len = ZSTR_LEN ( resource - > host ) ;
2008-05-13 05:03:49 +08:00
2017-08-06 17:48:05 +08:00
if ( FAILURE = = phar_get_archive ( & phar , ZSTR_VAL ( resource - > host ) , host_len , NULL , 0 , & error ) ) {
2017-11-16 19:29:27 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot create directory \" %s \" in phar \" %s \" , error retrieving phar information: %s " , ZSTR_VAL ( resource - > path ) + 1 , ZSTR_VAL ( resource - > host ) , error ) ;
2008-05-13 05:03:49 +08:00
efree ( error ) ;
php_url_free ( resource ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2017-08-06 17:48:05 +08:00
if ( ( e = phar_get_entry_info_dir ( phar , ZSTR_VAL ( resource - > path ) + 1 , ZSTR_LEN ( resource - > path ) - 1 , 2 , & error , 1 ) ) ) {
2008-05-13 05:03:49 +08:00
/* directory exists, or is a subdirectory of an existing file */
if ( e - > is_temp_dir ) {
efree ( e - > filename ) ;
efree ( e ) ;
}
2017-08-06 17:48:05 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot create directory \" %s \" in phar \" %s \" , directory already exists " , ZSTR_VAL ( resource - > path ) + 1 , ZSTR_VAL ( resource - > host ) ) ;
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( error ) {
2017-08-06 17:48:05 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot create directory \" %s \" in phar \" %s \" , %s " , ZSTR_VAL ( resource - > path ) + 1 , ZSTR_VAL ( resource - > host ) , error ) ;
2008-05-13 05:03:49 +08:00
efree ( error ) ;
php_url_free ( resource ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2008-08-01 21:48:45 +08:00
2017-08-06 17:48:05 +08:00
if ( phar_get_entry_info_dir ( phar , ZSTR_VAL ( resource - > path ) + 1 , ZSTR_LEN ( resource - > path ) - 1 , 0 , & error , 1 ) ) {
2008-05-13 05:03:49 +08:00
/* entry exists as a file */
2017-08-06 17:48:05 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot create directory \" %s \" in phar \" %s \" , file already exists " , ZSTR_VAL ( resource - > path ) + 1 , ZSTR_VAL ( resource - > host ) ) ;
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( error ) {
2017-08-06 17:48:05 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot create directory \" %s \" in phar \" %s \" , %s " , ZSTR_VAL ( resource - > path ) + 1 , ZSTR_VAL ( resource - > host ) , error ) ;
2008-05-13 05:03:49 +08:00
efree ( error ) ;
php_url_free ( resource ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
memset ( ( void * ) & entry , 0 , sizeof ( phar_entry_info ) ) ;
/* strip leading "/" */
if ( phar - > is_zip ) {
entry . is_zip = 1 ;
}
2008-08-01 21:48:45 +08:00
2017-08-06 17:48:05 +08:00
entry . filename = estrdup ( ZSTR_VAL ( resource - > path ) + 1 ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( phar - > is_tar ) {
entry . is_tar = 1 ;
entry . tar_type = TAR_DIR ;
}
2008-08-01 21:48:45 +08:00
2017-08-06 17:48:05 +08:00
entry . filename_len = ZSTR_LEN ( resource - > path ) - 1 ;
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
entry . is_dir = 1 ;
entry . phar = phar ;
entry . is_modified = 1 ;
entry . is_crc_checked = 1 ;
entry . flags = PHAR_ENT_PERM_DEF_DIR ;
entry . old_flags = PHAR_ENT_PERM_DEF_DIR ;
2008-08-01 21:48:45 +08:00
2014-05-08 22:30:07 +08:00
if ( NULL = = zend_hash_str_add_mem ( & phar - > manifest , entry . filename , entry . filename_len , ( void * ) & entry , sizeof ( phar_entry_info ) ) ) {
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot create directory \" %s \" in phar \" %s \" , adding to manifest failed " , entry . filename , phar - > fname ) ;
2008-05-13 05:03:49 +08:00
efree ( error ) ;
efree ( entry . filename ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2008-08-01 21:48:45 +08:00
2014-12-14 06:06:14 +08:00
phar_flush ( phar , 0 , 0 , 0 , & error ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( error ) {
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot create directory \" %s \" in phar \" %s \" , %s " , entry . filename , phar - > fname , error ) ;
2014-05-08 22:30:07 +08:00
zend_hash_str_del ( & phar - > manifest , entry . filename , entry . filename_len ) ;
2008-05-13 05:03:49 +08:00
efree ( error ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2008-08-01 21:48:45 +08:00
2014-12-14 06:06:14 +08:00
phar_add_virtual_dirs ( phar , entry . filename , entry . filename_len ) ;
2008-07-20 22:42:34 +08:00
return 1 ;
2008-05-13 05:03:49 +08:00
}
/* }}} */
/**
* Remove a directory within a phar archive
*/
2014-12-14 06:06:14 +08:00
int phar_wrapper_rmdir ( php_stream_wrapper * wrapper , const char * url , int options , php_stream_context * context ) /* { { { */
2008-05-13 05:03:49 +08:00
{
phar_entry_info * entry ;
phar_archive_data * phar = NULL ;
char * error , * arch , * entry2 ;
2018-04-17 21:09:31 +08:00
size_t arch_len , entry_len ;
2008-05-13 05:03:49 +08:00
php_url * resource = NULL ;
2016-11-26 22:18:42 +08:00
uint32_t host_len ;
2014-05-08 22:30:07 +08:00
zend_string * str_key ;
2014-08-26 01:24:55 +08:00
zend_ulong unused ;
2016-11-26 22:18:42 +08:00
uint32_t path_len ;
2008-05-13 05:03:49 +08:00
/* pre-readonly check, we need to know if this is a data phar */
2014-12-14 06:06:14 +08:00
if ( FAILURE = = phar_split_fname ( url , strlen ( url ) , & arch , & arch_len , & entry2 , & entry_len , 2 , 2 ) ) {
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot remove directory \" %s \" , no phar archive specified, or phar archive does not exist " , url ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2008-08-01 21:48:45 +08:00
2014-12-14 06:06:14 +08:00
if ( FAILURE = = phar_get_archive ( & phar , arch , arch_len , NULL , 0 , NULL ) ) {
2008-05-13 05:03:49 +08:00
phar = NULL ;
}
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
efree ( arch ) ;
efree ( entry2 ) ;
2008-08-01 21:48:45 +08:00
2008-05-13 05:03:49 +08:00
if ( PHAR_G ( readonly ) & & ( ! phar | | ! phar - > is_data ) ) {
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot rmdir directory \" %s \" , write operations disabled " , url ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2014-12-14 06:06:14 +08:00
if ( ( resource = phar_parse_url ( wrapper , url , " w " , options ) ) = = NULL ) {
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
/* we must have at the very least phar://alias.phar/internalfile.php */
if ( ! resource - > scheme | | ! resource - > host | | ! resource - > path ) {
php_url_free ( resource ) ;
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: invalid url \" %s \" " , url ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2017-08-06 17:48:05 +08:00
if ( ! zend_string_equals_literal_ci ( resource - > scheme , " phar " ) ) {
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: not a phar stream url \" %s \" " , url ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2017-08-06 17:48:05 +08:00
host_len = ZSTR_LEN ( resource - > host ) ;
2008-05-13 05:03:49 +08:00
2017-08-06 17:48:05 +08:00
if ( FAILURE = = phar_get_archive ( & phar , ZSTR_VAL ( resource - > host ) , host_len , NULL , 0 , & error ) ) {
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot remove directory \" %s \" in phar \" %s \" , error retrieving phar information: %s " , ZSTR_VAL ( resource - > path ) + 1 , ZSTR_VAL ( resource - > host ) , error ) ;
2008-05-13 05:03:49 +08:00
efree ( error ) ;
php_url_free ( resource ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2017-08-06 17:48:05 +08:00
path_len = ZSTR_LEN ( resource - > path ) - 1 ;
2008-08-01 21:48:45 +08:00
2017-08-06 17:48:05 +08:00
if ( ! ( entry = phar_get_entry_info_dir ( phar , ZSTR_VAL ( resource - > path ) + 1 , path_len , 2 , & error , 1 ) ) ) {
2008-05-13 05:03:49 +08:00
if ( error ) {
2017-08-06 17:48:05 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot remove directory \" %s \" in phar \" %s \" , %s " , ZSTR_VAL ( resource - > path ) + 1 , ZSTR_VAL ( resource - > host ) , error ) ;
2008-05-13 05:03:49 +08:00
efree ( error ) ;
} else {
2017-08-06 17:48:05 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot remove directory \" %s \" in phar \" %s \" , directory does not exist " , ZSTR_VAL ( resource - > path ) + 1 , ZSTR_VAL ( resource - > host ) ) ;
2008-05-13 05:03:49 +08:00
}
php_url_free ( resource ) ;
2008-07-20 22:42:34 +08:00
return 0 ;
2008-05-13 05:03:49 +08:00
}
2008-10-13 03:40:11 +08:00
if ( ! entry - > is_deleted ) {
for ( zend_hash_internal_pointer_reset ( & phar - > manifest ) ;
2014-12-24 05:00:18 +08:00
HASH_KEY_NON_EXISTENT ! = zend_hash_get_current_key ( & phar - > manifest , & str_key , & unused ) ;
2013-09-14 03:21:23 +08:00
zend_hash_move_forward ( & phar - > manifest )
) {
2015-06-30 09:05:24 +08:00
if ( ZSTR_LEN ( str_key ) > path_len & &
2017-08-06 17:48:05 +08:00
memcmp ( ZSTR_VAL ( str_key ) , ZSTR_VAL ( resource - > path ) + 1 , path_len ) = = 0 & &
2015-06-30 09:05:24 +08:00
IS_SLASH ( ZSTR_VAL ( str_key ) [ path_len ] ) ) {
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: Directory not empty " ) ;
2008-10-13 03:40:11 +08:00
if ( entry - > is_temp_dir ) {
efree ( entry - > filename ) ;
efree ( entry ) ;
}
php_url_free ( resource ) ;
return 0 ;
2008-07-20 22:42:34 +08:00
}
}
2008-10-13 03:40:11 +08:00
for ( zend_hash_internal_pointer_reset ( & phar - > virtual_dirs ) ;
2014-12-24 05:00:18 +08:00
HASH_KEY_NON_EXISTENT ! = zend_hash_get_current_key ( & phar - > virtual_dirs , & str_key , & unused ) ;
2008-10-13 03:40:11 +08:00
zend_hash_move_forward ( & phar - > virtual_dirs ) ) {
2015-01-03 17:22:58 +08:00
2015-06-30 09:05:24 +08:00
if ( ZSTR_LEN ( str_key ) > path_len & &
2017-08-06 17:48:05 +08:00
memcmp ( ZSTR_VAL ( str_key ) , ZSTR_VAL ( resource - > path ) + 1 , path_len ) = = 0 & &
2015-06-30 09:05:24 +08:00
IS_SLASH ( ZSTR_VAL ( str_key ) [ path_len ] ) ) {
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: Directory not empty " ) ;
2008-10-13 03:40:11 +08:00
if ( entry - > is_temp_dir ) {
efree ( entry - > filename ) ;
efree ( entry ) ;
}
php_url_free ( resource ) ;
return 0 ;
2008-07-20 22:42:34 +08:00
}
}
}
if ( entry - > is_temp_dir ) {
2017-08-06 17:48:05 +08:00
zend_hash_str_del ( & phar - > virtual_dirs , ZSTR_VAL ( resource - > path ) + 1 , path_len ) ;
2008-07-20 22:42:34 +08:00
efree ( entry - > filename ) ;
efree ( entry ) ;
} else {
entry - > is_deleted = 1 ;
entry - > is_modified = 1 ;
2014-12-14 06:06:14 +08:00
phar_flush ( phar , 0 , 0 , 0 , & error ) ;
2008-07-20 22:42:34 +08:00
if ( error ) {
2014-12-14 06:06:14 +08:00
php_stream_wrapper_log_error ( wrapper , options , " phar error: cannot remove directory \" %s \" in phar \" %s \" , %s " , entry - > filename , phar - > fname , error ) ;
2008-07-20 22:42:34 +08:00
php_url_free ( resource ) ;
efree ( error ) ;
return 0 ;
}
}
2008-05-13 05:03:49 +08:00
php_url_free ( resource ) ;
2008-07-20 22:42:34 +08:00
return 1 ;
2008-05-13 05:03:49 +08:00
}
/* }}} */