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

Generated by: LCOV version 1.10

Generated at Sat, 29 Aug 2015 10:22:21 +0000 (3 days ago)

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