PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - phar - stream.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 519
Code covered: 78.2 % Executed lines: 406
Legend: not executed executed

       1                 : /*
       2                 :   +----------------------------------------------------------------------+
       3                 :   | phar:// stream wrapper support                                       |
       4                 :   +----------------------------------------------------------------------+
       5                 :   | Copyright (c) 2005-2009 The PHP Group                                |
       6                 :   +----------------------------------------------------------------------+
       7                 :   | This source file is subject to version 3.01 of the PHP license,      |
       8                 :   | that is bundled with this package in the file LICENSE, and is        |
       9                 :   | available through the world-wide-web at the following url:           |
      10                 :   | http://www.php.net/license/3_01.txt.                                 |
      11                 :   | If you did not receive a copy of the PHP license and are unable to   |
      12                 :   | obtain it through the world-wide-web, please send a note to          |
      13                 :   | license@php.net so we can mail you a copy immediately.               |
      14                 :   +----------------------------------------------------------------------+
      15                 :   | Authors: Gregory Beaver <cellog@php.net>                             |
      16                 :   |          Marcus Boerger <helly@php.net>                              |
      17                 :   +----------------------------------------------------------------------+
      18                 : */
      19                 : 
      20                 : #define PHAR_STREAM 1
      21                 : #include "phar_internal.h"
      22                 : #include "stream.h"
      23                 : #include "dirstream.h"
      24                 : 
      25                 : php_stream_ops phar_ops = {
      26                 :         phar_stream_write, /* write */
      27                 :         phar_stream_read,  /* read */
      28                 :         phar_stream_close, /* close */
      29                 :         phar_stream_flush, /* flush */
      30                 :         "phar stream",
      31                 :         phar_stream_seek,  /* seek */
      32                 :         NULL,              /* cast */
      33                 :         phar_stream_stat,  /* stat */
      34                 :         NULL, /* set option */
      35                 : };
      36                 : 
      37                 : php_stream_wrapper_ops phar_stream_wops = {
      38                 :         phar_wrapper_open_url,
      39                 :         NULL,                  /* phar_wrapper_close */
      40                 :         NULL,                  /* phar_wrapper_stat, */
      41                 :         phar_wrapper_stat,     /* stat_url */
      42                 :         phar_wrapper_open_dir, /* opendir */
      43                 :         "phar",
      44                 :         phar_wrapper_unlink,   /* unlink */
      45                 :         phar_wrapper_rename,   /* rename */
      46                 :         phar_wrapper_mkdir,    /* create directory */
      47                 :         phar_wrapper_rmdir,    /* remove directory */
      48                 : };
      49                 : 
      50                 : php_stream_wrapper php_stream_phar_wrapper = {
      51                 :         &phar_stream_wops,
      52                 :         NULL,
      53                 :         0 /* is_url */
      54                 : };
      55                 : 
      56                 : /**
      57                 :  * Open a phar file for streams API
      58                 :  */
      59                 : php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC) /* {{{ */
      60            1540 : {
      61                 :         php_url *resource;
      62            1540 :         char *arch = NULL, *entry = NULL, *error;
      63                 :         int arch_len, entry_len;
      64                 : 
      65            1540 :         if (strlen(filename) < 7 || strncasecmp(filename, "phar://", 7)) {
      66               0 :                 return NULL;
      67                 :         }
      68            1540 :         if (mode[0] == 'a') {
      69               1 :                 if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
      70               1 :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: open mode append not supported");
      71                 :                 }
      72               1 :                 return NULL;
      73                 :         }
      74            1539 :         if (phar_split_fname(filename, strlen(filename), &arch, &arch_len, &entry, &entry_len, 2, (mode[0] == 'w' ? 2 : 0) TSRMLS_CC) == FAILURE) {
      75              19 :                 if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
      76              18 :                         if (arch && !entry) {
      77               5 :                                 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)", filename, arch);
      78               5 :                                 arch = NULL;
      79                 :                         } else {
      80               8 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url or non-existent phar \"%s\"", filename);
      81                 :                         }
      82                 :                 }
      83              19 :                 return NULL;
      84                 :         }
      85            1520 :         resource = ecalloc(1, sizeof(php_url));
      86            1520 :         resource->scheme = estrndup("phar", 4);
      87            1520 :         resource->host = arch;
      88                 : 
      89            1520 :         resource->path = entry;
      90                 : #if MBO_0
      91                 :                 if (resource) {
      92                 :                         fprintf(stderr, "Alias:     %s\n", alias);
      93                 :                         fprintf(stderr, "Scheme:    %s\n", resource->scheme);
      94                 : /*                      fprintf(stderr, "User:      %s\n", resource->user);*/
      95                 : /*                      fprintf(stderr, "Pass:      %s\n", resource->pass ? "***" : NULL);*/
      96                 :                         fprintf(stderr, "Host:      %s\n", resource->host);
      97                 : /*                      fprintf(stderr, "Port:      %d\n", resource->port);*/
      98                 :                         fprintf(stderr, "Path:      %s\n", resource->path);
      99                 : /*                      fprintf(stderr, "Query:     %s\n", resource->query);*/
     100                 : /*                      fprintf(stderr, "Fragment:  %s\n", resource->fragment);*/
     101                 :                 }
     102                 : #endif
     103            1624 :         if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) {
     104             122 :                 phar_archive_data **pphar = NULL, *phar;
     105                 : 
     106             122 :                 if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arBuckets && FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len, (void **)&pphar)) {
     107              39 :                         pphar = NULL;
     108                 :                 }
     109             122 :                 if (PHAR_G(readonly) && (!pphar || !(*pphar)->is_data)) {
     110              16 :                         if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
     111              15 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by INI setting");
     112                 :                         }
     113              16 :                         php_url_free(resource);
     114              16 :                         return NULL;
     115                 :                 }
     116             106 :                 if (phar_open_or_create_filename(resource->host, arch_len, NULL, 0, 0, options, &phar, &error TSRMLS_CC) == FAILURE)
     117                 :                 {
     118               2 :                         if (error) {
     119               2 :                                 if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
     120               2 :                                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
     121                 :                                 }
     122               2 :                                 efree(error);
     123                 :                         }
     124               2 :                         php_url_free(resource);
     125               2 :                         return NULL;
     126                 :                 }
     127             104 :                 if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
     128               0 :                         if (error) {
     129               0 :                                 spprintf(&error, 0, "Cannot open cached phar '%s' as writeable, copy on write failed", resource->host);
     130               0 :                                 if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
     131               0 :                                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
     132                 :                                 }
     133               0 :                                 efree(error);
     134                 :                         }
     135               0 :                         php_url_free(resource);
     136               0 :                         return NULL;
     137                 :                 }
     138                 :         } else {
     139            1398 :                 if (phar_open_from_filename(resource->host, arch_len, NULL, 0, options, NULL, &error TSRMLS_CC) == FAILURE)
     140                 :                 {
     141               9 :                         if (error) {
     142               7 :                                 if (!(options & PHP_STREAM_URL_STAT_QUIET)) {
     143               6 :                                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
     144                 :                                 }
     145               7 :                                 efree(error);
     146                 :                         }
     147               9 :                         php_url_free(resource);
     148               9 :                         return NULL;
     149                 :                 }
     150                 :         }
     151            1493 :         return resource;
     152                 : }
     153                 : /* }}} */
     154                 : 
     155                 : /**
     156                 :  * used for fopen('phar://...') and company
     157                 :  */
     158                 : static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
     159             614 : {
     160                 :         phar_archive_data *phar;
     161                 :         phar_entry_data *idata;
     162                 :         char *internal_file;
     163                 :         char *error;
     164                 :         HashTable *pharcontext;
     165             614 :         php_url *resource = NULL;
     166                 :         php_stream *fpf;
     167                 :         zval **pzoption, *metadata;
     168                 :         uint host_len;
     169                 : 
     170             614 :         if ((resource = phar_parse_url(wrapper, path, mode, options TSRMLS_CC)) == NULL) {
     171              27 :                 return NULL;
     172                 :         }
     173                 : 
     174                 :         /* we must have at the very least phar://alias.phar/internalfile.php */
     175             587 :         if (!resource->scheme || !resource->host || !resource->path) {
     176               0 :                 php_url_free(resource);
     177               0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", path);
     178               0 :                 return NULL;
     179                 :         }
     180                 : 
     181             587 :         if (strcasecmp("phar", resource->scheme)) {
     182               0 :                 php_url_free(resource);
     183               0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", path);
     184               0 :                 return NULL;
     185                 :         }
     186                 : 
     187             587 :         host_len = strlen(resource->host);
     188             587 :         phar_request_initialize(TSRMLS_C);
     189                 : 
     190                 :         /* strip leading "/" */
     191             587 :         internal_file = estrdup(resource->path + 1);
     192             587 :         if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) {
     193              51 :                 if (NULL == (idata = phar_get_or_create_entry_data(resource->host, host_len, internal_file, strlen(internal_file), mode, 0, &error, 1 TSRMLS_CC))) {
     194               4 :                         if (error) {
     195               4 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
     196               4 :                                 efree(error);
     197                 :                         } else {
     198               0 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, resource->host);
     199                 :                         }
     200               4 :                         efree(internal_file);
     201               4 :                         php_url_free(resource);
     202               4 :                         return NULL;
     203                 :                 }
     204              47 :                 if (error) {
     205               0 :                         efree(error);
     206                 :                 }
     207              47 :                 fpf = php_stream_alloc(&phar_ops, idata, NULL, mode);
     208              47 :                 php_url_free(resource);
     209              47 :                 efree(internal_file);
     210                 : #if PHP_MAJOR_VERSION >= 6
     211                 :                 if (context && context->options && phar_find_key(HASH_OF(context->options), "phar", sizeof("phar"), (void**)&pzoption TSRMLS_CC)) {
     212                 : #else
     213              47 :                 if (context && context->options && zend_hash_find(HASH_OF(context->options), "phar", sizeof("phar"), (void**)&pzoption) == SUCCESS) {
     214                 : #endif
     215               7 :                         pharcontext = HASH_OF(*pzoption);
     216               7 :                         if (idata->internal_file->uncompressed_filesize == 0
     217                 :                                 && idata->internal_file->compressed_filesize == 0
     218                 : #if PHP_MAJOR_VERSION >= 6
     219                 :                                 && phar_find_key(pharcontext, "compress", sizeof("compress"), (void**)&pzoption TSRMLS_CC)
     220                 : #else
     221                 :                                 && zend_hash_find(pharcontext, "compress", sizeof("compress"), (void**)&pzoption) == SUCCESS
     222                 : #endif
     223                 :                                 && Z_TYPE_PP(pzoption) == IS_LONG
     224                 :                                 && (Z_LVAL_PP(pzoption) & ~PHAR_ENT_COMPRESSION_MASK) == 0
     225                 :                         ) {
     226               5 :                                 idata->internal_file->flags &= ~PHAR_ENT_COMPRESSION_MASK;
     227               5 :                                 idata->internal_file->flags |= Z_LVAL_PP(pzoption);
     228                 :                         }
     229                 : #if PHP_MAJOR_VERSION >= 6
     230                 :                         if (phar_find_key(pharcontext, "metadata", sizeof("metadata"), (void**)&pzoption TSRMLS_CC)) {
     231                 : #else
     232               7 :                         if (zend_hash_find(pharcontext, "metadata", sizeof("metadata"), (void**)&pzoption) == SUCCESS) {
     233                 : #endif
     234               3 :                                 if (idata->internal_file->metadata) {
     235               1 :                                         zval_ptr_dtor(&idata->internal_file->metadata);
     236               1 :                                         idata->internal_file->metadata = NULL;
     237                 :                                 }
     238                 : 
     239               3 :                                 MAKE_STD_ZVAL(idata->internal_file->metadata);
     240               3 :                                 metadata = *pzoption;
     241               3 :                                 ZVAL_ZVAL(idata->internal_file->metadata, metadata, 1, 0);
     242               3 :                                 idata->phar->is_modified = 1;
     243                 :                         }
     244                 :                 }
     245              47 :                 if (opened_path) {
     246               0 :                         spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename);
     247                 :                 }
     248              47 :                 return fpf;
     249                 :         } else {
     250             536 :                 if (!*internal_file && (options & STREAM_OPEN_FOR_INCLUDE)) {
     251                 :                         /* retrieve the stub */
     252               2 :                         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, NULL TSRMLS_CC)) {
     253               0 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "file %s is not a valid phar archive");
     254               0 :                                 efree(internal_file);
     255               0 :                                 php_url_free(resource);
     256               0 :                                 return NULL;
     257                 :                         }
     258               2 :                         if (phar->is_tar || phar->is_zip) {
     259               1 :                                 if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, ".phar/stub.php", sizeof(".phar/stub.php")-1, "r", 0, &error, 0 TSRMLS_CC)) || !idata) {
     260                 :                                         goto idata_error;
     261                 :                                 }
     262               1 :                                 efree(internal_file);
     263               1 :                                 if (opened_path) {
     264               1 :                                         spprintf(opened_path, MAXPATHLEN, "%s", phar->fname);
     265                 :                                 }
     266               1 :                                 php_url_free(resource);
     267               1 :                                 goto phar_stub;
     268                 :                         } else {
     269                 :                                 phar_entry_info *entry;
     270                 : 
     271               1 :                                 entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
     272               1 :                                 entry->is_temp_dir = 1;
     273               1 :                                 entry->filename = estrndup("", 0);
     274               1 :                                 entry->filename_len = 0;
     275               1 :                                 entry->phar = phar;
     276               1 :                                 entry->offset = entry->offset_abs = 0;
     277               1 :                                 entry->compressed_filesize = entry->uncompressed_filesize = phar->halt_offset;
     278               1 :                                 entry->is_crc_checked = 1;
     279                 : 
     280               1 :                                 idata = (phar_entry_data *) ecalloc(1, sizeof(phar_entry_data));
     281               1 :                                 idata->fp = phar_get_pharfp(phar TSRMLS_CC);
     282               1 :                                 idata->phar = phar;
     283               1 :                                 idata->internal_file = entry;
     284               1 :                                 if (!phar->is_persistent) {
     285               1 :                                         ++(entry->phar->refcount);
     286                 :                                 }
     287               1 :                                 ++(entry->fp_refcount);
     288               1 :                                 php_url_free(resource);
     289               1 :                                 if (opened_path) {
     290               1 :                                         spprintf(opened_path, MAXPATHLEN, "%s", phar->fname);
     291                 :                                 }
     292               1 :                                 efree(internal_file);
     293               1 :                                 goto phar_stub;
     294                 :                         }
     295                 :                 }
     296                 :                 /* read-only access is allowed to magic files in .phar directory */
     297             534 :                 if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, strlen(internal_file), "r", 0, &error, 0 TSRMLS_CC)) || !idata) {
     298              29 : idata_error:
     299              29 :                         if (error) {
     300               8 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
     301               8 :                                 efree(error);
     302                 :                         } else {
     303              21 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, resource->host);
     304                 :                         }
     305              29 :                         efree(internal_file);
     306              29 :                         php_url_free(resource);
     307              29 :                         return NULL;
     308                 :                 }
     309                 :         }
     310             505 :         php_url_free(resource);
     311                 : #if MBO_0
     312                 :                 fprintf(stderr, "Pharname:   %s\n", idata->phar->filename);
     313                 :                 fprintf(stderr, "Filename:   %s\n", internal_file);
     314                 :                 fprintf(stderr, "Entry:      %s\n", idata->internal_file->filename);
     315                 :                 fprintf(stderr, "Size:       %u\n", idata->internal_file->uncompressed_filesize);
     316                 :                 fprintf(stderr, "Compressed: %u\n", idata->internal_file->flags);
     317                 :                 fprintf(stderr, "Offset:     %u\n", idata->internal_file->offset_within_phar);
     318                 :                 fprintf(stderr, "Cached:     %s\n", idata->internal_file->filedata ? "yes" : "no");
     319                 : #endif
     320                 : 
     321                 :         /* check length, crc32 */
     322             505 :         if (!idata->internal_file->is_crc_checked && phar_postprocess_file(idata, idata->internal_file->crc32, &error, 2 TSRMLS_CC) != SUCCESS) {
     323               2 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
     324               2 :                 efree(error);
     325               2 :                 phar_entry_delref(idata TSRMLS_CC);
     326               2 :                 efree(internal_file);
     327               2 :                 return NULL;
     328                 :         }
     329                 : 
     330             503 :         if (!PHAR_G(cwd_init) && options & STREAM_OPEN_FOR_INCLUDE) {
     331             137 :                 char *entry = idata->internal_file->filename, *cwd;
     332                 : 
     333             137 :                 PHAR_G(cwd_init) = 1;
     334             188 :                 if ((idata->phar->is_tar || idata->phar->is_zip) && idata->internal_file->filename_len == sizeof(".phar/stub.php")-1 && !strncmp(idata->internal_file->filename, ".phar/stub.php", sizeof(".phar/stub.php")-1)) {
     335                 :                         /* we're executing the stub, which doesn't count as a file */
     336              51 :                         PHAR_G(cwd_init) = 0;
     337              86 :                 } else if ((cwd = strrchr(entry, '/'))) {
     338              28 :                         PHAR_G(cwd_len) = cwd - entry;
     339              28 :                         PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len));
     340                 :                 } else {
     341                 :                         /* root directory */
     342              58 :                         PHAR_G(cwd_len) = 0;
     343              58 :                         PHAR_G(cwd) = NULL;
     344                 :                 }
     345                 :         }
     346             503 :         if (opened_path) {
     347             266 :                 spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename);
     348                 :         }
     349             503 :         efree(internal_file);
     350             505 : phar_stub:
     351             505 :         fpf = php_stream_alloc(&phar_ops, idata, NULL, mode);
     352             505 :         return fpf;
     353                 : }
     354                 : /* }}} */
     355                 : 
     356                 : /**
     357                 :  * Used for fclose($fp) where $fp is a phar archive
     358                 :  */
     359                 : static int phar_stream_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
     360             552 : {
     361             552 :         phar_entry_delref((phar_entry_data *)stream->abstract TSRMLS_CC);
     362                 : 
     363             552 :         return 0;
     364                 : }
     365                 : /* }}} */
     366                 : 
     367                 : /**
     368                 :  * used for fread($fp) and company on a fopen()ed phar file handle
     369                 :  */
     370                 : static size_t phar_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
     371             974 : {
     372             974 :         phar_entry_data *data = (phar_entry_data *)stream->abstract;
     373                 :         size_t got;
     374                 :         phar_entry_info *entry;
     375                 : 
     376             974 :         if (data->internal_file->link) {
     377               5 :                 entry = phar_get_link_source(data->internal_file TSRMLS_CC);
     378                 :         } else {
     379             969 :                 entry = data->internal_file;
     380                 :         }
     381                 : 
     382             974 :         if (entry->is_deleted) {
     383               0 :                 stream->eof = 1;
     384               0 :                 return 0;
     385                 :         }
     386                 : 
     387                 :         /* use our proxy position */
     388             974 :         php_stream_seek(data->fp, data->position + data->zero, SEEK_SET);
     389                 : 
     390             974 :         got = php_stream_read(data->fp, buf, MIN(count, entry->uncompressed_filesize - data->position));
     391             974 :         data->position = php_stream_tell(data->fp) - data->zero;
     392             974 :         stream->eof = (data->position == (off_t) entry->uncompressed_filesize);
     393                 : 
     394             974 :         return got;
     395                 : }
     396                 : /* }}} */
     397                 : 
     398                 : /**
     399                 :  * Used for fseek($fp) on a phar file handle
     400                 :  */
     401                 : static int phar_stream_seek(php_stream *stream, off_t offset, int whence, off_t *newoffset TSRMLS_DC) /* {{{ */
     402              42 : {
     403              42 :         phar_entry_data *data = (phar_entry_data *)stream->abstract;
     404                 :         phar_entry_info *entry;
     405                 :         int res;
     406                 :         off_t temp;
     407                 : 
     408              42 :         if (data->internal_file->link) {
     409               1 :                 entry = phar_get_link_source(data->internal_file TSRMLS_CC);
     410                 :         } else {
     411              41 :                 entry = data->internal_file;
     412                 :         }
     413                 : 
     414              42 :         switch (whence) {
     415                 :                 case SEEK_END :
     416               6 :                         temp = data->zero + entry->uncompressed_filesize + offset;
     417               6 :                         break;
     418                 :                 case SEEK_CUR :
     419               0 :                         temp = data->zero + data->position + offset;
     420               0 :                         break;
     421                 :                 case SEEK_SET :
     422              36 :                         temp = data->zero + offset;
     423                 :                         break;
     424                 :         }
     425              42 :         if (temp > data->zero + (off_t) entry->uncompressed_filesize) {
     426               4 :                 *newoffset = -1;
     427               4 :                 return -1;
     428                 :         }
     429              38 :         if (temp < data->zero) {
     430               4 :                 *newoffset = -1;
     431               4 :                 return -1;
     432                 :         }
     433              34 :         res = php_stream_seek(data->fp, temp, SEEK_SET);
     434              34 :         *newoffset = php_stream_tell(data->fp) - data->zero;
     435              34 :         data->position = *newoffset;
     436              34 :         return res;
     437                 : }
     438                 : /* }}} */
     439                 : 
     440                 : /**
     441                 :  * Used for writing to a phar file
     442                 :  */
     443                 : static size_t phar_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
     444              45 : {
     445              45 :         phar_entry_data *data = (phar_entry_data *) stream->abstract;
     446                 : 
     447              45 :         php_stream_seek(data->fp, data->position, SEEK_SET);
     448              45 :         if (count != php_stream_write(data->fp, buf, count)) {
     449               0 :                 php_stream_wrapper_log_error(stream->wrapper, stream->flags TSRMLS_CC, "phar error: Could not write %d characters to \"%s\" in phar \"%s\"", (int) count, data->internal_file->filename, data->phar->fname);
     450               0 :                 return -1;
     451                 :         }
     452              45 :         data->position = php_stream_tell(data->fp);
     453              45 :         if (data->position > (off_t)data->internal_file->uncompressed_filesize) {
     454              45 :                 data->internal_file->uncompressed_filesize = data->position;
     455                 :         }
     456              45 :         data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize;
     457              45 :         data->internal_file->old_flags = data->internal_file->flags;
     458              45 :         data->internal_file->is_modified = 1;
     459              45 :         return count;
     460                 : }
     461                 : /* }}} */
     462                 : 
     463                 : /**
     464                 :  * Used to save work done on a writeable phar
     465                 :  */
     466                 : static int phar_stream_flush(php_stream *stream TSRMLS_DC) /* {{{ */
     467             552 : {
     468                 :         char *error;
     469                 :         int ret;
     470             552 :         if (stream->mode[0] == 'w' || (stream->mode[0] == 'r' && stream->mode[1] == '+')) {
     471              47 :                 ret = phar_flush(((phar_entry_data *)stream->abstract)->phar, 0, 0, 0, &error TSRMLS_CC);
     472              47 :                 if (error) {
     473               0 :                         php_stream_wrapper_log_error(stream->wrapper, REPORT_ERRORS TSRMLS_CC, error);
     474               0 :                         efree(error);
     475                 :                 }
     476              47 :                 return ret;
     477                 :         } else {
     478             505 :                 return EOF;
     479                 :         }
     480                 : }
     481                 : /* }}} */
     482                 : 
     483                 :  /* {{{ phar_dostat */
     484                 : /**
     485                 :  * stat an opened phar file handle stream, used by phar_stat()
     486                 :  */
     487                 : void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, zend_bool is_temp_dir TSRMLS_DC)
     488            1090 : {
     489            1090 :         memset(ssb, 0, sizeof(php_stream_statbuf));
     490                 : 
     491            2045 :         if (!is_temp_dir && !data->is_dir) {
     492             955 :                 ssb->sb.st_size = data->uncompressed_filesize;
     493             955 :                 ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
     494             955 :                 ssb->sb.st_mode |= S_IFREG; /* regular file */
     495                 :                 /* timestamp is just the timestamp when this was added to the phar */
     496                 : #ifdef NETWARE
     497                 :                 ssb->sb.st_mtime.tv_sec = data->timestamp;
     498                 :                 ssb->sb.st_atime.tv_sec = data->timestamp;
     499                 :                 ssb->sb.st_ctime.tv_sec = data->timestamp;
     500                 : #else
     501             955 :                 ssb->sb.st_mtime = data->timestamp;
     502             955 :                 ssb->sb.st_atime = data->timestamp;
     503             955 :                 ssb->sb.st_ctime = data->timestamp;
     504                 : #endif
     505             206 :         } else if (!is_temp_dir && data->is_dir) {
     506              71 :                 ssb->sb.st_size = 0;
     507              71 :                 ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
     508              71 :                 ssb->sb.st_mode |= S_IFDIR; /* regular directory */
     509                 :                 /* timestamp is just the timestamp when this was added to the phar */
     510                 : #ifdef NETWARE
     511                 :                 ssb->sb.st_mtime.tv_sec = data->timestamp;
     512                 :                 ssb->sb.st_atime.tv_sec = data->timestamp;
     513                 :                 ssb->sb.st_ctime.tv_sec = data->timestamp;
     514                 : #else
     515              71 :                 ssb->sb.st_mtime = data->timestamp;
     516              71 :                 ssb->sb.st_atime = data->timestamp;
     517              71 :                 ssb->sb.st_ctime = data->timestamp;
     518                 : #endif
     519                 :         } else {
     520              64 :                 ssb->sb.st_size = 0;
     521              64 :                 ssb->sb.st_mode = 0777;
     522              64 :                 ssb->sb.st_mode |= S_IFDIR; /* regular directory */
     523                 : #ifdef NETWARE
     524                 :                 ssb->sb.st_mtime.tv_sec = phar->max_timestamp;
     525                 :                 ssb->sb.st_atime.tv_sec = phar->max_timestamp;
     526                 :                 ssb->sb.st_ctime.tv_sec = phar->max_timestamp;
     527                 : #else
     528              64 :                 ssb->sb.st_mtime = phar->max_timestamp;
     529              64 :                 ssb->sb.st_atime = phar->max_timestamp;
     530              64 :                 ssb->sb.st_ctime = phar->max_timestamp;
     531                 : #endif
     532                 :         }
     533            1090 :         if (!phar->is_writeable) {
     534             527 :                 ssb->sb.st_mode = (ssb->sb.st_mode & 0555) | (ssb->sb.st_mode & ~0777);
     535                 :         }
     536                 : 
     537            1090 :         ssb->sb.st_nlink = 1;
     538            1090 :         ssb->sb.st_rdev = -1;
     539                 :         /* this is only for APC, so use /dev/null device - no chance of conflict there! */
     540            1090 :         ssb->sb.st_dev = 0xc;
     541                 :         /* generate unique inode number for alias/filename, so no phars will conflict */
     542            1090 :         if (!is_temp_dir) {
     543            1026 :                 ssb->sb.st_ino = data->inode;
     544                 :         }
     545                 : #ifndef PHP_WIN32
     546            1090 :         ssb->sb.st_blksize = -1;
     547            1090 :         ssb->sb.st_blocks = -1;
     548                 : #endif
     549            1090 : }
     550                 : /* }}}*/
     551                 : 
     552                 : /**
     553                 :  * Stat an opened phar file handle
     554                 :  */
     555                 : static int phar_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */
     556             737 : {
     557             737 :         phar_entry_data *data = (phar_entry_data *)stream->abstract;
     558                 : 
     559                 :         /* If ssb is NULL then someone is misbehaving */
     560             737 :         if (!ssb) {
     561               0 :                 return -1;
     562                 :         }
     563                 : 
     564             737 :         phar_dostat(data->phar, data->internal_file, ssb, 0 TSRMLS_CC);
     565             737 :         return 0;
     566                 : }
     567                 : /* }}} */
     568                 : 
     569                 : /**
     570                 :  * Stream wrapper stat implementation of stat()
     571                 :  */
     572                 : static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
     573                 :                                   php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) /* {{{ */
     574             391 : {
     575             391 :         php_url *resource = NULL;
     576                 :         char *internal_file, *error;
     577                 :         phar_archive_data *phar;
     578                 :         phar_entry_info *entry;
     579                 :         uint host_len;
     580                 :         int internal_file_len;
     581                 : 
     582             391 :         if ((resource = phar_parse_url(wrapper, url, "r", flags|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
     583               6 :                 return FAILURE;
     584                 :         }
     585                 : 
     586                 :         /* we must have at the very least phar://alias.phar/internalfile.php */
     587             385 :         if (!resource->scheme || !resource->host || !resource->path) {
     588               0 :                 php_url_free(resource);
     589               0 :                 return FAILURE;
     590                 :         }
     591                 : 
     592             385 :         if (strcasecmp("phar", resource->scheme)) {
     593               0 :                 php_url_free(resource);
     594               0 :                 return FAILURE;
     595                 :         }
     596                 : 
     597             385 :         host_len = strlen(resource->host);
     598             385 :         phar_request_initialize(TSRMLS_C);
     599                 : 
     600             385 :         internal_file = resource->path + 1; /* strip leading "/" */
     601                 :         /* find the phar in our trusty global hash indexed by alias (host of phar://blah.phar/file.whatever) */
     602             385 :         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
     603               0 :                 php_url_free(resource);
     604               0 :                 if (error) {
     605               0 :                         efree(error);
     606                 :                 }
     607               0 :                 return FAILURE;
     608                 :         }
     609             385 :         if (error) {
     610               0 :                 efree(error);
     611                 :         }
     612             385 :         if (*internal_file == '\0') {
     613                 :                 /* root directory requested */
     614               1 :                 phar_dostat(phar, NULL, ssb, 1 TSRMLS_CC);
     615               1 :                 php_url_free(resource);
     616               1 :                 return SUCCESS;
     617                 :         }
     618             384 :         if (!phar->manifest.arBuckets) {
     619               0 :                 php_url_free(resource);
     620               0 :                 return FAILURE;
     621                 :         }
     622             384 :         internal_file_len = strlen(internal_file);
     623                 :         /* search through the manifest of files, and if we have an exact match, it's a file */
     624             384 :         if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
     625             287 :                 phar_dostat(phar, entry, ssb, 0 TSRMLS_CC);
     626             287 :                 php_url_free(resource);
     627             287 :                 return SUCCESS;
     628                 :         }
     629              97 :         if (zend_hash_exists(&(phar->virtual_dirs), internal_file, internal_file_len)) {
     630              63 :                 phar_dostat(phar, NULL, ssb, 1 TSRMLS_CC);
     631              63 :                 php_url_free(resource);
     632              63 :                 return SUCCESS;
     633                 :         }
     634                 :         /* check for mounted directories */
     635              34 :         if (phar->mounted_dirs.arBuckets && zend_hash_num_elements(&phar->mounted_dirs)) {
     636                 :                 phar_zstr key;
     637                 :                 char *str_key;
     638                 :                 ulong unused;
     639                 :                 uint keylen;
     640                 :                 HashPosition pos;
     641                 : 
     642               8 :                 zend_hash_internal_pointer_reset_ex(&phar->mounted_dirs, &pos);
     643               8 :                 while (FAILURE != zend_hash_has_more_elements_ex(&phar->mounted_dirs, &pos)) {
     644               8 :                         if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, &pos)) {
     645               0 :                                 break;
     646                 :                         }
     647               8 :                         PHAR_STR(key, str_key);
     648               8 :                         if ((int)keylen >= internal_file_len || strncmp(str_key, internal_file, keylen)) {
     649               6 :                                 zend_hash_move_forward_ex(&phar->mounted_dirs, &pos);
     650                 :                                 PHAR_STR_FREE(str_key);
     651               6 :                                 continue;
     652                 :                         } else {
     653                 :                                 char *test;
     654                 :                                 int test_len;
     655                 :                                 php_stream_statbuf ssbi;
     656                 : 
     657               2 :                                 if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
     658                 :                                         PHAR_STR_FREE(str_key);
     659               0 :                                         goto free_resource;
     660                 :                                 }
     661                 :                                 PHAR_STR_FREE(str_key);
     662               2 :                                 if (!entry->tmp || !entry->is_mounted) {
     663                 :                                         goto free_resource;
     664                 :                                 }
     665               2 :                                 test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen);
     666               2 :                                 if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
     667               0 :                                         efree(test);
     668               0 :                                         zend_hash_move_forward_ex(&phar->mounted_dirs, &pos);
     669               0 :                                         continue;
     670                 :                                 }
     671                 :                                 /* mount the file/directory just in time */
     672               2 :                                 if (SUCCESS != phar_mount_entry(phar, test, test_len, internal_file, internal_file_len TSRMLS_CC)) {
     673               0 :                                         efree(test);
     674               0 :                                         goto free_resource;
     675                 :                                 }
     676               2 :                                 efree(test);
     677               2 :                                 if (SUCCESS != zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
     678               0 :                                         goto free_resource;
     679                 :                                 }
     680               2 :                                 phar_dostat(phar, entry, ssb, 0 TSRMLS_CC);
     681               2 :                                 php_url_free(resource);
     682               2 :                                 return SUCCESS;
     683                 :                         }
     684                 :                 }
     685                 :         }
     686              32 : free_resource:
     687              32 :         php_url_free(resource);
     688              32 :         return FAILURE;
     689                 : }
     690                 : /* }}} */
     691                 : 
     692                 : /**
     693                 :  * Unlink a file within a phar archive
     694                 :  */
     695                 : static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
     696              19 : {
     697                 :         php_url *resource;
     698                 :         char *internal_file, *error;
     699                 :         int internal_file_len;
     700                 :         phar_entry_data *idata;
     701                 :         phar_archive_data **pphar;
     702                 :         uint host_len;
     703                 : 
     704              19 :         if ((resource = phar_parse_url(wrapper, url, "rb", options TSRMLS_CC)) == NULL) {
     705               3 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: unlink failed");
     706               3 :                 return 0;
     707                 :         }
     708                 : 
     709                 :         /* we must have at the very least phar://alias.phar/internalfile.php */
     710              16 :         if (!resource->scheme || !resource->host || !resource->path) {
     711               0 :                 php_url_free(resource);
     712               0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url);
     713               0 :                 return 0;
     714                 :         }
     715                 : 
     716              16 :         if (strcasecmp("phar", resource->scheme)) {
     717               0 :                 php_url_free(resource);
     718               0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url);
     719               0 :                 return 0;
     720                 :         }
     721                 : 
     722              16 :         host_len = strlen(resource->host);
     723              16 :         phar_request_initialize(TSRMLS_C);
     724                 : 
     725              16 :         if (FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), resource->host, host_len, (void **) &pphar)) {
     726               0 :                 pphar = NULL;
     727                 :         }
     728              16 :         if (PHAR_G(readonly) && (!pphar || !(*pphar)->is_data)) {
     729               3 :                 php_url_free(resource);
     730               3 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by INI setting");
     731               3 :                 return 0;
     732                 :         }
     733                 : 
     734                 :         /* need to copy to strip leading "/", will get touched again */
     735              13 :         internal_file = estrdup(resource->path + 1);
     736              13 :         internal_file_len = strlen(internal_file);
     737              13 :         if (FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, internal_file_len, "r", 0, &error, 1 TSRMLS_CC)) {
     738                 :                 /* constraints of fp refcount were not met */
     739               1 :                 if (error) {
     740               0 :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed: %s", url, error);
     741               0 :                         efree(error);
     742                 :                 } else {
     743               1 :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed, file does not exist", url);
     744                 :                 }
     745               1 :                 efree(internal_file);
     746               1 :                 php_url_free(resource);
     747               1 :                 return 0;
     748                 :         }
     749              12 :         if (error) {
     750               0 :                 efree(error);
     751                 :         }
     752              12 :         if (idata->internal_file->fp_refcount > 1) {
     753                 :                 /* more than just our fp resource is open for this file */
     754               3 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" in phar \"%s\", has open file pointers, cannot unlink", internal_file, resource->host);
     755               3 :                 efree(internal_file);
     756               3 :                 php_url_free(resource);
     757               3 :                 phar_entry_delref(idata TSRMLS_CC);
     758               3 :                 return 0;
     759                 :         }
     760               9 :         php_url_free(resource);
     761               9 :         efree(internal_file);
     762               9 :         phar_entry_remove(idata, &error TSRMLS_CC);
     763               9 :         if (error) {
     764               0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
     765               0 :                 efree(error);
     766                 :         }
     767               9 :         return 1;
     768                 : }
     769                 : /* }}} */
     770                 : 
     771                 : static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
     772              15 : {
     773                 :         php_url *resource_from, *resource_to;
     774                 :         char *error;
     775                 :         phar_archive_data *phar, *pfrom, *pto;
     776                 :         phar_entry_info *entry;
     777                 :         uint host_len;
     778              15 :         int is_dir = 0;
     779              15 :         int is_modified = 0;
     780                 : 
     781              15 :         error = NULL;
     782                 : 
     783              15 :         if ((resource_from = phar_parse_url(wrapper, url_from, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
     784               2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_from);
     785               2 :                 return 0;
     786                 :         }
     787              13 :         if (SUCCESS != phar_get_archive(&pfrom, resource_from->host, strlen(resource_from->host), NULL, 0, &error TSRMLS_CC)) {
     788               0 :                 pfrom = NULL;
     789               0 :                 if (error) {
     790               0 :                         efree(error);
     791                 :                 }
     792                 :         }
     793              13 :         if (PHAR_G(readonly) && (!pfrom || !pfrom->is_data)) {
     794               0 :                 php_url_free(resource_from);
     795               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: write operations disabled by phar.readonly INI setting");
     796               0 :                 return 0;
     797                 :         }
     798                 : 
     799              13 :         if ((resource_to = phar_parse_url(wrapper, url_to, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
     800               2 :                 php_url_free(resource_from);
     801               2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_to);
     802               2 :                 return 0;
     803                 :         }
     804              11 :         if (SUCCESS != phar_get_archive(&pto, resource_to->host, strlen(resource_to->host), NULL, 0, &error TSRMLS_CC)) {
     805               0 :                 if (error) {
     806               0 :                         efree(error);
     807                 :                 }
     808               0 :                 pto = NULL;
     809                 :         }
     810              11 :         if (PHAR_G(readonly) && (!pto || !pto->is_data)) {
     811               0 :                 php_url_free(resource_from);
     812               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: write operations disabled by phar.readonly INI setting");
     813               0 :                 return 0;
     814                 :         }
     815                 : 
     816              11 :         if (strcmp(resource_from->host, resource_to->host)) {
     817               1 :                 php_url_free(resource_from);
     818               1 :                 php_url_free(resource_to);
     819               1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\", not within the same phar archive", url_from, url_to);
     820               1 :                 return 0;
     821                 :         }
     822                 : 
     823                 :         /* we must have at the very least phar://alias.phar/internalfile.php */
     824              10 :         if (!resource_from->scheme || !resource_from->host || !resource_from->path) {
     825               0 :                 php_url_free(resource_from);
     826               0 :                 php_url_free(resource_to);
     827               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_from);
     828               0 :                 return 0;
     829                 :         }
     830                 : 
     831              10 :         if (!resource_to->scheme || !resource_to->host || !resource_to->path) {
     832               0 :                 php_url_free(resource_from);
     833               0 :                 php_url_free(resource_to);
     834               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid url \"%s\"", url_from, url_to, url_to);
     835               0 :                 return 0;
     836                 :         }
     837                 : 
     838              10 :         if (strcasecmp("phar", resource_from->scheme)) {
     839               0 :                 php_url_free(resource_from);
     840               0 :                 php_url_free(resource_to);
     841               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_from);
     842               0 :                 return 0;
     843                 :         }
     844                 : 
     845              10 :         if (strcasecmp("phar", resource_to->scheme)) {
     846               0 :                 php_url_free(resource_from);
     847               0 :                 php_url_free(resource_to);
     848               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_to);
     849               0 :                 return 0;
     850                 :         }
     851                 : 
     852              10 :         host_len = strlen(resource_from->host);
     853                 : 
     854              10 :         if (SUCCESS != phar_get_archive(&phar, resource_from->host, host_len, NULL, 0, &error TSRMLS_CC)) {
     855               0 :                 php_url_free(resource_from);
     856               0 :                 php_url_free(resource_to);
     857               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
     858               0 :                 efree(error);
     859               0 :                 return 0;
     860                 :         }
     861                 : 
     862              10 :         if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
     863               0 :                 php_url_free(resource_from);
     864               0 :                 php_url_free(resource_to);
     865               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": could not make cached phar writeable", url_from, url_to);
     866               0 :                 return 0;
     867                 :         }
     868                 : 
     869              10 :         if (SUCCESS == zend_hash_find(&(phar->manifest), resource_from->path+1, strlen(resource_from->path)-1, (void **)&entry)) {
     870                 :                 phar_entry_info new, *source;
     871                 : 
     872                 :                 /* perform rename magic */
     873               5 :                 if (entry->is_deleted) {
     874               0 :                         php_url_free(resource_from);
     875               0 :                         php_url_free(resource_to);
     876               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source has been deleted", url_from, url_to);
     877               0 :                         return 0;
     878                 :                 }
     879                 :                 /* transfer all data over to the new entry */
     880               5 :                 memcpy((void *) &new, (void *) entry, sizeof(phar_entry_info));
     881                 :                 /* mark the old one for deletion */
     882               5 :                 entry->is_deleted = 1;
     883               5 :                 entry->fp = NULL;
     884               5 :                 entry->metadata = 0;
     885               5 :                 entry->link = entry->tmp = NULL;
     886               5 :                 source = entry;
     887                 : 
     888                 :                 /* add to the manifest, and then store the pointer to the new guy in entry */
     889               5 :                 zend_hash_add(&(phar->manifest), resource_to->path+1, strlen(resource_to->path)-1, (void **)&new, sizeof(phar_entry_info), (void **) &entry);
     890                 : 
     891               5 :                 entry->filename = estrdup(resource_to->path+1);
     892               5 :                 if (FAILURE == phar_copy_entry_fp(source, entry, &error TSRMLS_CC)) {
     893               0 :                         php_url_free(resource_from);
     894               0 :                         php_url_free(resource_to);
     895               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
     896               0 :                         efree(error);
     897               0 :                         zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename));
     898               0 :                         return 0;
     899                 :                 }
     900               5 :                 is_modified = 1;
     901               5 :                 entry->is_modified = 1;
     902               5 :                 entry->filename_len = strlen(entry->filename);
     903               5 :                 is_dir = entry->is_dir;
     904                 :         } else {
     905               5 :                 is_dir = zend_hash_exists(&(phar->virtual_dirs), resource_from->path+1, strlen(resource_from->path)-1);
     906               5 :                 if (!is_dir) {
     907                 :                         /* file does not exist */
     908               1 :                         php_url_free(resource_from);
     909               1 :                         php_url_free(resource_to);
     910               1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\" from extracted phar archive, source does not exist", url_from, url_to);
     911               1 :                         return 0;
     912                 : 
     913                 :                 }
     914                 :         }
     915                 : 
     916                 :         /* Rename directory. Update all nested paths */
     917               9 :         if (is_dir) {
     918                 :                 int key_type;
     919                 :                 phar_zstr key, new_key;
     920                 :                 char *str_key, *new_str_key;
     921                 :                 uint key_len, new_key_len;
     922                 :                 ulong unused;
     923               4 :                 uint from_len = strlen(resource_from->path+1);
     924               4 :                 uint to_len = strlen(resource_to->path+1);
     925                 : 
     926               4 :                 for (zend_hash_internal_pointer_reset(&phar->manifest);
     927              17 :                         HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL)) &&
     928                 :                         SUCCESS == zend_hash_get_current_data(&phar->manifest, (void **) &entry);
     929               9 :                         zend_hash_move_forward(&phar->manifest)) {
     930                 : 
     931               9 :                         PHAR_STR(key, str_key);
     932                 : 
     933               9 :                         if (!entry->is_deleted &&
     934                 :                                 key_len > from_len &&
     935                 :                                 memcmp(str_key, resource_from->path+1, from_len) == 0 &&
     936                 :                                 IS_SLASH(str_key[from_len])) {
     937                 : 
     938               7 :                                 new_key_len = key_len + to_len - from_len;
     939               7 :                                 new_str_key = emalloc(new_key_len+1);
     940               7 :                                 memcpy(new_str_key, resource_to->path + 1, to_len);
     941               7 :                                 memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len);
     942               7 :                                 new_str_key[new_key_len] = 0;
     943                 : 
     944               7 :                                 is_modified = 1;
     945               7 :                                 entry->is_modified = 1;
     946               7 :                                 efree(entry->filename);
     947               7 :                                 entry->filename = new_str_key;
     948               7 :                                 entry->filename_len = new_key_len;
     949                 : 
     950               7 :                                 PHAR_ZSTR(new_str_key, new_key);
     951                 : #if PHP_VERSION_ID < 50300
     952                 :                                 zend_hash_update_current_key_ex(&phar->manifest, key_type, new_key, new_key_len, 0, NULL);
     953                 : #else
     954               7 :                                 zend_hash_update_current_key_ex(&phar->manifest, key_type, new_key, new_key_len, 0, HASH_UPDATE_KEY_ANYWAY, NULL);
     955                 : #endif
     956                 :                         }
     957                 :                         PHAR_STR_FREE(str_key);
     958                 :                 }
     959                 : 
     960               4 :                 for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
     961              15 :                         HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL));
     962               7 :                         zend_hash_move_forward(&phar->virtual_dirs)) {
     963                 : 
     964               7 :                         PHAR_STR(key, str_key);
     965                 : 
     966               7 :                         if (key_len >= from_len &&
     967                 :                                 memcmp(str_key, resource_from->path+1, from_len) == 0 &&
     968                 :                                 (key_len == from_len || IS_SLASH(str_key[from_len]))) {
     969                 : 
     970               5 :                                 new_key_len = key_len + to_len - from_len;
     971               5 :                                 new_str_key = emalloc(new_key_len+1);
     972               5 :                                 memcpy(new_str_key, resource_to->path + 1, to_len);
     973               5 :                                 memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len);
     974               5 :                                 new_str_key[new_key_len] = 0;
     975                 : 
     976               5 :                                 PHAR_ZSTR(new_str_key, new_key);
     977                 : #if PHP_VERSION_ID < 50300
     978                 :                                 zend_hash_update_current_key_ex(&phar->virtual_dirs, key_type, new_key, new_key_len, 0, NULL);
     979                 : #else
     980               5 :                                 zend_hash_update_current_key_ex(&phar->virtual_dirs, key_type, new_key, new_key_len, 0, HASH_UPDATE_KEY_ANYWAY, NULL);
     981                 : #endif
     982               5 :                                 efree(new_str_key);
     983                 :                         }
     984                 :                         PHAR_STR_FREE(str_key);
     985                 :                 }
     986                 : 
     987               4 :                 for (zend_hash_internal_pointer_reset(&phar->mounted_dirs);
     988               9 :                         HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &key_len, &unused, 0, NULL)) &&
     989                 :                         SUCCESS == zend_hash_get_current_data(&phar->mounted_dirs, (void **) &entry);
     990               1 :                         zend_hash_move_forward(&phar->mounted_dirs)) {
     991                 : 
     992               1 :                         PHAR_STR(key, str_key);
     993                 : 
     994               1 :                         if (key_len >= from_len &&
     995                 :                                 memcmp(str_key, resource_from->path+1, from_len) == 0 &&
     996                 :                                 (key_len == from_len || IS_SLASH(str_key[from_len]))) {
     997                 : 
     998               1 :                                 new_key_len = key_len + to_len - from_len;
     999               1 :                                 new_str_key = emalloc(new_key_len+1);
    1000               1 :                                 memcpy(new_str_key, resource_to->path + 1, to_len);
    1001               1 :                                 memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len);
    1002               1 :                                 new_str_key[new_key_len] = 0;
    1003                 : 
    1004               1 :                                 PHAR_ZSTR(new_str_key, new_key);
    1005                 : #if PHP_VERSION_ID < 50300
    1006                 :                                 zend_hash_update_current_key_ex(&phar->mounted_dirs, key_type, new_key, new_key_len, 0, NULL);
    1007                 : #else
    1008               1 :                                 zend_hash_update_current_key_ex(&phar->mounted_dirs, key_type, new_key, new_key_len, 0, HASH_UPDATE_KEY_ANYWAY, NULL);
    1009                 : #endif
    1010               1 :                                 efree(new_str_key);
    1011                 :                         }
    1012                 :                         PHAR_STR_FREE(str_key);
    1013                 :                 }
    1014                 :         }
    1015                 : 
    1016               9 :         if (is_modified) {
    1017               9 :                 phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
    1018               9 :                 if (error) {
    1019               0 :                         php_url_free(resource_from);
    1020               0 :                         php_url_free(resource_to);
    1021               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
    1022               0 :                         efree(error);
    1023               0 :                         return 0;
    1024                 :                 }
    1025                 :         }
    1026                 : 
    1027               9 :         php_url_free(resource_from);
    1028               9 :         php_url_free(resource_to);
    1029                 : 
    1030               9 :         return 1;
    1031                 : }
    1032                 : /* }}} */
    1033                 : 
    1034                 : /*
    1035                 :  * Local variables:
    1036                 :  * tab-width: 4
    1037                 :  * c-basic-offset: 4
    1038                 :  * End:
    1039                 :  * vim600: noet sw=4 ts=4 fdm=marker
    1040                 :  * vim<600: noet sw=4 ts=4
    1041                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:06 +0000 (3 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.