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: 419 533 78.6 %
Date: 2014-09-13 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        1556 : php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC) /* {{{ */
      60             : {
      61             :         php_url *resource;
      62        1556 :         char *arch = NULL, *entry = NULL, *error;
      63             :         int arch_len, entry_len;
      64             : 
      65        1556 :         if (strlen(filename) < 7 || strncasecmp(filename, "phar://", 7)) {
      66           0 :                 return NULL;
      67             :         }
      68        1556 :         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        1555 :         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        1536 :         resource = ecalloc(1, sizeof(php_url));
      86        1536 :         resource->scheme = estrndup("phar", 4);
      87        1536 :         resource->host = arch;
      88             : 
      89        1536 :         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        1648 :         if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) {
     104         130 :                 phar_archive_data **pphar = NULL, *phar;
     105             : 
     106         130 :                 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         130 :                 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         114 :                 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         112 :                 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        1406 :                 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        1509 :         return resource;
     152             : }
     153             : /* }}} */
     154             : 
     155             : /**
     156             :  * used for fopen('phar://...') and company
     157             :  */
     158         626 : static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */
     159             : {
     160             :         phar_archive_data *phar;
     161             :         phar_entry_data *idata;
     162             :         char *internal_file;
     163             :         char *error;
     164             :         HashTable *pharcontext;
     165         626 :         php_url *resource = NULL;
     166             :         php_stream *fpf;
     167             :         zval **pzoption, *metadata;
     168             :         uint host_len;
     169             : 
     170         626 :         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         599 :         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         599 :         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         599 :         host_len = strlen(resource->host);
     188         599 :         phar_request_initialize(TSRMLS_C);
     189             : 
     190             :         /* strip leading "/" */
     191         599 :         internal_file = estrdup(resource->path + 1);
     192         599 :         if (mode[0] == 'w' || (mode[0] == 'r' && mode[1] == '+')) {
     193          59 :                 if (NULL == (idata = phar_get_or_create_entry_data(resource->host, host_len, internal_file, strlen(internal_file), mode, 0, &error, 1 TSRMLS_CC))) {
     194           9 :                         if (error) {
     195           9 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error);
     196           9 :                                 efree(error);
     197             :                         } else {
     198           0 :                                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: file \"%s\" could not be created in phar \"%s\"", internal_file, resource->host);
     199             :                         }
     200           9 :                         efree(internal_file);
     201           9 :                         php_url_free(resource);
     202           9 :                         return NULL;
     203             :                 }
     204          50 :                 if (error) {
     205           0 :                         efree(error);
     206             :                 }
     207          50 :                 fpf = php_stream_alloc(&phar_ops, idata, NULL, mode);
     208          50 :                 php_url_free(resource);
     209          50 :                 efree(internal_file);
     210             : 
     211          50 :                 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          15 :                                 ZVAL_ZVAL(idata->internal_file->metadata, metadata, 1, 0);
     231           3 :                                 idata->phar->is_modified = 1;
     232             :                         }
     233             :                 }
     234          50 :                 if (opened_path) {
     235           0 :                         spprintf(opened_path, MAXPATHLEN, "phar://%s/%s", idata->phar->fname, idata->internal_file->filename);
     236             :                 }
     237          50 :                 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         267 :                 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         559 : static int phar_stream_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */
     349             : {
     350         559 :         phar_entry_delref((phar_entry_data *)stream->abstract TSRMLS_CC);
     351             : 
     352         559 :         return 0;
     353             : }
     354             : /* }}} */
     355             : 
     356             : /**
     357             :  * used for fread($fp) and company on a fopen()ed phar file handle
     358             :  */
     359         981 : static size_t phar_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */
     360             : {
     361         981 :         phar_entry_data *data = (phar_entry_data *)stream->abstract;
     362             :         size_t got;
     363             :         phar_entry_info *entry;
     364             : 
     365         981 :         if (data->internal_file->link) {
     366           5 :                 entry = phar_get_link_source(data->internal_file TSRMLS_CC);
     367             :         } else {
     368         976 :                 entry = data->internal_file;
     369             :         }
     370             : 
     371         981 :         if (entry->is_deleted) {
     372           0 :                 stream->eof = 1;
     373           0 :                 return 0;
     374             :         }
     375             : 
     376             :         /* use our proxy position */
     377         981 :         php_stream_seek(data->fp, data->position + data->zero, SEEK_SET);
     378             : 
     379         981 :         got = php_stream_read(data->fp, buf, MIN(count, entry->uncompressed_filesize - data->position));
     380         981 :         data->position = php_stream_tell(data->fp) - data->zero;
     381         981 :         stream->eof = (data->position == (off_t) entry->uncompressed_filesize);
     382             : 
     383         981 :         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          48 : static size_t phar_stream_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */
     435             : {
     436          48 :         phar_entry_data *data = (phar_entry_data *) stream->abstract;
     437             : 
     438          48 :         php_stream_seek(data->fp, data->position, SEEK_SET);
     439          48 :         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          48 :         data->position = php_stream_tell(data->fp);
     444          48 :         if (data->position > (off_t)data->internal_file->uncompressed_filesize) {
     445          48 :                 data->internal_file->uncompressed_filesize = data->position;
     446             :         }
     447          48 :         data->internal_file->compressed_filesize = data->internal_file->uncompressed_filesize;
     448          48 :         data->internal_file->old_flags = data->internal_file->flags;
     449          48 :         data->internal_file->is_modified = 1;
     450          48 :         return count;
     451             : }
     452             : /* }}} */
     453             : 
     454             : /**
     455             :  * Used to save work done on a writeable phar
     456             :  */
     457         559 : static int phar_stream_flush(php_stream *stream TSRMLS_DC) /* {{{ */
     458             : {
     459             :         char *error;
     460             :         int ret;
     461         559 :         phar_entry_data *data = (phar_entry_data *) stream->abstract;
     462             :         
     463         559 :         if (data->internal_file->is_modified) {
     464          50 :                 data->internal_file->timestamp = time(0);
     465          50 :                 ret = phar_flush(data->phar, 0, 0, 0, &error TSRMLS_CC);
     466          50 :                 if (error) {
     467           0 :                         php_stream_wrapper_log_error(stream->wrapper, REPORT_ERRORS TSRMLS_CC, "%s", error);
     468           0 :                         efree(error);
     469             :                 }
     470          50 :                 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        1096 : void phar_dostat(phar_archive_data *phar, phar_entry_info *data, php_stream_statbuf *ssb, zend_bool is_temp_dir TSRMLS_DC)
     482             : {
     483        1096 :         memset(ssb, 0, sizeof(php_stream_statbuf));
     484             : 
     485        2059 :         if (!is_temp_dir && !data->is_dir) {
     486         963 :                 ssb->sb.st_size = data->uncompressed_filesize;
     487         963 :                 ssb->sb.st_mode = data->flags & PHAR_ENT_PERM_MASK;
     488         963 :                 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         963 :                 ssb->sb.st_mtime = data->timestamp;
     496         963 :                 ssb->sb.st_atime = data->timestamp;
     497         963 :                 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        1096 :         if (!phar->is_writeable) {
     528         521 :                 ssb->sb.st_mode = (ssb->sb.st_mode & 0555) | (ssb->sb.st_mode & ~0777);
     529             :         }
     530             : 
     531        1096 :         ssb->sb.st_nlink = 1;
     532        1096 :         ssb->sb.st_rdev = -1;
     533             :         /* this is only for APC, so use /dev/null device - no chance of conflict there! */
     534        1096 :         ssb->sb.st_dev = 0xc;
     535             :         /* generate unique inode number for alias/filename, so no phars will conflict */
     536        1096 :         if (!is_temp_dir) {
     537        1034 :                 ssb->sb.st_ino = data->inode;
     538             :         }
     539             : #ifndef PHP_WIN32
     540        1096 :         ssb->sb.st_blksize = -1;
     541        1096 :         ssb->sb.st_blocks = -1;
     542             : #endif
     543        1096 : }
     544             : /* }}}*/
     545             : 
     546             : /**
     547             :  * Stat an opened phar file handle
     548             :  */
     549         742 : static int phar_stream_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */
     550             : {
     551         742 :         phar_entry_data *data = (phar_entry_data *)stream->abstract;
     552             : 
     553             :         /* If ssb is NULL then someone is misbehaving */
     554         742 :         if (!ssb) {
     555           0 :                 return -1;
     556             :         }
     557             : 
     558         742 :         phar_dostat(data->phar, data->internal_file, ssb, 0 TSRMLS_CC);
     559         742 :         return 0;
     560             : }
     561             : /* }}} */
     562             : 
     563             : /**
     564             :  * Stream wrapper stat implementation of stat()
     565             :  */
     566         392 : static int phar_wrapper_stat(php_stream_wrapper *wrapper, char *url, int flags,
     567             :                                   php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC) /* {{{ */
     568             : {
     569         392 :         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         392 :         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         386 :         if (!resource->scheme || !resource->host || !resource->path) {
     582           0 :                 php_url_free(resource);
     583           0 :                 return FAILURE;
     584             :         }
     585             : 
     586         386 :         if (strcasecmp("phar", resource->scheme)) {
     587           0 :                 php_url_free(resource);
     588           0 :                 return FAILURE;
     589             :         }
     590             : 
     591         386 :         host_len = strlen(resource->host);
     592         386 :         phar_request_initialize(TSRMLS_C);
     593             : 
     594         386 :         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         386 :         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         386 :         if (error) {
     604           0 :                 efree(error);
     605             :         }
     606         386 :         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         385 :         if (!phar->manifest.arBuckets) {
     613           0 :                 php_url_free(resource);
     614           0 :                 return FAILURE;
     615             :         }
     616         385 :         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         385 :         if (SUCCESS == zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
     619         290 :                 phar_dostat(phar, entry, ssb, 0 TSRMLS_CC);
     620         290 :                 php_url_free(resource);
     621         290 :                 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             :                 phar_zstr key;
     631             :                 char *str_key;
     632             :                 ulong unused;
     633             :                 uint keylen;
     634             :                 HashPosition pos;
     635             : 
     636           8 :                 zend_hash_internal_pointer_reset_ex(&phar->mounted_dirs, &pos);
     637           8 :                 while (FAILURE != zend_hash_has_more_elements_ex(&phar->mounted_dirs, &pos)) {
     638           8 :                         if (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &keylen, &unused, 0, &pos)) {
     639           0 :                                 break;
     640             :                         }
     641           8 :                         PHAR_STR(key, str_key);
     642           8 :                         if ((int)keylen >= internal_file_len || strncmp(str_key, internal_file, keylen)) {
     643           6 :                                 zend_hash_move_forward_ex(&phar->mounted_dirs, &pos);
     644             :                                 PHAR_STR_FREE(str_key);
     645           6 :                                 continue;
     646             :                         } else {
     647             :                                 char *test;
     648             :                                 int test_len;
     649             :                                 php_stream_statbuf ssbi;
     650             : 
     651           2 :                                 if (SUCCESS != zend_hash_find(&phar->manifest, str_key, keylen, (void **) &entry)) {
     652             :                                         PHAR_STR_FREE(str_key);
     653           0 :                                         goto free_resource;
     654             :                                 }
     655             :                                 PHAR_STR_FREE(str_key);
     656           2 :                                 if (!entry->tmp || !entry->is_mounted) {
     657             :                                         goto free_resource;
     658             :                                 }
     659           2 :                                 test_len = spprintf(&test, MAXPATHLEN, "%s%s", entry->tmp, internal_file + keylen);
     660           2 :                                 if (SUCCESS != php_stream_stat_path(test, &ssbi)) {
     661           0 :                                         efree(test);
     662           0 :                                         zend_hash_move_forward_ex(&phar->mounted_dirs, &pos);
     663           0 :                                         continue;
     664             :                                 }
     665             :                                 /* mount the file/directory just in time */
     666           2 :                                 if (SUCCESS != phar_mount_entry(phar, test, test_len, internal_file, internal_file_len TSRMLS_CC)) {
     667           0 :                                         efree(test);
     668           0 :                                         goto free_resource;
     669             :                                 }
     670           2 :                                 efree(test);
     671           2 :                                 if (SUCCESS != zend_hash_find(&phar->manifest, internal_file, internal_file_len, (void**)&entry)) {
     672           0 :                                         goto free_resource;
     673             :                                 }
     674           2 :                                 phar_dostat(phar, entry, ssb, 0 TSRMLS_CC);
     675           2 :                                 php_url_free(resource);
     676           2 :                                 return SUCCESS;
     677             :                         }
     678             :                 }
     679             :         }
     680             : free_resource:
     681          32 :         php_url_free(resource);
     682          32 :         return FAILURE;
     683             : }
     684             : /* }}} */
     685             : 
     686             : /**
     687             :  * Unlink a file within a phar archive
     688             :  */
     689          19 : static int phar_wrapper_unlink(php_stream_wrapper *wrapper, char *url, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
     690             : {
     691             :         php_url *resource;
     692             :         char *internal_file, *error;
     693             :         int internal_file_len;
     694             :         phar_entry_data *idata;
     695             :         phar_archive_data **pphar;
     696             :         uint host_len;
     697             : 
     698          19 :         if ((resource = phar_parse_url(wrapper, url, "rb", options TSRMLS_CC)) == NULL) {
     699           3 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: unlink failed");
     700           3 :                 return 0;
     701             :         }
     702             : 
     703             :         /* we must have at the very least phar://alias.phar/internalfile.php */
     704          16 :         if (!resource->scheme || !resource->host || !resource->path) {
     705           0 :                 php_url_free(resource);
     706           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: invalid url \"%s\"", url);
     707           0 :                 return 0;
     708             :         }
     709             : 
     710          16 :         if (strcasecmp("phar", resource->scheme)) {
     711           0 :                 php_url_free(resource);
     712           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: not a phar stream url \"%s\"", url);
     713           0 :                 return 0;
     714             :         }
     715             : 
     716          16 :         host_len = strlen(resource->host);
     717          16 :         phar_request_initialize(TSRMLS_C);
     718             : 
     719          16 :         if (FAILURE == zend_hash_find(&(PHAR_GLOBALS->phar_fname_map), resource->host, host_len, (void **) &pphar)) {
     720           0 :                 pphar = NULL;
     721             :         }
     722          16 :         if (PHAR_G(readonly) && (!pphar || !(*pphar)->is_data)) {
     723           3 :                 php_url_free(resource);
     724           3 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: write operations disabled by the php.ini setting phar.readonly");
     725           3 :                 return 0;
     726             :         }
     727             : 
     728             :         /* need to copy to strip leading "/", will get touched again */
     729          13 :         internal_file = estrdup(resource->path + 1);
     730          13 :         internal_file_len = strlen(internal_file);
     731          13 :         if (FAILURE == phar_get_entry_data(&idata, resource->host, host_len, internal_file, internal_file_len, "r", 0, &error, 1 TSRMLS_CC)) {
     732             :                 /* constraints of fp refcount were not met */
     733           1 :                 if (error) {
     734           0 :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed: %s", url, error);
     735           0 :                         efree(error);
     736             :                 } else {
     737           1 :                         php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "unlink of \"%s\" failed, file does not exist", url);
     738             :                 }
     739           1 :                 efree(internal_file);
     740           1 :                 php_url_free(resource);
     741           1 :                 return 0;
     742             :         }
     743          12 :         if (error) {
     744           0 :                 efree(error);
     745             :         }
     746          12 :         if (idata->internal_file->fp_refcount > 1) {
     747             :                 /* more than just our fp resource is open for this file */
     748           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);
     749           3 :                 efree(internal_file);
     750           3 :                 php_url_free(resource);
     751           3 :                 phar_entry_delref(idata TSRMLS_CC);
     752           3 :                 return 0;
     753             :         }
     754           9 :         php_url_free(resource);
     755           9 :         efree(internal_file);
     756           9 :         phar_entry_remove(idata, &error TSRMLS_CC);
     757           9 :         if (error) {
     758           0 :                 php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", error);
     759           0 :                 efree(error);
     760             :         }
     761           9 :         return 1;
     762             : }
     763             : /* }}} */
     764             : 
     765          15 : static int phar_wrapper_rename(php_stream_wrapper *wrapper, char *url_from, char *url_to, int options, php_stream_context *context TSRMLS_DC) /* {{{ */
     766             : {
     767             :         php_url *resource_from, *resource_to;
     768             :         char *error;
     769             :         phar_archive_data *phar, *pfrom, *pto;
     770             :         phar_entry_info *entry;
     771             :         uint host_len;
     772          15 :         int is_dir = 0;
     773          15 :         int is_modified = 0;
     774             : 
     775          15 :         error = NULL;
     776             : 
     777          15 :         if ((resource_from = phar_parse_url(wrapper, url_from, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
     778           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": invalid or non-writable url \"%s\"", url_from, url_to, url_from);
     779           2 :                 return 0;
     780             :         }
     781          13 :         if (SUCCESS != phar_get_archive(&pfrom, resource_from->host, strlen(resource_from->host), NULL, 0, &error TSRMLS_CC)) {
     782           0 :                 pfrom = NULL;
     783           0 :                 if (error) {
     784           0 :                         efree(error);
     785             :                 }
     786             :         }
     787          13 :         if (PHAR_G(readonly) && (!pfrom || !pfrom->is_data)) {
     788           0 :                 php_url_free(resource_from);
     789           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: Write operations disabled by the php.ini setting phar.readonly");
     790           0 :                 return 0;
     791             :         }
     792             : 
     793          13 :         if ((resource_to = phar_parse_url(wrapper, url_to, "wb", options|PHP_STREAM_URL_STAT_QUIET TSRMLS_CC)) == NULL) {
     794           2 :                 php_url_free(resource_from);
     795           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);
     796           2 :                 return 0;
     797             :         }
     798          11 :         if (SUCCESS != phar_get_archive(&pto, resource_to->host, strlen(resource_to->host), NULL, 0, &error TSRMLS_CC)) {
     799           0 :                 if (error) {
     800           0 :                         efree(error);
     801             :                 }
     802           0 :                 pto = NULL;
     803             :         }
     804          11 :         if (PHAR_G(readonly) && (!pto || !pto->is_data)) {
     805           0 :                 php_url_free(resource_from);
     806           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: Write operations disabled by the php.ini setting phar.readonly");
     807           0 :                 return 0;
     808             :         }
     809             : 
     810          11 :         if (strcmp(resource_from->host, resource_to->host)) {
     811           1 :                 php_url_free(resource_from);
     812           1 :                 php_url_free(resource_to);
     813           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);
     814           1 :                 return 0;
     815             :         }
     816             : 
     817             :         /* we must have at the very least phar://alias.phar/internalfile.php */
     818          10 :         if (!resource_from->scheme || !resource_from->host || !resource_from->path) {
     819           0 :                 php_url_free(resource_from);
     820           0 :                 php_url_free(resource_to);
     821           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);
     822           0 :                 return 0;
     823             :         }
     824             : 
     825          10 :         if (!resource_to->scheme || !resource_to->host || !resource_to->path) {
     826           0 :                 php_url_free(resource_from);
     827           0 :                 php_url_free(resource_to);
     828           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);
     829           0 :                 return 0;
     830             :         }
     831             : 
     832          10 :         if (strcasecmp("phar", resource_from->scheme)) {
     833           0 :                 php_url_free(resource_from);
     834           0 :                 php_url_free(resource_to);
     835           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);
     836           0 :                 return 0;
     837             :         }
     838             : 
     839          10 :         if (strcasecmp("phar", resource_to->scheme)) {
     840           0 :                 php_url_free(resource_from);
     841           0 :                 php_url_free(resource_to);
     842           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": not a phar stream url \"%s\"", url_from, url_to, url_to);
     843           0 :                 return 0;
     844             :         }
     845             : 
     846          10 :         host_len = strlen(resource_from->host);
     847             : 
     848          10 :         if (SUCCESS != phar_get_archive(&phar, resource_from->host, host_len, NULL, 0, &error 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\": %s", url_from, url_to, error);
     852           0 :                 efree(error);
     853           0 :                 return 0;
     854             :         }
     855             : 
     856          10 :         if (phar->is_persistent && FAILURE == phar_copy_on_write(&phar TSRMLS_CC)) {
     857           0 :                 php_url_free(resource_from);
     858           0 :                 php_url_free(resource_to);
     859           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);
     860           0 :                 return 0;
     861             :         }
     862             : 
     863          10 :         if (SUCCESS == zend_hash_find(&(phar->manifest), resource_from->path+1, strlen(resource_from->path)-1, (void **)&entry)) {
     864             :                 phar_entry_info new, *source;
     865             : 
     866             :                 /* perform rename magic */
     867           5 :                 if (entry->is_deleted) {
     868           0 :                         php_url_free(resource_from);
     869           0 :                         php_url_free(resource_to);
     870           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);
     871           0 :                         return 0;
     872             :                 }
     873             :                 /* transfer all data over to the new entry */
     874           5 :                 memcpy((void *) &new, (void *) entry, sizeof(phar_entry_info));
     875             :                 /* mark the old one for deletion */
     876           5 :                 entry->is_deleted = 1;
     877           5 :                 entry->fp = NULL;
     878           5 :                 entry->metadata = 0;
     879           5 :                 entry->link = entry->tmp = NULL;
     880           5 :                 source = entry;
     881             : 
     882             :                 /* add to the manifest, and then store the pointer to the new guy in entry */
     883           5 :                 zend_hash_add(&(phar->manifest), resource_to->path+1, strlen(resource_to->path)-1, (void **)&new, sizeof(phar_entry_info), (void **) &entry);
     884             : 
     885           5 :                 entry->filename = estrdup(resource_to->path+1);
     886           5 :                 if (FAILURE == phar_copy_entry_fp(source, entry, &error TSRMLS_CC)) {
     887           0 :                         php_url_free(resource_from);
     888           0 :                         php_url_free(resource_to);
     889           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
     890           0 :                         efree(error);
     891           0 :                         zend_hash_del(&(phar->manifest), entry->filename, strlen(entry->filename));
     892           0 :                         return 0;
     893             :                 }
     894           5 :                 is_modified = 1;
     895           5 :                 entry->is_modified = 1;
     896           5 :                 entry->filename_len = strlen(entry->filename);
     897           5 :                 is_dir = entry->is_dir;
     898             :         } else {
     899           5 :                 is_dir = zend_hash_exists(&(phar->virtual_dirs), resource_from->path+1, strlen(resource_from->path)-1);
     900           5 :                 if (!is_dir) {
     901             :                         /* file does not exist */
     902           1 :                         php_url_free(resource_from);
     903           1 :                         php_url_free(resource_to);
     904           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);
     905           1 :                         return 0;
     906             : 
     907             :                 }
     908             :         }
     909             : 
     910             :         /* Rename directory. Update all nested paths */
     911           9 :         if (is_dir) {
     912             :                 int key_type;
     913             :                 phar_zstr key, new_key;
     914             :                 char *str_key, *new_str_key;
     915             :                 uint key_len, new_key_len;
     916             :                 ulong unused;
     917           4 :                 uint from_len = strlen(resource_from->path+1);
     918           4 :                 uint to_len = strlen(resource_to->path+1);
     919             : 
     920          26 :                 for (zend_hash_internal_pointer_reset(&phar->manifest);
     921          13 :                         HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->manifest, &key, &key_len, &unused, 0, NULL)) &&
     922           9 :                         SUCCESS == zend_hash_get_current_data(&phar->manifest, (void **) &entry);
     923           9 :                         zend_hash_move_forward(&phar->manifest)) {
     924             : 
     925           9 :                         PHAR_STR(key, str_key);
     926             : 
     927          34 :                         if (!entry->is_deleted &&
     928           9 :                                 key_len > from_len &&
     929           9 :                                 memcmp(str_key, resource_from->path+1, from_len) == 0 &&
     930           7 :                                 IS_SLASH(str_key[from_len])) {
     931             : 
     932           7 :                                 new_key_len = key_len + to_len - from_len;
     933           7 :                                 new_str_key = emalloc(new_key_len+1);
     934           7 :                                 memcpy(new_str_key, resource_to->path + 1, to_len);
     935           7 :                                 memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len);
     936           7 :                                 new_str_key[new_key_len] = 0;
     937             : 
     938           7 :                                 is_modified = 1;
     939           7 :                                 entry->is_modified = 1;
     940           7 :                                 efree(entry->filename);
     941           7 :                                 entry->filename = new_str_key;
     942           7 :                                 entry->filename_len = new_key_len;
     943             : 
     944           7 :                                 PHAR_ZSTR(new_str_key, new_key);
     945             : #if PHP_VERSION_ID < 50300
     946             :                                 zend_hash_update_current_key_ex(&phar->manifest, key_type, new_key, new_key_len, 0, NULL);
     947             : #else
     948           7 :                                 zend_hash_update_current_key_ex(&phar->manifest, key_type, new_key, new_key_len, 0, HASH_UPDATE_KEY_ANYWAY, NULL);
     949             : #endif
     950             :                         }
     951             :                         PHAR_STR_FREE(str_key);
     952             :                 }
     953             : 
     954          15 :                 for (zend_hash_internal_pointer_reset(&phar->virtual_dirs);
     955          11 :                         HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->virtual_dirs, &key, &key_len, &unused, 0, NULL));
     956           7 :                         zend_hash_move_forward(&phar->virtual_dirs)) {
     957             : 
     958           7 :                         PHAR_STR(key, str_key);
     959             : 
     960          20 :                         if (key_len >= from_len &&
     961           7 :                                 memcmp(str_key, resource_from->path+1, from_len) == 0 &&
     962           6 :                                 (key_len == from_len || IS_SLASH(str_key[from_len]))) {
     963             : 
     964           5 :                                 new_key_len = key_len + to_len - from_len;
     965           5 :                                 new_str_key = emalloc(new_key_len+1);
     966           5 :                                 memcpy(new_str_key, resource_to->path + 1, to_len);
     967           5 :                                 memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len);
     968           5 :                                 new_str_key[new_key_len] = 0;
     969             : 
     970           5 :                                 PHAR_ZSTR(new_str_key, new_key);
     971             : #if PHP_VERSION_ID < 50300
     972             :                                 zend_hash_update_current_key_ex(&phar->virtual_dirs, key_type, new_key, new_key_len, 0, NULL);
     973             : #else
     974           5 :                                 zend_hash_update_current_key_ex(&phar->virtual_dirs, key_type, new_key, new_key_len, 0, HASH_UPDATE_KEY_ANYWAY, NULL);
     975             : #endif
     976           5 :                                 efree(new_str_key);
     977             :                         }
     978             :                         PHAR_STR_FREE(str_key);
     979             :                 }
     980             : 
     981          10 :                 for (zend_hash_internal_pointer_reset(&phar->mounted_dirs);
     982           5 :                         HASH_KEY_NON_EXISTANT != (key_type = zend_hash_get_current_key_ex(&phar->mounted_dirs, &key, &key_len, &unused, 0, NULL)) &&
     983           1 :                         SUCCESS == zend_hash_get_current_data(&phar->mounted_dirs, (void **) &entry);
     984           1 :                         zend_hash_move_forward(&phar->mounted_dirs)) {
     985             : 
     986           1 :                         PHAR_STR(key, str_key);
     987             : 
     988           4 :                         if (key_len >= from_len &&
     989           1 :                                 memcmp(str_key, resource_from->path+1, from_len) == 0 &&
     990           2 :                                 (key_len == from_len || IS_SLASH(str_key[from_len]))) {
     991             : 
     992           1 :                                 new_key_len = key_len + to_len - from_len;
     993           1 :                                 new_str_key = emalloc(new_key_len+1);
     994           1 :                                 memcpy(new_str_key, resource_to->path + 1, to_len);
     995           1 :                                 memcpy(new_str_key + to_len, str_key + from_len, key_len - from_len);
     996           1 :                                 new_str_key[new_key_len] = 0;
     997             : 
     998           1 :                                 PHAR_ZSTR(new_str_key, new_key);
     999             : #if PHP_VERSION_ID < 50300
    1000             :                                 zend_hash_update_current_key_ex(&phar->mounted_dirs, key_type, new_key, new_key_len, 0, NULL);
    1001             : #else
    1002           1 :                                 zend_hash_update_current_key_ex(&phar->mounted_dirs, key_type, new_key, new_key_len, 0, HASH_UPDATE_KEY_ANYWAY, NULL);
    1003             : #endif
    1004           1 :                                 efree(new_str_key);
    1005             :                         }
    1006             :                         PHAR_STR_FREE(str_key);
    1007             :                 }
    1008             :         }
    1009             : 
    1010           9 :         if (is_modified) {
    1011           9 :                 phar_flush(phar, 0, 0, 0, &error TSRMLS_CC);
    1012           9 :                 if (error) {
    1013           0 :                         php_url_free(resource_from);
    1014           0 :                         php_url_free(resource_to);
    1015           0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "phar error: cannot rename \"%s\" to \"%s\": %s", url_from, url_to, error);
    1016           0 :                         efree(error);
    1017           0 :                         return 0;
    1018             :                 }
    1019             :         }
    1020             : 
    1021           9 :         php_url_free(resource_from);
    1022           9 :         php_url_free(resource_to);
    1023             : 
    1024           9 :         return 1;
    1025             : }
    1026             : /* }}} */
    1027             : 
    1028             : /*
    1029             :  * Local variables:
    1030             :  * tab-width: 4
    1031             :  * c-basic-offset: 4
    1032             :  * End:
    1033             :  * vim600: noet sw=4 ts=4 fdm=marker
    1034             :  * vim<600: noet sw=4 ts=4
    1035             :  */

Generated by: LCOV version 1.10

Generated at Sat, 13 Sep 2014 16:24:31 +0000 (2 days ago)

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