2008-05-12 21:03:49 +00:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| phar : // stream wrapper support |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2008-12-31 11:15:49 +00:00
| Copyright ( c ) 2005 - 2009 The PHP Group |
2008-05-12 21:03:49 +00: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 ( )
2008-09-13 22:30:55 +00:00
void phar_dostat ( phar_archive_data * phar , phar_entry_info * data , php_stream_statbuf * ssb , zend_bool is_dir TSRMLS_DC ) ;
2008-05-12 21:03:49 +00:00
END_EXTERN_C ( )
php_stream_ops phar_dir_ops = {
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
*/
static int phar_dir_close ( php_stream * stream , int close_handle TSRMLS_DC ) /* { { { */
{
HashTable * data = ( HashTable * ) stream - > abstract ;
2008-08-01 13:48:45 +00:00
if ( data & & data - > arBuckets ) {
2008-05-12 21:03:49 +00:00
zend_hash_destroy ( data ) ;
data - > arBuckets = 0 ;
FREE_HASHTABLE ( data ) ;
stream - > abstract = NULL ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
return 0 ;
}
/* }}} */
/**
* Used for seeking on a phar directory handle
*/
static int phar_dir_seek ( php_stream * stream , off_t offset , int whence , off_t * newoffset TSRMLS_DC ) /* { { { */
{
HashTable * data = ( HashTable * ) stream - > abstract ;
2008-08-01 13:48:45 +00:00
if ( ! data ) {
2008-05-12 21:03:49 +00:00
return - 1 ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( whence = = SEEK_END ) {
whence = SEEK_SET ;
offset = zend_hash_num_elements ( data ) + offset ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00: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
*/
static size_t phar_dir_read ( php_stream * stream , char * buf , size_t count TSRMLS_DC ) /* { { { */
{
size_t to_read ;
HashTable * data = ( HashTable * ) stream - > abstract ;
2008-05-14 21:29:51 +00:00
phar_zstr key ;
char * str_key ;
2008-05-12 21:03:49 +00:00
uint keylen ;
ulong unused ;
if ( FAILURE = = zend_hash_has_more_elements ( data ) ) {
return 0 ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( HASH_KEY_NON_EXISTANT = = zend_hash_get_current_key_ex ( data , & key , & keylen , & unused , 0 , NULL ) ) {
return 0 ;
}
2008-08-01 13:48:45 +00:00
2008-05-14 21:29:51 +00:00
PHAR_STR ( key , str_key ) ;
2008-05-12 21:03:49 +00:00
zend_hash_move_forward ( data ) ;
to_read = MIN ( keylen , count ) ;
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( to_read = = 0 | | count < keylen ) {
return 0 ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
memset ( buf , 0 , sizeof ( php_stream_dirent ) ) ;
2008-05-14 21:29:51 +00:00
memcpy ( ( ( php_stream_dirent * ) buf ) - > d_name , str_key , to_read ) ;
2008-05-12 21:03:49 +00: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 )
*/
static size_t phar_dir_write ( php_stream * stream , const char * buf , size_t count TSRMLS_DC ) /* { { { */
{
return 0 ;
}
/* }}} */
/**
* Dummy : Used for flushing writes to a phar directory ( i . e . not used )
*/
static int phar_dir_flush ( php_stream * stream TSRMLS_DC ) /* { { { */
{
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 .
*/
static int phar_add_empty ( HashTable * ht , char * arKey , uint nKeyLength ) /* { { { */
{
2008-06-18 06:38:47 +00:00
void * dummy = ( char * ) 1 ;
2008-05-12 21:03:49 +00:00
2008-06-18 06:38:47 +00:00
return zend_hash_update ( ht , arKey , nKeyLength , ( void * ) & dummy , sizeof ( void * ) , NULL ) ;
2008-05-12 21:03:49 +00:00
}
/* }}} */
/**
* Used for sorting directories alphabetically
*/
static int phar_compare_dir_name ( const void * a , const void * b TSRMLS_DC ) /* { { { */
{
Bucket * f ;
Bucket * s ;
int result ;
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
f = * ( ( Bucket * * ) a ) ;
s = * ( ( Bucket * * ) b ) ;
# if (PHP_MAJOR_VERSION < 6)
result = zend_binary_strcmp ( f - > arKey , f - > nKeyLength , s - > arKey , s - > nKeyLength ) ;
# else
result = zend_binary_strcmp ( f - > key . arKey . s , f - > nKeyLength , s - > key . arKey . s , s - > nKeyLength ) ;
# endif
if ( result < 0 ) {
return - 1 ;
} else if ( result > 0 ) {
return 1 ;
} else {
return 0 ;
}
}
/* }}} */
/**
* 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
*/
static php_stream * phar_make_dirstream ( char * dir , HashTable * manifest TSRMLS_DC ) /* { { { */
{
HashTable * data ;
int dirlen = strlen ( dir ) ;
2008-05-14 21:29:51 +00:00
phar_zstr key ;
char * entry , * found , * save , * str_key ;
2008-05-12 21:03:49 +00:00
uint keylen ;
ulong unused ;
2008-05-14 21:29:51 +00:00
2008-05-12 21:03:49 +00:00
ALLOC_HASHTABLE ( data ) ;
zend_hash_init ( data , 64 , zend_get_hash_value , NULL , 0 ) ;
2008-05-15 16:09:01 +00:00
if ( ( * dir = = ' / ' & & dirlen = = 1 & & ( manifest - > nNumOfElements = = 0 ) ) | | ( dirlen > = sizeof ( " .phar " ) - 1 & & ! memcmp ( dir , " .phar " , sizeof ( " .phar " ) - 1 ) ) ) {
2008-05-12 21:03:49 +00:00
/* make empty root directory for empty phar */
2008-05-15 16:09:01 +00:00
/* make empty directory for .phar magic directory */
2008-05-12 21:03:49 +00:00
efree ( dir ) ;
return php_stream_alloc ( & phar_dir_ops , data , NULL , " r " ) ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
zend_hash_internal_pointer_reset ( manifest ) ;
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
while ( FAILURE ! = zend_hash_has_more_elements ( manifest ) ) {
if ( HASH_KEY_NON_EXISTANT = = zend_hash_get_current_key_ex ( manifest , & key , & keylen , & unused , 0 , NULL ) ) {
break ;
}
2008-08-01 13:48:45 +00:00
2008-05-14 21:29:51 +00:00
PHAR_STR ( key , str_key ) ;
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( keylen < = ( uint ) dirlen ) {
2008-05-14 21:29:51 +00:00
if ( keylen < ( uint ) dirlen | | ! strncmp ( str_key , dir , dirlen ) ) {
2008-05-12 21:03:49 +00:00
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
continue ;
}
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( * dir = = ' / ' ) {
/* root directory */
2008-05-15 16:09:01 +00:00
if ( keylen > = sizeof ( " .phar " ) - 1 & & ! memcmp ( str_key , " .phar " , sizeof ( " .phar " ) - 1 ) ) {
/* do not add any magic entries to this directory */
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
continue ;
}
2008-08-01 13:48:45 +00:00
2008-05-14 21:29:51 +00:00
if ( NULL ! = ( found = ( char * ) memchr ( str_key , ' / ' , keylen ) ) ) {
2008-05-12 21:03:49 +00:00
/* the entry has a path separator and is a subdirectory */
2008-05-14 21:29:51 +00:00
entry = ( char * ) safe_emalloc ( found - str_key , 1 , 1 ) ;
memcpy ( entry , str_key , found - str_key ) ;
keylen = found - str_key ;
2008-05-12 21:03:49 +00:00
entry [ keylen ] = ' \0 ' ;
} else {
entry = ( char * ) safe_emalloc ( keylen , 1 , 1 ) ;
2008-05-14 21:29:51 +00:00
memcpy ( entry , str_key , keylen ) ;
2008-05-12 21:03:49 +00:00
entry [ keylen ] = ' \0 ' ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
goto PHAR_ADD_ENTRY ;
} else {
2008-05-14 21:29:51 +00:00
if ( 0 ! = memcmp ( str_key , dir , dirlen ) ) {
2008-05-12 21:03:49 +00:00
/* entry in directory not found */
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
continue ;
} else {
2008-05-14 21:29:51 +00:00
if ( str_key [ dirlen ] ! = ' / ' ) {
2008-05-12 21:03:49 +00:00
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
continue ;
}
}
}
2008-08-01 13:48:45 +00:00
2008-05-14 21:29:51 +00:00
save = str_key ;
2008-05-12 21:03:49 +00:00
save + = dirlen + 1 ; /* seek to just past the path separator */
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00: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 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
efree ( entry ) ;
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( SUCCESS ! = zend_hash_move_forward ( manifest ) ) {
break ;
}
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( FAILURE ! = zend_hash_has_more_elements ( data ) ) {
efree ( dir ) ;
if ( zend_hash_sort ( data , zend_qsort , phar_compare_dir_name , 0 TSRMLS_CC ) = = FAILURE ) {
FREE_HASHTABLE ( data ) ;
return NULL ;
}
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
*/
2008-08-01 13:48:45 +00:00
php_stream * phar_wrapper_open_dir ( php_stream_wrapper * wrapper , char * path , char * mode , int options , char * * opened_path , php_stream_context * context STREAMS_DC TSRMLS_DC ) /* { { { */
2008-05-12 21:03:49 +00:00
{
php_url * resource = NULL ;
php_stream * ret ;
2008-05-14 21:29:51 +00:00
char * internal_file , * error , * str_key ;
phar_zstr key ;
2008-05-12 21:03:49 +00:00
uint keylen ;
ulong unused ;
phar_archive_data * phar ;
phar_entry_info * entry = NULL ;
uint host_len ;
2008-05-30 22:38:46 +00:00
if ( ( resource = phar_parse_url ( wrapper , path , mode , options TSRMLS_CC ) ) = = NULL ) {
2008-05-12 21:03:49 +00:00
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar url \" %s \" is unknown " , path ) ;
return NULL ;
}
/* we must have at the very least phar://alias.phar/ */
if ( ! resource - > scheme | | ! resource - > host | | ! resource - > path ) {
if ( resource - > host & & ! resource - > path ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: no directory in \" %s \" , must have at least phar://%s/ for root directory (always use full path to a new phar) " , path , resource - > host ) ;
php_url_free ( resource ) ;
return NULL ;
}
php_url_free ( resource ) ;
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: invalid url \" %s \" , must have at least phar://%s/ " , path , path ) ;
return NULL ;
}
if ( strcasecmp ( " phar " , resource - > scheme ) ) {
php_url_free ( resource ) ;
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: not a phar url \" %s \" " , path ) ;
return NULL ;
}
host_len = strlen ( resource - > host ) ;
phar_request_initialize ( TSRMLS_C ) ;
internal_file = resource - > path + 1 ; /* strip leading "/" */
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( FAILURE = = phar_get_archive ( & phar , resource - > host , host_len , NULL , 0 , & error TSRMLS_CC ) ) {
if ( error ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , error ) ;
efree ( error ) ;
} else {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar file \" %s \" is unknown " , resource - > host ) ;
}
php_url_free ( resource ) ;
return NULL ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( error ) {
efree ( error ) ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( * internal_file = = ' \0 ' ) {
/* root directory requested */
internal_file = estrndup ( internal_file - 1 , 1 ) ;
ret = phar_make_dirstream ( internal_file , & phar - > manifest TSRMLS_CC ) ;
php_url_free ( resource ) ;
return ret ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( ! phar - > manifest . arBuckets ) {
php_url_free ( resource ) ;
return NULL ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( SUCCESS = = zend_hash_find ( & phar - > manifest , internal_file , strlen ( internal_file ) , ( void * * ) & entry ) & & ! entry - > is_dir ) {
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 ) ;
return phar_make_dirstream ( internal_file , & phar - > manifest TSRMLS_CC ) ;
} else {
int i_len = strlen ( internal_file ) ;
/* search for directory */
zend_hash_internal_pointer_reset ( & phar - > manifest ) ;
while ( FAILURE ! = zend_hash_has_more_elements ( & phar - > manifest ) ) {
if ( HASH_KEY_NON_EXISTANT ! =
zend_hash_get_current_key_ex (
& phar - > manifest , & key , & keylen , & unused , 0 , NULL ) ) {
2008-05-14 21:29:51 +00:00
PHAR_STR ( key , str_key ) ;
if ( keylen > ( uint ) i_len & & 0 = = memcmp ( str_key , internal_file , i_len ) ) {
2008-05-12 21:03:49 +00:00
/* directory found */
internal_file = estrndup ( internal_file ,
i_len ) ;
php_url_free ( resource ) ;
return phar_make_dirstream ( internal_file , & phar - > manifest TSRMLS_CC ) ;
}
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( SUCCESS ! = zend_hash_move_forward ( & phar - > manifest ) ) {
break ;
}
}
}
php_url_free ( resource ) ;
return NULL ;
}
/* }}} */
/**
* Make a new directory within a phar archive
*/
int phar_wrapper_mkdir ( php_stream_wrapper * wrapper , char * url_from , int mode , int options , php_stream_context * context TSRMLS_DC ) /* { { { */
{
phar_entry_info entry , * e ;
phar_archive_data * phar = NULL ;
char * error , * arch , * entry2 ;
int arch_len , entry_len ;
php_url * resource = NULL ;
uint host_len ;
/* pre-readonly check, we need to know if this is a data phar */
if ( FAILURE = = phar_split_fname ( url_from , strlen ( url_from ) , & arch , & arch_len , & entry2 , & entry_len , 2 , 2 TSRMLS_CC ) ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot create directory \" %s \" , no phar archive specified " , url_from ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( FAILURE = = phar_get_archive ( & phar , arch , arch_len , NULL , 0 , NULL TSRMLS_CC ) ) {
phar = NULL ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
efree ( arch ) ;
efree ( entry2 ) ;
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( PHAR_G ( readonly ) & & ( ! phar | | ! phar - > is_data ) ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot create directory \" %s \" , write operations disabled " , url_from ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-05-30 22:38:46 +00:00
if ( ( resource = phar_parse_url ( wrapper , url_from , " w " , options TSRMLS_CC ) ) = = NULL ) {
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
/* we must have at the very least phar://alias.phar/internalfile.php */
if ( ! resource - > scheme | | ! resource - > host | | ! resource - > path ) {
php_url_free ( resource ) ;
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: invalid url \" %s \" " , url_from ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
if ( strcasecmp ( " phar " , resource - > scheme ) ) {
php_url_free ( resource ) ;
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: not a phar stream url \" %s \" " , url_from ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
host_len = strlen ( resource - > host ) ;
if ( FAILURE = = phar_get_archive ( & phar , resource - > host , host_len , NULL , 0 , & error TSRMLS_CC ) ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot create directory \" %s \" in phar \" %s \" , error retrieving phar information: %s " , resource - > path + 1 , resource - > host , error ) ;
efree ( error ) ;
php_url_free ( resource ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-05-15 16:09:01 +00:00
if ( ( e = phar_get_entry_info_dir ( phar , resource - > path + 1 , strlen ( resource - > path + 1 ) , 2 , & error , 1 TSRMLS_CC ) ) ) {
2008-05-12 21:03:49 +00:00
/* directory exists, or is a subdirectory of an existing file */
if ( e - > is_temp_dir ) {
efree ( e - > filename ) ;
efree ( e ) ;
}
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot create directory \" %s \" in phar \" %s \" , directory already exists " , resource - > path + 1 , resource - > host ) ;
php_url_free ( resource ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( error ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot create directory \" %s \" in phar \" %s \" , %s " , resource - > path + 1 , resource - > host , error ) ;
efree ( error ) ;
php_url_free ( resource ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-08-01 13:48:45 +00:00
2008-05-15 16:09:01 +00:00
if ( ( e = phar_get_entry_info_dir ( phar , resource - > path + 1 , strlen ( resource - > path + 1 ) , 0 , & error , 1 TSRMLS_CC ) ) ) {
2008-05-12 21:03:49 +00:00
/* entry exists as a file */
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot create directory \" %s \" in phar \" %s \" , file already exists " , resource - > path + 1 , resource - > host ) ;
php_url_free ( resource ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( error ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot create directory \" %s \" in phar \" %s \" , %s " , resource - > path + 1 , resource - > host , error ) ;
efree ( error ) ;
php_url_free ( resource ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
memset ( ( void * ) & entry , 0 , sizeof ( phar_entry_info ) ) ;
/* strip leading "/" */
if ( phar - > is_zip ) {
entry . is_zip = 1 ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
entry . filename = estrdup ( resource - > path + 1 ) ;
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( phar - > is_tar ) {
entry . is_tar = 1 ;
entry . tar_type = TAR_DIR ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
entry . filename_len = strlen ( resource - > path + 1 ) ;
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 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( SUCCESS ! = zend_hash_add ( & phar - > manifest , entry . filename , entry . filename_len , ( void * ) & entry , sizeof ( phar_entry_info ) , NULL ) ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot create directory \" %s \" in phar \" %s \" , adding to manifest failed " , entry . filename , phar - > fname ) ;
efree ( error ) ;
efree ( entry . filename ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
phar_flush ( phar , 0 , 0 , 0 , & error TSRMLS_CC ) ;
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( error ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot create directory \" %s \" in phar \" %s \" , %s " , entry . filename , phar - > fname , error ) ;
zend_hash_del ( & phar - > manifest , entry . filename , entry . filename_len ) ;
efree ( error ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-08-01 13:48:45 +00:00
2008-06-15 18:15:48 +00:00
phar_add_virtual_dirs ( phar , entry . filename , entry . filename_len TSRMLS_CC ) ;
2008-07-20 14:42:34 +00:00
return 1 ;
2008-05-12 21:03:49 +00:00
}
/* }}} */
/**
* Remove a directory within a phar archive
*/
int phar_wrapper_rmdir ( php_stream_wrapper * wrapper , char * url , int options , php_stream_context * context TSRMLS_DC ) /* { { { */
{
phar_entry_info * entry ;
phar_archive_data * phar = NULL ;
char * error , * arch , * entry2 ;
int arch_len , entry_len ;
php_url * resource = NULL ;
uint host_len ;
2008-08-30 23:47:55 +00:00
phar_zstr key ;
char * str_key ;
2008-07-20 14:42:34 +00:00
uint key_len ;
ulong unused ;
uint path_len ;
2008-05-12 21:03:49 +00:00
/* pre-readonly check, we need to know if this is a data phar */
if ( FAILURE = = phar_split_fname ( url , strlen ( url ) , & arch , & arch_len , & entry2 , & entry_len , 2 , 2 TSRMLS_CC ) ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot remove directory \" %s \" , no phar archive specified, or phar archive does not exist " , url ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( FAILURE = = phar_get_archive ( & phar , arch , arch_len , NULL , 0 , NULL TSRMLS_CC ) ) {
phar = NULL ;
}
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
efree ( arch ) ;
efree ( entry2 ) ;
2008-08-01 13:48:45 +00:00
2008-05-12 21:03:49 +00:00
if ( PHAR_G ( readonly ) & & ( ! phar | | ! phar - > is_data ) ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot rmdir directory \" %s \" , write operations disabled " , url ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-05-30 22:38:46 +00:00
if ( ( resource = phar_parse_url ( wrapper , url , " w " , options TSRMLS_CC ) ) = = NULL ) {
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
/* we must have at the very least phar://alias.phar/internalfile.php */
if ( ! resource - > scheme | | ! resource - > host | | ! resource - > path ) {
php_url_free ( resource ) ;
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: invalid url \" %s \" " , url ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
if ( strcasecmp ( " phar " , resource - > scheme ) ) {
php_url_free ( resource ) ;
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: not a phar stream url \" %s \" " , url ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
host_len = strlen ( resource - > host ) ;
if ( FAILURE = = phar_get_archive ( & phar , resource - > host , host_len , NULL , 0 , & error TSRMLS_CC ) ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot remove directory \" %s \" in phar \" %s \" , error retrieving phar information: %s " , resource - > path + 1 , resource - > host , error ) ;
efree ( error ) ;
php_url_free ( resource ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-07-20 14:42:34 +00:00
path_len = strlen ( resource - > path + 1 ) ;
2008-08-01 13:48:45 +00:00
2008-07-20 14:42:34 +00:00
if ( ! ( entry = phar_get_entry_info_dir ( phar , resource - > path + 1 , path_len , 2 , & error , 1 TSRMLS_CC ) ) ) {
2008-05-12 21:03:49 +00:00
if ( error ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot remove directory \" %s \" in phar \" %s \" , %s " , resource - > path + 1 , resource - > host , error ) ;
efree ( error ) ;
} else {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot remove directory \" %s \" in phar \" %s \" , directory does not exist " , resource - > path + 1 , resource - > host ) ;
}
php_url_free ( resource ) ;
2008-07-20 14:42:34 +00:00
return 0 ;
2008-05-12 21:03:49 +00:00
}
2008-10-12 19:40:11 +00:00
if ( ! entry - > is_deleted ) {
for ( zend_hash_internal_pointer_reset ( & phar - > manifest ) ;
2008-08-30 23:47:55 +00:00
HASH_KEY_NON_EXISTANT ! = zend_hash_get_current_key_ex ( & phar - > manifest , & key , & key_len , & unused , 0 , NULL ) ;
2008-08-01 13:48:45 +00:00
zend_hash_move_forward ( & phar - > manifest ) ) {
2008-07-20 14:42:34 +00:00
2008-10-12 19:40:11 +00:00
PHAR_STR ( key , str_key ) ;
2008-08-30 23:47:55 +00:00
2008-10-12 19:40:11 +00:00
if ( key_len > path_len & &
memcmp ( str_key , resource - > path + 1 , path_len ) = = 0 & &
IS_SLASH ( str_key [ path_len ] ) ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: Directory not empty " ) ;
if ( entry - > is_temp_dir ) {
efree ( entry - > filename ) ;
efree ( entry ) ;
}
php_url_free ( resource ) ;
return 0 ;
2008-07-20 14:42:34 +00:00
}
}
2008-10-12 19:40:11 +00:00
for ( zend_hash_internal_pointer_reset ( & phar - > virtual_dirs ) ;
HASH_KEY_NON_EXISTANT ! = zend_hash_get_current_key_ex ( & phar - > virtual_dirs , & key , & key_len , & unused , 0 , NULL ) ;
zend_hash_move_forward ( & phar - > virtual_dirs ) ) {
PHAR_STR ( key , str_key ) ;
if ( key_len > path_len & &
memcmp ( str_key , resource - > path + 1 , path_len ) = = 0 & &
IS_SLASH ( str_key [ path_len ] ) ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: Directory not empty " ) ;
if ( entry - > is_temp_dir ) {
efree ( entry - > filename ) ;
efree ( entry ) ;
}
php_url_free ( resource ) ;
return 0 ;
2008-07-20 14:42:34 +00:00
}
}
}
if ( entry - > is_temp_dir ) {
zend_hash_del ( & phar - > virtual_dirs , resource - > path + 1 , path_len ) ;
efree ( entry - > filename ) ;
efree ( entry ) ;
} else {
entry - > is_deleted = 1 ;
entry - > is_modified = 1 ;
phar_flush ( phar , 0 , 0 , 0 , & error TSRMLS_CC ) ;
if ( error ) {
php_stream_wrapper_log_error ( wrapper , options TSRMLS_CC , " phar error: cannot remove directory \" %s \" in phar \" %s \" , %s " , entry - > filename , phar - > fname , error ) ;
php_url_free ( resource ) ;
efree ( error ) ;
return 0 ;
}
}
2008-05-12 21:03:49 +00:00
php_url_free ( resource ) ;
2008-07-20 14:42:34 +00:00
return 1 ;
2008-05-12 21:03:49 +00:00
}
/* }}} */
2008-07-29 10:52:08 +00:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* End :
* vim600 : noet sw = 4 ts = 4 fdm = marker
* vim < 600 : noet sw = 4 ts = 4
*/