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

LCOV - code coverage report
Current view: top level - ext/phar - stream.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 404 515 78.4 %
Date: 2014-10-14 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   +----------------------------------------------------------------------+
       3             :   | phar:// stream wrapper support                                       |
       4             :   +----------------------------------------------------------------------+
       5             :   | Copyright (c) 2005-2014 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        1580 : php_url* phar_parse_url(php_stream_wrapper *wrapper, const char *filename, const char *mode, int options TSRMLS_DC) /* {{{ */
      60             : {
      61             :         php_url *resource;
      62        1580 :         char *arch = NULL, *entry = NULL, *error;
      63             :         int arch_len, entry_len;
      64             : 
      65        1580 :         if (strlen(filename) < 7 || strncasecmp(filename, "phar://", 7)) {
      66           0 :                 return NULL;
      67             :         }
      68        1580 :         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        1579 :         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        1560 :         resource = ecalloc(1, sizeof(php_url));
      86        1560 :         resource->scheme = estrndup("phar", 4);
      87        1560 :         resource->host = arch;
      88             : 
      89        1560 :         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        1668 :         if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) {
     104         126 :                 phar_archive_data *pphar = NULL, *phar;
     105             : 
     106         252 :                 if (PHAR_GLOBALS->request_init && PHAR_GLOBALS->phar_fname_map.arHash && NULL == (pphar = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_fname_map), arch, arch_len))) {
     107          37 :                         pphar = NULL;
     108             :                 }
     109         126 :                 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 the php.ini setting phar.readonly");
     112             :                         }
     113          16 :                         php_url_free(resource);
     114          16 :                         return NULL;
     115             :                 }
     116         110 :                 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, "%s", error);
     121             :                                 }
     122           2 :                                 efree(error);
     123             :                         }
     124           2 :                         php_url_free(resource);
     125           2 :                         return NULL;
     126             :                 }
     127         108 :                 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, "%s", error);
     132             :                                 }
     133           0 :                                 efree(error);
     134             :                         }
     135           0 :                         php_url_free(resource);
     136           0 :                         return NULL;
     137             :                 }
     138             :         } else {
     139        1434 :                 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, "%s", error);
     144             :                                 }
     145           7 :                                 efree(error);
     146             :                         }
     147           9 :                         php_url_free(resource);
     148           9 :                         return NULL;
     149             :                 }
     150             :         }
     151        1533 :         return resource;
     152             : }
     153             : /* }}} */
     154             : 
     155             : /**
     156             :  * used for fopen('phar://...') and company
     157             :  */
     158         619 : static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
     159             : {
     160             :         phar_archive_data *phar;
     161             :         phar_entry_data *idata;
     162             :         char *internal_file;
     163             :         char *error;
     164             :         HashTable *pharcontext;
     165         619 :         php_url *resource = NULL;
     166             :         php_stream *fpf;
     167             :         zval *pzoption, *metadata;
     168             :         uint host_len;
     169             : 
     170         619 :         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         592 :         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         592 :         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         592 :         host_len = strlen(resource->host);
     188         592 :         phar_request_initialize(TSRMLS_C);
     189             : 
     190             :         /* strip leading "/" */
     191         592 :         internal_file = estrdup(resource->path + 1);
     192         592 :         if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) {
     193          57 :                 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           9 :                         if (error) {
     195           9 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error);
     196           9 :                                 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           9 :                         efree(internal_file);
     201           9 :                         php_url_free(resource);
     202           9 :                         return NULL;
     203             :                 }
     204          48 :                 if (error) {
     205           0 :                         efree(error);
     206             :                 }
     207          48 :                 fpf = php_stream_alloc(&phar_ops, idata, NULL, mode);
     208          48 :                 php_url_free(resource);
     209          48 :                 efree(internal_file);
     210             : 
     211         144 :                 if (context && Z_TYPE(context->options) != IS_UNDEF && (pzoption = zend_hash_str_find(HASH_OF(&context->options), "phar", sizeof("phar")-1)) != NULL) {
     212           7 :                         pharcontext = HASH_OF(pzoption);
     213          36 :                         if (idata->internal_file->uncompressed_filesize == 0
     214          13 :                                 && idata->internal_file->compressed_filesize == 0
     215          12 :                                 && (pzoption = zend_hash_str_find(pharcontext, "compress", sizeof("compress")-1)) != NULL
     216             :                                 && Z_TYPE_P(pzoption) == IS_LONG
     217           5 :                                 && (Z_LVAL_P(pzoption) & ~PHAR_ENT_COMPRESSION_MASK) == 0
     218             :                         ) {
     219           5 :                                 idata->internal_file->flags &= ~PHAR_ENT_COMPRESSION_MASK;
     220           5 :                                 idata->internal_file->flags |= Z_LVAL_P(pzoption);
     221             :                         }
     222           7 :                         if ((pzoption = zend_hash_str_find(pharcontext, "metadata", sizeof("metadata")-1)) != NULL) {
     223           6 :                                 if (Z_TYPE(idata->internal_file->metadata) != IS_UNDEF) {
     224           1 :                                         zval_ptr_dtor(&idata->internal_file->metadata);
     225           1 :                                         ZVAL_UNDEF(&idata->internal_file->metadata);
     226             :                                 }
     227             : 
     228           3 :                                 metadata = pzoption;
     229           6 :                                 ZVAL_ZVAL(&idata->internal_file->metadata, metadata, 1, 0);
     230           3 :                                 idata->phar->is_modified = 1;
     231             :                         }
     232             :                 }
     233          48 :                 if (opened_path) {
     234           0 :                         spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename);
     235             :                 }
     236          48 :                 return fpf;
     237             :         } else {
     238         535 :                 if (!*internal_file && (options & STREAM_OPEN_FOR_INCLUDE)) {
     239             :                         /* retrieve the stub */
     240           2 :                         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, NULL TSRMLS_CC)) {
     241           0 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "file %s is not a valid phar archive", resource->host);
     242           0 :                                 efree(internal_file);
     243           0 :                                 php_url_free(resource);
     244           0 :                                 return NULL;
     245             :                         }
     246           2 :                         if (phar->is_tar || phar->is_zip) {
     247           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) {
     248             :                                         goto idata_error;
     249             :                                 }
     250           1 :                                 efree(internal_file);
     251           1 :                                 if (opened_path) {
     252           1 :                                         spprintf(opened_path, MAXPATHLEN, "%s", phar->fname);
     253             :                                 }
     254           1 :                                 php_url_free(resource);
     255           1 :                                 goto phar_stub;
     256             :                         } else {
     257             :                                 phar_entry_info *entry;
     258             : 
     259           1 :                                 entry = (phar_entry_info *) ecalloc(1, sizeof(phar_entry_info));
     260           1 :                                 entry->is_temp_dir = 1;
     261           1 :                                 entry->filename = estrndup("", 0);
     262           1 :                                 entry->filename_len = 0;
     263           1 :                                 entry->phar = phar;
     264           1 :                                 entry->offset = entry->offset_abs = 0;
     265           1 :                                 entry->compressed_filesize = entry->uncompressed_filesize = phar->halt_offset;
     266           1 :                                 entry->is_crc_checked = 1;
     267             : 
     268           1 :                                 idata = (phar_entry_data *) ecalloc(1, sizeof(phar_entry_data));
     269           1 :                                 idata->fp = phar_get_pharfp(phar TSRMLS_CC);
     270           1 :                                 idata->phar = phar;
     271           1 :                                 idata->internal_file = entry;
     272           1 :                                 if (!phar->is_persistent) {
     273           1 :                                         ++(entry->phar->refcount);
     274             :                                 }
     275           1 :                                 ++(entry->fp_refcount);
     276           1 :                                 php_url_free(resource);
     277           1 :                                 if (opened_path) {
     278           1 :                                         spprintf(opened_path, MAXPATHLEN, "%s", phar->fname);
     279             :                                 }
     280           1 :                                 efree(internal_file);
     281           1 :                                 goto phar_stub;
     282             :                         }
     283             :                 }
     284             :                 /* read-only access is allowed to magic files in .phar directory */
     285         533 :                 if ((FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, strlen(internal_file), "r", 0, &error, 0 TSRMLS_CC)) || !idata) {
     286             : idata_error:
     287          27 :                         if (error) {
     288           6 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error);
     289           6 :                                 efree(error);
     290             :                         } else {
     291          21 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: \"%s\" is not a file in phar \"%s\"", internal_file, resource->host);
     292             :                         }
     293          27 :                         efree(internal_file);
     294          27 :                         php_url_free(resource);
     295          27 :                         return NULL;
     296             :                 }
     297             :         }
     298         506 :         php_url_free(resource);
     299             : #if MBO_0
     300             :                 fprintf(stderr, "Pharname:   %s\n", idata->phar->filename);
     301             :                 fprintf(stderr, "Filename:   %s\n", internal_file);
     302             :                 fprintf(stderr, "Entry:      %s\n", idata->internal_file->filename);
     303             :                 fprintf(stderr, "Size:       %u\n", idata->internal_file->uncompressed_filesize);
     304             :                 fprintf(stderr, "Compressed: %u\n", idata->internal_file->flags);
     305             :                 fprintf(stderr, "Offset:     %u\n", idata->internal_file->offset_within_phar);
     306             :                 fprintf(stderr, "Cached:     %s\n", idata->internal_file->filedata ? "yes" : "no");
     307             : #endif
     308             : 
     309             :         /* check length, crc32 */
     310         506 :         if (!idata->internal_file->is_crc_checked && phar_postprocess_file(idata, idata->internal_file->crc32, &error, 2 TSRMLS_CC) != SUCCESS) {
     311           2 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error);
     312           2 :                 efree(error);
     313           2 :                 phar_entry_delref(idata TSRMLS_CC);
     314           2 :                 efree(internal_file);
     315           2 :                 return NULL;
     316             :         }
     317             : 
     318         504 :         if (!PHAR_G(cwd_init) && options & STREAM_OPEN_FOR_INCLUDE) {
     319         135 :                 char *entry = idata->internal_file->filename, *cwd;
     320             : 
     321         135 :                 PHAR_G(cwd_init) = 1;
     322         186 :                 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)) {
     323             :                         /* we're executing the stub, which doesn't count as a file */
     324          51 :                         PHAR_G(cwd_init) = 0;
     325          84 :                 } else if ((cwd = strrchr(entry, '/'))) {
     326          26 :                         PHAR_G(cwd_len) = cwd - entry;
     327          26 :                         PHAR_G(cwd) = estrndup(entry, PHAR_G(cwd_len));
     328             :                 } else {
     329             :                         /* root directory */
     330          58 :                         PHAR_G(cwd_len) = 0;
     331          58 :                         PHAR_G(cwd) = NULL;
     332             :                 }
     333             :         }
     334         504 :         if (opened_path) {
     335         265 :                 spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename);
     336             :         }
     337         504 :         efree(internal_file);
     338             : phar_stub:
     339         506 :         fpf = php_stream_alloc(&phar_ops, idata, NULL, mode);
     340         506 :         return fpf;
     341             : }
     342             : /* }}} */
     343             : 
     344             : /**
     345             :  * Used for fclose($fp) where $fp is a phar archive
     346             :  */
     347         554 : static int phar_stream_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
     348             : {
     349         554 :         phar_entry_delref((phar_entry_data *)stream->abstract TSRMLS_CC);
     350             : 
     351         554 :         return 0;
     352             : }
     353             : /* }}} */
     354             : 
     355             : /**
     356             :  * used for fread($fp) and company on a fopen()ed phar file handle
     357             :  */
     358         974 : static size_t phar_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
     359             : {
     360         974 :         phar_entry_data *data = (phar_entry_data *)stream->abstract;
     361             :         size_t got;
     362             :         phar_entry_info *entry;
     363             : 
     364         974 :         if (data->internal_file->link) {
     365           5 :                 entry = phar_get_link_source(data->internal_file TSRMLS_CC);
     366             :         } else {
     367         969 :                 entry = data->internal_file;
     368             :         }
     369             : 
     370         974 :         if (entry->is_deleted) {
     371           0 :                 stream->eof = 1;
     372           0 :                 return 0;
     373             :         }
     374             : 
     375             :         /* use our proxy position */
     376         974 :         php_stream_seek(data->fp, data->position + data->zero, SEEK_SET);
     377             : 
     378         974 :         got = php_stream_read(data->fp, buf, MIN(count, entry->uncompressed_filesize - data->position));
     379         974 :         data->position = php_stream_tell(data->fp) - data->zero;
     380         974 :         stream->eof = (data->position == (zend_off_t) entry->uncompressed_filesize);
     381             : 
     382         974 :         return got;
     383             : }
     384             : /* }}} */
     385             : 
     386             : /**
     387             :  * Used for fseek($fp) on a phar file handle
     388             :  */
     389          42 : static int phar_stream_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffset TSRMLS_DC) /* {{{ */
     390             : {
     391          42 :         phar_entry_data *data = (phar_entry_data *)stream->abstract;
     392             :         phar_entry_info *entry;
     393             :         int res;
     394             :         zend_off_t temp;
     395             : 
     396          42 :         if (data->internal_file->link) {
     397           1 :                 entry = phar_get_link_source(data->internal_file TSRMLS_CC);
     398             :         } else {
     399          41 :                 entry = data->internal_file;
     400             :         }
     401             : 
     402          42 :         switch (whence) {
     403             :                 case SEEK_END :
     404           6 :                         temp = data->zero + entry->uncompressed_filesize + offset;
     405           6 :                         break;
     406             :                 case SEEK_CUR :
     407           0 :                         temp = data->zero + data->position + offset;
     408           0 :                         break;
     409             :                 case SEEK_SET :
     410          36 :                         temp = data->zero + offset;
     411          36 :                         break;
     412             :                 default:
     413           0 :                         temp = 0;
     414             :         }
     415          42 :         if (temp > data->zero + (zend_off_t) entry->uncompressed_filesize) {
     416           4 :                 *newoffset = -1;
     417           4 :                 return -1;
     418             :         }
     419          38 :         if (temp < data->zero) {
     420           4 :                 *newoffset = -1;
     421           4 :                 return -1;
     422             :         }
     423          34 :         res = php_stream_seek(data->fp, temp, SEEK_SET);
     424          34 :         *newoffset = php_stream_tell(data->fp) - data->zero;
     425          34 :         data->position = *newoffset;
     426          34 :         return res;
     427             : }
     428             : /* }}} */
     429             : 
     430             : /**
     431             :  * Used for writing to a phar file
     432             :  */
     433          46 : static size_t phar_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
     434             : {
     435          46 :         phar_entry_data *data = (phar_entry_data *) stream->abstract;
     436             : 
     437          46 :         php_stream_seek(data->fp, data->position, SEEK_SET);
     438          46 :         if (count != php_stream_write(data->fp, buf, count)) {
     439           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);
     440           0 :                 return -1;
     441             :         }
     442          46 :         data->position = php_stream_tell(data->fp);
     443          46 :         if (data->position > (zend_off_t)data->internal_file->uncompressed_filesize) {
     444          46 :                 data->internal_file->uncompressed_filesize = data->position;
     445             :         }
     446          46 :         data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize;
     447          46 :         data->internal_file->old_flags = data->internal_file->flags;
     448          46 :         data->internal_file->is_modified = 1;
     449          46 :         return count;
     450             : }
     451             : /* }}} */
     452             : 
     453             : /**
     454             :  * Used to save work done on a writeable phar
     455             :  */
     456         554 : static int phar_stream_flush(php_stream *stream TSRMLS_DC) /* {{{ */
     457             : {
     458             :         char *error;
     459             :         int ret;
     460         554 :         phar_entry_data *data = (phar_entry_data *) stream->abstract;
     461             :         
     462         554 :         if (data->internal_file->is_modified) {
     463          48 :                 data->internal_file->timestamp = time(0);
     464          48 :                 ret = phar_flush(data->phar, 0, 0, 0, &error TSRMLS_CC);
     465          48 :                 if (error) {
     466           0 :                         php_stream_wrapper_log_error(stream->wrapper, REPORT_ERRORS TSRMLS_CC, "%s", error);
     467           0 :                         efree(error);
     468             :                 }
     469          48 :                 return ret;
     470             :         } else {
     471         506 :                 return EOF;
     472             :         }
     473             : }
     474             : /* }}} */
     475             : 
     476             :  /* {{{ phar_dostat */
     477             : /**
     478             :  * stat an opened phar file handle stream, used by phar_stat()
     479             :  */
     480        1126 : void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, zend_bool is_temp_dir TSRMLS_DC)
     481             : {
     482        1126 :         memset(ssb, 0, sizeof(php_stream_statbuf));
     483             : 
     484        2119 :         if (!is_temp_dir && !data->is_dir) {
     485         993 :                 ssb->sb.st_size = data->uncompressed_filesize;
     486         993 :                 ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
     487         993 :                 ssb->sb.st_mode |= S_IFREG; /* regular file */
     488             :                 /* timestamp is just the timestamp when this was added to the phar */
     489             : #ifdef NETWARE
     490             :                 ssb->sb.st_mtime.tv_sec = data->timestamp;
     491             :                 ssb->sb.st_atime.tv_sec = data->timestamp;
     492             :                 ssb->sb.st_ctime.tv_sec = data->timestamp;
     493             : #else
     494         993 :                 ssb->sb.st_mtime = data->timestamp;
     495         993 :                 ssb->sb.st_atime = data->timestamp;
     496         993 :                 ssb->sb.st_ctime = data->timestamp;
     497             : #endif
     498         204 :         } else if (!is_temp_dir && data->is_dir) {
     499          71 :                 ssb->sb.st_size = 0;
     500          71 :                 ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
     501          71 :                 ssb->sb.st_mode |= S_IFDIR; /* regular directory */
     502             :                 /* timestamp is just the timestamp when this was added to the phar */
     503             : #ifdef NETWARE
     504             :                 ssb->sb.st_mtime.tv_sec = data->timestamp;
     505             :                 ssb->sb.st_atime.tv_sec = data->timestamp;
     506             :                 ssb->sb.st_ctime.tv_sec = data->timestamp;
     507             : #else
     508          71 :                 ssb->sb.st_mtime = data->timestamp;
     509          71 :                 ssb->sb.st_atime = data->timestamp;
     510          71 :                 ssb->sb.st_ctime = data->timestamp;
     511             : #endif
     512             :         } else {
     513          62 :                 ssb->sb.st_size = 0;
     514          62 :                 ssb->sb.st_mode = 0777;
     515          62 :                 ssb->sb.st_mode |= S_IFDIR; /* regular directory */
     516             : #ifdef NETWARE
     517             :                 ssb->sb.st_mtime.tv_sec = phar->max_timestamp;
     518             :                 ssb->sb.st_atime.tv_sec = phar->max_timestamp;
     519             :                 ssb->sb.st_ctime.tv_sec = phar->max_timestamp;
     520             : #else
     521          62 :                 ssb->sb.st_mtime = phar->max_timestamp;
     522          62 :                 ssb->sb.st_atime = phar->max_timestamp;
     523          62 :                 ssb->sb.st_ctime = phar->max_timestamp;
     524             : #endif
     525             :         }
     526        1126 :         if (!phar->is_writeable) {
     527         555 :                 ssb->sb.st_mode = (ssb->sb.st_mode & 0555) | (ssb->sb.st_mode & ~0777);
     528             :         }
     529             : 
     530        1126 :         ssb->sb.st_nlink = 1;
     531        1126 :         ssb->sb.st_rdev = -1;
     532             :         /* this is only for APC, so use /dev/null device - no chance of conflict there! */
     533        1126 :         ssb->sb.st_dev = 0xc;
     534             :         /* generate unique inode number for alias/filename, so no phars will conflict */
     535        1126 :         if (!is_temp_dir) {
     536        1064 :                 ssb->sb.st_ino = data->inode;
     537             :         }
     538             : #ifndef PHP_WIN32
     539        1126 :         ssb->sb.st_blksize = -1;
     540        1126 :         ssb->sb.st_blocks = -1;
     541             : #endif
     542        1126 : }
     543             : /* }}}*/
     544             : 
     545             : /**
     546             :  * Stat an opened phar file handle
     547             :  */
     548         738 : static int phar_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */
     549             : {
     550         738 :         phar_entry_data *data = (phar_entry_data *)stream->abstract;
     551             : 
     552             :         /* If ssb is NULL then someone is misbehaving */
     553         738 :         if (!ssb) {
     554           0 :                 return -1;
     555             :         }
     556             : 
     557         738 :         phar_dostat(data->phar, data->internal_file, ssb, 0 TSRMLS_CC);
     558         738 :         return 0;
     559             : }
     560             : /* }}} */
     561             : 
     562             : /**
     563             :  * Stream wrapper stat implementation of stat()
     564             :  */
     565         425 : static int phar_wrapper_stat(php_stream_wrapper *wrapper, const char *url, int flags,
     566             :                                   php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) /* {{{ */
     567             : {
     568         425 :         php_url *resource = NULL;
     569             :         char *internal_file, *error;
     570             :         phar_archive_data *phar;
     571             :         phar_entry_info *entry;
     572             :         uint host_len;
     573             :         int internal_file_len;
     574             : 
     575         425 :         if ((resource = phar_parse_url(wrapper, url, "r", flags|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
     576           6 :                 return FAILURE;
     577             :         }
     578             : 
     579             :         /* we must have at the very least phar://alias.phar/internalfile.php */
     580         419 :         if (!resource->scheme || !resource->host || !resource->path) {
     581           0 :                 php_url_free(resource);
     582           0 :                 return FAILURE;
     583             :         }
     584             : 
     585         419 :         if (strcasecmp("phar", resource->scheme)) {
     586           0 :                 php_url_free(resource);
     587           0 :                 return FAILURE;
     588             :         }
     589             : 
     590         419 :         host_len = strlen(resource->host);
     591         419 :         phar_request_initialize(TSRMLS_C);
     592             : 
     593         419 :         internal_file = resource->path + 1; /* strip leading "/" */
     594             :         /* find the phar in our trusty global hash indexed by alias (host of phar://blah.phar/file.whatever) */
     595         419 :         if (FAILURE == phar_get_archive(&phar, resource->host, host_len, NULL, 0, &error TSRMLS_CC)) {
     596           0 :                 php_url_free(resource);
     597           0 :                 if (error) {
     598           0 :                         efree(error);
     599             :                 }
     600           0 :                 return FAILURE;
     601             :         }
     602         419 :         if (error) {
     603           0 :                 efree(error);
     604             :         }
     605         419 :         if (*internal_file == '\0') {
     606             :                 /* root directory requested */
     607           1 :                 phar_dostat(phar, NULL, ssb, 1 TSRMLS_CC);
     608           1 :                 php_url_free(resource);
     609           1 :                 return SUCCESS;
     610             :         }
     611         418 :         if (!phar->manifest.arHash) {
     612           0 :                 php_url_free(resource);
     613           0 :                 return FAILURE;
     614             :         }
     615         418 :         internal_file_len = strlen(internal_file);
     616             :         /* search through the manifest of files, and if we have an exact match, it's a file */
     617         836 :         if (NULL != (entry = zend_hash_str_find_ptr(&phar->manifest, internal_file, internal_file_len))) {
     618         324 :                 phar_dostat(phar, entry, ssb, 0 TSRMLS_CC);
     619         324 :                 php_url_free(resource);
     620         324 :                 return SUCCESS;
     621             :         }
     622          94 :         if (zend_hash_str_exists(&(phar->virtual_dirs), internal_file, internal_file_len)) {
     623          61 :                 phar_dostat(phar, NULL, ssb, 1 TSRMLS_CC);
     624          61 :                 php_url_free(resource);
     625          61 :                 return SUCCESS;
     626             :         }
     627             :         /* check for mounted directories */
     628          33 :         if (phar->mounted_dirs.arHash && zend_hash_num_elements(&phar->mounted_dirs)) {
     629             :                 zend_string *str_key;
     630             : 
     631          22 :                 ZEND_HASH_FOREACH_STR_KEY(&phar->mounted_dirs, str_key) {
     632           8 :                         if ((int)str_key->len >= internal_file_len || strncmp(str_key->val, internal_file, str_key->len)) {
     633           6 :                                 continue;
     634             :                         } else {
     635             :                                 char *test;
     636             :                                 int test_len;
     637             :                                 php_stream_statbuf ssbi;
     638             : 
     639           4 :                                 if (NULL == (entry = zend_hash_find_ptr(&phar->manifest, str_key))) {
     640           0 :                                         goto free_resource;
     641             :                                 }
     642           2 :                                 if (!entry->tmp || !entry->is_mounted) {
     643             :                                         goto free_resource;
     644             :                                 }
     645           2 :                                 test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + str_key->len);
     646           2 :                                 if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
     647           0 :                                         efree(test);
     648           0 :                                         continue;
     649             :                                 }
     650             :                                 /* mount the file/directory just in time */
     651           2 :                                 if (SUCCESS != phar_mount_entry(phar, test, test_len, internal_file, internal_file_len TSRMLS_CC)) {
     652           0 :                                         efree(test);
     653           0 :                                         goto free_resource;
     654             :                                 }
     655           2 :                                 efree(test);
     656           4 :                                 if (NULL == (entry = zend_hash_str_find_ptr(&phar->manifest, internal_file, internal_file_len))) {
     657           0 :                                         goto free_resource;
     658             :                                 }
     659           2 :                                 phar_dostat(phar, entry, ssb, 0 TSRMLS_CC);
     660           2 :                                 php_url_free(resource);
     661           2 :                                 return SUCCESS;
     662             :                         }
     663             :                 } ZEND_HASH_FOREACH_END();
     664             :         }
     665             : free_resource:
     666          31 :         php_url_free(resource);
     667          31 :         return FAILURE;
     668             : }
     669             : /* }}} */
     670             : 
     671             : /**
     672             :  * Unlink a file within a phar archive
     673             :  */
     674          19 : static int phar_wrapper_unlink(php_stream_wrapper *wrapper, const char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
     675             : {
     676             :         php_url *resource;
     677             :         char *internal_file, *error;
     678             :         int internal_file_len;
     679             :         phar_entry_data *idata;
     680             :         phar_archive_data *pphar;
     681             :         uint host_len;
     682             : 
     683          19 :         if ((resource = phar_parse_url(wrapper, url, "rb", options TSRMLS_CC)) == NULL) {
     684           3 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: unlink failed");
     685           3 :                 return 0;
     686             :         }
     687             : 
     688             :         /* we must have at the very least phar://alias.phar/internalfile.php */
     689          16 :         if (!resource->scheme || !resource->host || !resource->path) {
     690           0 :                 php_url_free(resource);
     691           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url);
     692           0 :                 return 0;
     693             :         }
     694             : 
     695          16 :         if (strcasecmp("phar", resource->scheme)) {
     696           0 :                 php_url_free(resource);
     697           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url);
     698           0 :                 return 0;
     699             :         }
     700             : 
     701          16 :         host_len = strlen(resource->host);
     702          16 :         phar_request_initialize(TSRMLS_C);
     703             : 
     704          32 :         pphar = zend_hash_str_find_ptr(&(PHAR_GLOBALS->phar_fname_map), resource->host, host_len);
     705          16 :         if (PHAR_G(readonly) && (!pphar || !pphar->is_data)) {
     706           3 :                 php_url_free(resource);
     707           3 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by the php.ini setting phar.readonly");
     708           3 :                 return 0;
     709             :         }
     710             : 
     711             :         /* need to copy to strip leading "/", will get touched again */
     712          13 :         internal_file = estrdup(resource->path + 1);
     713          13 :         internal_file_len = strlen(internal_file);
     714          13 :         if (FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, internal_file_len, "r", 0, &error, 1 TSRMLS_CC)) {
     715             :                 /* constraints of fp refcount were not met */
     716           1 :                 if (error) {
     717           0 :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed: %s", url, error);
     718           0 :                         efree(error);
     719             :                 } else {
     720           1 :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed, file does not exist", url);
     721             :                 }
     722           1 :                 efree(internal_file);
     723           1 :                 php_url_free(resource);
     724           1 :                 return 0;
     725             :         }
     726          12 :         if (error) {
     727           0 :                 efree(error);
     728             :         }
     729          12 :         if (idata->internal_file->fp_refcount > 1) {
     730             :                 /* more than just our fp resource is open for this file */
     731           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);
     732           3 :                 efree(internal_file);
     733           3 :                 php_url_free(resource);
     734           3 :                 phar_entry_delref(idata TSRMLS_CC);
     735           3 :                 return 0;
     736             :         }
     737           9 :         php_url_free(resource);
     738           9 :         efree(internal_file);
     739           9 :         phar_entry_remove(idata, &error TSRMLS_CC);
     740           9 :         if (error) {
     741           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error);
     742           0 :                 efree(error);
     743             :         }
     744           9 :         return 1;
     745             : }
     746             : /* }}} */
     747             : 
     748          15 : static int phar_wrapper_rename(php_stream_wrapper *wrapper, const char *url_from, const char *url_to, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
     749             : {
     750             :         php_url *resource_from, *resource_to;
     751             :         char *error;
     752             :         phar_archive_data *phar, *pfrom, *pto;
     753             :         phar_entry_info *entry;
     754             :         uint host_len;
     755          15 :         int is_dir = 0;
     756          15 :         int is_modified = 0;
     757             : 
     758          15 :         error = NULL;
     759             : 
     760          15 :         if ((resource_from = phar_parse_url(wrapper, url_from, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
     761           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);
     762           2 :                 return 0;
     763             :         }
     764          13 :         if (SUCCESS != phar_get_archive(&pfrom, resource_from->host, strlen(resource_from->host), NULL, 0, &error TSRMLS_CC)) {
     765           0 :                 pfrom = NULL;
     766           0 :                 if (error) {
     767           0 :                         efree(error);
     768             :                 }
     769             :         }
     770          13 :         if (PHAR_G(readonly) && (!pfrom || !pfrom->is_data)) {
     771           0 :                 php_url_free(resource_from);
     772           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: Write operations disabled by the php.ini setting phar.readonly");
     773           0 :                 return 0;
     774             :         }
     775             : 
     776          13 :         if ((resource_to = phar_parse_url(wrapper, url_to, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
     777           2 :                 php_url_free(resource_from);
     778           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);
     779           2 :                 return 0;
     780             :         }
     781          11 :         if (SUCCESS != phar_get_archive(&pto, resource_to->host, strlen(resource_to->host), NULL, 0, &error TSRMLS_CC)) {
     782           0 :                 if (error) {
     783           0 :                         efree(error);
     784             :                 }
     785           0 :                 pto = NULL;
     786             :         }
     787          11 :         if (PHAR_G(readonly) && (!pto || !pto->is_data)) {
     788           0 :                 php_url_free(resource_from);
     789           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: Write operations disabled by the php.ini setting phar.readonly");
     790           0 :                 return 0;
     791             :         }
     792             : 
     793          11 :         if (strcmp(resource_from->host, resource_to->host)) {
     794           1 :                 php_url_free(resource_from);
     795           1 :                 php_url_free(resource_to);
     796           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);
     797           1 :                 return 0;
     798             :         }
     799             : 
     800             :         /* we must have at the very least phar://alias.phar/internalfile.php */
     801          10 :         if (!resource_from->scheme || !resource_from->host || !resource_from->path) {
     802           0 :                 php_url_free(resource_from);
     803           0 :                 php_url_free(resource_to);
     804           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);
     805           0 :                 return 0;
     806             :         }
     807             : 
     808          10 :         if (!resource_to->scheme || !resource_to->host || !resource_to->path) {
     809           0 :                 php_url_free(resource_from);
     810           0 :                 php_url_free(resource_to);
     811           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);
     812           0 :                 return 0;
     813             :         }
     814             : 
     815          10 :         if (strcasecmp("phar", resource_from->scheme)) {
     816           0 :                 php_url_free(resource_from);
     817           0 :                 php_url_free(resource_to);
     818           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);
     819           0 :                 return 0;
     820             :         }
     821             : 
     822          10 :         if (strcasecmp("phar", resource_to->scheme)) {
     823           0 :                 php_url_free(resource_from);
     824           0 :                 php_url_free(resource_to);
     825           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);
     826           0 :                 return 0;
     827             :         }
     828             : 
     829          10 :         host_len = strlen(resource_from->host);
     830             : 
     831          10 :         if (SUCCESS != phar_get_archive(&phar, resource_from->host, host_len, NULL, 0, &error TSRMLS_CC)) {
     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\": %s", url_from, url_to, error);
     835           0 :                 efree(error);
     836           0 :                 return 0;
     837             :         }
     838             : 
     839          10 :         if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
     840           0 :                 php_url_free(resource_from);
     841           0 :                 php_url_free(resource_to);
     842           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);
     843           0 :                 return 0;
     844             :         }
     845             : 
     846          20 :         if (NULL != (entry = zend_hash_str_find_ptr(&(phar->manifest), resource_from->path+1, strlen(resource_from->path)-1))) {
     847             :                 phar_entry_info new, *source;
     848             : 
     849             :                 /* perform rename magic */
     850           5 :                 if (entry->is_deleted) {
     851           0 :                         php_url_free(resource_from);
     852           0 :                         php_url_free(resource_to);
     853           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);
     854           0 :                         return 0;
     855             :                 }
     856             :                 /* transfer all data over to the new entry */
     857           5 :                 memcpy((void *) &new, (void *) entry, sizeof(phar_entry_info));
     858             :                 /* mark the old one for deletion */
     859           5 :                 entry->is_deleted = 1;
     860           5 :                 entry->fp = NULL;
     861           5 :                 ZVAL_UNDEF(&entry->metadata);
     862           5 :                 entry->link = entry->tmp = NULL;
     863           5 :                 source = entry;
     864             : 
     865             :                 /* add to the manifest, and then store the pointer to the new guy in entry */
     866          10 :                 entry = zend_hash_str_add_mem(&(phar->manifest), resource_to->path+1, strlen(resource_to->path)-1, (void **)&new, sizeof(phar_entry_info));
     867             : 
     868           5 :                 entry->filename = estrdup(resource_to->path+1);
     869           5 :                 if (FAILURE == phar_copy_entry_fp(source, entry, &error TSRMLS_CC)) {
     870           0 :                         php_url_free(resource_from);
     871           0 :                         php_url_free(resource_to);
     872           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
     873           0 :                         efree(error);
     874           0 :                         zend_hash_str_del(&(phar->manifest), entry->filename, strlen(entry->filename));
     875           0 :                         return 0;
     876             :                 }
     877           5 :                 is_modified = 1;
     878           5 :                 entry->is_modified = 1;
     879           5 :                 entry->filename_len = strlen(entry->filename);
     880           5 :                 is_dir = entry->is_dir;
     881             :         } else {
     882           5 :                 is_dir = zend_hash_str_exists(&(phar->virtual_dirs), resource_from->path+1, strlen(resource_from->path)-1);
     883           5 :                 if (!is_dir) {
     884             :                         /* file does not exist */
     885           1 :                         php_url_free(resource_from);
     886           1 :                         php_url_free(resource_to);
     887           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);
     888           1 :                         return 0;
     889             : 
     890             :                 }
     891             :         }
     892             : 
     893             :         /* Rename directory. Update all nested paths */
     894           9 :         if (is_dir) {
     895             :                 Bucket *b;
     896             :                 zend_string *str_key;
     897             :                 zend_string *new_str_key;
     898           4 :                 uint from_len = strlen(resource_from->path+1);
     899           4 :                 uint to_len = strlen(resource_to->path+1);
     900             : 
     901          22 :                 ZEND_HASH_FOREACH_BUCKET(&phar->manifest, b) {
     902           9 :                         str_key = b->key;
     903           9 :                         entry = Z_PTR(b->val);
     904          34 :                         if (!entry->is_deleted &&
     905           9 :                                 str_key->len > from_len &&
     906           9 :                                 memcmp(str_key->val, resource_from->path+1, from_len) == 0 &&
     907           7 :                                 IS_SLASH(str_key->val[from_len])) {
     908             : 
     909          14 :                                 new_str_key = zend_string_alloc(str_key->len + to_len - from_len, 0);
     910           7 :                                 memcpy(new_str_key->val, resource_to->path + 1, to_len);
     911           7 :                                 memcpy(new_str_key->val + to_len, str_key->val + from_len, str_key->len - from_len);
     912           7 :                                 new_str_key->val[new_str_key->len] = 0;
     913             : 
     914           7 :                                 is_modified = 1;
     915           7 :                                 entry->is_modified = 1;
     916           7 :                                 efree(entry->filename);
     917             :                                 // TODO: avoid reallocation (make entry->filename zend_string*)
     918           7 :                                 entry->filename = estrndup(new_str_key->val, new_str_key->len);
     919           7 :                                 entry->filename_len = new_str_key->len;
     920             : 
     921             :                                 zend_string_release(str_key);
     922           7 :                                 b->h = zend_string_hash_val(new_str_key);
     923           7 :                                 b->key = new_str_key;
     924             :                         }
     925             :                 } ZEND_HASH_FOREACH_END();
     926           4 :                 zend_hash_rehash(&phar->manifest);
     927             : 
     928          18 :                 ZEND_HASH_FOREACH_BUCKET(&phar->virtual_dirs, b) {
     929           7 :                         str_key = b->key;
     930          20 :                         if (str_key->len >= from_len &&
     931           7 :                                 memcmp(str_key->val, resource_from->path+1, from_len) == 0 &&
     932           6 :                                 (str_key->len == from_len || IS_SLASH(str_key->val[from_len]))) {
     933             : 
     934          10 :                                 new_str_key = zend_string_alloc(str_key->len + to_len - from_len, 0);
     935           5 :                                 memcpy(new_str_key->val, resource_to->path + 1, to_len);
     936           5 :                                 memcpy(new_str_key->val + to_len, str_key->val + from_len, str_key->len - from_len);
     937           5 :                                 new_str_key->val[new_str_key->len] = 0;
     938             : 
     939             :                                 zend_string_release(str_key);
     940           5 :                                 b->h = zend_string_hash_val(new_str_key);
     941           5 :                                 b->key = new_str_key;
     942             :                         }
     943             :                 } ZEND_HASH_FOREACH_END();
     944           4 :                 zend_hash_rehash(&phar->virtual_dirs);
     945             : 
     946           6 :                 ZEND_HASH_FOREACH_BUCKET(&phar->mounted_dirs, b) {
     947           1 :                         str_key = b->key;
     948           4 :                         if (str_key->len >= from_len &&
     949           1 :                                 memcmp(str_key->val, resource_from->path+1, from_len) == 0 &&
     950           2 :                                 (str_key->len == from_len || IS_SLASH(str_key->val[from_len]))) {
     951             : 
     952           2 :                                 new_str_key = zend_string_alloc(str_key->len + to_len - from_len, 0);
     953           1 :                                 memcpy(new_str_key->val, resource_to->path + 1, to_len);
     954           1 :                                 memcpy(new_str_key->val + to_len, str_key->val + from_len, str_key->len - from_len);
     955           1 :                                 new_str_key->val[new_str_key->len] = 0;
     956             : 
     957             :                                 zend_string_release(str_key);
     958           1 :                                 b->h = zend_string_hash_val(new_str_key);
     959           1 :                                 b->key = new_str_key;
     960             :                         }
     961             :                 } ZEND_HASH_FOREACH_END();
     962           4 :                 zend_hash_rehash(&phar->mounted_dirs);
     963             :         }
     964             : 
     965           9 :         if (is_modified) {
     966           9 :                 phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
     967           9 :                 if (error) {
     968           0 :                         php_url_free(resource_from);
     969           0 :                         php_url_free(resource_to);
     970           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
     971           0 :                         efree(error);
     972           0 :                         return 0;
     973             :                 }
     974             :         }
     975             : 
     976           9 :         php_url_free(resource_from);
     977           9 :         php_url_free(resource_to);
     978             : 
     979           9 :         return 1;
     980             : }
     981             : /* }}} */
     982             : 
     983             : /*
     984             :  * Local variables:
     985             :  * tab-width: 4
     986             :  * c-basic-offset: 4
     987             :  * End:
     988             :  * vim600: noet sw=4 ts=4 fdm=marker
     989             :  * vim<600: noet sw=4 ts=4
     990             :  */

Generated by: LCOV version 1.10

Generated at Tue, 14 Oct 2014 07:25:47 +0000 (6 days ago)

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