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

Generated by: LCOV version 1.10

Generated at Wed, 24 Aug 2016 12:20:28 +0000 (2 days ago)

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