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: 415 527 78.7 %
Date: 2014-04-16 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 16 Apr 2014 12:47:54 +0000 (2 days ago)

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